• Main Page
  • Related Pages
  • Data Structures
  • Files
  • File List
  • Globals

spawn.c

Go to the documentation of this file.
00001 
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 #include <string.h>
00020 #include <signal.h>
00021 #include <stdarg.h>
00022 #include <unistd.h>
00023 #include <fcntl.h>
00024 #include <errno.h>
00025 #include <sys/types.h>
00026 
00027 #ifndef __MINGW32__
00028 #include <sys/wait.h>
00029 #else
00030 #include <windows.h>
00031 #endif
00032 #include <grass/config.h>
00033 #include <grass/gis.h>
00034 #include <grass/glocale.h>
00035 #include <grass/spawn.h>
00036 
00044 #define MAX_ARGS 256
00045 #define MAX_BINDINGS 256
00046 #define MAX_SIGNALS 32
00047 #define MAX_REDIRECTS 32
00048 
00049 
00061 struct redirect
00062 {
00063     int dst_fd;
00064     int src_fd;
00065     const char *file;
00066     int mode;
00067 };
00068 
00069 struct signal
00070 {
00071     int which;
00072     int action;
00073     int signum;
00074     int valid;
00075 #ifndef __MINGW32__
00076     struct sigaction old_act;
00077     sigset_t old_mask;
00078 #endif
00079 };
00080 
00081 struct binding
00082 {
00083     const char *var;
00084     const char *val;
00085 };
00086 
00087 struct spawn
00088 {
00089     const char *args[MAX_ARGS];
00090     int num_args;
00091     struct redirect redirects[MAX_REDIRECTS];
00092     int num_redirects;
00093     struct signal signals[MAX_SIGNALS];
00094     int num_signals;
00095     struct binding bindings[MAX_BINDINGS];
00096     int num_bindings;
00097     int background;
00098     const char *directory;
00099 };
00100 
00101 static void parse_arglist(struct spawn *sp, va_list va);
00102 static void parse_argvec(struct spawn *sp, const char **va);
00103 
00104 #ifdef __MINGW32__
00105 
00106 struct buffer {
00107     char *str;
00108     size_t len;
00109     size_t size;
00110 };
00111 
00112 static const int INCREMENT = 50;
00113 
00114 static void clear(struct buffer *b)
00115 {
00116     b->len = 0;
00117     b->str[b->len] = '\0';
00118 }
00119 
00120 static void init(struct buffer *b)
00121 {
00122     b->str = G_malloc(1);
00123     b->size = 1;
00124     clear(b);
00125 }
00126 
00127 static char *release(struct buffer *b)
00128 {
00129     char *p = b->str;
00130 
00131     b->str = NULL;
00132     b->size = 0;
00133     b->len = 0;
00134 
00135     return p;
00136 }
00137 
00138 static void finish(struct buffer *b)
00139 {
00140     if (b->str)
00141         G_free(b->str);
00142     release(b);
00143 }
00144 
00145 static void ensure(struct buffer *b, size_t n)
00146 {
00147     if (b->size <= b->len + n + 1) {
00148         b->size = b->len + n + INCREMENT;
00149         b->str = G_realloc(b->str, b->size);
00150     }
00151 }
00152 
00153 static void append(struct buffer *b, const char *str)
00154 {
00155     size_t n = strlen(str);
00156 
00157     ensure(b, n);
00158     memcpy(&b->str[b->len], str, n);
00159     b->len += n;
00160     b->str[b->len] = '\0';
00161 }
00162 
00163 static void append_char(struct buffer *b, char c)
00164 {
00165     ensure(b, 1);
00166     b->str[b->len] = c;
00167     b->len++;
00168     b->str[b->len] = '\0';
00169 }
00170 
00171 static void escape_arg(struct buffer *result, const char *arg)
00172 {
00173     struct buffer buf;
00174     int quote, j;
00175 
00176     init(&buf);
00177 
00178     quote = arg[0] == '\0' || strchr(arg, ' ') || strchr(arg, '\t');
00179 
00180     if (quote)
00181         append_char(result, '\"');
00182 
00183     for (j = 0; arg[j]; j++) {
00184         int c = arg[j];
00185         int k;
00186 
00187         switch (c) {
00188         case '\\':
00189             append_char(&buf, '\\');
00190             break;
00191         case '\"':
00192             for (k = 0; k < buf.len; k++)
00193                 append(result, "\\\\");
00194             clear(&buf);
00195             append(result, "\\\"");
00196             break;
00197         default:
00198             if (buf.len > 0) {
00199                 append(result, buf.str);
00200                 clear(&buf);
00201             }
00202             append_char(result, c);
00203         }
00204     }
00205 
00206     if (buf.len > 0)
00207         append(result, buf.str);
00208 
00209     if (quote) {
00210         append(result, buf.str);
00211         append_char(result, '\"');
00212     }
00213 
00214     finish(&buf);
00215 }
00216 
00217 static char *check_program(const char *pgm, const char *dir, const char *ext)
00218 {
00219     char pathname[GPATH_MAX];
00220 
00221     sprintf(pathname, "%s%s%s%s", dir, *dir ? "\\" : "", pgm, ext);
00222     return access(pathname, 0) == 0
00223         ? G_store(pathname)
00224         : NULL;
00225 }
00226 
00227 static char *find_program_ext(const char *pgm, const char *dir, char **pathext)
00228 {
00229     char *result;
00230     int i;
00231 
00232     if (result = check_program(pgm, dir, ""), result)
00233         return result;
00234 
00235     for (i = 0; pathext[i]; i++) {
00236         const char *ext = pathext[i];
00237         if (result = check_program(pgm, dir, ext), result)
00238             return result;
00239     }
00240 
00241     return NULL;
00242 }
00243 
00244 static char *find_program_dir_ext(const char *pgm, char **path, char **pathext)
00245 {
00246     char *result = NULL;
00247     int i;
00248 
00249     if (strchr(pgm, '\\') || strchr(pgm, '/')) {
00250         if (result = find_program_ext(pgm, "", pathext), result)
00251             return result;
00252     }
00253     else {
00254         if (result = find_program_ext(pgm, ".", pathext), result)
00255             return result;
00256 
00257         for (i = 0; path[i]; i++) {
00258             const char *dir = path[i];
00259             if (result = find_program_ext(pgm, dir, pathext), result)
00260                 return result;
00261         }
00262     }
00263 
00264     return NULL;
00265 }
00266 
00267 static char *find_program(const char *pgm)
00268 {
00269     char **path = G_tokenize(getenv("PATH"), ";");
00270     char **pathext = G_tokenize(getenv("PATHEXT"), ";");
00271     char *result = find_program_dir_ext(pgm, path, pathext);
00272     G_free_tokens(path);
00273     G_free_tokens(pathext);
00274     return result;
00275 }
00276 
00277 static char *make_command_line(int shell, const char *cmd, const char **argv)
00278 {
00279     struct buffer result;
00280     int i;
00281 
00282     init(&result);
00283 
00284     if (shell) {
00285         const char *comspec = getenv("COMSPEC");
00286         append(&result, comspec ? comspec : "cmd.exe");
00287         append(&result, " /c \"");
00288         escape_arg(&result, cmd);
00289     }
00290 
00291     for (i = shell ? 1 : 0; argv[i]; i++) {
00292         if (result.len > 0)
00293             append_char(&result, ' ');
00294         escape_arg(&result, argv[i]);
00295     }
00296 
00297     append(&result, "\"");
00298 
00299     return release(&result);
00300 }
00301 
00302 static char *make_environment(const char **envp)
00303 {
00304     struct buffer result;
00305     int i;
00306 
00307     init(&result);
00308 
00309     for (i = 0; envp[i]; i++) {
00310         const char *env = envp[i];
00311 
00312         append(&result, env);
00313         append_char(&result, '\0');
00314     }
00315 
00316     return release(&result);
00317 }
00318 
00319 static HANDLE get_handle(int fd)
00320 {
00321     HANDLE h1, h2;
00322 
00323     if (fd < 0)
00324         return INVALID_HANDLE_VALUE;
00325 
00326     h1 = (HANDLE) _get_osfhandle(fd);
00327     if (!DuplicateHandle(GetCurrentProcess(), h1,
00328                          GetCurrentProcess(), &h2,
00329                          0, TRUE, DUPLICATE_SAME_ACCESS))
00330         return INVALID_HANDLE_VALUE;
00331 
00332     return h2;
00333 }
00334 
00335 static int win_spawn(const char *cmd, const char **argv, const char **envp,
00336                      const char *cwd, HANDLE handles[3], int background,
00337                      int shell)
00338 {
00339     char *args = make_command_line(shell, cmd, argv);
00340     char *env = make_environment(envp);
00341     char *program = shell ? NULL : find_program(cmd);
00342     STARTUPINFO si;
00343     PROCESS_INFORMATION pi;
00344     BOOL result;
00345     DWORD exitcode;
00346 
00347     if (!shell) {
00348         G_debug(3, "win_spawn: program = %s", program);
00349 
00350         if (!program) {
00351             G_free(args);
00352             G_free(env);
00353             return -1;
00354         }
00355     }
00356 
00357     G_debug(3, "win_spawn: args = %s", args);
00358 
00359     memset(&si, 0, sizeof(si));
00360     si.cb = sizeof(si);
00361 
00362     si.dwFlags |= STARTF_USESTDHANDLES;
00363     si.hStdInput  = handles[0];
00364     si.hStdOutput = handles[1];
00365     si.hStdError  = handles[2];
00366 
00367     result = CreateProcess(
00368         program,        /* lpApplicationName */
00369         args,           /* lpCommandLine */
00370         NULL,           /* lpProcessAttributes */
00371         NULL,           /* lpThreadAttributes */
00372         1,              /* bInheritHandles */
00373         0,              /* dwCreationFlags */
00374         env,            /* lpEnvironment */
00375         cwd,            /* lpCurrentDirectory */
00376         &si,            /* lpStartupInfo */
00377         &pi             /* lpProcessInformation */
00378         );
00379 
00380     G_free(args);
00381     G_free(env);
00382     G_free(program);
00383 
00384     if (!result) {
00385         G_warning(_("CreateProcess() failed: error = %d"), GetLastError());
00386         return -1;
00387     }
00388 
00389     if (!background) {
00390         WaitForSingleObject(pi.hProcess, INFINITE);
00391         if (!GetExitCodeProcess(pi.hProcess, &exitcode))
00392             return -1;
00393         return (int) exitcode;
00394     }
00395 
00396     return pi.dwProcessId;
00397 }
00398 
00399 static void do_redirects(struct redirect *redirects, int num_redirects, HANDLE handles[3])
00400 {
00401     int i;
00402 
00403     for (i = 0; i < 3; i++)
00404         handles[i] = get_handle(i);
00405 
00406     for (i = 0; i < num_redirects; i++) {
00407         struct redirect *r = &redirects[i];
00408 
00409         if (r->dst_fd < 0 || r->dst_fd > 2) {
00410             G_warning(_("G_spawn: unable to redirect descriptor %d"), r->dst_fd);
00411             continue;
00412         }
00413 
00414         if (r->file) {
00415             r->src_fd = open(r->file, r->mode, 0666);
00416 
00417             if (r->src_fd < 0) {
00418                 G_warning(_("G_spawn: unable to open file %s"), r->file);
00419                 _exit(127);
00420             }
00421 
00422             handles[r->dst_fd] = get_handle(r->src_fd);
00423 
00424             close(r->src_fd);
00425 
00426         }
00427         else if (r->src_fd >= 0) {
00428             handles[r->dst_fd] = get_handle(r->src_fd);
00429         }
00430         else
00431             handles[r->dst_fd] = INVALID_HANDLE_VALUE;
00432     }
00433 }
00434 
00435 static void add_binding(const char **env, int *pnum, const struct binding *b)
00436 {
00437     char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
00438     int n = *pnum;
00439     int i;
00440 
00441     sprintf(str, "%s=%s", b->var, b->val);
00442 
00443     for (i = 0; i < n; i++)
00444         if (G_strcasecmp(env[i], b->var) == 0) {
00445             env[i] = str;
00446             return;
00447         }
00448 
00449     env[n++] = str;
00450     *pnum = n;
00451 }
00452 
00453 static const char **do_bindings(const struct binding *bindings, int num_bindings)
00454 {
00455     const char **newenv;
00456     int i, n;
00457 
00458     for (i = 0; _environ[i]; i++)
00459         ;
00460     n = i;
00461 
00462     newenv = G_malloc((num_bindings + n + 1) * sizeof(char *));
00463 
00464     for (i = 0; i < n; i++)
00465         newenv[i] = _environ[i];
00466 
00467     for (i = 0; i < num_bindings; i++)
00468         add_binding(newenv, &n, &bindings[i]);
00469 
00470     newenv[num_bindings + n] = NULL;
00471 
00472     return newenv;
00473 }
00474 
00475 static int do_spawn(struct spawn *sp, const char *command)
00476 {
00477     HANDLE handles[3];
00478     const char **env;
00479     int status;
00480 
00481     do_redirects(sp->redirects, sp->num_redirects, handles);
00482     env = do_bindings(sp->bindings, sp->num_bindings);
00483 
00484     status = win_spawn(command, sp->args, env, sp->directory, handles, sp->background, 1);
00485 
00486     if (!sp->background && status < 0)
00487         G_warning(_("Unable to execute command"));
00488 
00489     return status;
00490 }
00491 
00492 #else /* __MINGW32__ */
00493 
00494 static int undo_signals(const struct signal *signals, int num_signals, int which)
00495 {
00496     int error = 0;
00497     int i;
00498 
00499     for (i = num_signals - 1; i >= 0; i--) {
00500         const struct signal *s = &signals[i];
00501 
00502         if (s->which != which)
00503             continue;
00504 
00505         if (!s->valid)
00506             continue;
00507 
00508         switch (s->action) {
00509         case SSA_IGNORE:
00510         case SSA_DEFAULT:
00511             if (sigaction(s->signum, &s->old_act, NULL) < 0) {
00512                 G_warning(_("G_spawn: unable to restore signal %d"),
00513                           s->signum);
00514                 error = 1;
00515             }
00516             break;
00517         case SSA_BLOCK:
00518         case SSA_UNBLOCK:
00519             if (sigprocmask(SIG_UNBLOCK, &s->old_mask, NULL) < 0) {
00520                 G_warning(_("G_spawn: unable to restore signal %d"),
00521                           s->signum);
00522                 error = 1;
00523             }
00524             break;
00525         }
00526     }
00527 
00528     return !error;
00529 }
00530 
00531 static int do_signals(struct signal *signals, int num_signals, int which)
00532 {
00533     struct sigaction act;
00534     sigset_t mask;
00535     int error = 0;
00536     int i;
00537 
00538     sigemptyset(&act.sa_mask);
00539     act.sa_flags = SA_RESTART;
00540 
00541     for (i = 0; i < num_signals; i++) {
00542         struct signal *s = &signals[i];
00543 
00544         if (s->which != which)
00545             continue;
00546 
00547         switch (s->action) {
00548         case SSA_IGNORE:
00549             act.sa_handler = SIG_IGN;
00550             if (sigaction(s->signum, &act, &s->old_act) < 0) {
00551                 G_warning(_("G_spawn: unable to reset signal %d"), s->signum);
00552                 error = 1;
00553             }
00554             else
00555                 s->valid = 1;
00556             break;
00557         case SSA_DEFAULT:
00558             act.sa_handler = SIG_DFL;
00559             if (sigaction(s->signum, &act, &s->old_act) < 0) {
00560                 G_warning(_("G_spawn: unable to ignore signal %d"),
00561                           s->signum);
00562                 error = 1;
00563             }
00564             else
00565                 s->valid = 1;
00566             break;
00567         case SSA_BLOCK:
00568             sigemptyset(&mask);
00569             sigaddset(&mask, s->signum);
00570             if (sigprocmask(SIG_BLOCK, &mask, &s->old_mask) < 0) {
00571                 G_warning(_("G_spawn: unable to block signal %d"), s->signum);
00572                 error = 1;
00573             }
00574             break;
00575         case SSA_UNBLOCK:
00576             sigemptyset(&mask);
00577             sigaddset(&mask, s->signum);
00578             if (sigprocmask(SIG_UNBLOCK, &mask, &s->old_mask) < 0) {
00579                 G_warning(_("G_spawn: unable to unblock signal %d"),
00580                           s->signum);
00581                 error = 1;
00582             }
00583             else
00584                 s->valid = 1;
00585             break;
00586         }
00587     }
00588 
00589     return !error;
00590 }
00591 
00592 static void do_redirects(struct redirect *redirects, int num_redirects)
00593 {
00594     int i;
00595 
00596     for (i = 0; i < num_redirects; i++) {
00597         struct redirect *r = &redirects[i];
00598 
00599         if (r->file) {
00600             r->src_fd = open(r->file, r->mode, 0666);
00601 
00602             if (r->src_fd < 0) {
00603                 G_warning(_("G_spawn: unable to open file %s"), r->file);
00604                 _exit(127);
00605             }
00606 
00607             if (dup2(r->src_fd, r->dst_fd) < 0) {
00608                 G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
00609                           r->src_fd, r->dst_fd);
00610                 _exit(127);
00611             }
00612 
00613             close(r->src_fd);
00614         }
00615         else if (r->src_fd >= 0) {
00616             if (dup2(r->src_fd, r->dst_fd) < 0) {
00617                 G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
00618                           r->src_fd, r->dst_fd);
00619                 _exit(127);
00620             }
00621         }
00622         else
00623             close(r->dst_fd);
00624     }
00625 }
00626 
00627 static void do_bindings(const struct binding *bindings, int num_bindings)
00628 {
00629     int i;
00630 
00631     for (i = 0; i < num_bindings; i++) {
00632         const struct binding *b = &bindings[i];
00633         char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
00634 
00635         sprintf(str, "%s=%s", b->var, b->val);
00636         putenv(str);
00637     }
00638 }
00639 
00640 static int do_spawn(struct spawn *sp, const char *command)
00641 {
00642     int status = -1;
00643     pid_t pid;
00644 
00645     if (!do_signals(sp->signals, sp->num_signals, SST_PRE))
00646         return status;
00647 
00648     pid = fork();
00649     if (pid < 0) {
00650         G_warning(_("Unable to create a new process"));
00651         undo_signals(sp->signals, sp->num_signals, SST_PRE);
00652 
00653         return status;
00654     }
00655 
00656     if (pid == 0) {
00657         if (!undo_signals(sp->signals, sp->num_signals, SST_PRE))
00658             _exit(127);
00659 
00660         if (!do_signals(sp->signals, sp->num_signals, SST_CHILD))
00661             _exit(127);
00662 
00663         if (sp->directory)
00664             if (chdir(sp->directory) < 0) {
00665                 G_warning(_("Unable to change directory to %s"), sp->directory);
00666                 _exit(127);
00667             }
00668 
00669         do_redirects(sp->redirects, sp->num_redirects);
00670         do_bindings(sp->bindings, sp->num_bindings);
00671 
00672         execvp(command, (char **)sp->args);
00673         G_warning(_("Unable to execute command"));
00674         _exit(127);
00675     }
00676 
00677     do_signals(sp->signals, sp->num_signals, SST_POST);
00678 
00679     if (sp->background)
00680         status = (int)pid;
00681     else {
00682         pid_t n;
00683 
00684         do
00685             n = waitpid(pid, &status, 0);
00686         while (n == (pid_t) - 1 && errno == EINTR);
00687 
00688         if (n != pid)
00689             status = -1;
00690         else {
00691             if (WIFEXITED(status))
00692                 status = WEXITSTATUS(status);
00693             else if (WIFSIGNALED(status))
00694                 status = WTERMSIG(status);
00695             else
00696                 status = -0x100;
00697         }
00698     }
00699 
00700     undo_signals(sp->signals, sp->num_signals, SST_POST);
00701     undo_signals(sp->signals, sp->num_signals, SST_PRE);
00702 
00703     return status;
00704 }
00705 
00706 #endif /* __MINGW32__ */
00707 
00708 static void begin_spawn(struct spawn *sp)
00709 {
00710     sp->num_args = 0;
00711     sp->num_redirects = 0;
00712     sp->num_signals = 0;
00713     sp->num_bindings = 0;
00714     sp->background = 0;
00715     sp->directory = NULL;
00716 }
00717 
00718 #define NEXT_ARG(var, type) ((type) (ssize_t) *(var)++)
00719 
00720 static void parse_argvec(struct spawn *sp, const char **va)
00721 {
00722     for (;;) {
00723         const char *arg = NEXT_ARG(va, const char *);
00724         const char *var, *val;
00725 
00726         if (!arg) {
00727             sp->args[sp->num_args++] = NULL;
00728             break;
00729         }
00730         else if (arg == SF_REDIRECT_FILE) {
00731             sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
00732 
00733             sp->redirects[sp->num_redirects].src_fd = -1;
00734             sp->redirects[sp->num_redirects].mode = NEXT_ARG(va, int);
00735             sp->redirects[sp->num_redirects].file = NEXT_ARG(va, const char *);
00736 
00737             sp->num_redirects++;
00738         }
00739         else if (arg == SF_REDIRECT_DESCRIPTOR) {
00740             sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
00741             sp->redirects[sp->num_redirects].src_fd = NEXT_ARG(va, int);
00742 
00743             sp->redirects[sp->num_redirects].file = NULL;
00744             sp->num_redirects++;
00745         }
00746         else if (arg == SF_CLOSE_DESCRIPTOR) {
00747             sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
00748 
00749             sp->redirects[sp->num_redirects].src_fd = -1;
00750             sp->redirects[sp->num_redirects].file = NULL;
00751             sp->num_redirects++;
00752         }
00753         else if (arg == SF_SIGNAL) {
00754             sp->signals[sp->num_signals].which = NEXT_ARG(va, int);
00755             sp->signals[sp->num_signals].action = NEXT_ARG(va, int);
00756             sp->signals[sp->num_signals].signum = NEXT_ARG(va, int);
00757 
00758             sp->signals[sp->num_signals].valid = 0;
00759             sp->num_signals++;
00760         }
00761         else if (arg == SF_VARIABLE) {
00762             var = NEXT_ARG(va, const char *);
00763 
00764             val = getenv(var);
00765             sp->args[sp->num_args++] = val ? val : "";
00766         }
00767         else if (arg == SF_BINDING) {
00768             sp->bindings[sp->num_bindings].var = NEXT_ARG(va, const char *);
00769             sp->bindings[sp->num_bindings].val = NEXT_ARG(va, const char *);
00770 
00771             sp->num_bindings++;
00772         }
00773         else if (arg == SF_BACKGROUND) {
00774             sp->background = 1;
00775         }
00776         else if (arg == SF_DIRECTORY) {
00777             sp->directory = NEXT_ARG(va, const char *);
00778 
00779         }
00780         else if (arg == SF_ARGVEC) {
00781             parse_argvec(sp, NEXT_ARG(va, const char **));
00782         }
00783         else
00784             sp->args[sp->num_args++] = arg;
00785     }
00786 }
00787 
00788 static void parse_arglist(struct spawn *sp, va_list va)
00789 {
00790     for (;;) {
00791         const char *arg = va_arg(va, const char *);
00792         const char *var, *val;
00793 
00794         if (!arg) {
00795             sp->args[sp->num_args++] = NULL;
00796             break;
00797         }
00798         else if (arg == SF_REDIRECT_FILE) {
00799             sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
00800 
00801             sp->redirects[sp->num_redirects].src_fd = -1;
00802             sp->redirects[sp->num_redirects].mode = va_arg(va, int);
00803             sp->redirects[sp->num_redirects].file = va_arg(va, const char *);
00804 
00805             sp->num_redirects++;
00806         }
00807         else if (arg == SF_REDIRECT_DESCRIPTOR) {
00808             sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
00809             sp->redirects[sp->num_redirects].src_fd = va_arg(va, int);
00810 
00811             sp->redirects[sp->num_redirects].file = NULL;
00812             sp->num_redirects++;
00813         }
00814         else if (arg == SF_CLOSE_DESCRIPTOR) {
00815             sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
00816 
00817             sp->redirects[sp->num_redirects].src_fd = -1;
00818             sp->redirects[sp->num_redirects].file = NULL;
00819             sp->num_redirects++;
00820         }
00821         else if (arg == SF_SIGNAL) {
00822             sp->signals[sp->num_signals].which = va_arg(va, int);
00823             sp->signals[sp->num_signals].action = va_arg(va, int);
00824             sp->signals[sp->num_signals].signum = va_arg(va, int);
00825 
00826             sp->signals[sp->num_signals].valid = 0;
00827             sp->num_signals++;
00828         }
00829         else if (arg == SF_VARIABLE) {
00830             var = va_arg(va, char *);
00831 
00832             val = getenv(var);
00833             sp->args[sp->num_args++] = val ? val : "";
00834         }
00835         else if (arg == SF_BINDING) {
00836             sp->bindings[sp->num_bindings].var = va_arg(va, const char *);
00837             sp->bindings[sp->num_bindings].val = va_arg(va, const char *);
00838 
00839             sp->num_bindings++;
00840         }
00841         else if (arg == SF_BACKGROUND) {
00842             sp->background = 1;
00843         }
00844         else if (arg == SF_DIRECTORY) {
00845             sp->directory = va_arg(va, const char *);
00846         }
00847         else if (arg == SF_ARGVEC) {
00848             parse_argvec(sp, va_arg(va, const char **));
00849         }
00850         else
00851             sp->args[sp->num_args++] = arg;
00852     }
00853 }
00854 
00865 int G_vspawn_ex(const char *command, const char **args)
00866 {
00867     struct spawn sp;
00868 
00869     begin_spawn(&sp);
00870 
00871     parse_argvec(&sp, args);
00872 
00873     return do_spawn(&sp, command);
00874 }
00875 
00886 int G_spawn_ex(const char *command, ...)
00887 {
00888     struct spawn sp;
00889     va_list va;
00890 
00891     begin_spawn(&sp);
00892 
00893     va_start(va, command);
00894     parse_arglist(&sp, va);
00895     va_end(va);
00896 
00897     return do_spawn(&sp, command);
00898 }
00899 
00908 int G_spawn(const char *command, ...)
00909 {
00910     const char *args[MAX_ARGS];
00911     int num_args = 0, i;
00912     va_list va;
00913     int status = -1;
00914 
00915     va_start(va, command);
00916 
00917     for (i = 0; ; i++) {
00918         const char *arg = va_arg(va, const char *);
00919         args[num_args++] = arg;
00920         if (!arg)
00921             break;
00922     }
00923 
00924     va_end(va);
00925 
00926     status = G_spawn_ex(
00927         command,
00928 #ifndef __MINGW32__
00929         SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGINT,
00930         SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGQUIT,
00931         SF_SIGNAL, SST_PRE, SSA_BLOCK, SIGCHLD,
00932 #endif
00933         SF_ARGVEC, args,
00934         NULL);
00935 
00936     return status;
00937 }
00938 

Generated on Thu Dec 9 2010 20:46:05 for GRASS Programmer's Manual by  doxygen 1.7.2