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