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)
149 dispatch_free_all(qelement *head)
151 command_buffer *item;
153 while (!EMPTYQUE(*head)) {
154 item = (command_buffer *) head->q_forw;
155 dispatch_free_command(item);
159 static command_buffer *
160 dispatch_add_command(qelement *head, char *string)
162 command_buffer *new = NULL;
164 new = malloc(sizeof(command_buffer));
168 new->string = strdup(string);
171 * We failed to copy `string'; clean up the allocated
174 if (new->string == NULL) {
178 INSQUEUE(new, head->q_back);
189 /* Just convenience */
191 dispatch_shutdown(dialogMenuItem *unused)
194 return DITEM_FAILURE;
198 dispatch_systemExecute(dialogMenuItem *unused)
200 char *cmd = variable_get(VAR_COMMAND);
203 return systemExecute(cmd) ? DITEM_FAILURE : DITEM_SUCCESS;
205 msgDebug("_systemExecute: No command passed in `command' variable.\n");
206 return DITEM_FAILURE;
210 dispatch_msgConfirm(dialogMenuItem *unused)
212 char *msg = variable_get(VAR_COMMAND);
215 msgConfirm("%s", msg);
216 return DITEM_SUCCESS;
219 msgDebug("_msgConfirm: No message passed in `command' variable.\n");
220 return DITEM_FAILURE;
224 dispatch_mediaOpen(dialogMenuItem *unused)
230 dispatch_mediaClose(dialogMenuItem *unused)
233 return DITEM_SUCCESS;
237 call_possible_resword(char *name, dialogMenuItem *value, int *status)
242 for (i = 0; resWords[i].name; i++) {
243 if (!strcmp(name, resWords[i].name)) {
244 *status = resWords[i].handler(value);
252 /* For a given string, call it or spit out an undefined command diagnostic */
254 dispatchCommand(char *str)
260 msgConfirm("Null or zero-length string passed to dispatchCommand");
261 return DITEM_FAILURE;
264 /* Fixup DOS abuse */
265 if ((cp = index(str, '\r')) != NULL)
268 /* If it's got a `=' sign in there, assume it's a variable setting */
269 if (index(str, '=')) {
271 msgDebug("dispatch: setting variable `%s'\n", str);
272 variable_set(str, 0);
276 /* A command might be a pathname if it's encoded in argv[0], which
278 if ((cp = rindex(str, '/')) != NULL)
281 msgDebug("dispatch: calling resword `%s'\n", str);
282 if (!call_possible_resword(str, NULL, &i)) {
283 msgNotify("Warning: No such command ``%s''", str);
287 * Allow a user to prefix a command with "noError" to cause
288 * us to ignore any errors for that one command.
290 if (i != DITEM_SUCCESS && variable_get(VAR_NO_ERROR))
292 variable_unset(VAR_NO_ERROR);
303 dispatch_load_fp(FILE *fp)
306 char buf[BUFSIZ], *cp;
308 head = malloc(sizeof(qelement));
315 while (fgets(buf, sizeof buf, fp)) {
316 /* Fix up DOS abuse */
317 if ((cp = index(buf, '\r')) != NULL)
319 /* If it's got a new line, trim it */
320 if ((cp = index(buf, '\n')) != NULL)
322 if (*buf == '\0' || *buf == '#')
325 if (!dispatch_add_command(head, buf))
333 dispatch_execute(qelement *head)
335 int result = DITEM_SUCCESS;
336 command_buffer *item;
337 char *old_interactive;
340 return result | DITEM_FAILURE;
342 old_interactive = variable_get(VAR_NONINTERACTIVE);
344 old_interactive = strdup(old_interactive); /* save copy */
346 /* Hint to others that we're running from a script, should they care */
347 variable_set2(VAR_NONINTERACTIVE, "yes", 0);
349 while (!EMPTYQUE(*head)) {
350 item = (command_buffer *) head->q_forw;
352 if (DITEM_STATUS(dispatchCommand(item->string)) != DITEM_SUCCESS) {
353 msgConfirm("Command `%s' failed - rest of script aborted.\n",
355 result |= DITEM_FAILURE;
358 dispatch_free_command(item);
361 dispatch_free_all(head);
363 if (!old_interactive)
364 variable_unset(VAR_NONINTERACTIVE);
366 variable_set2(VAR_NONINTERACTIVE, old_interactive, 0);
367 free(old_interactive);
374 dispatch_load_file_int(int quiet)
381 static const char *names[] = {
383 "/stand/install.cfg",
389 cp = variable_get(VAR_CONFIG_FILE);
391 for (i = 0; names[i]; i++)
392 if ((fp = fopen(names[i], "r")) != NULL)
399 msgConfirm("Unable to open %s: %s", cp, strerror(errno));
400 return DITEM_FAILURE;
403 list = dispatch_load_fp(fp);
406 return dispatch_execute(list);
410 dispatch_load_file(dialogMenuItem *self)
412 return dispatch_load_file_int(FALSE);
416 dispatch_load_floppy(dialogMenuItem *self)
418 int what = DITEM_SUCCESS;
419 extern char *distWanted;
425 cp = variable_get_value(VAR_INSTALL_CFG,
426 "Specify the name of a configuration file", 0);
428 variable_unset(VAR_INSTALL_CFG);
429 what |= DITEM_FAILURE;
434 /* Try to open the floppy drive */
435 if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) {
436 msgConfirm("Unable to set media device to floppy.");
437 what |= DITEM_FAILURE;
442 if (!DEVICE_INIT(mediaDevice)) {
443 msgConfirm("Unable to mount floppy filesystem.");
444 what |= DITEM_FAILURE;
449 fp = DEVICE_GET(mediaDevice, cp, TRUE);
451 list = dispatch_load_fp(fp);
455 what |= dispatch_execute(list);
458 if (!variable_get(VAR_NO_ERROR))
459 msgConfirm("Configuration file '%s' not found.", cp);
460 variable_unset(VAR_INSTALL_CFG);
461 what |= DITEM_FAILURE;
468 dispatch_load_cdrom(dialogMenuItem *self)
470 int what = DITEM_SUCCESS;
471 extern char *distWanted;
477 cp = variable_get_value(VAR_INSTALL_CFG,
478 "Specify the name of a configuration file\n"
479 "residing on the CDROM.", 0);
481 variable_unset(VAR_INSTALL_CFG);
482 what |= DITEM_FAILURE;
487 /* Try to open the floppy drive */
488 if (DITEM_STATUS(mediaSetCDROM(NULL)) == DITEM_FAILURE) {
489 msgConfirm("Unable to set media device to CDROM.");
490 what |= DITEM_FAILURE;
495 if (!DEVICE_INIT(mediaDevice)) {
496 msgConfirm("Unable to CDROM filesystem.");
497 what |= DITEM_FAILURE;
502 fp = DEVICE_GET(mediaDevice, cp, TRUE);
504 list = dispatch_load_fp(fp);
508 what |= dispatch_execute(list);
511 if (!variable_get(VAR_NO_ERROR))
512 msgConfirm("Configuration file '%s' not found.", cp);
513 variable_unset(VAR_INSTALL_CFG);
514 what |= DITEM_FAILURE;
521 * Create a menu based on available disk devices
524 dispatch_load_menu(dialogMenuItem *self)
529 int what, i, j, msize, count;
530 DeviceType dtypes[] = {DEVICE_TYPE_FLOPPY, DEVICE_TYPE_CDROM,
531 DEVICE_TYPE_DOS, DEVICE_TYPE_UFS, DEVICE_TYPE_USB};
533 fprintf(stderr, "dispatch_load_menu called\n");
535 msize = sizeof(DMenu) + (sizeof(dialogMenuItem) * 2);
538 what = DITEM_SUCCESS;
540 if ((menu = malloc(msize)) == NULL) {
541 err = "Failed to allocate memory for menu";
545 bcopy(&MenuConfig, menu, sizeof(DMenu));
547 bzero(&menu->items[count], sizeof(menu->items[0]));
548 menu->items[count].prompt = strdup("X Exit");
549 menu->items[count].title = strdup("Exit this menu (returning to previous)");
550 menu->items[count].fire = dmenuExit;
553 for (i = 0; i < sizeof(dtypes) / sizeof(dtypes[0]); i++) {
554 if ((devlist = deviceFind(NULL, dtypes[i])) == NULL) {
555 fprintf(stderr, "No devices found for type %d\n", dtypes[i]);
559 for (j = 0; devlist[j] != NULL; j++) {
560 fprintf(stderr, "device type %d device name %s\n", dtypes[i], devlist[j]->name);
561 msize += sizeof(dialogMenuItem);
562 if ((menu = realloc(menu, msize)) == NULL) {
563 err = "Failed to allocate memory for menu item";
567 bzero(&menu->items[count], sizeof(menu->items[0]));
568 menu->items[count].fire = cfgModuleFire;
570 menu->items[count].prompt = strdup(devlist[j]->name);
571 menu->items[count].title = strdup(devlist[j]->description);
572 /* XXX: dialog(3) sucks */
573 menu->items[count].aux = (long)devlist[j];
578 menu->items[count].prompt = NULL;
579 menu->items[count].title = NULL;
581 dmenuOpenSimple(menu, FALSE);
584 for (i = 0; i < count; i++) {
585 free(menu->items[i].prompt);
586 free(menu->items[i].title);
592 what |= DITEM_FAILURE;
593 if (!variable_get(VAR_NO_ERROR))
602 cfgModuleFire(dialogMenuItem *self) {
605 int what = DITEM_SUCCESS;
606 extern char *distWanted;
610 d = (Device *)self->aux;
612 msgDebug("cfgModuleFire: User selected %s (%s)\n", self->prompt, d->devname);
616 cp = variable_get_value(VAR_INSTALL_CFG,
617 "Specify the name of a configuration file", 0);
619 variable_unset(VAR_INSTALL_CFG);
620 what |= DITEM_FAILURE;
627 if (!DEVICE_INIT(mediaDevice)) {
628 msgConfirm("Unable to mount filesystem.");
629 what |= DITEM_FAILURE;
633 msgDebug("getting fp for %s\n", cp);
635 fp = DEVICE_GET(mediaDevice, cp, TRUE);
637 msgDebug("opened OK, processing..\n");
639 list = dispatch_load_fp(fp);
643 what |= dispatch_execute(list);
645 if (!variable_get(VAR_NO_ERROR))
646 msgConfirm("Configuration file '%s' not found.", cp);
647 variable_unset(VAR_INSTALL_CFG);
648 what |= DITEM_FAILURE;