dispatch.c revision 161060
1/*
2 * $FreeBSD: head/usr.sbin/sade/dispatch.c 161060 2006-08-07 23:35:49Z netchild $
3 *
4 * Copyright (c) 1995
5 *	Jordan Hubbard.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer,
12 *    verbatim and that no modifications are made prior to this
13 *    point in the file.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 */
31
32#include "sade.h"
33#include <ctype.h>
34#include <errno.h>
35#include <sys/signal.h>
36#include <sys/fcntl.h>
37
38#include "list.h"
39
40static int dispatch_systemExecute(dialogMenuItem *unused);
41static int dispatch_msgConfirm(dialogMenuItem *unused);
42
43static struct _word {
44    char *name;
45    int (*handler)(dialogMenuItem *self);
46} resWords[] = {
47#ifdef WITH_SLICES
48    { "diskPartitionEditor",	diskPartitionEditor	},
49#endif
50    { "diskPartitionWrite",	diskPartitionWrite	},
51    { "diskLabelEditor",	diskLabelEditor		},
52    { "diskLabelCommit",	diskLabelCommit		},
53    { "msgConfirm",		dispatch_msgConfirm	},
54    { "system",			dispatch_systemExecute	},
55    { "dumpVariables",		dump_variables		},
56    { NULL, NULL },
57};
58
59/*
60 * Helper routines for buffering data.
61 *
62 * We read an entire configuration into memory before executing it
63 * so that we are truely standalone and can do things like nuke the
64 * file or disk we're working on.
65 */
66
67typedef struct command_buffer_ {
68    qelement	queue;
69    char *	string;
70} command_buffer;
71
72static void
73dispatch_free_command(command_buffer *item)
74{
75    REMQUE(item);
76    free(item->string);
77    free(item);
78}
79
80static void
81dispatch_free_all(qelement *head)
82{
83    command_buffer *item;
84
85    while (!EMPTYQUE(*head)) {
86	item = (command_buffer *) head->q_forw;
87	dispatch_free_command(item);
88    }
89}
90
91static command_buffer *
92dispatch_add_command(qelement *head, char *string)
93{
94    command_buffer *new;
95
96    new = malloc(sizeof(command_buffer));
97
98    if (!new)
99	return NULL;
100
101    new->string = strdup(string);
102    INSQUEUE(new, head->q_back);
103
104    return new;
105}
106
107/*
108 * Command processing
109 */
110
111static int
112dispatch_systemExecute(dialogMenuItem *unused)
113{
114    char *cmd = variable_get(VAR_COMMAND);
115
116    if (cmd)
117	return systemExecute(cmd) ? DITEM_FAILURE : DITEM_SUCCESS;
118    else
119	msgDebug("_systemExecute: No command passed in `command' variable.\n");
120    return DITEM_FAILURE;
121}
122
123static int
124dispatch_msgConfirm(dialogMenuItem *unused)
125{
126    char *msg = variable_get(VAR_COMMAND);
127
128    if (msg) {
129	msgConfirm("%s", msg);
130	return DITEM_SUCCESS;
131    }
132
133    msgDebug("_msgConfirm: No message passed in `command' variable.\n");
134    return DITEM_FAILURE;
135}
136
137static int
138call_possible_resword(char *name, dialogMenuItem *value, int *status)
139{
140    int i, rval;
141
142    rval = 0;
143    for (i = 0; resWords[i].name; i++) {
144	if (!strcmp(name, resWords[i].name)) {
145	    *status = resWords[i].handler(value);
146	    rval = 1;
147	    break;
148	}
149    }
150    return rval;
151}
152
153/* For a given string, call it or spit out an undefined command diagnostic */
154int
155dispatchCommand(char *str)
156{
157    int i;
158    char *cp;
159
160    if (!str || !*str) {
161	msgConfirm("Null or zero-length string passed to dispatchCommand");
162	return DITEM_FAILURE;
163    }
164    /* If it's got a newline, trim it */
165    if ((cp = index(str, '\n')) != NULL)
166	*cp = '\0';
167
168    /* If it's got a `=' sign in there, assume it's a variable setting */
169    if (index(str, '=')) {
170	if (isDebug())
171	    msgDebug("dispatch: setting variable `%s'\n", str);
172	variable_set(str, 0);
173	i = DITEM_SUCCESS;
174    }
175    else {
176	/* A command might be a pathname if it's encoded in argv[0], which
177	   we also support */
178	if ((cp = rindex(str, '/')) != NULL)
179	    str = cp + 1;
180	if (isDebug())
181	    msgDebug("dispatch: calling resword `%s'\n", str);
182	if (!call_possible_resword(str, NULL, &i)) {
183	    msgNotify("Warning: No such command ``%s''", str);
184	    i = DITEM_FAILURE;
185	}
186	/*
187	 * Allow a user to prefix a command with "noError" to cause
188	 * us to ignore any errors for that one command.
189	 */
190	if (i != DITEM_SUCCESS && variable_get(VAR_NO_ERROR))
191	    i = DITEM_SUCCESS;
192	variable_unset(VAR_NO_ERROR);
193    }
194    return i;
195}
196
197
198/*
199 * File processing
200 */
201
202static qelement *
203dispatch_load_fp(FILE *fp)
204{
205    qelement *head;
206    char buf[BUFSIZ], *cp;
207
208    head = malloc(sizeof(qelement));
209
210    if (!head)
211	return NULL;
212
213    INITQUE(*head);
214
215    while (fgets(buf, sizeof buf, fp)) {
216
217	if ((cp = strchr(buf, '\n')) != NULL)
218	    *cp = '\0';
219	if (*buf == '\0' || *buf == '#')
220	    continue;
221
222	if (!dispatch_add_command(head, buf))
223	    return NULL;
224    }
225
226    return head;
227}
228
229static int
230dispatch_execute(qelement *head)
231{
232    int result = DITEM_SUCCESS;
233    command_buffer *item;
234    char *old_interactive;
235
236    if (!head)
237	return result | DITEM_FAILURE;
238
239    old_interactive = variable_get(VAR_NONINTERACTIVE);
240    if (old_interactive)
241	 old_interactive = strdup(old_interactive);	/* save copy */
242
243    /* Hint to others that we're running from a script, should they care */
244    variable_set2(VAR_NONINTERACTIVE, "yes", 0);
245
246    while (!EMPTYQUE(*head)) {
247	item = (command_buffer *) head->q_forw;
248
249	if (DITEM_STATUS(dispatchCommand(item->string)) != DITEM_SUCCESS) {
250	    msgConfirm("Command `%s' failed - rest of script aborted.\n",
251		       item->string);
252	    result |= DITEM_FAILURE;
253	    break;
254	}
255	dispatch_free_command(item);
256    }
257
258    dispatch_free_all(head);
259
260    if (!old_interactive)
261	variable_unset(VAR_NONINTERACTIVE);
262    else {
263	variable_set2(VAR_NONINTERACTIVE, old_interactive, 0);
264	free(old_interactive);
265    }
266
267    return result;
268}
269