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