* Add this nice filesystem testing tool that I've recently
[dragonfly.git] / release / 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: src/release/sysinstall/dispatch.c,v 1.35.2.7 2002/07/02 21:37:49 jhb Exp $
8  * $DragonFly: src/release/sysinstall/Attic/dispatch.c,v 1.2 2003/06/17 04:27:21 dillon Exp $
9  *
10  * Copyright (c) 1995
11  *      Jordan Hubbard.  All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer,
18  *    verbatim and that no modifications are made prior to this
19  *    point in the file.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  */
37
38 #include "sysinstall.h"
39 #include <ctype.h>
40 #include <errno.h>
41 #include <sys/signal.h>
42 #include <sys/fcntl.h>
43
44 #include "list.h"
45
46 static int dispatch_shutdown(dialogMenuItem *unused);
47 static int dispatch_systemExecute(dialogMenuItem *unused);
48 static int dispatch_msgConfirm(dialogMenuItem *unused);
49 static int dispatch_mediaClose(dialogMenuItem *unused);
50
51 static struct _word {
52     char *name;
53     int (*handler)(dialogMenuItem *self);
54 } resWords[] = {
55     { "configAnonFTP",          configAnonFTP           },
56     { "configRouter",           configRouter            },
57     { "configInetd",            configInetd             },
58     { "configNFSServer",        configNFSServer         },
59     { "configNTP",              configNTP               },
60     { "configPCNFSD",           configPCNFSD            },
61     { "configPackages",         configPackages          },
62     { "configUsers",            configUsers             },
63     { "configXSetup",           configXSetup    },
64     { "configXDesktop",         configXDesktop  },
65     { "diskPartitionEditor",    diskPartitionEditor     },
66     { "diskPartitionWrite",     diskPartitionWrite      },
67     { "diskLabelEditor",        diskLabelEditor         },
68     { "diskLabelCommit",        diskLabelCommit         },
69     { "distReset",              distReset               },
70     { "distSetCustom",          distSetCustom           },
71     { "distUnsetCustom",        distUnsetCustom         },
72     { "distSetDeveloper",       distSetDeveloper        },
73     { "distSetXDeveloper",      distSetXDeveloper       },
74     { "distSetKernDeveloper",   distSetKernDeveloper    },
75     { "distSetUser",            distSetUser             },
76     { "distSetXUser",           distSetXUser            },
77     { "distSetMinimum",         distSetMinimum          },
78     { "distSetEverything",      distSetEverything       },
79     { "distSetSrc",             distSetSrc              },
80     { "distSetXF86",            distSetXF86             },
81     { "distExtractAll",         distExtractAll          },
82     { "docBrowser",             docBrowser              },
83     { "docShowDocument",        docShowDocument         },
84     { "installCommit",          installCommit           },
85     { "installExpress",         installExpress          },
86     { "installStandard",        installStandard         },
87     { "installUpgrade",         installUpgrade          },
88     { "installFixupBin",        installFixupBin         },
89 #ifndef X_AS_PKG
90     { "installFixupXFree",      installFixupXFree       },
91 #endif
92     { "installFixitHoloShell",  installFixitHoloShell   },
93     { "installFixitCDROM",      installFixitCDROM       },
94     { "installFixitFloppy",     installFixitFloppy      },
95     { "installFilesystems",     installFilesystems      },
96     { "installVarDefaults",     installVarDefaults      },
97     { "loadConfig",             dispatch_load_file      },
98     { "loadFloppyConfig",       dispatch_load_floppy    },
99     { "mediaClose",             dispatch_mediaClose     },
100     { "mediaSetCDROM",          mediaSetCDROM           },
101     { "mediaSetFloppy",         mediaSetFloppy          },
102     { "mediaSetDOS",            mediaSetDOS             },
103     { "mediaSetTape",           mediaSetTape            },
104     { "mediaSetFTP",            mediaSetFTP             },
105     { "mediaSetFTPActive",      mediaSetFTPActive       },
106     { "mediaSetFTPPassive",     mediaSetFTPPassive      },
107     { "mediaSetHTTP",           mediaSetHTTP            },
108     { "mediaSetUFS",            mediaSetUFS             },
109     { "mediaSetNFS",            mediaSetNFS             },
110     { "mediaSetFTPUserPass",    mediaSetFTPUserPass     },
111     { "mediaSetCPIOVerbosity",  mediaSetCPIOVerbosity   },
112     { "mediaGetType",           mediaGetType            },
113     { "msgConfirm",             dispatch_msgConfirm     },
114     { "optionsEditor",          optionsEditor           },
115     { "packageAdd",             packageAdd              },
116     { "addGroup",               userAddGroup            },
117     { "addUser",                userAddUser             },
118     { "shutdown",               dispatch_shutdown       },
119     { "system",                 dispatch_systemExecute  },
120     { "dumpVariables",          dump_variables          },
121     { "tcpMenuSelect",          tcpMenuSelect           },
122     { NULL, NULL },
123 };
124
125 /*
126  * Helper routines for buffering data.
127  *
128  * We read an entire configuration into memory before executing it
129  * so that we are truely standalone and can do things like nuke the
130  * file or disk we're working on.
131  */
132
133 typedef struct command_buffer_ {
134     qelement    queue;
135     char *      string;
136 } command_buffer;
137
138 static void
139 dispatch_free_command(command_buffer *item)
140 {
141     REMQUE(item);
142     free(item->string);
143     free(item);
144 }
145
146 static void
147 dispatch_free_all(qelement *head)
148 {
149     command_buffer *item;
150
151     while (!EMPTYQUE(*head)) {
152         item = (command_buffer *) head->q_forw;
153         dispatch_free_command(item);
154     }
155 }
156
157 static command_buffer *
158 dispatch_add_command(qelement *head, char *string)
159 {
160     command_buffer *new;
161
162     new = malloc(sizeof(command_buffer));
163
164     if (!new)
165         return NULL;
166
167     new->string = strdup(string);
168     INSQUEUE(new, head->q_back);
169
170     return new;
171 }
172 \f
173 /*
174  * Command processing
175  */
176
177 /* Just convenience */
178 static int
179 dispatch_shutdown(dialogMenuItem *unused)
180 {
181     systemShutdown(0);
182     return DITEM_FAILURE;
183 }
184
185 static int
186 dispatch_systemExecute(dialogMenuItem *unused)
187 {
188     char *cmd = variable_get(VAR_COMMAND);
189
190     if (cmd)
191         return systemExecute(cmd) ? DITEM_FAILURE : DITEM_SUCCESS;
192     else
193         msgDebug("_systemExecute: No command passed in `command' variable.\n");
194     return DITEM_FAILURE;
195 }
196
197 static int
198 dispatch_msgConfirm(dialogMenuItem *unused)
199 {
200     char *msg = variable_get(VAR_COMMAND);
201
202     if (msg) {
203         msgConfirm("%s", msg);
204         return DITEM_SUCCESS;
205     }
206
207     msgDebug("_msgConfirm: No message passed in `command' variable.\n");
208     return DITEM_FAILURE;
209 }
210
211 static int
212 dispatch_mediaClose(dialogMenuItem *unused)
213 {
214     mediaClose();
215     return DITEM_SUCCESS;
216 }
217
218 static int
219 call_possible_resword(char *name, dialogMenuItem *value, int *status)
220 {
221     int i, rval;
222
223     rval = 0;
224     for (i = 0; resWords[i].name; i++) {
225         if (!strcmp(name, resWords[i].name)) {
226             *status = resWords[i].handler(value);
227             rval = 1;
228             break;
229         }
230     }
231     return rval;
232 }
233
234 /* For a given string, call it or spit out an undefined command diagnostic */
235 int
236 dispatchCommand(char *str)
237 {
238     int i;
239     char *cp;
240
241     if (!str || !*str) {
242         msgConfirm("Null or zero-length string passed to dispatchCommand");
243         return DITEM_FAILURE;
244     }
245     /* If it's got a newline, trim it */
246     if ((cp = index(str, '\n')) != NULL)
247         *cp = '\0';
248
249     /* If it's got a `=' sign in there, assume it's a variable setting */
250     if (index(str, '=')) {
251         if (isDebug())
252             msgDebug("dispatch: setting variable `%s'\n", str);
253         variable_set(str, 0);
254         i = DITEM_SUCCESS;
255     }
256     else {
257         /* A command might be a pathname if it's encoded in argv[0], which
258            we also support */
259         if ((cp = rindex(str, '/')) != NULL)
260             str = cp + 1;
261         if (isDebug())
262             msgDebug("dispatch: calling resword `%s'\n", str);
263         if (!call_possible_resword(str, NULL, &i)) {
264             msgNotify("Warning: No such command ``%s''", str);
265             i = DITEM_FAILURE;
266         }
267         /*
268          * Allow a user to prefix a command with "noError" to cause
269          * us to ignore any errors for that one command.
270          */
271         if (i != DITEM_SUCCESS && variable_get(VAR_NO_ERROR))
272             i = DITEM_SUCCESS;
273         variable_unset(VAR_NO_ERROR);
274     }
275     return i;
276 }
277
278 \f
279 /*
280  * File processing
281  */
282
283 static qelement *
284 dispatch_load_fp(FILE *fp)
285 {
286     qelement *head;
287     char buf[BUFSIZ], *cp;
288
289     head = malloc(sizeof(qelement));
290
291     if (!head)
292         return NULL;
293
294     INITQUE(*head);
295
296     while (fgets(buf, sizeof buf, fp)) {
297
298         if ((cp = strchr(buf, '\n')) != NULL)
299             *cp = '\0';
300         if (*buf == '\0' || *buf == '#')
301             continue;
302
303         if (!dispatch_add_command(head, buf))
304             return NULL;
305     }
306
307     return head;
308 }
309
310 static int
311 dispatch_execute(qelement *head)
312 {
313     int result = DITEM_SUCCESS;
314     command_buffer *item;
315     char *old_interactive;
316
317     if (!head)
318         return result | DITEM_FAILURE;
319
320     old_interactive = variable_get(VAR_NONINTERACTIVE);
321     if (old_interactive)
322          old_interactive = strdup(old_interactive);     /* save copy */
323
324     /* Hint to others that we're running from a script, should they care */
325     variable_set2(VAR_NONINTERACTIVE, "yes", 0);
326
327     while (!EMPTYQUE(*head)) {
328         item = (command_buffer *) head->q_forw;
329         
330         if (DITEM_STATUS(dispatchCommand(item->string)) != DITEM_SUCCESS) {
331             msgConfirm("Command `%s' failed - rest of script aborted.\n",
332                        item->string);
333             result |= DITEM_FAILURE;
334             break;
335         }
336         dispatch_free_command(item);
337     }
338
339     dispatch_free_all(head);
340
341     if (!old_interactive)
342         variable_unset(VAR_NONINTERACTIVE);
343     else {
344         variable_set2(VAR_NONINTERACTIVE, old_interactive, 0);
345         free(old_interactive);
346     }
347
348     return result;
349 }
350
351 int
352 dispatch_load_file_int(int quiet)
353 {
354     FILE *fp;
355     char *cp;
356     int  i;
357     qelement *list;
358
359     static const char *names[] = {
360         "install.cfg",
361         "/stand/install.cfg",
362         "/tmp/install.cfg",
363         NULL
364     };
365
366     fp = NULL;
367     cp = variable_get(VAR_CONFIG_FILE);
368     if (!cp) {
369         for (i = 0; names[i]; i++)
370             if ((fp = fopen(names[i], "r")) != NULL)
371                 break;
372     } else
373         fp = fopen(cp, "r");
374
375     if (!fp) {
376         if (!quiet)
377             msgConfirm("Unable to open %s: %s", cp, strerror(errno));
378         return DITEM_FAILURE;
379     }
380
381     list = dispatch_load_fp(fp);
382     fclose(fp);
383
384     return dispatch_execute(list);
385 }
386
387 int
388 dispatch_load_file(dialogMenuItem *self)
389 {
390     return dispatch_load_file_int(FALSE);
391 }
392
393 int
394 dispatch_load_floppy(dialogMenuItem *self)
395 {
396     int             what = DITEM_SUCCESS;
397     extern char    *distWanted;
398     char           *cp;
399     FILE           *fp;
400     qelement       *list;
401
402     mediaClose();
403     cp = variable_get_value(VAR_INSTALL_CFG,
404                             "Specify the name of a configuration file\n"
405                             "residing on a MSDOS or UFS floppy.", 0);
406     if (!cp || !*cp) {
407         variable_unset(VAR_INSTALL_CFG);
408         what |= DITEM_FAILURE;
409         return what;
410     }
411
412     distWanted = cp;
413     /* Try to open the floppy drive */
414     if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) {
415         msgConfirm("Unable to set media device to floppy.");
416         what |= DITEM_FAILURE;
417         mediaClose();
418         return what;
419     }
420
421     if (!DEVICE_INIT(mediaDevice)) {
422         msgConfirm("Unable to mount floppy filesystem.");
423         what |= DITEM_FAILURE;
424         mediaClose();
425         return what;
426     }
427
428     fp = DEVICE_GET(mediaDevice, cp, TRUE);
429     if (fp) {
430         list = dispatch_load_fp(fp);
431         fclose(fp);
432         mediaClose();
433
434         what |= dispatch_execute(list);
435     }
436     else {
437         if (!variable_get(VAR_NO_ERROR))
438             msgConfirm("Configuration file '%s' not found.", cp);
439         variable_unset(VAR_INSTALL_CFG);
440         what |= DITEM_FAILURE;
441         mediaClose();
442     }
443     return what;
444 }
445