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