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