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