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