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 { "mediaSetHTTPDirect", mediaSetHTTPDirect },
107 { "mediaSetUFS", mediaSetUFS },
108 { "mediaSetNFS", mediaSetNFS },
109 { "mediaSetFTPUserPass", mediaSetFTPUserPass },
110 { "mediaSetCPIOVerbosity", mediaSetCPIOVerbosity },
111 { "mediaGetType", mediaGetType },
112 { "msgConfirm", dispatch_msgConfirm },
113 { "optionsEditor", optionsEditor },
114 { "packageAdd", packageAdd },
115 { "addGroup", userAddGroup },
116 { "addUser", userAddUser },
117 { "shutdown", dispatch_shutdown },
118 { "system", dispatch_systemExecute },
119 { "dumpVariables", dump_variables },
120 { "tcpMenuSelect", tcpMenuSelect },
125 * Helper routines for buffering data.
127 * We read an entire configuration into memory before executing it
128 * so that we are truely standalone and can do things like nuke the
129 * file or disk we're working on.
132 typedef struct command_buffer_ {
138 dispatch_free_command(command_buffer *item)
150 dispatch_free_all(qelement *head)
152 command_buffer *item;
154 while (!EMPTYQUE(*head)) {
155 item = (command_buffer *) head->q_forw;
156 dispatch_free_command(item);
160 static command_buffer *
161 dispatch_add_command(qelement *head, char *string)
163 command_buffer *new = NULL;
165 new = malloc(sizeof(command_buffer));
169 new->string = strdup(string);
172 * We failed to copy `string'; clean up the allocated
175 if (new->string == NULL) {
179 INSQUEUE(new, head->q_back);
190 /* Just convenience */
192 dispatch_shutdown(dialogMenuItem *unused)
195 return DITEM_FAILURE;
199 dispatch_systemExecute(dialogMenuItem *unused)
201 char *cmd = variable_get(VAR_COMMAND);
204 return systemExecute(cmd) ? DITEM_FAILURE : DITEM_SUCCESS;
206 msgDebug("_systemExecute: No command passed in `command' variable.\n");
207 return DITEM_FAILURE;
211 dispatch_msgConfirm(dialogMenuItem *unused)
213 char *msg = variable_get(VAR_COMMAND);
216 msgConfirm("%s", msg);
217 return DITEM_SUCCESS;
220 msgDebug("_msgConfirm: No message passed in `command' variable.\n");
221 return DITEM_FAILURE;
225 dispatch_mediaOpen(dialogMenuItem *unused)
231 dispatch_mediaClose(dialogMenuItem *unused)
234 return DITEM_SUCCESS;
238 call_possible_resword(char *name, dialogMenuItem *value, int *status)
243 for (i = 0; resWords[i].name; i++) {
244 if (!strcmp(name, resWords[i].name)) {
245 *status = resWords[i].handler(value);
253 /* For a given string, call it or spit out an undefined command diagnostic */
255 dispatchCommand(char *str)
261 msgConfirm("Null or zero-length string passed to dispatchCommand");
262 return DITEM_FAILURE;
265 /* Fixup DOS abuse */
266 if ((cp = index(str, '\r')) != NULL)
269 /* If it's got a `=' sign in there, assume it's a variable setting */
270 if (index(str, '=')) {
272 msgDebug("dispatch: setting variable `%s'\n", str);
273 variable_set(str, 0);
277 /* A command might be a pathname if it's encoded in argv[0], which
279 if ((cp = rindex(str, '/')) != NULL)
282 msgDebug("dispatch: calling resword `%s'\n", str);
283 if (!call_possible_resword(str, NULL, &i)) {
284 msgNotify("Warning: No such command ``%s''", str);
288 * Allow a user to prefix a command with "noError" to cause
289 * us to ignore any errors for that one command.
291 if (i != DITEM_SUCCESS && variable_get(VAR_NO_ERROR))
293 variable_unset(VAR_NO_ERROR);
304 dispatch_load_fp(FILE *fp)
307 char buf[BUFSIZ], *cp;
309 head = malloc(sizeof(qelement));
316 while (fgets(buf, sizeof buf, fp)) {
317 /* Fix up DOS abuse */
318 if ((cp = index(buf, '\r')) != NULL)
320 /* If it's got a new line, trim it */
321 if ((cp = index(buf, '\n')) != NULL)
323 if (*buf == '\0' || *buf == '#')
326 if (!dispatch_add_command(head, buf))
334 dispatch_execute(qelement *head)
336 int result = DITEM_SUCCESS;
337 command_buffer *item;
338 char *old_interactive;
341 return result | DITEM_FAILURE;
343 old_interactive = variable_get(VAR_NONINTERACTIVE);
345 old_interactive = strdup(old_interactive); /* save copy */
347 /* Hint to others that we're running from a script, should they care */
348 variable_set2(VAR_NONINTERACTIVE, "yes", 0);
350 while (!EMPTYQUE(*head)) {
351 item = (command_buffer *) head->q_forw;
353 if (DITEM_STATUS(dispatchCommand(item->string)) != DITEM_SUCCESS) {
354 msgConfirm("Command `%s' failed - rest of script aborted.\n",
356 result |= DITEM_FAILURE;
359 dispatch_free_command(item);
362 dispatch_free_all(head);
364 if (!old_interactive)
365 variable_unset(VAR_NONINTERACTIVE);
367 variable_set2(VAR_NONINTERACTIVE, old_interactive, 0);
368 free(old_interactive);
375 dispatch_load_file_int(int quiet)
382 static const char *names[] = {
384 "/stand/install.cfg",
390 cp = variable_get(VAR_CONFIG_FILE);
392 for (i = 0; names[i]; i++)
393 if ((fp = fopen(names[i], "r")) != NULL)
400 msgConfirm("Unable to open %s: %s", cp, strerror(errno));
401 return DITEM_FAILURE;
404 list = dispatch_load_fp(fp);
407 return dispatch_execute(list);
411 dispatch_load_file(dialogMenuItem *self)
413 return dispatch_load_file_int(FALSE);
417 dispatch_load_floppy(dialogMenuItem *self)
419 int what = DITEM_SUCCESS;
420 extern char *distWanted;
426 cp = variable_get_value(VAR_INSTALL_CFG,
427 "Specify the name of a configuration file", 0);
429 variable_unset(VAR_INSTALL_CFG);
430 what |= DITEM_FAILURE;
435 /* Try to open the floppy drive */
436 if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) {
437 msgConfirm("Unable to set media device to floppy.");
438 what |= DITEM_FAILURE;
443 if (!DEVICE_INIT(mediaDevice)) {
444 msgConfirm("Unable to mount floppy filesystem.");
445 what |= DITEM_FAILURE;
450 fp = DEVICE_GET(mediaDevice, cp, TRUE);
452 list = dispatch_load_fp(fp);
456 what |= dispatch_execute(list);
459 if (!variable_get(VAR_NO_ERROR))
460 msgConfirm("Configuration file '%s' not found.", cp);
461 variable_unset(VAR_INSTALL_CFG);
462 what |= DITEM_FAILURE;
469 dispatch_load_cdrom(dialogMenuItem *self)
471 int what = DITEM_SUCCESS;
472 extern char *distWanted;
478 cp = variable_get_value(VAR_INSTALL_CFG,
479 "Specify the name of a configuration file\n"
480 "residing on the CDROM.", 0);
482 variable_unset(VAR_INSTALL_CFG);
483 what |= DITEM_FAILURE;
488 /* Try to open the floppy drive */
489 if (DITEM_STATUS(mediaSetCDROM(NULL)) == DITEM_FAILURE) {
490 msgConfirm("Unable to set media device to CDROM.");
491 what |= DITEM_FAILURE;
496 if (!DEVICE_INIT(mediaDevice)) {
497 msgConfirm("Unable to CDROM filesystem.");
498 what |= DITEM_FAILURE;
503 fp = DEVICE_GET(mediaDevice, cp, TRUE);
505 list = dispatch_load_fp(fp);
509 what |= dispatch_execute(list);
512 if (!variable_get(VAR_NO_ERROR))
513 msgConfirm("Configuration file '%s' not found.", cp);
514 variable_unset(VAR_INSTALL_CFG);
515 what |= DITEM_FAILURE;
522 * Create a menu based on available disk devices
525 dispatch_load_menu(dialogMenuItem *self)
530 int what, i, j, msize, count;
531 DeviceType dtypes[] = {DEVICE_TYPE_FLOPPY, DEVICE_TYPE_CDROM,
532 DEVICE_TYPE_DOS, DEVICE_TYPE_UFS, DEVICE_TYPE_USB};
534 fprintf(stderr, "dispatch_load_menu called\n");
536 msize = sizeof(DMenu) + (sizeof(dialogMenuItem) * 2);
539 what = DITEM_SUCCESS;
541 if ((menu = malloc(msize)) == NULL) {
542 err = "Failed to allocate memory for menu";
546 bcopy(&MenuConfig, menu, sizeof(DMenu));
548 bzero(&menu->items[count], sizeof(menu->items[0]));
549 menu->items[count].prompt = strdup("X Exit");
550 menu->items[count].title = strdup("Exit this menu (returning to previous)");
551 menu->items[count].fire = dmenuExit;
554 for (i = 0; i < sizeof(dtypes) / sizeof(dtypes[0]); i++) {
555 if ((devlist = deviceFind(NULL, dtypes[i])) == NULL) {
556 fprintf(stderr, "No devices found for type %d\n", dtypes[i]);
560 for (j = 0; devlist[j] != NULL; j++) {
561 fprintf(stderr, "device type %d device name %s\n", dtypes[i], devlist[j]->name);
562 msize += sizeof(dialogMenuItem);
563 if ((menu = realloc(menu, msize)) == NULL) {
564 err = "Failed to allocate memory for menu item";
568 bzero(&menu->items[count], sizeof(menu->items[0]));
569 menu->items[count].fire = cfgModuleFire;
571 menu->items[count].prompt = strdup(devlist[j]->name);
572 menu->items[count].title = strdup(devlist[j]->description);
573 /* XXX: dialog(3) sucks */
574 menu->items[count].aux = (long)devlist[j];
579 menu->items[count].prompt = NULL;
580 menu->items[count].title = NULL;
582 dmenuOpenSimple(menu, FALSE);
585 for (i = 0; i < count; i++) {
586 free(menu->items[i].prompt);
587 free(menu->items[i].title);
593 what |= DITEM_FAILURE;
594 if (!variable_get(VAR_NO_ERROR))
595 msgConfirm("%s", err);
603 cfgModuleFire(dialogMenuItem *self) {
606 int what = DITEM_SUCCESS;
607 extern char *distWanted;
611 d = (Device *)self->aux;
613 msgDebug("cfgModuleFire: User selected %s (%s)\n", self->prompt, d->devname);
617 cp = variable_get_value(VAR_INSTALL_CFG,
618 "Specify the name of a configuration file", 0);
620 variable_unset(VAR_INSTALL_CFG);
621 what |= DITEM_FAILURE;
628 if (!DEVICE_INIT(mediaDevice)) {
629 msgConfirm("Unable to mount filesystem.");
630 what |= DITEM_FAILURE;
634 msgDebug("getting fp for %s\n", cp);
636 fp = DEVICE_GET(mediaDevice, cp, TRUE);
638 msgDebug("opened OK, processing..\n");
640 list = dispatch_load_fp(fp);
644 what |= dispatch_execute(list);
646 if (!variable_get(VAR_NO_ERROR))
647 msgConfirm("Configuration file '%s' not found.", cp);
648 variable_unset(VAR_INSTALL_CFG);
649 what |= DITEM_FAILURE;