]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - usr.sbin/sysinstall/dispatch.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.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
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 #ifdef WITH_SLICES
64     { "diskPartitionEditor",    diskPartitionEditor     },
65 #endif
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     { "distExtractAll",         distExtractAll          },
81     { "docBrowser",             docBrowser              },
82     { "docShowDocument",        docShowDocument         },
83     { "installCommit",          installCommit           },
84     { "installExpress",         installExpress          },
85     { "installStandard",        installStandard         },
86     { "installUpgrade",         installUpgrade          },
87     { "installFixupBase",       installFixupBase        },
88     { "installFixitHoloShell",  installFixitHoloShell   },
89     { "installFixitCDROM",      installFixitCDROM       },
90     { "installFixitFloppy",     installFixitFloppy      },
91     { "installFilesystems",     installFilesystems      },
92     { "installVarDefaults",     installVarDefaults      },
93     { "loadConfig",             dispatch_load_file      },
94     { "loadFloppyConfig",       dispatch_load_floppy    },
95     { "mediaOpen",              dispatch_mediaOpen      },
96     { "mediaClose",             dispatch_mediaClose     },
97     { "mediaSetCDROM",          mediaSetCDROM           },
98     { "mediaSetFloppy",         mediaSetFloppy          },
99     { "mediaSetDOS",            mediaSetDOS             },
100     { "mediaSetTape",           mediaSetTape            },
101     { "mediaSetFTP",            mediaSetFTP             },
102     { "mediaSetFTPActive",      mediaSetFTPActive       },
103     { "mediaSetFTPPassive",     mediaSetFTPPassive      },
104     { "mediaSetHTTP",           mediaSetHTTP            },
105     { "mediaSetUFS",            mediaSetUFS             },
106     { "mediaSetNFS",            mediaSetNFS             },
107     { "mediaSetFTPUserPass",    mediaSetFTPUserPass     },
108     { "mediaSetCPIOVerbosity",  mediaSetCPIOVerbosity   },
109     { "mediaGetType",           mediaGetType            },
110     { "msgConfirm",             dispatch_msgConfirm     },
111     { "optionsEditor",          optionsEditor           },
112     { "packageAdd",             packageAdd              },
113     { "addGroup",               userAddGroup            },
114     { "addUser",                userAddUser             },
115     { "shutdown",               dispatch_shutdown       },
116     { "system",                 dispatch_systemExecute  },
117     { "dumpVariables",          dump_variables          },
118     { "tcpMenuSelect",          tcpMenuSelect           },
119     { NULL, NULL },
120 };
121
122 /*
123  * Helper routines for buffering data.
124  *
125  * We read an entire configuration into memory before executing it
126  * so that we are truely standalone and can do things like nuke the
127  * file or disk we're working on.
128  */
129
130 typedef struct command_buffer_ {
131     qelement    queue;
132     char *      string;
133 } command_buffer;
134
135 static void
136 dispatch_free_command(command_buffer *item)
137 {
138     REMQUE(item);
139     free(item->string);
140     free(item);
141 }
142
143 static void
144 dispatch_free_all(qelement *head)
145 {
146     command_buffer *item;
147
148     while (!EMPTYQUE(*head)) {
149         item = (command_buffer *) head->q_forw;
150         dispatch_free_command(item);
151     }
152 }
153
154 static command_buffer *
155 dispatch_add_command(qelement *head, char *string)
156 {
157     command_buffer *new;
158
159     new = malloc(sizeof(command_buffer));
160
161     if (!new)
162         return NULL;
163
164     new->string = strdup(string);
165     INSQUEUE(new, head->q_back);
166
167     return new;
168 }
169 \f
170 /*
171  * Command processing
172  */
173
174 /* Just convenience */
175 static int
176 dispatch_shutdown(dialogMenuItem *unused)
177 {
178     systemShutdown(0);
179     return DITEM_FAILURE;
180 }
181
182 static int
183 dispatch_systemExecute(dialogMenuItem *unused)
184 {
185     char *cmd = variable_get(VAR_COMMAND);
186
187     if (cmd)
188         return systemExecute(cmd) ? DITEM_FAILURE : DITEM_SUCCESS;
189     else
190         msgDebug("_systemExecute: No command passed in `command' variable.\n");
191     return DITEM_FAILURE;
192 }
193
194 static int
195 dispatch_msgConfirm(dialogMenuItem *unused)
196 {
197     char *msg = variable_get(VAR_COMMAND);
198
199     if (msg) {
200         msgConfirm("%s", msg);
201         return DITEM_SUCCESS;
202     }
203
204     msgDebug("_msgConfirm: No message passed in `command' variable.\n");
205     return DITEM_FAILURE;
206 }
207
208 static int
209 dispatch_mediaOpen(dialogMenuItem *unused)
210 {
211     return mediaOpen();
212 }
213
214 static int
215 dispatch_mediaClose(dialogMenuItem *unused)
216 {
217     mediaClose();
218     return DITEM_SUCCESS;
219 }
220
221 static int
222 call_possible_resword(char *name, dialogMenuItem *value, int *status)
223 {
224     int i, rval;
225
226     rval = 0;
227     for (i = 0; resWords[i].name; i++) {
228         if (!strcmp(name, resWords[i].name)) {
229             *status = resWords[i].handler(value);
230             rval = 1;
231             break;
232         }
233     }
234     return rval;
235 }
236
237 /* For a given string, call it or spit out an undefined command diagnostic */
238 int
239 dispatchCommand(char *str)
240 {
241     int i;
242     char *cp;
243
244     if (!str || !*str) {
245         msgConfirm("Null or zero-length string passed to dispatchCommand");
246         return DITEM_FAILURE;
247     }
248     /* If it's got a newline, trim it */
249     if ((cp = index(str, '\n')) != NULL)
250         *cp = '\0';
251
252     /* If it's got a `=' sign in there, assume it's a variable setting */
253     if (index(str, '=')) {
254         if (isDebug())
255             msgDebug("dispatch: setting variable `%s'\n", str);
256         variable_set(str, 0);
257         i = DITEM_SUCCESS;
258     }
259     else {
260         /* A command might be a pathname if it's encoded in argv[0], which
261            we also support */
262         if ((cp = rindex(str, '/')) != NULL)
263             str = cp + 1;
264         if (isDebug())
265             msgDebug("dispatch: calling resword `%s'\n", str);
266         if (!call_possible_resword(str, NULL, &i)) {
267             msgNotify("Warning: No such command ``%s''", str);
268             i = DITEM_FAILURE;
269         }
270         /*
271          * Allow a user to prefix a command with "noError" to cause
272          * us to ignore any errors for that one command.
273          */
274         if (i != DITEM_SUCCESS && variable_get(VAR_NO_ERROR))
275             i = DITEM_SUCCESS;
276         variable_unset(VAR_NO_ERROR);
277     }
278     return i;
279 }
280
281 \f
282 /*
283  * File processing
284  */
285
286 static qelement *
287 dispatch_load_fp(FILE *fp)
288 {
289     qelement *head;
290     char buf[BUFSIZ], *cp;
291
292     head = malloc(sizeof(qelement));
293
294     if (!head)
295         return NULL;
296
297     INITQUE(*head);
298
299     while (fgets(buf, sizeof buf, fp)) {
300
301         if ((cp = strchr(buf, '\n')) != NULL)
302             *cp = '\0';
303         if (*buf == '\0' || *buf == '#')
304             continue;
305
306         if (!dispatch_add_command(head, buf))
307             return NULL;
308     }
309
310     return head;
311 }
312
313 static int
314 dispatch_execute(qelement *head)
315 {
316     int result = DITEM_SUCCESS;
317     command_buffer *item;
318     char *old_interactive;
319
320     if (!head)
321         return result | DITEM_FAILURE;
322
323     old_interactive = variable_get(VAR_NONINTERACTIVE);
324     if (old_interactive)
325          old_interactive = strdup(old_interactive);     /* save copy */
326
327     /* Hint to others that we're running from a script, should they care */
328     variable_set2(VAR_NONINTERACTIVE, "yes", 0);
329
330     while (!EMPTYQUE(*head)) {
331         item = (command_buffer *) head->q_forw;
332         
333         if (DITEM_STATUS(dispatchCommand(item->string)) != DITEM_SUCCESS) {
334             msgConfirm("Command `%s' failed - rest of script aborted.\n",
335                        item->string);
336             result |= DITEM_FAILURE;
337             break;
338         }
339         dispatch_free_command(item);
340     }
341
342     dispatch_free_all(head);
343
344     if (!old_interactive)
345         variable_unset(VAR_NONINTERACTIVE);
346     else {
347         variable_set2(VAR_NONINTERACTIVE, old_interactive, 0);
348         free(old_interactive);
349     }
350
351     return result;
352 }
353
354 int
355 dispatch_load_file_int(int quiet)
356 {
357     FILE *fp;
358     char *cp;
359     int  i;
360     qelement *list;
361
362     static const char *names[] = {
363         "install.cfg",
364         "/stand/install.cfg",
365         "/tmp/install.cfg",
366         NULL
367     };
368
369     fp = NULL;
370     cp = variable_get(VAR_CONFIG_FILE);
371     if (!cp) {
372         for (i = 0; names[i]; i++)
373             if ((fp = fopen(names[i], "r")) != NULL)
374                 break;
375     } else
376         fp = fopen(cp, "r");
377
378     if (!fp) {
379         if (!quiet)
380             msgConfirm("Unable to open %s: %s", cp, strerror(errno));
381         return DITEM_FAILURE;
382     }
383
384     list = dispatch_load_fp(fp);
385     fclose(fp);
386
387     return dispatch_execute(list);
388 }
389
390 int
391 dispatch_load_file(dialogMenuItem *self)
392 {
393     return dispatch_load_file_int(FALSE);
394 }
395
396 int
397 dispatch_load_floppy(dialogMenuItem *self)
398 {
399     int             what = DITEM_SUCCESS;
400     extern char    *distWanted;
401     char           *cp;
402     FILE           *fp;
403     qelement       *list;
404
405     mediaClose();
406     cp = variable_get_value(VAR_INSTALL_CFG,
407                             "Specify the name of a configuration file\n"
408                             "residing on a MSDOS or UFS floppy.", 0);
409     if (!cp || !*cp) {
410         variable_unset(VAR_INSTALL_CFG);
411         what |= DITEM_FAILURE;
412         return what;
413     }
414
415     distWanted = cp;
416     /* Try to open the floppy drive */
417     if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) {
418         msgConfirm("Unable to set media device to floppy.");
419         what |= DITEM_FAILURE;
420         mediaClose();
421         return what;
422     }
423
424     if (!DEVICE_INIT(mediaDevice)) {
425         msgConfirm("Unable to mount floppy filesystem.");
426         what |= DITEM_FAILURE;
427         mediaClose();
428         return what;
429     }
430
431     fp = DEVICE_GET(mediaDevice, cp, TRUE);
432     if (fp) {
433         list = dispatch_load_fp(fp);
434         fclose(fp);
435         mediaClose();
436
437         what |= dispatch_execute(list);
438     }
439     else {
440         if (!variable_get(VAR_NO_ERROR))
441             msgConfirm("Configuration file '%s' not found.", cp);
442         variable_unset(VAR_INSTALL_CFG);
443         what |= DITEM_FAILURE;
444         mediaClose();
445     }
446     return what;
447 }
448