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