dispatch.c revision 119152
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 119152 2003-08-19 23:23:27Z 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); 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 { "distExtractAll", distExtractAll }, 82 { "docBrowser", docBrowser }, 83 { "docShowDocument", docShowDocument }, 84 { "installCommit", installCommit }, 85 { "installExpress", installExpress }, 86 { "installStandard", installStandard }, 87 { "installUpgrade", installUpgrade }, 88 { "installFixupBase", installFixupBase }, 89 { "installFixitHoloShell", installFixitHoloShell }, 90 { "installFixitCDROM", installFixitCDROM }, 91 { "installFixitFloppy", installFixitFloppy }, 92 { "installFilesystems", installFilesystems }, 93 { "installVarDefaults", installVarDefaults }, 94 { "loadConfig", dispatch_load_file }, 95 { "loadFloppyConfig", dispatch_load_floppy }, 96 { "mediaClose", dispatch_mediaClose }, 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 209dispatch_mediaClose(dialogMenuItem *unused) 210{ 211 mediaClose(); 212 return DITEM_SUCCESS; 213} 214 215static int 216call_possible_resword(char *name, dialogMenuItem *value, int *status) 217{ 218 int i, rval; 219 220 rval = 0; 221 for (i = 0; resWords[i].name; i++) { 222 if (!strcmp(name, resWords[i].name)) { 223 *status = resWords[i].handler(value); 224 rval = 1; 225 break; 226 } 227 } 228 return rval; 229} 230 231/* For a given string, call it or spit out an undefined command diagnostic */ 232int 233dispatchCommand(char *str) 234{ 235 int i; 236 char *cp; 237 238 if (!str || !*str) { 239 msgConfirm("Null or zero-length string passed to dispatchCommand"); 240 return DITEM_FAILURE; 241 } 242 /* If it's got a newline, trim it */ 243 if ((cp = index(str, '\n')) != NULL) 244 *cp = '\0'; 245 246 /* If it's got a `=' sign in there, assume it's a variable setting */ 247 if (index(str, '=')) { 248 if (isDebug()) 249 msgDebug("dispatch: setting variable `%s'\n", str); 250 variable_set(str, 0); 251 i = DITEM_SUCCESS; 252 } 253 else { 254 /* A command might be a pathname if it's encoded in argv[0], which 255 we also support */ 256 if ((cp = rindex(str, '/')) != NULL) 257 str = cp + 1; 258 if (isDebug()) 259 msgDebug("dispatch: calling resword `%s'\n", str); 260 if (!call_possible_resword(str, NULL, &i)) { 261 msgNotify("Warning: No such command ``%s''", str); 262 i = DITEM_FAILURE; 263 } 264 /* 265 * Allow a user to prefix a command with "noError" to cause 266 * us to ignore any errors for that one command. 267 */ 268 if (i != DITEM_SUCCESS && variable_get(VAR_NO_ERROR)) 269 i = DITEM_SUCCESS; 270 variable_unset(VAR_NO_ERROR); 271 } 272 return i; 273} 274 275 276/* 277 * File processing 278 */ 279 280static qelement * 281dispatch_load_fp(FILE *fp) 282{ 283 qelement *head; 284 char buf[BUFSIZ], *cp; 285 286 head = malloc(sizeof(qelement)); 287 288 if (!head) 289 return NULL; 290 291 INITQUE(*head); 292 293 while (fgets(buf, sizeof buf, fp)) { 294 295 if ((cp = strchr(buf, '\n')) != NULL) 296 *cp = '\0'; 297 if (*buf == '\0' || *buf == '#') 298 continue; 299 300 if (!dispatch_add_command(head, buf)) 301 return NULL; 302 } 303 304 return head; 305} 306 307static int 308dispatch_execute(qelement *head) 309{ 310 int result = DITEM_SUCCESS; 311 command_buffer *item; 312 char *old_interactive; 313 314 if (!head) 315 return result | DITEM_FAILURE; 316 317 old_interactive = variable_get(VAR_NONINTERACTIVE); 318 if (old_interactive) 319 old_interactive = strdup(old_interactive); /* save copy */ 320 321 /* Hint to others that we're running from a script, should they care */ 322 variable_set2(VAR_NONINTERACTIVE, "yes", 0); 323 324 while (!EMPTYQUE(*head)) { 325 item = (command_buffer *) head->q_forw; 326 327 if (DITEM_STATUS(dispatchCommand(item->string)) != DITEM_SUCCESS) { 328 msgConfirm("Command `%s' failed - rest of script aborted.\n", 329 item->string); 330 result |= DITEM_FAILURE; 331 break; 332 } 333 dispatch_free_command(item); 334 } 335 336 dispatch_free_all(head); 337 338 if (!old_interactive) 339 variable_unset(VAR_NONINTERACTIVE); 340 else { 341 variable_set2(VAR_NONINTERACTIVE, old_interactive, 0); 342 free(old_interactive); 343 } 344 345 return result; 346} 347 348int 349dispatch_load_file_int(int quiet) 350{ 351 FILE *fp; 352 char *cp; 353 int i; 354 qelement *list; 355 356 static const char *names[] = { 357 "install.cfg", 358 "/stand/install.cfg", 359 "/tmp/install.cfg", 360 NULL 361 }; 362 363 fp = NULL; 364 cp = variable_get(VAR_CONFIG_FILE); 365 if (!cp) { 366 for (i = 0; names[i]; i++) 367 if ((fp = fopen(names[i], "r")) != NULL) 368 break; 369 } else 370 fp = fopen(cp, "r"); 371 372 if (!fp) { 373 if (!quiet) 374 msgConfirm("Unable to open %s: %s", cp, strerror(errno)); 375 return DITEM_FAILURE; 376 } 377 378 list = dispatch_load_fp(fp); 379 fclose(fp); 380 381 return dispatch_execute(list); 382} 383 384int 385dispatch_load_file(dialogMenuItem *self) 386{ 387 return dispatch_load_file_int(FALSE); 388} 389 390int 391dispatch_load_floppy(dialogMenuItem *self) 392{ 393 int what = DITEM_SUCCESS; 394 extern char *distWanted; 395 char *cp; 396 FILE *fp; 397 qelement *list; 398 399 mediaClose(); 400 cp = variable_get_value(VAR_INSTALL_CFG, 401 "Specify the name of a configuration file\n" 402 "residing on a MSDOS or UFS floppy.", 0); 403 if (!cp || !*cp) { 404 variable_unset(VAR_INSTALL_CFG); 405 what |= DITEM_FAILURE; 406 return what; 407 } 408 409 distWanted = cp; 410 /* Try to open the floppy drive */ 411 if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) { 412 msgConfirm("Unable to set media device to floppy."); 413 what |= DITEM_FAILURE; 414 mediaClose(); 415 return what; 416 } 417 418 if (!DEVICE_INIT(mediaDevice)) { 419 msgConfirm("Unable to mount floppy filesystem."); 420 what |= DITEM_FAILURE; 421 mediaClose(); 422 return what; 423 } 424 425 fp = DEVICE_GET(mediaDevice, cp, TRUE); 426 if (fp) { 427 list = dispatch_load_fp(fp); 428 fclose(fp); 429 mediaClose(); 430 431 what |= dispatch_execute(list); 432 } 433 else { 434 if (!variable_get(VAR_NO_ERROR)) 435 msgConfirm("Configuration file '%s' not found.", cp); 436 variable_unset(VAR_INSTALL_CFG); 437 what |= DITEM_FAILURE; 438 mediaClose(); 439 } 440 return what; 441} 442 443