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