GRASS Programmer's Manual 6.4.1(2011)
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             if (r->file || r->src_fd >= 0)
00411                 G_warning(_("G_spawn: unable to redirect descriptor %d"), r->dst_fd);
00412             continue;
00413         }
00414 
00415         if (r->file) {
00416             r->src_fd = open(r->file, r->mode, 0666);
00417 
00418             if (r->src_fd < 0) {
00419                 G_warning(_("G_spawn: unable to open file %s"), r->file);
00420                 _exit(127);
00421             }
00422 
00423             handles[r->dst_fd] = get_handle(r->src_fd);
00424 
00425             close(r->src_fd);
00426 
00427         }
00428         else if (r->src_fd >= 0) {
00429             handles[r->dst_fd] = get_handle(r->src_fd);
00430         }
00431         else
00432             handles[r->dst_fd] = INVALID_HANDLE_VALUE;
00433     }
00434 }
00435 
00436 static void add_binding(const char **env, int *pnum, const struct binding *b)
00437 {
00438     char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
00439     int n = *pnum;
00440     int i;
00441 
00442     sprintf(str, "%s=%s", b->var, b->val);
00443 
00444     for (i = 0; i < n; i++)
00445         if (G_strcasecmp(env[i], b->var) == 0) {
00446             env[i] = str;
00447             return;
00448         }
00449 
00450     env[n++] = str;
00451     *pnum = n;
00452 }
00453 
00454 static const char **do_bindings(const struct binding *bindings, int num_bindings)
00455 {
00456     const char **newenv;
00457     int i, n;
00458 
00459     for (i = 0; _environ[i]; i++)
00460         ;
00461     n = i;
00462 
00463     newenv = G_malloc((num_bindings + n + 1) * sizeof(char *));
00464 
00465     for (i = 0; i < n; i++)
00466         newenv[i] = _environ[i];
00467 
00468     for (i = 0; i < num_bindings; i++)
00469         add_binding(newenv, &n, &bindings[i]);
00470 
00471     newenv[num_bindings + n] = NULL;
00472 
00473     return newenv;
00474 }
00475 
00476 static int do_spawn(struct spawn *sp, const char *command)
00477 {
00478     HANDLE handles[3];
00479     const char **env;
00480     int status;
00481 
00482     do_redirects(sp->redirects, sp->num_redirects, handles);
00483     env = do_bindings(sp->bindings, sp->num_bindings);
00484 
00485     status = win_spawn(command, sp->args, env, sp->directory, handles, sp->background, 1);
00486 
00487     if (!sp->background && status < 0)
00488         G_warning(_("Unable to execute command"));
00489 
00490     return status;
00491 }
00492 
00493 #else /* __MINGW32__ */
00494 
00495 static int undo_signals(const struct signal *signals, int num_signals, int which)
00496 {
00497     int error = 0;
00498     int i;
00499 
00500     for (i = num_signals - 1; i >= 0; i--) {
00501         const struct signal *s = &signals[i];
00502 
00503         if (s->which != which)
00504             continue;
00505 
00506         if (!s->valid)
00507             continue;
00508 
00509         switch (s->action) {
00510         case SSA_IGNORE:
00511         case SSA_DEFAULT:
00512             if (sigaction(s->signum, &s->old_act, NULL) < 0) {
00513                 G_warning(_("G_spawn: unable to restore signal %d"),
00514                           s->signum);
00515                 error = 1;
00516             }
00517             break;
00518         case SSA_BLOCK:
00519         case SSA_UNBLOCK:
00520             if (sigprocmask(SIG_UNBLOCK, &s->old_mask, NULL) < 0) {
00521                 G_warning(_("G_spawn: unable to restore signal %d"),
00522                           s->signum);
00523                 error = 1;
00524             }
00525             break;
00526         }
00527     }
00528 
00529     return !error;
00530 }
00531 
00532 static int do_signals(struct signal *signals, int num_signals, int which)
00533 {
00534     struct sigaction act;
00535     sigset_t mask;
00536     int error = 0;
00537     int i;
00538 
00539     sigemptyset(&act.sa_mask);
00540     act.sa_flags = SA_RESTART;
00541 
00542     for (i = 0; i < num_signals; i++) {
00543         struct signal *s = &signals[i];
00544 
00545         if (s->which != which)
00546             continue;
00547 
00548         switch (s->action) {
00549         case SSA_IGNORE:
00550             act.sa_handler = SIG_IGN;
00551             if (sigaction(s->signum, &act, &s->old_act) < 0) {
00552                 G_warning(_("G_spawn: unable to reset signal %d"), s->signum);
00553                 error = 1;
00554             }
00555             else
00556                 s->valid = 1;
00557             break;
00558         case SSA_DEFAULT:
00559             act.sa_handler = SIG_DFL;
00560             if (sigaction(s->signum, &act, &s->old_act) < 0) {
00561                 G_warning(_("G_spawn: unable to ignore signal %d"),
00562                           s->signum);
00563                 error = 1;
00564             }
00565             else
00566                 s->valid = 1;
00567             break;
00568         case SSA_BLOCK:
00569             sigemptyset(&mask);
00570             sigaddset(&mask, s->signum);
00571             if (sigprocmask(SIG_BLOCK, &mask, &s->old_mask) < 0) {
00572                 G_warning(_("G_spawn: unable to block signal %d"), s->signum);
00573                 error = 1;
00574             }
00575             break;
00576         case SSA_UNBLOCK:
00577             sigemptyset(&mask);
00578             sigaddset(&mask, s->signum);
00579             if (sigprocmask(SIG_UNBLOCK, &mask, &s->old_mask) < 0) {
00580                 G_warning(_("G_spawn: unable to unblock signal %d"),
00581                           s->signum);
00582                 error = 1;
00583             }
00584             else
00585                 s->valid = 1;
00586             break;
00587         }
00588     }
00589 
00590     return !error;
00591 }
00592 
00593 static void do_redirects(struct redirect *redirects, int num_redirects)
00594 {
00595     int i;
00596 
00597     for (i = 0; i < num_redirects; i++) {
00598         struct redirect *r = &redirects[i];
00599 
00600         if (r->file) {
00601             r->src_fd = open(r->file, r->mode, 0666);
00602 
00603             if (r->src_fd < 0) {
00604                 G_warning(_("G_spawn: unable to open file %s"), r->file);
00605                 _exit(127);
00606             }
00607 
00608             if (dup2(r->src_fd, r->dst_fd) < 0) {
00609                 G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
00610                           r->src_fd, r->dst_fd);
00611                 _exit(127);
00612             }
00613 
00614             close(r->src_fd);
00615         }
00616         else if (r->src_fd >= 0) {
00617             if (dup2(r->src_fd, r->dst_fd) < 0) {
00618                 G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
00619                           r->src_fd, r->dst_fd);
00620                 _exit(127);
00621             }
00622         }
00623         else
00624             close(r->dst_fd);
00625     }
00626 }
00627 
00628 static void do_bindings(const struct binding *bindings, int num_bindings)
00629 {
00630     int i;
00631 
00632     for (i = 0; i < num_bindings; i++) {
00633         const struct binding *b = &bindings[i];
00634         char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
00635 
00636         sprintf(str, "%s=%s", b->var, b->val);
00637         putenv(str);
00638     }
00639 }
00640 
00641 static int do_spawn(struct spawn *sp, const char *command)
00642 {
00643     int status = -1;
00644     pid_t pid;
00645 
00646     if (!do_signals(sp->signals, sp->num_signals, SST_PRE))
00647         return status;
00648 
00649     pid = fork();
00650     if (pid < 0) {
00651         G_warning(_("Unable to create a new process"));
00652         undo_signals(sp->signals, sp->num_signals, SST_PRE);
00653 
00654         return status;
00655     }
00656 
00657     if (pid == 0) {
00658         if (!undo_signals(sp->signals, sp->num_signals, SST_PRE))
00659             _exit(127);
00660 
00661         if (!do_signals(sp->signals, sp->num_signals, SST_CHILD))
00662             _exit(127);
00663 
00664         if (sp->directory)
00665             if (chdir(sp->directory) < 0) {
00666                 G_warning(_("Unable to change directory to %s"), sp->directory);
00667                 _exit(127);
00668             }
00669 
00670         do_redirects(sp->redirects, sp->num_redirects);
00671         do_bindings(sp->bindings, sp->num_bindings);
00672 
00673         execvp(command, (char **)sp->args);
00674         G_warning(_("Unable to execute command"));
00675         _exit(127);
00676     }
00677 
00678     do_signals(sp->signals, sp->num_signals, SST_POST);
00679 
00680     if (sp->background)
00681         status = (int)pid;
00682     else {
00683         pid_t n;
00684 
00685         do
00686             n = waitpid(pid, &status, 0);
00687         while (n == (pid_t) - 1 && errno == EINTR);
00688 
00689         if (n != pid)
00690             status = -1;
00691         else {
00692             if (WIFEXITED(status))
00693                 status = WEXITSTATUS(status);
00694             else if (WIFSIGNALED(status))
00695                 status = WTERMSIG(status);
00696             else
00697                 status = -0x100;
00698         }
00699     }
00700 
00701     undo_signals(sp->signals, sp->num_signals, SST_POST);
00702     undo_signals(sp->signals, sp->num_signals, SST_PRE);
00703 
00704     return status;
00705 }
00706 
00707 #endif /* __MINGW32__ */
00708 
00709 static void begin_spawn(struct spawn *sp)
00710 {
00711     sp->num_args = 0;
00712     sp->num_redirects = 0;
00713     sp->num_signals = 0;
00714     sp->num_bindings = 0;
00715     sp->background = 0;
00716     sp->directory = NULL;
00717 }
00718 
00719 #define NEXT_ARG(var, type) ((type) (ssize_t) *(var)++)
00720 
00721 static void parse_argvec(struct spawn *sp, const char **va)
00722 {
00723     for (;;) {
00724         const char *arg = NEXT_ARG(va, const char *);
00725         const char *var, *val;
00726 
00727         if (!arg) {
00728             sp->args[sp->num_args++] = NULL;
00729             break;
00730         }
00731         else if (arg == SF_REDIRECT_FILE) {
00732             sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
00733 
00734             sp->redirects[sp->num_redirects].src_fd = -1;
00735             sp->redirects[sp->num_redirects].mode = NEXT_ARG(va, int);
00736             sp->redirects[sp->num_redirects].file = NEXT_ARG(va, const char *);
00737 
00738             sp->num_redirects++;
00739         }
00740         else if (arg == SF_REDIRECT_DESCRIPTOR) {
00741             sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
00742             sp->redirects[sp->num_redirects].src_fd = NEXT_ARG(va, int);
00743 
00744             sp->redirects[sp->num_redirects].file = NULL;
00745             sp->num_redirects++;
00746         }
00747         else if (arg == SF_CLOSE_DESCRIPTOR) {
00748             sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
00749 
00750             sp->redirects[sp->num_redirects].src_fd = -1;
00751             sp->redirects[sp->num_redirects].file = NULL;
00752             sp->num_redirects++;
00753         }
00754         else if (arg == SF_SIGNAL) {
00755             sp->signals[sp->num_signals].which = NEXT_ARG(va, int);
00756             sp->signals[sp->num_signals].action = NEXT_ARG(va, int);
00757             sp->signals[sp->num_signals].signum = NEXT_ARG(va, int);
00758 
00759             sp->signals[sp->num_signals].valid = 0;
00760             sp->num_signals++;
00761         }
00762         else if (arg == SF_VARIABLE) {
00763             var = NEXT_ARG(va, const char *);
00764 
00765             val = getenv(var);
00766             sp->args[sp->num_args++] = val ? val : "";
00767         }
00768         else if (arg == SF_BINDING) {
00769             sp->bindings[sp->num_bindings].var = NEXT_ARG(va, const char *);
00770             sp->bindings[sp->num_bindings].val = NEXT_ARG(va, const char *);
00771 
00772             sp->num_bindings++;
00773         }
00774         else if (arg == SF_BACKGROUND) {
00775             sp->background = 1;
00776         }
00777         else if (arg == SF_DIRECTORY) {
00778             sp->directory = NEXT_ARG(va, const char *);
00779 
00780         }
00781         else if (arg == SF_ARGVEC) {
00782             parse_argvec(sp, NEXT_ARG(va, const char **));
00783         }
00784         else
00785             sp->args[sp->num_args++] = arg;
00786     }
00787 }
00788 
00789 static void parse_arglist(struct spawn *sp, va_list va)
00790 {
00791     for (;;) {
00792         const char *arg = va_arg(va, const char *);
00793         const char *var, *val;
00794 
00795         if (!arg) {
00796             sp->args[sp->num_args++] = NULL;
00797             break;
00798         }
00799         else if (arg == SF_REDIRECT_FILE) {
00800             sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
00801 
00802             sp->redirects[sp->num_redirects].src_fd = -1;
00803             sp->redirects[sp->num_redirects].mode = va_arg(va, int);
00804             sp->redirects[sp->num_redirects].file = va_arg(va, const char *);
00805 
00806             sp->num_redirects++;
00807         }
00808         else if (arg == SF_REDIRECT_DESCRIPTOR) {
00809             sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
00810             sp->redirects[sp->num_redirects].src_fd = va_arg(va, int);
00811 
00812             sp->redirects[sp->num_redirects].file = NULL;
00813             sp->num_redirects++;
00814         }
00815         else if (arg == SF_CLOSE_DESCRIPTOR) {
00816             sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
00817 
00818             sp->redirects[sp->num_redirects].src_fd = -1;
00819             sp->redirects[sp->num_redirects].file = NULL;
00820             sp->num_redirects++;
00821         }
00822         else if (arg == SF_SIGNAL) {
00823             sp->signals[sp->num_signals].which = va_arg(va, int);
00824             sp->signals[sp->num_signals].action = va_arg(va, int);
00825             sp->signals[sp->num_signals].signum = va_arg(va, int);
00826 
00827             sp->signals[sp->num_signals].valid = 0;
00828             sp->num_signals++;
00829         }
00830         else if (arg == SF_VARIABLE) {
00831             var = va_arg(va, char *);
00832 
00833             val = getenv(var);
00834             sp->args[sp->num_args++] = val ? val : "";
00835         }
00836         else if (arg == SF_BINDING) {
00837             sp->bindings[sp->num_bindings].var = va_arg(va, const char *);
00838             sp->bindings[sp->num_bindings].val = va_arg(va, const char *);
00839 
00840             sp->num_bindings++;
00841         }
00842         else if (arg == SF_BACKGROUND) {
00843             sp->background = 1;
00844         }
00845         else if (arg == SF_DIRECTORY) {
00846             sp->directory = va_arg(va, const char *);
00847         }
00848         else if (arg == SF_ARGVEC) {
00849             parse_argvec(sp, va_arg(va, const char **));
00850         }
00851         else
00852             sp->args[sp->num_args++] = arg;
00853     }
00854 }
00855 
00866 int G_vspawn_ex(const char *command, const char **args)
00867 {
00868     struct spawn sp;
00869 
00870     begin_spawn(&sp);
00871 
00872     parse_argvec(&sp, args);
00873 
00874     return do_spawn(&sp, command);
00875 }
00876 
00887 int G_spawn_ex(const char *command, ...)
00888 {
00889     struct spawn sp;
00890     va_list va;
00891 
00892     begin_spawn(&sp);
00893 
00894     va_start(va, command);
00895     parse_arglist(&sp, va);
00896     va_end(va);
00897 
00898     return do_spawn(&sp, command);
00899 }
00900 
00909 int G_spawn(const char *command, ...)
00910 {
00911     const char *args[MAX_ARGS];
00912     int num_args = 0, i;
00913     va_list va;
00914     int status = -1;
00915 
00916     va_start(va, command);
00917 
00918     for (i = 0; ; i++) {
00919         const char *arg = va_arg(va, const char *);
00920         args[num_args++] = arg;
00921         if (!arg)
00922             break;
00923     }
00924 
00925     va_end(va);
00926 
00927     status = G_spawn_ex(
00928         command,
00929 #ifndef __MINGW32__
00930         SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGINT,
00931         SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGQUIT,
00932         SF_SIGNAL, SST_PRE, SSA_BLOCK, SIGCHLD,
00933 #endif
00934         SF_ARGVEC, args,
00935         NULL);
00936 
00937     return status;
00938 }
00939 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines