dispatch.c revision 79304
1151497Sru/* 2104862Sru * The new sysinstall program. 3104862Sru * 4104862Sru * This is probably the last program in the `sysinstall' line - the next 5104862Sru * generation being essentially a complete rewrite. 6104862Sru * 7104862Sru * $FreeBSD: head/usr.sbin/sade/dispatch.c 79304 2001-07-05 09:51:09Z kris $ 8104862Sru * 9104862Sru * Copyright (c) 1995 10104862Sru * Jordan Hubbard. All rights reserved. 11104862Sru * 12104862Sru * Redistribution and use in source and binary forms, with or without 13104862Sru * modification, are permitted provided that the following conditions 14104862Sru * are met: 15104862Sru * 1. Redistributions of source code must retain the above copyright 16104862Sru * notice, this list of conditions and the following disclaimer, 17104862Sru * verbatim and that no modifications are made prior to this 18151497Sru * point in the file. 19104862Sru * 2. Redistributions in binary form must reproduce the above copyright 20114402Sru * notice, this list of conditions and the following disclaimer in the 21114402Sru * documentation and/or other materials provided with the distribution. 22151497Sru * 23114402Sru * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 24151497Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25151497Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26151497Sru * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 27104862Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28104862Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29104862Sru * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 30104862Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31104862Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32104862Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33104862Sru * SUCH DAMAGE. 34104862Sru * 35104862Sru */ 36104862Sru 37104862Sru#include "sysinstall.h" 38104862Sru#include <ctype.h> 39104862Sru#include <errno.h> 40104862Sru#include <sys/signal.h> 41104862Sru#include <sys/fcntl.h> 42104862Sru 43104862Sru#include "list.h" 44104862Sru 45104862Srustatic int dispatch_shutdown(dialogMenuItem *unused); 46104862Srustatic int dispatch_systemExecute(dialogMenuItem *unused); 47104862Srustatic int dispatch_msgConfirm(dialogMenuItem *unused); 48114402Sru 49104862Srustatic struct _word { 50104862Sru char *name; 51114402Sru int (*handler)(dialogMenuItem *self); 52104862Sru} resWords[] = { 53104862Sru { "configAnonFTP", configAnonFTP }, 54104862Sru { "configRouter", configRouter }, 55104862Sru { "configNFSServer", configNFSServer }, 56104862Sru { "configNTP", configNTP }, 57104862Sru { "configPCNFSD", configPCNFSD }, 58104862Sru { "configPackages", configPackages }, 59104862Sru { "configUsers", configUsers }, 60104862Sru { "configXSetup", configXSetup }, 61104862Sru { "configXDesktop", configXDesktop }, 62104862Sru { "diskPartitionEditor", diskPartitionEditor }, 63104862Sru { "diskPartitionWrite", diskPartitionWrite }, 64104862Sru { "diskLabelEditor", diskLabelEditor }, 65104862Sru { "diskLabelCommit", diskLabelCommit }, 66151497Sru { "distReset", distReset }, 67151497Sru { "distSetCustom", distSetCustom }, 68151497Sru { "distUnsetCustom", distUnsetCustom }, 69104862Sru { "distSetDeveloper", distSetDeveloper }, 70104862Sru { "distSetXDeveloper", distSetXDeveloper }, 71104862Sru { "distSetKernDeveloper", distSetKernDeveloper }, 72104862Sru { "distSetUser", distSetUser }, 73104862Sru { "distSetXUser", distSetXUser }, 74151497Sru { "distSetMinimum", distSetMinimum }, 75104862Sru { "distSetEverything", distSetEverything }, 76104862Sru { "distSetSrc", distSetSrc }, 77104862Sru { "distSetXF86", distSetXF86 }, 78104862Sru { "distExtractAll", distExtractAll }, 79104862Sru { "docBrowser", docBrowser }, 80104862Sru { "docShowDocument", docShowDocument }, 81104862Sru { "installCommit", installCommit }, 82104862Sru { "installExpress", installExpress }, 83104862Sru { "installStandard", installStandard }, 84104862Sru { "installUpgrade", installUpgrade }, 85104862Sru { "installFixupBin", installFixupBin }, 86104862Sru { "installFixupXFree", installFixupXFree }, 87104862Sru { "installFixitHoloShell", installFixitHoloShell }, 88104862Sru { "installFixitCDROM", installFixitCDROM }, 89104862Sru { "installFixitFloppy", installFixitFloppy }, 90104862Sru { "installFilesystems", installFilesystems }, 91104862Sru { "installVarDefaults", installVarDefaults }, 92104862Sru { "loadConfig", dispatch_load_file }, 93104862Sru { "loadFloppyConfig", dispatch_load_floppy }, 94104862Sru { "mediaSetCDROM", mediaSetCDROM }, 95104862Sru { "mediaSetFloppy", mediaSetFloppy }, 96151497Sru { "mediaSetDOS", mediaSetDOS }, 97151497Sru { "mediaSetTape", mediaSetTape }, 98151497Sru { "mediaSetFTP", mediaSetFTP }, 99151497Sru { "mediaSetFTPActive", mediaSetFTPActive }, 100151497Sru { "mediaSetFTPPassive", mediaSetFTPPassive }, 101104862Sru { "mediaSetHTTP", mediaSetHTTP }, 102104862Sru { "mediaSetUFS", mediaSetUFS }, 103104862Sru { "mediaSetNFS", mediaSetNFS }, 104104862Sru { "mediaSetFTPUserPass", mediaSetFTPUserPass }, 105104862Sru { "mediaSetCPIOVerbosity", mediaSetCPIOVerbosity }, 106151497Sru { "mediaGetType", mediaGetType }, 107104862Sru { "msgConfirm", dispatch_msgConfirm }, 108104862Sru { "optionsEditor", optionsEditor }, 109104862Sru { "packageAdd", packageAdd }, 110104862Sru { "addGroup", userAddGroup }, 111104862Sru { "addUser", userAddUser }, 112104862Sru { "shutdown", dispatch_shutdown }, 113104862Sru { "system", dispatch_systemExecute }, 114104862Sru { "dumpVariables", dump_variables }, 115104862Sru { "tcpMenuSelect", tcpMenuSelect }, 116104862Sru { NULL, NULL }, 117104862Sru}; 118104862Sru 119104862Sru/* 120104862Sru * Helper routines for buffering data. 121104862Sru * 122104862Sru * We read an entire configuration into memory before executing it 123104862Sru * so that we are truely standalone and can do things like nuke the 124104862Sru * file or disk we're working on. 125104862Sru */ 126104862Sru 127104862Srutypedef struct command_buffer_ { 128104862Sru qelement queue; 129104862Sru char * string; 130104862Sru} command_buffer; 131151497Sru 132151497Srustatic void 133151497Srudispatch_free_command(command_buffer *item) 134104862Sru{ 135151497Sru REMQUE(item); 136151497Sru free(item->string); 137151497Sru free(item); 138151497Sru} 139151497Sru 140151497Srustatic void 141151497Srudispatch_free_all(qelement *head) 142151497Sru{ 143151497Sru command_buffer *item; 144104862Sru 145104862Sru while (!EMPTYQUE(*head)) { 146151497Sru item = (command_buffer *) head->q_forw; 147104862Sru dispatch_free_command(item); 148104862Sru } 149114402Sru} 150114402Sru 151151497Srustatic command_buffer * 152104862Srudispatch_add_command(qelement *head, char *string) 153104862Sru{ 154104862Sru command_buffer *new; 155151497Sru 156151497Sru new = malloc(sizeof(command_buffer)); 157151497Sru 158151497Sru if (!new) 159151497Sru return NULL; 160151497Sru 161104862Sru new->string = strdup(string); 162104862Sru INSQUEUE(new, head->q_back); 163104862Sru 164104862Sru return new; 165104862Sru} 166104862Sru 167104862Sru/* 168104862Sru * Command processing 169104862Sru */ 170104862Sru 171104862Sru/* Just convenience */ 172104862Srustatic int 173104862Srudispatch_shutdown(dialogMenuItem *unused) 174151497Sru{ 175104862Sru systemShutdown(0); 176104862Sru return DITEM_FAILURE; 177104862Sru} 178104862Sru 179104862Srustatic int 180104862Srudispatch_systemExecute(dialogMenuItem *unused) 181104862Sru{ 182104862Sru char *cmd = variable_get(VAR_COMMAND); 183104862Sru 184104862Sru if (cmd) 185104862Sru return systemExecute(cmd) ? DITEM_FAILURE : DITEM_SUCCESS; 186104862Sru else 187104862Sru msgDebug("_systemExecute: No command passed in `command' variable.\n"); 188104862Sru return DITEM_FAILURE; 189104862Sru} 190104862Sru 191104862Srustatic int 192104862Srudispatch_msgConfirm(dialogMenuItem *unused) 193104862Sru{ 194104862Sru char *msg = variable_get(VAR_COMMAND); 195104862Sru 196104862Sru if (msg) { 197104862Sru msgConfirm("%s", msg); 198104862Sru return DITEM_SUCCESS; 199104862Sru } 200151497Sru 201104862Sru msgDebug("_msgConfirm: No message passed in `command' variable.\n"); 202104862Sru return DITEM_FAILURE; 203104862Sru} 204104862Sru 205104862Srustatic int 206104862Srucall_possible_resword(char *name, dialogMenuItem *value, int *status) 207104862Sru{ 208104862Sru int i, rval; 209104862Sru 210104862Sru rval = 0; 211104862Sru for (i = 0; resWords[i].name; i++) { 212104862Sru if (!strcmp(name, resWords[i].name)) { 213104862Sru *status = resWords[i].handler(value); 214104862Sru rval = 1; 215104862Sru break; 216104862Sru } 217151497Sru } 218104862Sru return rval; 219104862Sru} 220151497Sru 221104862Sru/* For a given string, call it or spit out an undefined command diagnostic */ 222104862Sruint 223104862SrudispatchCommand(char *str) 224151497Sru{ 225104862Sru int i; 226104862Sru char *cp; 227104862Sru 228104862Sru if (!str || !*str) { 229151497Sru msgConfirm("Null or zero-length string passed to dispatchCommand"); 230104862Sru return DITEM_FAILURE; 231104862Sru } 232104862Sru /* If it's got a newline, trim it */ 233104862Sru if ((cp = index(str, '\n')) != NULL) 234 *cp = '\0'; 235 236 /* If it's got a `=' sign in there, assume it's a variable setting */ 237 if (index(str, '=')) { 238 if (isDebug()) 239 msgDebug("dispatch: setting variable `%s'\n", str); 240 variable_set(str, 0); 241 i = DITEM_SUCCESS; 242 } 243 else { 244 /* A command might be a pathname if it's encoded in argv[0], which 245 we also support */ 246 if ((cp = rindex(str, '/')) != NULL) 247 str = cp + 1; 248 if (isDebug()) 249 msgDebug("dispatch: calling resword `%s'\n", str); 250 if (!call_possible_resword(str, NULL, &i)) { 251 msgNotify("Warning: No such command ``%s''", str); 252 i = DITEM_FAILURE; 253 } 254 } 255 return i; 256} 257 258 259/* 260 * File processing 261 */ 262 263static qelement * 264dispatch_load_fp(FILE *fp) 265{ 266 qelement *head; 267 char buf[BUFSIZ], *cp; 268 269 head = malloc(sizeof(qelement)); 270 271 if (!head) 272 return NULL; 273 274 INITQUE(*head); 275 276 while (fgets(buf, sizeof buf, fp)) { 277 278 if ((cp = strchr(buf, '\n')) != NULL) 279 *cp = '\0'; 280 if (*buf == '\0' || *buf == '#') 281 continue; 282 283 if (!dispatch_add_command(head, buf)) 284 return NULL; 285 } 286 287 return head; 288} 289 290static int 291dispatch_execute(qelement *head) 292{ 293 int result = DITEM_SUCCESS; 294 command_buffer *item; 295 char *old_interactive; 296 297 if (!head) 298 return result | DITEM_FAILURE; 299 300 old_interactive = variable_get(VAR_NONINTERACTIVE); 301 if (old_interactive) 302 old_interactive = strdup(old_interactive); /* save copy */ 303 304 /* Hint to others that we're running from a script, should they care */ 305 variable_set2(VAR_NONINTERACTIVE, "yes", 0); 306 307 while (!EMPTYQUE(*head)) { 308 item = (command_buffer *) head->q_forw; 309 310 if (DITEM_STATUS(dispatchCommand(item->string)) != DITEM_SUCCESS) { 311 /* 312 * Allow a user to prefix a command with "noError" to cause 313 * us to ignore any errors for that one command. 314 */ 315 if (variable_get(VAR_NO_ERROR)) 316 variable_unset(VAR_NO_ERROR); 317 else { 318 msgConfirm("Command `%s' failed - rest of script aborted.\n", 319 item->string); 320 result |= DITEM_FAILURE; 321 break; 322 } 323 } 324 dispatch_free_command(item); 325 } 326 327 dispatch_free_all(head); 328 329 if (!old_interactive) 330 variable_unset(VAR_NONINTERACTIVE); 331 else { 332 variable_set2(VAR_NONINTERACTIVE, old_interactive, 0); 333 free(old_interactive); 334 } 335 336 return result; 337} 338 339int 340dispatch_load_file_int(int quiet) 341{ 342 FILE *fp; 343 char *cp; 344 int i; 345 qelement *list; 346 347 static const char *names[] = { 348 "install.cfg", 349 "/stand/install.cfg", 350 "/tmp/install.cfg", 351 NULL 352 }; 353 354 fp = NULL; 355 cp = variable_get(VAR_CONFIG_FILE); 356 if (!cp) { 357 for (i = 0; names[i]; i++) 358 if ((fp = fopen(names[i], "r")) != NULL) 359 break; 360 } else 361 fp = fopen(cp, "r"); 362 363 if (!fp) { 364 if (!quiet) 365 msgConfirm("Unable to open %s: %s", cp, strerror(errno)); 366 return DITEM_FAILURE; 367 } 368 369 list = dispatch_load_fp(fp); 370 fclose(fp); 371 372 return dispatch_execute(list); 373} 374 375int 376dispatch_load_file(dialogMenuItem *self) 377{ 378 return dispatch_load_file_int(FALSE); 379} 380 381int 382dispatch_load_floppy(dialogMenuItem *self) 383{ 384 int what = DITEM_SUCCESS; 385 extern char *distWanted; 386 char *cp; 387 FILE *fp; 388 qelement *list; 389 390 mediaClose(); 391 cp = variable_get_value(VAR_INSTALL_CFG, 392 "Specify the name of a configuration file\n" 393 "residing on a MSDOS or UFS floppy.", 0); 394 if (!cp || !*cp) { 395 variable_unset(VAR_INSTALL_CFG); 396 what |= DITEM_FAILURE; 397 return what; 398 } 399 400 distWanted = cp; 401 /* Try to open the floppy drive */ 402 if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) { 403 msgConfirm("Unable to set media device to floppy."); 404 what |= DITEM_FAILURE; 405 mediaClose(); 406 return what; 407 } 408 409 if (!DEVICE_INIT(mediaDevice)) { 410 msgConfirm("Unable to mount floppy filesystem."); 411 what |= DITEM_FAILURE; 412 mediaClose(); 413 return what; 414 } 415 416 fp = DEVICE_GET(mediaDevice, cp, TRUE); 417 if (fp) { 418 list = dispatch_load_fp(fp); 419 fclose(fp); 420 mediaClose(); 421 422 what |= dispatch_execute(list); 423 } 424 else { 425 if (!variable_get(VAR_NO_ERROR)) 426 msgConfirm("Configuration file '%s' not found.", cp); 427 variable_unset(VAR_INSTALL_CFG); 428 what |= DITEM_FAILURE; 429 mediaClose(); 430 } 431 return what; 432} 433 434