dispatch.c revision 41162
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 * $Id: dispatch.c,v 1.25 1998/07/18 09:41:58 jkh Exp $ 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); 48 49static struct _word { 50 char *name; 51 int (*handler)(dialogMenuItem *self); 52} resWords[] = { 53 { "configAnonFTP", configAnonFTP }, 54 { "configRouter", configRouter }, 55 { "configNFSServer", configNFSServer }, 56 { "configNTP", configNTP }, 57 { "configPCNFSD", configPCNFSD }, 58 { "configPackages", configPackages }, 59 { "configRegister", configRegister }, 60 { "configUsers", configUsers }, 61 { "configXEnvironment", configXEnvironment }, 62 { "diskPartitionEditor", diskPartitionEditor }, 63 { "diskPartitionWrite", diskPartitionWrite }, 64 { "diskLabelEditor", diskLabelEditor }, 65 { "diskLabelCommit", diskLabelCommit }, 66 { "distReset", distReset }, 67 { "distSetCustom", distSetCustom }, 68 { "distSetDeveloper", distSetDeveloper }, 69 { "distSetXDeveloper", distSetXDeveloper }, 70 { "distSetKernDeveloper", distSetKernDeveloper }, 71 { "distSetUser", distSetUser }, 72 { "distSetXUser", distSetXUser }, 73 { "distSetMinimum", distSetMinimum }, 74 { "distSetEverything", distSetEverything }, 75 { "distSetDES", distSetDES }, 76 { "distSetSrc", distSetSrc }, 77 { "distSetXF86", distSetXF86 }, 78 { "distExtractAll", distExtractAll }, 79 { "docBrowser", docBrowser }, 80 { "docShowDocument", docShowDocument }, 81 { "installCommit", installCommit }, 82 { "installExpress", installExpress }, 83 { "installNovice", installNovice }, 84 { "installUpgrade", installUpgrade }, 85 { "installFixupBin", installFixupBin }, 86 { "installFixupXFree", installFixupXFree }, 87 { "installFixitHoloShell", installFixitHoloShell }, 88 { "installFixitCDROM", installFixitCDROM }, 89 { "installFixitFloppy", installFixitFloppy }, 90 { "installFilesystems", installFilesystems }, 91 { "installVarDefaults", installVarDefaults }, 92 { "loadConfig", dispatch_load_file }, 93 { "loadFloppyConfig", dispatch_load_floppy }, 94 { "mediaSetCDROM", mediaSetCDROM }, 95 { "mediaSetFloppy", mediaSetFloppy }, 96 { "mediaSetDOS", mediaSetDOS }, 97 { "mediaSetTape", mediaSetTape }, 98 { "mediaSetFTP", mediaSetFTP }, 99 { "mediaSetFTPActive", mediaSetFTPActive }, 100 { "mediaSetFTPPassive", mediaSetFTPPassive }, 101 { "mediaSetUFS", mediaSetUFS }, 102 { "mediaSetNFS", mediaSetNFS }, 103 { "mediaSetFTPUserPass", mediaSetFTPUserPass }, 104 { "mediaSetCPIOVerbosity", mediaSetCPIOVerbosity }, 105 { "mediaGetType", mediaGetType }, 106 { "msgConfirm", dispatch_msgConfirm }, 107 { "optionsEditor", optionsEditor }, 108 { "register", configRegister }, /* Alias */ 109 { "packageAdd", packageAdd }, 110 { "addGroup", userAddGroup }, 111 { "addUser", userAddUser }, 112 { "shutdown", dispatch_shutdown }, 113 { "system", dispatch_systemExecute }, 114 { "dumpVariables", dump_variables }, 115 { "tcpMenuSelect", tcpMenuSelect }, 116 { NULL, NULL }, 117}; 118 119/* 120 * Helper routines for buffering data. 121 * 122 * We read an entire configuration into memory before executing it 123 * so that we are truely standalone and can do things like nuke the 124 * file or disk we're working on. 125 */ 126 127typedef struct command_buffer_ { 128 qelement queue; 129 char * string; 130} command_buffer; 131 132static void 133dispatch_free_command(command_buffer *item) 134{ 135 REMQUE(item); 136 free(item->string); 137 free(item); 138} 139 140static void 141dispatch_free_all(qelement *head) 142{ 143 command_buffer *item; 144 145 while (!EMPTYQUE(*head)) { 146 item = (command_buffer *) head->q_forw; 147 dispatch_free_command(item); 148 } 149} 150 151static command_buffer * 152dispatch_add_command(qelement *head, char *string) 153{ 154 command_buffer *new; 155 156 new = malloc(sizeof(command_buffer)); 157 158 if (!new) 159 return NULL; 160 161 new->string = strdup(string); 162 INSQUEUE(new, head->q_back); 163 164 return new; 165} 166 167/* 168 * Command processing 169 */ 170 171/* Just convenience */ 172static int 173dispatch_shutdown(dialogMenuItem *unused) 174{ 175 systemShutdown(0); 176 return DITEM_FAILURE; 177} 178 179static int 180dispatch_systemExecute(dialogMenuItem *unused) 181{ 182 char *cmd = variable_get(VAR_COMMAND); 183 184 if (cmd) 185 return systemExecute(cmd) ? DITEM_FAILURE : DITEM_SUCCESS; 186 else 187 msgDebug("_systemExecute: No command passed in `command' variable.\n"); 188 return DITEM_FAILURE; 189} 190 191static int 192dispatch_msgConfirm(dialogMenuItem *unused) 193{ 194 char *msg = variable_get(VAR_COMMAND); 195 196 if (msg) { 197 msgConfirm(msg); 198 return DITEM_SUCCESS; 199 } 200 201 msgDebug("_msgConfirm: No message passed in `command' variable.\n"); 202 return DITEM_FAILURE; 203} 204 205static int 206call_possible_resword(char *name, dialogMenuItem *value, int *status) 207{ 208 int i, rval; 209 210 rval = 0; 211 for (i = 0; resWords[i].name; i++) { 212 if (!strcmp(name, resWords[i].name)) { 213 *status = resWords[i].handler(value); 214 rval = 1; 215 break; 216 } 217 } 218 return rval; 219} 220 221/* For a given string, call it or spit out an undefined command diagnostic */ 222int 223dispatchCommand(char *str) 224{ 225 int i; 226 char *cp; 227 228 if (!str || !*str) { 229 msgConfirm("Null or zero-length string passed to dispatchCommand"); 230 return DITEM_FAILURE; 231 } 232 /* If it's got a newline, trim it */ 233 if ((cp = index(str, '\n')) != NULL) 234 *cp = '\0'; 235 236 /* If it's got a `=' sign in there, assume it's a variable setting */ 237 if (index(str, '=')) { 238 if (isDebug()) 239 msgDebug("dispatch: setting variable `%s'\n", str); 240 variable_set(str); 241 i = DITEM_SUCCESS; 242 } 243 else { 244 /* A command might be a pathname if it's encoded in argv[0], which 245 we also support */ 246 if ((cp = rindex(str, '/')) != NULL) 247 str = cp + 1; 248 if (isDebug()) 249 msgDebug("dispatch: calling resword `%s'\n", str); 250 if (!call_possible_resword(str, NULL, &i)) { 251 msgNotify("Warning: No such command ``%s''", str); 252 i = DITEM_FAILURE; 253 } 254 } 255 return i; 256} 257 258 259/* 260 * File processing 261 */ 262 263static qelement * 264dispatch_load_fp(FILE *fp) 265{ 266 qelement *head; 267 char buf[BUFSIZ], *cp; 268 269 head = malloc(sizeof(qelement)); 270 271 if (!head) 272 return NULL; 273 274 INITQUE(*head); 275 276 while (fgets(buf, sizeof buf, fp)) { 277 278 if ((cp = strchr(buf, '\n')) != NULL) 279 *cp = '\0'; 280 if (*buf == '\0' || *buf == '#') 281 continue; 282 283 if (!dispatch_add_command(head, buf)) 284 return NULL; 285 } 286 287 return head; 288} 289 290static int 291dispatch_execute(qelement *head) 292{ 293 int result = DITEM_SUCCESS; 294 command_buffer *item; 295 char *old_interactive; 296 297 if (!head) 298 return result | DITEM_FAILURE; 299 300 old_interactive = variable_get(VAR_NONINTERACTIVE); 301 if (old_interactive) 302 old_interactive = strdup(old_interactive); /* save copy */ 303 304 /* Hint to others that we're running from a script, should they care */ 305 variable_set2(VAR_NONINTERACTIVE, "yes"); 306 307 while (!EMPTYQUE(*head)) { 308 item = (command_buffer *) head->q_forw; 309 310 if (DITEM_STATUS(dispatchCommand(item->string)) != DITEM_SUCCESS) { 311 /* 312 * Allow a user to prefix a command with "noError" to cause 313 * us to ignore any errors for that one command. 314 */ 315 if (variable_get(VAR_NO_ERROR)) 316 variable_unset(VAR_NO_ERROR); 317 else { 318 msgConfirm("Command `%s' failed - rest of script aborted.\n", 319 item->string); 320 result |= DITEM_FAILURE; 321 break; 322 } 323 } 324 dispatch_free_command(item); 325 } 326 327 dispatch_free_all(head); 328 329 if (!old_interactive) 330 variable_unset(VAR_NONINTERACTIVE); 331 else { 332 variable_set2(VAR_NONINTERACTIVE, old_interactive); 333 free(old_interactive); 334 } 335 336 return result; 337} 338 339int 340dispatch_load_file_int(int quiet) 341{ 342 FILE *fp; 343 char *cp; 344 int i; 345 qelement *list; 346 347 static const char *names[] = { 348 "install.cfg", 349 "/stand/install.cfg", 350 "/tmp/install.cfg", 351 NULL 352 }; 353 354 fp = NULL; 355 cp = variable_get(VAR_CONFIG_FILE); 356 if (!cp) { 357 for (i = 0; names[i]; i++) 358 if ((fp = fopen(names[i], "r")) != NULL) 359 break; 360 } else 361 fp = fopen(cp, "r"); 362 363 if (!fp) { 364 if (!quiet) 365 msgConfirm("Unable to open %s: %s", cp, strerror(errno)); 366 return DITEM_FAILURE; 367 } 368 369 list = dispatch_load_fp(fp); 370 fclose(fp); 371 372 return dispatch_execute(list); 373} 374 375int 376dispatch_load_file(dialogMenuItem *self) 377{ 378 return dispatch_load_file_int(FALSE); 379} 380 381int 382dispatch_load_floppy(dialogMenuItem *self) 383{ 384 int what = DITEM_RESTORE | DITEM_SUCCESS; 385 extern char *distWanted; 386 char *cp; 387 FILE *fp; 388 qelement *list; 389 390 mediaClose(); 391 dialog_clear_norefresh(); 392 393 cp = variable_get_value(VAR_INSTALL_CFG, 394 "Specify the name of a configuration file\n" 395 "residing on a MSDOS or UFS floppy."); 396 if (!cp || !*cp) { 397 variable_unset(VAR_INSTALL_CFG); 398 what |= DITEM_FAILURE; 399 return what; 400 } 401 402 distWanted = cp; 403 /* Try to open the floppy drive */ 404 if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) { 405 msgConfirm("Unable to set media device to floppy."); 406 what |= DITEM_FAILURE; 407 mediaClose(); 408 return what; 409 } 410 411 if (!mediaDevice->init(mediaDevice)) { 412 msgConfirm("Unable to mount floppy filesystem."); 413 what |= DITEM_FAILURE; 414 mediaClose(); 415 return what; 416 } 417 418 fp = mediaDevice->get(mediaDevice, cp, TRUE); 419 if (fp) { 420 list = dispatch_load_fp(fp); 421 fclose(fp); 422 mediaClose(); 423 424 what |= dispatch_execute(list); 425 } 426 else { 427 if (!variable_get(VAR_NO_ERROR)) 428 msgConfirm("Configuration file '%s' not found.", cp); 429 variable_unset(VAR_INSTALL_CFG); 430 what |= DITEM_FAILURE; 431 mediaClose(); 432 } 433 434 return what; 435} 436 437