]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.sbin/sysinstall/dispatch.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / usr.sbin / sysinstall / dispatch.c
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$
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
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);
51
52 static struct _word {
53     char *name;
54     int (*handler)(dialogMenuItem *self);
55 } resWords[] = {
56     { "configAnonFTP",          configAnonFTP           },
57     { "configRouter",           configRouter            },
58     { "configInetd",            configInetd             },
59     { "configNFSServer",        configNFSServer         },
60     { "configNTP",              configNTP               },
61     { "configPCNFSD",           configPCNFSD            },
62     { "configPackages",         configPackages          },
63     { "configUsers",            configUsers             },
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     { "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           },
120     { NULL, NULL },
121 };
122
123 /*
124  * Helper routines for buffering data.
125  *
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.
129  */
130
131 typedef struct command_buffer_ {
132     qelement    queue;
133     char *      string;
134 } command_buffer;
135
136 static void
137 dispatch_free_command(command_buffer *item)
138 {
139     REMQUE(item);
140     free(item->string);
141     free(item);
142 }
143
144 static void
145 dispatch_free_all(qelement *head)
146 {
147     command_buffer *item;
148
149     while (!EMPTYQUE(*head)) {
150         item = (command_buffer *) head->q_forw;
151         dispatch_free_command(item);
152     }
153 }
154
155 static command_buffer *
156 dispatch_add_command(qelement *head, char *string)
157 {
158     command_buffer *new;
159
160     new = malloc(sizeof(command_buffer));
161
162     if (!new)
163         return NULL;
164
165     new->string = strdup(string);
166     INSQUEUE(new, head->q_back);
167
168     return new;
169 }
170 \f
171 /*
172  * Command processing
173  */
174
175 /* Just convenience */
176 static int
177 dispatch_shutdown(dialogMenuItem *unused)
178 {
179     systemShutdown(0);
180     return DITEM_FAILURE;
181 }
182
183 static int
184 dispatch_systemExecute(dialogMenuItem *unused)
185 {
186     char *cmd = variable_get(VAR_COMMAND);
187
188     if (cmd)
189         return systemExecute(cmd) ? DITEM_FAILURE : DITEM_SUCCESS;
190     else
191         msgDebug("_systemExecute: No command passed in `command' variable.\n");
192     return DITEM_FAILURE;
193 }
194
195 static int
196 dispatch_msgConfirm(dialogMenuItem *unused)
197 {
198     char *msg = variable_get(VAR_COMMAND);
199
200     if (msg) {
201         msgConfirm("%s", msg);
202         return DITEM_SUCCESS;
203     }
204
205     msgDebug("_msgConfirm: No message passed in `command' variable.\n");
206     return DITEM_FAILURE;
207 }
208
209 static int
210 dispatch_mediaOpen(dialogMenuItem *unused)
211 {
212     return mediaOpen();
213 }
214
215 static int
216 dispatch_mediaClose(dialogMenuItem *unused)
217 {
218     mediaClose();
219     return DITEM_SUCCESS;
220 }
221
222 static int
223 call_possible_resword(char *name, dialogMenuItem *value, int *status)
224 {
225     int i, rval;
226
227     rval = 0;
228     for (i = 0; resWords[i].name; i++) {
229         if (!strcmp(name, resWords[i].name)) {
230             *status = resWords[i].handler(value);
231             rval = 1;
232             break;
233         }
234     }
235     return rval;
236 }
237
238 /* For a given string, call it or spit out an undefined command diagnostic */
239 int
240 dispatchCommand(char *str)
241 {
242     int i;
243     char *cp;
244
245     if (!str || !*str) {
246         msgConfirm("Null or zero-length string passed to dispatchCommand");
247         return DITEM_FAILURE;
248     }
249
250     /* Fixup DOS abuse */
251     if ((cp = index(str, '\r')) != NULL)
252         *cp = '\0';
253
254     /* If it's got a `=' sign in there, assume it's a variable setting */
255     if (index(str, '=')) {
256         if (isDebug())
257             msgDebug("dispatch: setting variable `%s'\n", str);
258         variable_set(str, 0);
259         i = DITEM_SUCCESS;
260     }
261     else {
262         /* A command might be a pathname if it's encoded in argv[0], which
263            we also support */
264         if ((cp = rindex(str, '/')) != NULL)
265             str = cp + 1;
266         if (isDebug())
267             msgDebug("dispatch: calling resword `%s'\n", str);
268         if (!call_possible_resword(str, NULL, &i)) {
269             msgNotify("Warning: No such command ``%s''", str);
270             i = DITEM_FAILURE;
271         }
272         /*
273          * Allow a user to prefix a command with "noError" to cause
274          * us to ignore any errors for that one command.
275          */
276         if (i != DITEM_SUCCESS && variable_get(VAR_NO_ERROR))
277             i = DITEM_SUCCESS;
278         variable_unset(VAR_NO_ERROR);
279     }
280     return i;
281 }
282
283 \f
284 /*
285  * File processing
286  */
287
288 static qelement *
289 dispatch_load_fp(FILE *fp)
290 {
291     qelement *head;
292     char buf[BUFSIZ], *cp;
293
294     head = malloc(sizeof(qelement));
295
296     if (!head)
297         return NULL;
298
299     INITQUE(*head);
300
301     while (fgets(buf, sizeof buf, fp)) {
302         /* Fix up DOS abuse */
303         if ((cp = index(buf, '\r')) != NULL)
304             *cp = '\0';
305         /* If it's got a new line, trim it */
306        if ((cp = index(buf, '\n')) != NULL)
307             *cp = '\0';
308         if (*buf == '\0' || *buf == '#')
309             continue;
310
311         if (!dispatch_add_command(head, buf))
312             return NULL;
313     }
314
315     return head;
316 }
317
318 static int
319 dispatch_execute(qelement *head)
320 {
321     int result = DITEM_SUCCESS;
322     command_buffer *item;
323     char *old_interactive;
324
325     if (!head)
326         return result | DITEM_FAILURE;
327
328     old_interactive = variable_get(VAR_NONINTERACTIVE);
329     if (old_interactive)
330          old_interactive = strdup(old_interactive);     /* save copy */
331
332     /* Hint to others that we're running from a script, should they care */
333     variable_set2(VAR_NONINTERACTIVE, "yes", 0);
334
335     while (!EMPTYQUE(*head)) {
336         item = (command_buffer *) head->q_forw;
337
338         if (DITEM_STATUS(dispatchCommand(item->string)) != DITEM_SUCCESS) {
339             msgConfirm("Command `%s' failed - rest of script aborted.\n",
340                        item->string);
341             result |= DITEM_FAILURE;
342             break;
343         }
344         dispatch_free_command(item);
345     }
346
347     dispatch_free_all(head);
348
349     if (!old_interactive)
350         variable_unset(VAR_NONINTERACTIVE);
351     else {
352         variable_set2(VAR_NONINTERACTIVE, old_interactive, 0);
353         free(old_interactive);
354     }
355
356     return result;
357 }
358
359 int
360 dispatch_load_file_int(int quiet)
361 {
362     FILE *fp;
363     char *cp;
364     int  i;
365     qelement *list;
366
367     static const char *names[] = {
368         "install.cfg",
369         "/stand/install.cfg",
370         "/tmp/install.cfg",
371         NULL
372     };
373
374     fp = NULL;
375     cp = variable_get(VAR_CONFIG_FILE);
376     if (!cp) {
377         for (i = 0; names[i]; i++)
378             if ((fp = fopen(names[i], "r")) != NULL)
379                 break;
380     } else
381         fp = fopen(cp, "r");
382
383     if (!fp) {
384         if (!quiet)
385             msgConfirm("Unable to open %s: %s", cp, strerror(errno));
386         return DITEM_FAILURE;
387     }
388
389     list = dispatch_load_fp(fp);
390     fclose(fp);
391
392     return dispatch_execute(list);
393 }
394
395 int
396 dispatch_load_file(dialogMenuItem *self)
397 {
398     return dispatch_load_file_int(FALSE);
399 }
400
401 int
402 dispatch_load_floppy(dialogMenuItem *self)
403 {
404     int             what = DITEM_SUCCESS;
405     extern char    *distWanted;
406     char           *cp;
407     FILE           *fp;
408     qelement       *list;
409
410     mediaClose();
411     cp = variable_get_value(VAR_INSTALL_CFG,
412                             "Specify the name of a configuration file", 0);
413     if (!cp || !*cp) {
414         variable_unset(VAR_INSTALL_CFG);
415         what |= DITEM_FAILURE;
416         return what;
417     }
418
419     distWanted = cp;
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;
424         mediaClose();
425         return what;
426     }
427
428     if (!DEVICE_INIT(mediaDevice)) {
429         msgConfirm("Unable to mount floppy filesystem.");
430         what |= DITEM_FAILURE;
431         mediaClose();
432         return what;
433     }
434
435     fp = DEVICE_GET(mediaDevice, cp, TRUE);
436     if (fp) {
437         list = dispatch_load_fp(fp);
438         fclose(fp);
439         mediaClose();
440
441         what |= dispatch_execute(list);
442     }
443     else {
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;
448         mediaClose();
449     }
450     return what;
451 }
452
453 int
454 dispatch_load_cdrom(dialogMenuItem *self)
455 {
456     int             what = DITEM_SUCCESS;
457     extern char    *distWanted;
458     char           *cp;
459     FILE           *fp;
460     qelement       *list;
461
462     mediaClose();
463     cp = variable_get_value(VAR_INSTALL_CFG,
464                             "Specify the name of a configuration file\n"
465                             "residing on the CDROM.", 0);
466     if (!cp || !*cp) {
467         variable_unset(VAR_INSTALL_CFG);
468         what |= DITEM_FAILURE;
469         return what;
470     }
471
472     distWanted = cp;
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;
477         mediaClose();
478         return what;
479     }
480
481     if (!DEVICE_INIT(mediaDevice)) {
482         msgConfirm("Unable to CDROM filesystem.");
483         what |= DITEM_FAILURE;
484         mediaClose();
485         return what;
486     }
487
488     fp = DEVICE_GET(mediaDevice, cp, TRUE);
489     if (fp) {
490         list = dispatch_load_fp(fp);
491         fclose(fp);
492         mediaClose();
493
494         what |= dispatch_execute(list);
495     }
496     else {
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;
501         mediaClose();
502     }
503     return what;
504 }
505
506 /*
507  * Create a menu based on available disk devices
508  */
509 int
510 dispatch_load_menu(dialogMenuItem *self)
511 {
512     DMenu       *menu;
513     Device      **devlist;
514     char        *err;
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};
518
519     fprintf(stderr, "dispatch_load_menu called\n");
520
521     msize = sizeof(DMenu) + (sizeof(dialogMenuItem) * 2);
522     count = 0;
523     err = NULL;
524     what = DITEM_SUCCESS;
525
526     if ((menu = malloc(msize)) == NULL) {
527         err = "Failed to allocate memory for menu";
528         goto errout;
529     }
530
531     bcopy(&MenuConfig, menu, sizeof(DMenu));
532
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;
537     count++;
538
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]);
542             continue;
543         }
544
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";
550                 goto errout;
551             }
552
553             bzero(&menu->items[count], sizeof(menu->items[0]));
554             menu->items[count].fire = cfgModuleFire;
555
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];
560             count++;
561         }
562     }
563
564     menu->items[count].prompt = NULL;
565     menu->items[count].title = NULL;
566
567     dmenuOpenSimple(menu, FALSE);
568
569   errout:
570     for (i = 0; i < count; i++) {
571         free(menu->items[i].prompt);
572         free(menu->items[i].title);
573     }
574
575     free(menu);
576
577     if (err != NULL) {
578         what |= DITEM_FAILURE;
579         if (!variable_get(VAR_NO_ERROR))
580             msgConfirm(err);
581     }
582
583     return (what);
584
585 }
586
587 static int
588 cfgModuleFire(dialogMenuItem *self) {
589     Device      *d;
590     FILE        *fp;
591     int         what = DITEM_SUCCESS;
592     extern char *distWanted;
593     qelement    *list;
594     char        *cp;
595
596     d = (Device *)self->aux;
597
598     msgDebug("cfgModuleFire: User selected %s (%s)\n", self->prompt, d->devname);
599
600     mediaClose();
601
602     cp = variable_get_value(VAR_INSTALL_CFG,
603                             "Specify the name of a configuration file", 0);
604     if (!cp || !*cp) {
605         variable_unset(VAR_INSTALL_CFG);
606         what |= DITEM_FAILURE;
607         return what;
608     }
609
610     distWanted = cp;
611
612     mediaDevice = d;
613     if (!DEVICE_INIT(mediaDevice)) {
614         msgConfirm("Unable to mount filesystem.");
615         what |= DITEM_FAILURE;
616         mediaClose();
617         return what;
618     }
619     msgDebug("getting fp for %s\n", cp);
620
621     fp = DEVICE_GET(mediaDevice, cp, TRUE);
622     if (fp) {
623         msgDebug("opened OK, processing..\n");
624
625         list = dispatch_load_fp(fp);
626         fclose(fp);
627         mediaClose();
628
629         what |= dispatch_execute(list);
630     } else {
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;
635         mediaClose();
636     }
637
638     return(what);
639  }