dispatch.c revision 107330
1/* 2 * The new sysinstall program. 3 * 4 * This is probably the last program in the `sysinstall' line - the next 5 * generation being essentially a complete rewrite. 6 * 7 * $FreeBSD: head/usr.sbin/sade/dispatch.c 107330 2002-11-27 18:36:30Z jhb $ 8 * 9 * Copyright (c) 1995 10 * Jordan Hubbard. All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer, 17 * verbatim and that no modifications are made prior to this 18 * point in the file. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 */ 36 37#include "sysinstall.h" 38#include <ctype.h> 39#include <errno.h> 40#include <sys/signal.h> 41#include <sys/fcntl.h> 42 43#include "list.h" 44 45static int dispatch_shutdown(dialogMenuItem *unused); 46static int dispatch_systemExecute(dialogMenuItem *unused); 47static int dispatch_msgConfirm(dialogMenuItem *unused); 48static int dispatch_mediaClose(dialogMenuItem *unused); 49 50static struct _word { 51 char *name; 52 int (*handler)(dialogMenuItem *self); 53} resWords[] = { 54 { "configAnonFTP", configAnonFTP }, 55 { "configRouter", configRouter }, 56 { "configInetd", configInetd }, 57 { "configNFSServer", configNFSServer }, 58 { "configNTP", configNTP }, 59 { "configPCNFSD", configPCNFSD }, 60 { "configPackages", configPackages }, 61 { "configUsers", configUsers }, 62 { "configXSetup", configXSetup }, 63 { "configXDesktop", configXDesktop }, 64 { "diskPartitionEditor", diskPartitionEditor }, 65 { "diskPartitionWrite", diskPartitionWrite }, 66 { "diskLabelEditor", diskLabelEditor }, 67 { "diskLabelCommit", diskLabelCommit }, 68 { "distReset", distReset }, 69 { "distSetCustom", distSetCustom }, 70 { "distUnsetCustom", distUnsetCustom }, 71 { "distSetDeveloper", distSetDeveloper }, 72 { "distSetXDeveloper", distSetXDeveloper }, 73 { "distSetKernDeveloper", distSetKernDeveloper }, 74 { "distSetUser", distSetUser }, 75 { "distSetXUser", distSetXUser }, 76 { "distSetMinimum", distSetMinimum }, 77 { "distSetEverything", distSetEverything }, 78 { "distSetSrc", distSetSrc }, 79#ifndef X_AS_PKG 80 { "distSetXF86", distSetXF86 }, 81#endif 82 { "distExtractAll", distExtractAll }, 83 { "docBrowser", docBrowser }, 84 { "docShowDocument", docShowDocument }, 85 { "installCommit", installCommit }, 86 { "installExpress", installExpress }, 87 { "installStandard", installStandard }, 88 { "installUpgrade", installUpgrade }, 89 { "installFixupBin", installFixupBin }, 90#ifndef X_AS_PKG 91 { "installFixupXFree", installFixupXFree }, 92#endif 93 { "installFixitHoloShell", installFixitHoloShell }, 94 { "installFixitCDROM", installFixitCDROM }, 95 { "installFixitFloppy", installFixitFloppy }, 96 { "installFilesystems", installFilesystems }, 97 { "installVarDefaults", installVarDefaults }, 98 { "loadConfig", dispatch_load_file }, 99 { "loadFloppyConfig", dispatch_load_floppy }, 100 { "mediaClose", dispatch_mediaClose }, 101 { "mediaSetCDROM", mediaSetCDROM }, 102 { "mediaSetFloppy", mediaSetFloppy }, 103 { "mediaSetDOS", mediaSetDOS }, 104 { "mediaSetTape", mediaSetTape }, 105 { "mediaSetFTP", mediaSetFTP }, 106 { "mediaSetFTPActive", mediaSetFTPActive }, 107 { "mediaSetFTPPassive", mediaSetFTPPassive }, 108 { "mediaSetHTTP", mediaSetHTTP }, 109 { "mediaSetUFS", mediaSetUFS }, 110 { "mediaSetNFS", mediaSetNFS }, 111 { "mediaSetFTPUserPass", mediaSetFTPUserPass }, 112 { "mediaSetCPIOVerbosity", mediaSetCPIOVerbosity }, 113 { "mediaGetType", mediaGetType }, 114 { "msgConfirm", dispatch_msgConfirm }, 115 { "optionsEditor", optionsEditor }, 116 { "packageAdd", packageAdd }, 117 { "addGroup", userAddGroup }, 118 { "addUser", userAddUser }, 119 { "shutdown", dispatch_shutdown }, 120 { "system", dispatch_systemExecute }, 121 { "dumpVariables", dump_variables }, 122 { "tcpMenuSelect", tcpMenuSelect }, 123 { NULL, NULL }, 124}; 125 126/* 127 * Helper routines for buffering data. 128 * 129 * We read an entire configuration into memory before executing it 130 * so that we are truely standalone and can do things like nuke the 131 * file or disk we're working on. 132 */ 133 134typedef struct command_buffer_ { 135 qelement queue; 136 char * string; 137} command_buffer; 138 139static void 140dispatch_free_command(command_buffer *item) 141{ 142 REMQUE(item); 143 free(item->string); 144 free(item); 145} 146 147static void 148dispatch_free_all(qelement *head) 149{ 150 command_buffer *item; 151 152 while (!EMPTYQUE(*head)) { 153 item = (command_buffer *) head->q_forw; 154 dispatch_free_command(item); 155 } 156} 157 158static command_buffer * 159dispatch_add_command(qelement *head, char *string) 160{ 161 command_buffer *new; 162 163 new = malloc(sizeof(command_buffer)); 164 165 if (!new) 166 return NULL; 167 168 new->string = strdup(string); 169 INSQUEUE(new, head->q_back); 170 171 return new; 172} 173 174/* 175 * Command processing 176 */ 177 178/* Just convenience */ 179static int 180dispatch_shutdown(dialogMenuItem *unused) 181{ 182 systemShutdown(0); 183 return DITEM_FAILURE; 184} 185 186static int 187dispatch_systemExecute(dialogMenuItem *unused) 188{ 189 char *cmd = variable_get(VAR_COMMAND); 190 191 if (cmd) 192 return systemExecute(cmd) ? DITEM_FAILURE : DITEM_SUCCESS; 193 else 194 msgDebug("_systemExecute: No command passed in `command' variable.\n"); 195 return DITEM_FAILURE; 196} 197 198static int 199dispatch_msgConfirm(dialogMenuItem *unused) 200{ 201 char *msg = variable_get(VAR_COMMAND); 202 203 if (msg) { 204 msgConfirm("%s", msg); 205 return DITEM_SUCCESS; 206 } 207 208 msgDebug("_msgConfirm: No message passed in `command' variable.\n"); 209 return DITEM_FAILURE; 210} 211 212static int 213dispatch_mediaClose(dialogMenuItem *unused) 214{ 215 mediaClose(); 216 return DITEM_SUCCESS; 217} 218 219static int 220call_possible_resword(char *name, dialogMenuItem *value, int *status) 221{ 222 int i, rval; 223 224 rval = 0; 225 for (i = 0; resWords[i].name; i++) { 226 if (!strcmp(name, resWords[i].name)) { 227 *status = resWords[i].handler(value); 228 rval = 1; 229 break; 230 } 231 } 232 return rval; 233} 234 235/* For a given string, call it or spit out an undefined command diagnostic */ 236int 237dispatchCommand(char *str) 238{ 239 int i; 240 char *cp; 241 242 if (!str || !*str) { 243 msgConfirm("Null or zero-length string passed to dispatchCommand"); 244 return DITEM_FAILURE; 245 } 246 /* If it's got a newline, trim it */ 247 if ((cp = index(str, '\n')) != NULL) 248 *cp = '\0'; 249 250 /* If it's got a `=' sign in there, assume it's a variable setting */ 251 if (index(str, '=')) { 252 if (isDebug()) 253 msgDebug("dispatch: setting variable `%s'\n", str); 254 variable_set(str, 0); 255 i = DITEM_SUCCESS; 256 } 257 else { 258 /* A command might be a pathname if it's encoded in argv[0], which 259 we also support */ 260 if ((cp = rindex(str, '/')) != NULL) 261 str = cp + 1; 262 if (isDebug()) 263 msgDebug("dispatch: calling resword `%s'\n", str); 264 if (!call_possible_resword(str, NULL, &i)) { 265 msgNotify("Warning: No such command ``%s''", str); 266 i = DITEM_FAILURE; 267 } 268 /* 269 * Allow a user to prefix a command with "noError" to cause 270 * us to ignore any errors for that one command. 271 */ 272 if (i != DITEM_SUCCESS && variable_get(VAR_NO_ERROR)) 273 i = DITEM_SUCCESS; 274 variable_unset(VAR_NO_ERROR); 275 } 276 return i; 277} 278 279 280/* 281 * File processing 282 */ 283 284static qelement * 285dispatch_load_fp(FILE *fp) 286{ 287 qelement *head; 288 char buf[BUFSIZ], *cp; 289 290 head = malloc(sizeof(qelement)); 291 292 if (!head) 293 return NULL; 294 295 INITQUE(*head); 296 297 while (fgets(buf, sizeof buf, fp)) { 298 299 if ((cp = strchr(buf, '\n')) != NULL) 300 *cp = '\0'; 301 if (*buf == '\0' || *buf == '#') 302 continue; 303 304 if (!dispatch_add_command(head, buf)) 305 return NULL; 306 } 307 308 return head; 309} 310 311static int 312dispatch_execute(qelement *head) 313{ 314 int result = DITEM_SUCCESS; 315 command_buffer *item; 316 char *old_interactive; 317 318 if (!head) 319 return result | DITEM_FAILURE; 320 321 old_interactive = variable_get(VAR_NONINTERACTIVE); 322 if (old_interactive) 323 old_interactive = strdup(old_interactive); /* save copy */ 324 325 /* Hint to others that we're running from a script, should they care */ 326 variable_set2(VAR_NONINTERACTIVE, "yes", 0); 327 328 while (!EMPTYQUE(*head)) { 329 item = (command_buffer *) head->q_forw; 330 331 if (DITEM_STATUS(dispatchCommand(item->string)) != DITEM_SUCCESS) { 332 msgConfirm("Command `%s' failed - rest of script aborted.\n", 333 item->string); 334 result |= DITEM_FAILURE; 335 break; 336 } 337 dispatch_free_command(item); 338 } 339 340 dispatch_free_all(head); 341 342 if (!old_interactive) 343 variable_unset(VAR_NONINTERACTIVE); 344 else { 345 variable_set2(VAR_NONINTERACTIVE, old_interactive, 0); 346 free(old_interactive); 347 } 348 349 return result; 350} 351 352int 353dispatch_load_file_int(int quiet) 354{ 355 FILE *fp; 356 char *cp; 357 int i; 358 qelement *list; 359 360 static const char *names[] = { 361 "install.cfg", 362 "/stand/install.cfg", 363 "/tmp/install.cfg", 364 NULL 365 }; 366 367 fp = NULL; 368 cp = variable_get(VAR_CONFIG_FILE); 369 if (!cp) { 370 for (i = 0; names[i]; i++) 371 if ((fp = fopen(names[i], "r")) != NULL) 372 break; 373 } else 374 fp = fopen(cp, "r"); 375 376 if (!fp) { 377 if (!quiet) 378 msgConfirm("Unable to open %s: %s", cp, strerror(errno)); 379 return DITEM_FAILURE; 380 } 381 382 list = dispatch_load_fp(fp); 383 fclose(fp); 384 385 return dispatch_execute(list); 386} 387 388int 389dispatch_load_file(dialogMenuItem *self) 390{ 391 return dispatch_load_file_int(FALSE); 392} 393 394int 395dispatch_load_floppy(dialogMenuItem *self) 396{ 397 int what = DITEM_SUCCESS; 398 extern char *distWanted; 399 char *cp; 400 FILE *fp; 401 qelement *list; 402 403 mediaClose(); 404 cp = variable_get_value(VAR_INSTALL_CFG, 405 "Specify the name of a configuration file\n" 406 "residing on a MSDOS or UFS floppy.", 0); 407 if (!cp || !*cp) { 408 variable_unset(VAR_INSTALL_CFG); 409 what |= DITEM_FAILURE; 410 return what; 411 } 412 413 distWanted = cp; 414 /* Try to open the floppy drive */ 415 if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) { 416 msgConfirm("Unable to set media device to floppy."); 417 what |= DITEM_FAILURE; 418 mediaClose(); 419 return what; 420 } 421 422 if (!DEVICE_INIT(mediaDevice)) { 423 msgConfirm("Unable to mount floppy filesystem."); 424 what |= DITEM_FAILURE; 425 mediaClose(); 426 return what; 427 } 428 429 fp = DEVICE_GET(mediaDevice, cp, TRUE); 430 if (fp) { 431 list = dispatch_load_fp(fp); 432 fclose(fp); 433 mediaClose(); 434 435 what |= dispatch_execute(list); 436 } 437 else { 438 if (!variable_get(VAR_NO_ERROR)) 439 msgConfirm("Configuration file '%s' not found.", cp); 440 variable_unset(VAR_INSTALL_CFG); 441 what |= DITEM_FAILURE; 442 mediaClose(); 443 } 444 return what; 445} 446 447