2 * The new sysinstall program.
4 * This is probably the last program in the `sysinstall' line - the next
5 * generation being essentially a complete rewrite.
10 * Jordan Hubbard. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
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
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.
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
37 #include "sysinstall.h"
40 #include <sys/signal.h>
41 #include <sys/fcntl.h>
45 static int dispatch_shutdown(dialogMenuItem *unused);
46 static int dispatch_systemExecute(dialogMenuItem *unused);
47 static int dispatch_msgConfirm(dialogMenuItem *unused);
48 static int dispatch_mediaOpen(dialogMenuItem *unused);
49 static int dispatch_mediaClose(dialogMenuItem *unused);
50 static int cfgModuleFire(dialogMenuItem *self);
54 int (*handler)(dialogMenuItem *self);
56 { "configAnonFTP", configAnonFTP },
57 { "configRouter", configRouter },
58 { "configInetd", configInetd },
59 { "configNFSServer", configNFSServer },
60 { "configNTP", configNTP },
61 { "configPCNFSD", configPCNFSD },
62 { "configPackages", configPackages },
63 { "configUsers", configUsers },
65 { "diskPartitionEditor", diskPartitionEditor },
67 { "diskPartitionWrite", diskPartitionWrite },
68 { "diskLabelEditor", diskLabelEditor },
69 { "diskLabelCommit", diskLabelCommit },
70 { "distReset", distReset },
71 { "distSetCustom", distSetCustom },
72 { "distUnsetCustom", distUnsetCustom },
73 { "distSetDeveloper", distSetDeveloper },
74 { "distSetKernDeveloper", distSetKernDeveloper },
75 { "distSetUser", distSetUser },
76 { "distSetMinimum", distSetMinimum },
77 { "distSetEverything", distSetEverything },
78 { "distSetSrc", distSetSrc },
79 { "distExtractAll", distExtractAll },
80 { "docBrowser", docBrowser },
81 { "docShowDocument", docShowDocument },
82 { "installCommit", installCommit },
83 { "installExpress", installExpress },
84 { "installStandard", installStandard },
85 { "installUpgrade", installUpgrade },
86 { "installFixupBase", installFixupBase },
87 { "installFixitHoloShell", installFixitHoloShell },
88 { "installFixitCDROM", installFixitCDROM },
89 { "installFixitUSB", installFixitUSB },
90 { "installFixitFloppy", installFixitFloppy },
91 { "installFilesystems", installFilesystems },
92 { "installVarDefaults", installVarDefaults },
93 { "loadConfig", dispatch_load_file },
94 { "loadFloppyConfig", dispatch_load_floppy },
95 { "loadCDROMConfig", dispatch_load_cdrom },
96 { "mediaOpen", dispatch_mediaOpen },
97 { "mediaClose", dispatch_mediaClose },
98 { "mediaSetCDROM", mediaSetCDROM },
99 { "mediaSetFloppy", mediaSetFloppy },
100 { "mediaSetUSB", mediaSetUSB },
101 { "mediaSetDOS", mediaSetDOS },
102 { "mediaSetFTP", mediaSetFTP },
103 { "mediaSetFTPActive", mediaSetFTPActive },
104 { "mediaSetFTPPassive", mediaSetFTPPassive },
105 { "mediaSetHTTP", mediaSetHTTP },
106 { "mediaSetUFS", mediaSetUFS },
107 { "mediaSetNFS", mediaSetNFS },
108 { "mediaSetFTPUserPass", mediaSetFTPUserPass },
109 { "mediaSetCPIOVerbosity", mediaSetCPIOVerbosity },
110 { "mediaGetType", mediaGetType },
111 { "msgConfirm", dispatch_msgConfirm },
112 { "optionsEditor", optionsEditor },
113 { "packageAdd", packageAdd },
114 { "addGroup", userAddGroup },
115 { "addUser", userAddUser },
116 { "shutdown", dispatch_shutdown },
117 { "system", dispatch_systemExecute },
118 { "dumpVariables", dump_variables },
119 { "tcpMenuSelect", tcpMenuSelect },
124 * Helper routines for buffering data.
126 * We read an entire configuration into memory before executing it
127 * so that we are truely standalone and can do things like nuke the
128 * file or disk we're working on.
131 typedef struct command_buffer_ {
137 dispatch_free_command(command_buffer *item)
145 dispatch_free_all(qelement *head)
147 command_buffer *item;
149 while (!EMPTYQUE(*head)) {
150 item = (command_buffer *) head->q_forw;
151 dispatch_free_command(item);
155 static command_buffer *
156 dispatch_add_command(qelement *head, char *string)
160 new = malloc(sizeof(command_buffer));
165 new->string = strdup(string);
166 INSQUEUE(new, head->q_back);
175 /* Just convenience */
177 dispatch_shutdown(dialogMenuItem *unused)
180 return DITEM_FAILURE;
184 dispatch_systemExecute(dialogMenuItem *unused)
186 char *cmd = variable_get(VAR_COMMAND);
189 return systemExecute(cmd) ? DITEM_FAILURE : DITEM_SUCCESS;
191 msgDebug("_systemExecute: No command passed in `command' variable.\n");
192 return DITEM_FAILURE;
196 dispatch_msgConfirm(dialogMenuItem *unused)
198 char *msg = variable_get(VAR_COMMAND);
201 msgConfirm("%s", msg);
202 return DITEM_SUCCESS;
205 msgDebug("_msgConfirm: No message passed in `command' variable.\n");
206 return DITEM_FAILURE;
210 dispatch_mediaOpen(dialogMenuItem *unused)
216 dispatch_mediaClose(dialogMenuItem *unused)
219 return DITEM_SUCCESS;
223 call_possible_resword(char *name, dialogMenuItem *value, int *status)
228 for (i = 0; resWords[i].name; i++) {
229 if (!strcmp(name, resWords[i].name)) {
230 *status = resWords[i].handler(value);
238 /* For a given string, call it or spit out an undefined command diagnostic */
240 dispatchCommand(char *str)
246 msgConfirm("Null or zero-length string passed to dispatchCommand");
247 return DITEM_FAILURE;
250 /* Fixup DOS abuse */
251 if ((cp = index(str, '\r')) != NULL)
254 /* If it's got a `=' sign in there, assume it's a variable setting */
255 if (index(str, '=')) {
257 msgDebug("dispatch: setting variable `%s'\n", str);
258 variable_set(str, 0);
262 /* A command might be a pathname if it's encoded in argv[0], which
264 if ((cp = rindex(str, '/')) != NULL)
267 msgDebug("dispatch: calling resword `%s'\n", str);
268 if (!call_possible_resword(str, NULL, &i)) {
269 msgNotify("Warning: No such command ``%s''", str);
273 * Allow a user to prefix a command with "noError" to cause
274 * us to ignore any errors for that one command.
276 if (i != DITEM_SUCCESS && variable_get(VAR_NO_ERROR))
278 variable_unset(VAR_NO_ERROR);
289 dispatch_load_fp(FILE *fp)
292 char buf[BUFSIZ], *cp;
294 head = malloc(sizeof(qelement));
301 while (fgets(buf, sizeof buf, fp)) {
302 /* Fix up DOS abuse */
303 if ((cp = index(buf, '\r')) != NULL)
305 /* If it's got a new line, trim it */
306 if ((cp = index(buf, '\n')) != NULL)
308 if (*buf == '\0' || *buf == '#')
311 if (!dispatch_add_command(head, buf))
319 dispatch_execute(qelement *head)
321 int result = DITEM_SUCCESS;
322 command_buffer *item;
323 char *old_interactive;
326 return result | DITEM_FAILURE;
328 old_interactive = variable_get(VAR_NONINTERACTIVE);
330 old_interactive = strdup(old_interactive); /* save copy */
332 /* Hint to others that we're running from a script, should they care */
333 variable_set2(VAR_NONINTERACTIVE, "yes", 0);
335 while (!EMPTYQUE(*head)) {
336 item = (command_buffer *) head->q_forw;
338 if (DITEM_STATUS(dispatchCommand(item->string)) != DITEM_SUCCESS) {
339 msgConfirm("Command `%s' failed - rest of script aborted.\n",
341 result |= DITEM_FAILURE;
344 dispatch_free_command(item);
347 dispatch_free_all(head);
349 if (!old_interactive)
350 variable_unset(VAR_NONINTERACTIVE);
352 variable_set2(VAR_NONINTERACTIVE, old_interactive, 0);
353 free(old_interactive);
360 dispatch_load_file_int(int quiet)
367 static const char *names[] = {
369 "/stand/install.cfg",
375 cp = variable_get(VAR_CONFIG_FILE);
377 for (i = 0; names[i]; i++)
378 if ((fp = fopen(names[i], "r")) != NULL)
385 msgConfirm("Unable to open %s: %s", cp, strerror(errno));
386 return DITEM_FAILURE;
389 list = dispatch_load_fp(fp);
392 return dispatch_execute(list);
396 dispatch_load_file(dialogMenuItem *self)
398 return dispatch_load_file_int(FALSE);
402 dispatch_load_floppy(dialogMenuItem *self)
404 int what = DITEM_SUCCESS;
405 extern char *distWanted;
411 cp = variable_get_value(VAR_INSTALL_CFG,
412 "Specify the name of a configuration file", 0);
414 variable_unset(VAR_INSTALL_CFG);
415 what |= DITEM_FAILURE;
420 /* Try to open the floppy drive */
421 if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) {
422 msgConfirm("Unable to set media device to floppy.");
423 what |= DITEM_FAILURE;
428 if (!DEVICE_INIT(mediaDevice)) {
429 msgConfirm("Unable to mount floppy filesystem.");
430 what |= DITEM_FAILURE;
435 fp = DEVICE_GET(mediaDevice, cp, TRUE);
437 list = dispatch_load_fp(fp);
441 what |= dispatch_execute(list);
444 if (!variable_get(VAR_NO_ERROR))
445 msgConfirm("Configuration file '%s' not found.", cp);
446 variable_unset(VAR_INSTALL_CFG);
447 what |= DITEM_FAILURE;
454 dispatch_load_cdrom(dialogMenuItem *self)
456 int what = DITEM_SUCCESS;
457 extern char *distWanted;
463 cp = variable_get_value(VAR_INSTALL_CFG,
464 "Specify the name of a configuration file\n"
465 "residing on the CDROM.", 0);
467 variable_unset(VAR_INSTALL_CFG);
468 what |= DITEM_FAILURE;
473 /* Try to open the floppy drive */
474 if (DITEM_STATUS(mediaSetCDROM(NULL)) == DITEM_FAILURE) {
475 msgConfirm("Unable to set media device to CDROM.");
476 what |= DITEM_FAILURE;
481 if (!DEVICE_INIT(mediaDevice)) {
482 msgConfirm("Unable to CDROM filesystem.");
483 what |= DITEM_FAILURE;
488 fp = DEVICE_GET(mediaDevice, cp, TRUE);
490 list = dispatch_load_fp(fp);
494 what |= dispatch_execute(list);
497 if (!variable_get(VAR_NO_ERROR))
498 msgConfirm("Configuration file '%s' not found.", cp);
499 variable_unset(VAR_INSTALL_CFG);
500 what |= DITEM_FAILURE;
507 * Create a menu based on available disk devices
510 dispatch_load_menu(dialogMenuItem *self)
515 int what, i, j, msize, count;
516 DeviceType dtypes[] = {DEVICE_TYPE_FLOPPY, DEVICE_TYPE_CDROM,
517 DEVICE_TYPE_DOS, DEVICE_TYPE_UFS, DEVICE_TYPE_USB};
519 fprintf(stderr, "dispatch_load_menu called\n");
521 msize = sizeof(DMenu) + (sizeof(dialogMenuItem) * 2);
524 what = DITEM_SUCCESS;
526 if ((menu = malloc(msize)) == NULL) {
527 err = "Failed to allocate memory for menu";
531 bcopy(&MenuConfig, menu, sizeof(DMenu));
533 bzero(&menu->items[count], sizeof(menu->items[0]));
534 menu->items[count].prompt = strdup("X Exit");
535 menu->items[count].title = strdup("Exit this menu (returning to previous)");
536 menu->items[count].fire = dmenuExit;
539 for (i = 0; i < sizeof(dtypes) / sizeof(dtypes[0]); i++) {
540 if ((devlist = deviceFind(NULL, dtypes[i])) == NULL) {
541 fprintf(stderr, "No devices found for type %d\n", dtypes[i]);
545 for (j = 0; devlist[j] != NULL; j++) {
546 fprintf(stderr, "device type %d device name %s\n", dtypes[i], devlist[j]->name);
547 msize += sizeof(dialogMenuItem);
548 if ((menu = realloc(menu, msize)) == NULL) {
549 err = "Failed to allocate memory for menu item";
553 bzero(&menu->items[count], sizeof(menu->items[0]));
554 menu->items[count].fire = cfgModuleFire;
556 menu->items[count].prompt = strdup(devlist[j]->name);
557 menu->items[count].title = strdup(devlist[j]->description);
558 /* XXX: dialog(3) sucks */
559 menu->items[count].aux = (long)devlist[j];
564 menu->items[count].prompt = NULL;
565 menu->items[count].title = NULL;
567 dmenuOpenSimple(menu, FALSE);
570 for (i = 0; i < count; i++) {
571 free(menu->items[i].prompt);
572 free(menu->items[i].title);
578 what |= DITEM_FAILURE;
579 if (!variable_get(VAR_NO_ERROR))
588 cfgModuleFire(dialogMenuItem *self) {
591 int what = DITEM_SUCCESS;
592 extern char *distWanted;
596 d = (Device *)self->aux;
598 msgDebug("cfgModuleFire: User selected %s (%s)\n", self->prompt, d->devname);
602 cp = variable_get_value(VAR_INSTALL_CFG,
603 "Specify the name of a configuration file", 0);
605 variable_unset(VAR_INSTALL_CFG);
606 what |= DITEM_FAILURE;
613 if (!DEVICE_INIT(mediaDevice)) {
614 msgConfirm("Unable to mount filesystem.");
615 what |= DITEM_FAILURE;
619 msgDebug("getting fp for %s\n", cp);
621 fp = DEVICE_GET(mediaDevice, cp, TRUE);
623 msgDebug("opened OK, processing..\n");
625 list = dispatch_load_fp(fp);
629 what |= dispatch_execute(list);
631 if (!variable_get(VAR_NO_ERROR))
632 msgConfirm("Configuration file '%s' not found.", cp);
633 variable_unset(VAR_INSTALL_CFG);
634 what |= DITEM_FAILURE;