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