00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <string.h>
00004 #include <signal.h>
00005 #include <stdarg.h>
00006 #include <unistd.h>
00007 #include <fcntl.h>
00008 #include <errno.h>
00009 #include <sys/types.h>
00010 #include <sys/wait.h>
00011
00012 #include "config.h"
00013 #include "gis.h"
00014 #include "glocale.h"
00015 #include "spawn.h"
00016
00017 #define MAX_ARGS 256
00018 #define MAX_BINDINGS 256
00019 #define MAX_SIGNALS 32
00020 #define MAX_REDIRECTS 32
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 int G_spawn(char *command, ...)
00031 {
00032 va_list va;
00033 char *args[MAX_ARGS];
00034 int num_args = 0;
00035 struct sigaction act, intr, quit;
00036 sigset_t block, oldmask;
00037 int status = -1;
00038 pid_t pid;
00039
00040 args[0] = command;
00041
00042 va_start(va, command);
00043
00044 for (num_args = 1; num_args < MAX_ARGS; )
00045 {
00046 char *arg = va_arg(va, char *);
00047 if (!arg)
00048 break;
00049 args[num_args++] = arg;
00050 }
00051
00052 va_end(va);
00053
00054 if (num_args >= MAX_ARGS)
00055 {
00056 G_warning(_("too many arguments"));
00057 return -1;
00058 }
00059
00060 sigemptyset(&act.sa_mask);
00061 act.sa_flags = SA_RESTART;
00062
00063 act.sa_handler = SIG_IGN;
00064 if (sigaction(SIGINT, &act, &intr) < 0)
00065 goto error_1;
00066 if (sigaction(SIGQUIT, &act, &quit) < 0)
00067 goto error_2;
00068
00069 sigemptyset(&block);
00070 sigaddset(&block, SIGCHLD);
00071 if (sigprocmask(SIG_BLOCK, &block, &oldmask) < 0)
00072 goto error_3;
00073
00074 pid = fork();
00075
00076 if (pid < 0)
00077 {
00078 G_warning(_("unable to create a new process"));
00079 goto error_4;
00080 }
00081
00082 if (pid == 0)
00083 {
00084 sigaction(SIGINT, &intr, NULL);
00085 sigaction(SIGQUIT, &quit, NULL);
00086
00087 execvp(command, args);
00088 G_warning(_("unable to execute command"));
00089 _exit(127);
00090 }
00091 else
00092 {
00093 pid_t n;
00094
00095 do n = waitpid(pid, &status, 0);
00096 while (n == (pid_t) -1 && errno == EINTR);
00097
00098 if (n != pid)
00099 status = -1;
00100 }
00101
00102 error_4:
00103 sigprocmask(SIG_SETMASK, &oldmask, NULL);
00104 error_3:
00105 sigaction(SIGQUIT, &quit, NULL);
00106 error_2:
00107 sigaction(SIGINT, &intr, NULL);
00108 error_1:
00109 return status;
00110 }
00111
00112
00113
00114
00115
00116
00117
00118
00119 struct redirect
00120 {
00121 int dst_fd;
00122 int src_fd;
00123 char *file;
00124 int mode;
00125 };
00126
00127 struct signal
00128 {
00129 int which;
00130 int action;
00131 int signum;
00132 int valid;
00133 struct sigaction old_act;
00134 sigset_t old_mask;
00135 };
00136
00137 struct binding
00138 {
00139 char *var;
00140 char *val;
00141 };
00142
00143 static int undo_signals(struct signal *signals, int num_signals, int which)
00144 {
00145 int error = 0;
00146 int i;
00147
00148 for (i = num_signals-1; i >= 0; i--)
00149 {
00150 struct signal *s = &signals[i];
00151
00152 if (s->which != which)
00153 continue;
00154
00155 if (!s->valid)
00156 continue;
00157
00158 switch (s->action)
00159 {
00160 case SSA_IGNORE:
00161 case SSA_DEFAULT:
00162 if (sigaction(s->signum, &s->old_act, NULL) < 0)
00163 {
00164 G_warning(_("G_spawn: unable to restore signal %d"), s->signum);
00165 error = 1;
00166 }
00167 break;
00168 case SSA_BLOCK:
00169 case SSA_UNBLOCK:
00170 if (sigprocmask(SIG_UNBLOCK, &s->old_mask, NULL) < 0)
00171 {
00172 G_warning(_("G_spawn: unable to restore signal %d"), s->signum);
00173 error = 1;
00174 }
00175 break;
00176 }
00177 }
00178
00179 return !error;
00180 }
00181
00182 static int do_signals(struct signal *signals, int num_signals, int which)
00183 {
00184 struct sigaction act;
00185 sigset_t mask;
00186 int error = 0;
00187 int i;
00188
00189 sigemptyset(&act.sa_mask);
00190 act.sa_flags = SA_RESTART;
00191
00192 for (i = 0; i < num_signals; i++)
00193 {
00194 struct signal *s = &signals[i];
00195
00196 if (s->which != which)
00197 continue;
00198
00199 switch (s->action)
00200 {
00201 case SSA_IGNORE:
00202 act.sa_handler = SIG_IGN;
00203 if (sigaction(s->signum, &act, &s->old_act) < 0)
00204 {
00205 G_warning(_("G_spawn: unable to reset signal %d"), s->signum);
00206 error = 1;
00207 }
00208 else
00209 s->valid = 1;
00210 break;
00211 case SSA_DEFAULT:
00212 act.sa_handler = SIG_DFL;
00213 if (sigaction(s->signum, &act, &s->old_act) < 0)
00214 {
00215 G_warning(_("G_spawn: unable to ignore signal %d"), s->signum);
00216 error = 1;
00217 }
00218 else
00219 s->valid = 1;
00220 break;
00221 case SSA_BLOCK:
00222 sigemptyset(&mask);
00223 sigaddset(&mask, s->signum);
00224 if (sigprocmask(SIG_BLOCK, &mask, &s->old_mask) < 0)
00225 {
00226 G_warning(_("G_spawn: unable to block signal %d"), s->signum);
00227 error = 1;
00228 }
00229 break;
00230 case SSA_UNBLOCK:
00231 sigemptyset(&mask);
00232 sigaddset(&mask, s->signum);
00233 if (sigprocmask(SIG_UNBLOCK, &mask, &s->old_mask) < 0)
00234 {
00235 G_warning(_("G_spawn: unable to unblock signal %d"), s->signum);
00236 error = 1;
00237 }
00238 else
00239 s->valid = 1;
00240 break;
00241 }
00242 }
00243
00244 return !error;
00245 }
00246
00247 static void do_redirects(struct redirect *redirects, int num_redirects)
00248 {
00249 int i;
00250
00251 for (i = 0; i < num_redirects; i++)
00252 {
00253 struct redirect *r = &redirects[i];
00254
00255 if (r->file)
00256 {
00257 r->src_fd = open(r->file, r->mode, 0666);
00258
00259 if (r->src_fd < 0)
00260 {
00261 G_warning(_("G_spawn: unable to open file %s"), r->file);
00262 _exit(127);
00263 }
00264
00265 if (dup2(r->src_fd, r->dst_fd) < 0)
00266 {
00267 G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"), r->src_fd, r->dst_fd);
00268 _exit(127);
00269 }
00270
00271 close(r->src_fd);
00272 }
00273 else if (r->src_fd >= 0)
00274 {
00275 if (dup2(r->src_fd, r->dst_fd) < 0)
00276 {
00277 G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"), r->src_fd, r->dst_fd);
00278 _exit(127);
00279 }
00280 }
00281 else
00282 close(r->dst_fd);
00283 }
00284 }
00285
00286 static void do_bindings(struct binding *bindings, int num_bindings)
00287 {
00288 int i;
00289
00290 for (i = 0; i < num_bindings; i++)
00291 {
00292 struct binding *b = &bindings[i];
00293 char *str;
00294
00295 str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
00296 sprintf(str, "%s=%s", b->var, b->val);
00297 putenv(str);
00298 }
00299 }
00300
00301 int G_spawn_ex(char *command, ...)
00302 {
00303 char *args[MAX_ARGS];
00304 int num_args = 0;
00305 struct redirect redirects[MAX_REDIRECTS];
00306 int num_redirects = 0;
00307 struct signal signals[MAX_SIGNALS];
00308 int num_signals = 0;
00309 struct binding bindings[MAX_BINDINGS];
00310 int num_bindings = 0;
00311 int background = 0;
00312 char *directory = NULL;
00313 va_list va;
00314 char *var, *val;
00315 int status = -1;
00316 pid_t pid;
00317
00318 args[num_args++] = command;
00319
00320 va_start(va, command);
00321
00322 for (;;)
00323 {
00324 char *arg = va_arg(va, char *);
00325
00326 switch ((int) arg)
00327 {
00328 case 0:
00329 args[num_args++] = NULL;
00330 break;
00331 case ((int) SF_REDIRECT_FILE):
00332 redirects[num_redirects].dst_fd = va_arg(va, int);
00333 redirects[num_redirects].src_fd = -1;
00334 redirects[num_redirects].mode = va_arg(va, int);
00335 redirects[num_redirects].file = va_arg(va, char *);
00336 num_redirects++;
00337 break;
00338 case ((int) SF_REDIRECT_DESCRIPTOR):
00339 redirects[num_redirects].dst_fd = va_arg(va, int);
00340 redirects[num_redirects].src_fd = va_arg(va, int);
00341 redirects[num_redirects].file = NULL;
00342 num_redirects++;
00343 break;
00344 case ((int) SF_CLOSE_DESCRIPTOR):
00345 redirects[num_redirects].dst_fd = va_arg(va, int);
00346 redirects[num_redirects].src_fd = -1;
00347 redirects[num_redirects].file = NULL;
00348 num_redirects++;
00349 break;
00350 case ((int) SF_SIGNAL):
00351 signals[num_signals].which = va_arg(va, int);
00352 signals[num_signals].action = va_arg(va, int);
00353 signals[num_signals].signum = va_arg(va, int);
00354 signals[num_signals].valid = 0;;
00355 num_signals++;
00356 break;
00357 case ((int) SF_VARIABLE):
00358 var = va_arg(va, char *);
00359 val = getenv(var);
00360 args[num_args++] = val ? val : "";
00361 break;
00362 case ((int) SF_BINDING):
00363 bindings[num_bindings].var = va_arg(va, char *);
00364 bindings[num_bindings].val = va_arg(va, char *);
00365 num_bindings++;
00366 break;
00367 case ((int) SF_BACKGROUND):
00368 background = 1;
00369 break;
00370 case ((int) SF_DIRECTORY):
00371 directory = va_arg(va, char *);
00372 break;
00373 default:
00374 args[num_args++] = arg;
00375 break;
00376 }
00377
00378 if (!arg)
00379 break;
00380 }
00381
00382 va_end(va);
00383
00384 if (!do_signals(signals, num_signals, SST_PRE))
00385 goto error_1;
00386
00387 pid = fork();
00388 if (pid < 0)
00389 {
00390 G_warning(_("unable to create a new process"));
00391 goto error_2;
00392 }
00393
00394 if (pid == 0)
00395 {
00396 if (!undo_signals(signals, num_signals, SST_PRE))
00397 _exit(127);
00398
00399 if (!do_signals(signals, num_signals, SST_CHILD))
00400 _exit(127);
00401
00402 if (directory)
00403 if (chdir(directory) < 0)
00404 {
00405 G_warning(_("unable to change directory to %s"), directory);
00406 _exit(127);
00407 }
00408
00409 do_redirects(redirects, num_redirects);
00410 do_bindings(bindings, num_bindings);
00411
00412 execvp(command, args);
00413 G_warning(_("unable to execute command"));
00414 _exit(127);
00415 }
00416
00417 do_signals(signals, num_signals, SST_POST);
00418
00419 if (background)
00420 status = (int) pid;
00421 else
00422 {
00423 pid_t n;
00424
00425 do n = waitpid(pid, &status, 0);
00426 while (n == (pid_t) -1 && errno == EINTR);
00427
00428 if (n != pid)
00429 status = -1;
00430 }
00431
00432 undo_signals(signals, num_signals, SST_POST);
00433 error_2:
00434 undo_signals(signals, num_signals, SST_PRE);
00435 error_1:
00436
00437 return status;
00438 }
00439