GRASS Programmer's Manual 6.4.1(2011)
|
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