GRASS Programmer's Manual
6.4.2(2012)
|
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