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