]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/sysinstall/dispatch.c
This commit was generated by cvs2svn to compensate for changes in r94209,
[FreeBSD/FreeBSD.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
49 static struct _word {
50     char *name;
51     int (*handler)(dialogMenuItem *self);
52 } resWords[] = {
53     { "configAnonFTP",          configAnonFTP           },
54     { "configRouter",           configRouter            },
55     { "configInetd",            configInetd             },
56     { "configNFSServer",        configNFSServer         },
57     { "configNTP",              configNTP               },
58     { "configPCNFSD",           configPCNFSD            },
59     { "configPackages",         configPackages          },
60     { "configUsers",            configUsers             },
61     { "configXSetup",           configXSetup    },
62     { "configXDesktop",         configXDesktop  },
63     { "diskPartitionEditor",    diskPartitionEditor     },
64     { "diskPartitionWrite",     diskPartitionWrite      },
65     { "diskLabelEditor",        diskLabelEditor         },
66     { "diskLabelCommit",        diskLabelCommit         },
67     { "distReset",              distReset               },
68     { "distSetCustom",          distSetCustom           },
69     { "distUnsetCustom",        distUnsetCustom         },
70     { "distSetDeveloper",       distSetDeveloper        },
71     { "distSetXDeveloper",      distSetXDeveloper       },
72     { "distSetKernDeveloper",   distSetKernDeveloper    },
73     { "distSetUser",            distSetUser             },
74     { "distSetXUser",           distSetXUser            },
75     { "distSetMinimum",         distSetMinimum          },
76     { "distSetEverything",      distSetEverything       },
77     { "distSetSrc",             distSetSrc              },
78     { "distSetXF86",            distSetXF86             },
79     { "distExtractAll",         distExtractAll          },
80     { "docBrowser",             docBrowser              },
81     { "docShowDocument",        docShowDocument         },
82     { "installCommit",          installCommit           },
83     { "installExpress",         installExpress          },
84     { "installStandard",        installStandard         },
85     { "installUpgrade",         installUpgrade          },
86     { "installFixupBin",        installFixupBin         },
87 #ifndef X_AS_PKG
88     { "installFixupXFree",      installFixupXFree       },
89 #endif
90     { "installFixitHoloShell",  installFixitHoloShell   },
91     { "installFixitCDROM",      installFixitCDROM       },
92     { "installFixitFloppy",     installFixitFloppy      },
93     { "installFilesystems",     installFilesystems      },
94     { "installVarDefaults",     installVarDefaults      },
95     { "loadConfig",             dispatch_load_file      },
96     { "loadFloppyConfig",       dispatch_load_floppy    },
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 call_possible_resword(char *name, dialogMenuItem *value, int *status)
210 {
211     int i, rval;
212
213     rval = 0;
214     for (i = 0; resWords[i].name; i++) {
215         if (!strcmp(name, resWords[i].name)) {
216             *status = resWords[i].handler(value);
217             rval = 1;
218             break;
219         }
220     }
221     return rval;
222 }
223
224 /* For a given string, call it or spit out an undefined command diagnostic */
225 int
226 dispatchCommand(char *str)
227 {
228     int i;
229     char *cp;
230
231     if (!str || !*str) {
232         msgConfirm("Null or zero-length string passed to dispatchCommand");
233         return DITEM_FAILURE;
234     }
235     /* If it's got a newline, trim it */
236     if ((cp = index(str, '\n')) != NULL)
237         *cp = '\0';
238
239     /* If it's got a `=' sign in there, assume it's a variable setting */
240     if (index(str, '=')) {
241         if (isDebug())
242             msgDebug("dispatch: setting variable `%s'\n", str);
243         variable_set(str, 0);
244         i = DITEM_SUCCESS;
245     }
246     else {
247         /* A command might be a pathname if it's encoded in argv[0], which
248            we also support */
249         if ((cp = rindex(str, '/')) != NULL)
250             str = cp + 1;
251         if (isDebug())
252             msgDebug("dispatch: calling resword `%s'\n", str);
253         if (!call_possible_resword(str, NULL, &i)) {
254             msgNotify("Warning: No such command ``%s''", str);
255             i = DITEM_FAILURE;
256         }
257     }
258     return i;
259 }
260
261 \f
262 /*
263  * File processing
264  */
265
266 static qelement *
267 dispatch_load_fp(FILE *fp)
268 {
269     qelement *head;
270     char buf[BUFSIZ], *cp;
271
272     head = malloc(sizeof(qelement));
273
274     if (!head)
275         return NULL;
276
277     INITQUE(*head);
278
279     while (fgets(buf, sizeof buf, fp)) {
280
281         if ((cp = strchr(buf, '\n')) != NULL)
282             *cp = '\0';
283         if (*buf == '\0' || *buf == '#')
284             continue;
285
286         if (!dispatch_add_command(head, buf))
287             return NULL;
288     }
289
290     return head;
291 }
292
293 static int
294 dispatch_execute(qelement *head)
295 {
296     int result = DITEM_SUCCESS;
297     command_buffer *item;
298     char *old_interactive;
299
300     if (!head)
301         return result | DITEM_FAILURE;
302
303     old_interactive = variable_get(VAR_NONINTERACTIVE);
304     if (old_interactive)
305          old_interactive = strdup(old_interactive);     /* save copy */
306
307     /* Hint to others that we're running from a script, should they care */
308     variable_set2(VAR_NONINTERACTIVE, "yes", 0);
309
310     while (!EMPTYQUE(*head)) {
311         item = (command_buffer *) head->q_forw;
312         
313         if (DITEM_STATUS(dispatchCommand(item->string)) != DITEM_SUCCESS) {
314             /*
315              * Allow a user to prefix a command with "noError" to cause
316              * us to ignore any errors for that one command.
317              */
318             if (variable_get(VAR_NO_ERROR))
319                 variable_unset(VAR_NO_ERROR);
320             else {
321                 msgConfirm("Command `%s' failed - rest of script aborted.\n",
322                            item->string);
323                 result |= DITEM_FAILURE;
324                 break;
325             }
326         }
327         dispatch_free_command(item);
328     }
329
330     dispatch_free_all(head);
331
332     if (!old_interactive)
333         variable_unset(VAR_NONINTERACTIVE);
334     else {
335         variable_set2(VAR_NONINTERACTIVE, old_interactive, 0);
336         free(old_interactive);
337     }
338
339     return result;
340 }
341
342 int
343 dispatch_load_file_int(int quiet)
344 {
345     FILE *fp;
346     char *cp;
347     int  i;
348     qelement *list;
349
350     static const char *names[] = {
351         "install.cfg",
352         "/stand/install.cfg",
353         "/tmp/install.cfg",
354         NULL
355     };
356
357     fp = NULL;
358     cp = variable_get(VAR_CONFIG_FILE);
359     if (!cp) {
360         for (i = 0; names[i]; i++)
361             if ((fp = fopen(names[i], "r")) != NULL)
362                 break;
363     } else
364         fp = fopen(cp, "r");
365
366     if (!fp) {
367         if (!quiet)
368             msgConfirm("Unable to open %s: %s", cp, strerror(errno));
369         return DITEM_FAILURE;
370     }
371
372     list = dispatch_load_fp(fp);
373     fclose(fp);
374
375     return dispatch_execute(list);
376 }
377
378 int
379 dispatch_load_file(dialogMenuItem *self)
380 {
381     return dispatch_load_file_int(FALSE);
382 }
383
384 int
385 dispatch_load_floppy(dialogMenuItem *self)
386 {
387     int             what = DITEM_SUCCESS;
388     extern char    *distWanted;
389     char           *cp;
390     FILE           *fp;
391     qelement       *list;
392
393     mediaClose();
394     cp = variable_get_value(VAR_INSTALL_CFG,
395                             "Specify the name of a configuration file\n"
396                             "residing on a MSDOS or UFS floppy.", 0);
397     if (!cp || !*cp) {
398         variable_unset(VAR_INSTALL_CFG);
399         what |= DITEM_FAILURE;
400         return what;
401     }
402
403     distWanted = cp;
404     /* Try to open the floppy drive */
405     if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) {
406         msgConfirm("Unable to set media device to floppy.");
407         what |= DITEM_FAILURE;
408         mediaClose();
409         return what;
410     }
411
412     if (!DEVICE_INIT(mediaDevice)) {
413         msgConfirm("Unable to mount floppy filesystem.");
414         what |= DITEM_FAILURE;
415         mediaClose();
416         return what;
417     }
418
419     fp = DEVICE_GET(mediaDevice, cp, TRUE);
420     if (fp) {
421         list = dispatch_load_fp(fp);
422         fclose(fp);
423         mediaClose();
424
425         what |= dispatch_execute(list);
426     }
427     else {
428         if (!variable_get(VAR_NO_ERROR))
429             msgConfirm("Configuration file '%s' not found.", cp);
430         variable_unset(VAR_INSTALL_CFG);
431         what |= DITEM_FAILURE;
432         mediaClose();
433     }
434     return what;
435 }
436