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