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