123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995 |
- /*!
- * \file lib/gis/spawn.c
- *
- * \brief GIS Library - Handles process spawning.
- *
- * (C) 2001-2014 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public License
- * (>=v2). Read the file COPYING that comes with GRASS for details.
- *
- * \author Glynn Clements
- *
- * \date 2004-2006
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <signal.h>
- #include <stdarg.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <sys/types.h>
- #ifndef __MINGW32__
- #include <sys/wait.h>
- #else
- #include <windows.h>
- #endif
- #include <grass/config.h>
- #include <grass/gis.h>
- #include <grass/glocale.h>
- #include <grass/spawn.h>
- /** \def MAX_ARGS Maximum number of arguments */
- /** \def MAX_BINDINGS Maximum number of bindings */
- /** \def MAX_SIGNALS Maximum number of signals */
- /** \def MAX_REDIRECTS Maximum number of redirects */
- #define MAX_ARGS 256
- #define MAX_BINDINGS 256
- #define MAX_SIGNALS 32
- #define MAX_REDIRECTS 32
- /**
- * \brief Spawns a new process.
- *
- * A more useful alternative to G_system(), which takes the
- * arguments of <b>command</b> as parameters.
- *
- * \param[in] command command to execute
- * \return -1 on error
- * \return process status on success
- */
- struct redirect
- {
- int dst_fd;
- int src_fd;
- const char *file;
- int mode;
- };
- struct signal
- {
- int which;
- int action;
- int signum;
- int valid;
- #ifndef __MINGW32__
- struct sigaction old_act;
- sigset_t old_mask;
- #endif
- };
- struct binding
- {
- const char *var;
- const char *val;
- };
- struct spawn
- {
- const char *args[MAX_ARGS];
- int num_args;
- struct redirect redirects[MAX_REDIRECTS];
- int num_redirects;
- struct signal signals[MAX_SIGNALS];
- int num_signals;
- struct binding bindings[MAX_BINDINGS];
- int num_bindings;
- int background;
- const char *directory;
- };
- static void parse_arglist(struct spawn *sp, va_list va);
- static void parse_argvec(struct spawn *sp, const char **va);
- #ifdef __MINGW32__
- struct buffer {
- char *str;
- size_t len;
- size_t size;
- };
- static const int INCREMENT = 50;
- static void clear(struct buffer *b)
- {
- b->len = 0;
- b->str[b->len] = '\0';
- }
- static void init(struct buffer *b)
- {
- b->str = G_malloc(1);
- b->size = 1;
- clear(b);
- }
- static char *release(struct buffer *b)
- {
- char *p = b->str;
- b->str = NULL;
- b->size = 0;
- b->len = 0;
- return p;
- }
- static void finish(struct buffer *b)
- {
- if (b->str)
- G_free(b->str);
- release(b);
- }
- static void ensure(struct buffer *b, size_t n)
- {
- if (b->size <= b->len + n + 1) {
- b->size = b->len + n + INCREMENT;
- b->str = G_realloc(b->str, b->size);
- }
- }
- static void append(struct buffer *b, const char *str)
- {
- size_t n = strlen(str);
- ensure(b, n);
- memcpy(&b->str[b->len], str, n);
- b->len += n;
- b->str[b->len] = '\0';
- }
- static void append_char(struct buffer *b, char c)
- {
- ensure(b, 1);
- b->str[b->len] = c;
- b->len++;
- b->str[b->len] = '\0';
- }
- static void escape_arg(struct buffer *result, const char *arg)
- {
- struct buffer buf;
- int quote, j;
- init(&buf);
- quote = arg[0] == '\0' || strchr(arg, ' ') || strchr(arg, '\t');
- if (quote)
- append_char(result, '\"');
- for (j = 0; arg[j]; j++) {
- int c = arg[j];
- int k;
- switch (c) {
- case '\\':
- append_char(&buf, '\\');
- break;
- case '\"':
- for (k = 0; k < buf.len; k++)
- append(result, "\\\\");
- clear(&buf);
- append(result, "\\\"");
- break;
- default:
- if (buf.len > 0) {
- append(result, buf.str);
- clear(&buf);
- }
- append_char(result, c);
- }
- }
- if (buf.len > 0)
- append(result, buf.str);
- if (quote) {
- append(result, buf.str);
- append_char(result, '\"');
- }
- finish(&buf);
- }
- static char *check_program(const char *pgm, const char *dir, const char *ext)
- {
- char pathname[GPATH_MAX];
- sprintf(pathname, "%s%s%s%s", dir, *dir ? "\\" : "", pgm, ext);
- return access(pathname, 0) == 0
- ? G_store(pathname)
- : NULL;
- }
- static char *find_program_ext(const char *pgm, const char *dir, char **pathext)
- {
- char *result;
- int i;
- if (result = check_program(pgm, dir, ""), result)
- return result;
- for (i = 0; pathext[i]; i++) {
- const char *ext = pathext[i];
- if (result = check_program(pgm, dir, ext), result)
- return result;
- }
- return NULL;
- }
- static char *find_program_dir_ext(const char *pgm, char **path, char **pathext)
- {
- char *result = NULL;
- int i;
- if (strchr(pgm, '\\') || strchr(pgm, '/')) {
- if (result = find_program_ext(pgm, "", pathext), result)
- return result;
- }
- else {
- if (result = find_program_ext(pgm, ".", pathext), result)
- return result;
- for (i = 0; path[i]; i++) {
- const char *dir = path[i];
- if (result = find_program_ext(pgm, dir, pathext), result)
- return result;
- }
- }
- return NULL;
- }
- static char *find_program(const char *pgm)
- {
- char **path = G_tokenize(getenv("PATH"), ";");
- char **pathext = G_tokenize(getenv("PATHEXT"), ";");
- char *result = find_program_dir_ext(pgm, path, pathext);
- G_free_tokens(path);
- G_free_tokens(pathext);
- return result;
- }
- static char *make_command_line(int shell, const char *cmd, const char **argv)
- {
- struct buffer result;
- int i;
- init(&result);
- if (shell) {
- const char *comspec = getenv("COMSPEC");
- append(&result, comspec ? comspec : "cmd.exe");
- append(&result, " /c \"");
- escape_arg(&result, cmd);
- }
- for (i = shell ? 1 : 0; argv[i]; i++) {
- if (result.len > 0)
- append_char(&result, ' ');
- escape_arg(&result, argv[i]);
- }
- append(&result, "\"");
- return release(&result);
- }
- static char *make_environment(const char **envp)
- {
- struct buffer result;
- int i;
- init(&result);
- for (i = 0; envp[i]; i++) {
- const char *env = envp[i];
- append(&result, env);
- append_char(&result, '\0');
- }
- return release(&result);
- }
- static HANDLE get_handle(int fd)
- {
- HANDLE h1, h2;
- if (fd < 0)
- return INVALID_HANDLE_VALUE;
- h1 = (HANDLE) _get_osfhandle(fd);
- if (!DuplicateHandle(GetCurrentProcess(), h1,
- GetCurrentProcess(), &h2,
- 0, TRUE, DUPLICATE_SAME_ACCESS))
- return INVALID_HANDLE_VALUE;
- return h2;
- }
- static int win_spawn(const char *cmd, const char **argv, const char **envp,
- const char *cwd, HANDLE handles[3], int background,
- int shell)
- {
- char *args = make_command_line(shell, cmd, argv);
- char *env = make_environment(envp);
- char *program = shell ? NULL : find_program(cmd);
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
- BOOL result;
- DWORD exitcode;
- int i;
- if (!shell) {
- G_debug(3, "win_spawn: program = %s", program);
- if (!program) {
- G_free(args);
- G_free(env);
- return -1;
- }
- }
- G_debug(3, "win_spawn: args = %s", args);
- memset(&si, 0, sizeof(si));
- si.cb = sizeof(si);
- si.dwFlags |= STARTF_USESTDHANDLES;
- si.hStdInput = handles[0];
- si.hStdOutput = handles[1];
- si.hStdError = handles[2];
- result = CreateProcess(
- program, /* lpApplicationName */
- args, /* lpCommandLine */
- NULL, /* lpProcessAttributes */
- NULL, /* lpThreadAttributes */
- 1, /* bInheritHandles */
- 0, /* dwCreationFlags */
- env, /* lpEnvironment */
- cwd, /* lpCurrentDirectory */
- &si, /* lpStartupInfo */
- &pi /* lpProcessInformation */
- );
- G_free(args);
- G_free(env);
- G_free(program);
- if (!result) {
- G_warning(_("CreateProcess() failed: error = %d"), GetLastError());
- return -1;
- }
- CloseHandle(pi.hThread);
- for (i = 0; i < 3; i++)
- if (handles[i] != INVALID_HANDLE_VALUE)
- CloseHandle(handles[i]);
- if (!background) {
- WaitForSingleObject(pi.hProcess, INFINITE);
- if (!GetExitCodeProcess(pi.hProcess, &exitcode))
- return -1;
- CloseHandle(pi.hProcess);
- return (int) exitcode;
- }
- CloseHandle(pi.hProcess);
- return pi.dwProcessId;
- }
- static void do_redirects(struct redirect *redirects, int num_redirects, HANDLE handles[3])
- {
- int i;
- for (i = 0; i < 3; i++)
- handles[i] = get_handle(i);
- for (i = 0; i < num_redirects; i++) {
- struct redirect *r = &redirects[i];
- if (r->dst_fd < 0 || r->dst_fd > 2) {
- if (r->file || r->src_fd >= 0)
- G_warning(_("G_spawn: unable to redirect descriptor %d"), r->dst_fd);
- continue;
- }
- if (r->file) {
- r->src_fd = open(r->file, r->mode, 0666);
- if (r->src_fd < 0) {
- G_warning(_("G_spawn: unable to open file %s"), r->file);
- _exit(127);
- }
- handles[r->dst_fd] = get_handle(r->src_fd);
- close(r->src_fd);
- }
- else if (r->src_fd >= 0) {
- handles[r->dst_fd] = get_handle(r->src_fd);
- }
- else {
- if (r->dst_fd < 3) {
- CloseHandle(handles[r->dst_fd]);
- handles[r->dst_fd] = INVALID_HANDLE_VALUE;
- }
- close(r->dst_fd);
- }
- }
- }
- static void add_binding(const char **env, int *pnum, const struct binding *b)
- {
- char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
- int n = *pnum;
- int i;
- sprintf(str, "%s=%s", b->var, b->val);
- for (i = 0; i < n; i++)
- if (G_strcasecmp(env[i], b->var) == 0) {
- env[i] = str;
- return;
- }
- env[n++] = str;
- *pnum = n;
- }
- static const char **do_bindings(const struct binding *bindings, int num_bindings)
- {
- const char **newenv;
- int i, n;
- for (i = 0; _environ[i]; i++)
- ;
- n = i;
- newenv = G_malloc((num_bindings + n + 1) * sizeof(char *));
- for (i = 0; i < n; i++)
- newenv[i] = _environ[i];
- for (i = 0; i < num_bindings; i++)
- add_binding(newenv, &n, &bindings[i]);
- newenv[num_bindings + n] = NULL;
- return newenv;
- }
- static int do_spawn(struct spawn *sp, const char *command)
- {
- HANDLE handles[3];
- const char **env;
- int status;
- do_redirects(sp->redirects, sp->num_redirects, handles);
- env = do_bindings(sp->bindings, sp->num_bindings);
- status = win_spawn(command, sp->args, env, sp->directory, handles, sp->background, 1);
- if (!sp->background && status < 0)
- G_warning(_("G_spawn: unable to execute command"));
- return status;
- }
- #else /* __MINGW32__ */
- static int undo_signals(const struct signal *signals, int num_signals, int which)
- {
- int error = 0;
- int i;
- for (i = num_signals - 1; i >= 0; i--) {
- const struct signal *s = &signals[i];
- if (s->which != which)
- continue;
- if (!s->valid)
- continue;
- switch (s->action) {
- case SSA_IGNORE:
- case SSA_DEFAULT:
- if (sigaction(s->signum, &s->old_act, NULL) < 0) {
- G_warning(_("G_spawn: unable to restore signal %d"),
- s->signum);
- error = 1;
- }
- break;
- case SSA_BLOCK:
- case SSA_UNBLOCK:
- if (sigprocmask(SIG_UNBLOCK, &s->old_mask, NULL) < 0) {
- G_warning(_("G_spawn: unable to restore signal %d"),
- s->signum);
- error = 1;
- }
- break;
- }
- }
- return !error;
- }
- static int do_signals(struct signal *signals, int num_signals, int which)
- {
- struct sigaction act;
- sigset_t mask;
- int error = 0;
- int i;
- sigemptyset(&act.sa_mask);
- act.sa_flags = SA_RESTART;
- for (i = 0; i < num_signals; i++) {
- struct signal *s = &signals[i];
- if (s->which != which)
- continue;
- switch (s->action) {
- case SSA_IGNORE:
- act.sa_handler = SIG_IGN;
- if (sigaction(s->signum, &act, &s->old_act) < 0) {
- G_warning(_("G_spawn: unable to reset signal %d"), s->signum);
- error = 1;
- }
- else
- s->valid = 1;
- break;
- case SSA_DEFAULT:
- act.sa_handler = SIG_DFL;
- if (sigaction(s->signum, &act, &s->old_act) < 0) {
- G_warning(_("G_spawn: unable to ignore signal %d"),
- s->signum);
- error = 1;
- }
- else
- s->valid = 1;
- break;
- case SSA_BLOCK:
- sigemptyset(&mask);
- sigaddset(&mask, s->signum);
- if (sigprocmask(SIG_BLOCK, &mask, &s->old_mask) < 0) {
- G_warning(_("G_spawn: unable to block signal %d"), s->signum);
- error = 1;
- }
- break;
- case SSA_UNBLOCK:
- sigemptyset(&mask);
- sigaddset(&mask, s->signum);
- if (sigprocmask(SIG_UNBLOCK, &mask, &s->old_mask) < 0) {
- G_warning(_("G_spawn: unable to unblock signal %d"),
- s->signum);
- error = 1;
- }
- else
- s->valid = 1;
- break;
- }
- }
- return !error;
- }
- static void do_redirects(struct redirect *redirects, int num_redirects)
- {
- int i;
- for (i = 0; i < num_redirects; i++) {
- struct redirect *r = &redirects[i];
- if (r->file) {
- r->src_fd = open(r->file, r->mode, 0666);
- if (r->src_fd < 0) {
- G_warning(_("G_spawn: unable to open file %s"), r->file);
- _exit(127);
- }
- if (dup2(r->src_fd, r->dst_fd) < 0) {
- G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
- r->src_fd, r->dst_fd);
- _exit(127);
- }
- close(r->src_fd);
- }
- else if (r->src_fd >= 0) {
- if (dup2(r->src_fd, r->dst_fd) < 0) {
- G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
- r->src_fd, r->dst_fd);
- _exit(127);
- }
- }
- else
- close(r->dst_fd);
- }
- }
- static void do_bindings(const struct binding *bindings, int num_bindings)
- {
- int i;
- for (i = 0; i < num_bindings; i++) {
- const struct binding *b = &bindings[i];
- char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
- sprintf(str, "%s=%s", b->var, b->val);
- putenv(str);
- }
- }
- static int do_spawn(struct spawn *sp, const char *command)
- {
- int status = -1;
- pid_t pid;
- if (!do_signals(sp->signals, sp->num_signals, SST_PRE))
- return status;
- pid = fork();
- if (pid < 0) {
- G_warning(_("Unable to create a new process: %s"), strerror(errno));
- undo_signals(sp->signals, sp->num_signals, SST_PRE);
- return status;
- }
- if (pid == 0) {
- if (!undo_signals(sp->signals, sp->num_signals, SST_PRE))
- _exit(127);
- if (!do_signals(sp->signals, sp->num_signals, SST_CHILD))
- _exit(127);
- if (sp->directory)
- if (chdir(sp->directory) < 0) {
- G_warning(_("Unable to change directory to %s"), sp->directory);
- _exit(127);
- }
- do_redirects(sp->redirects, sp->num_redirects);
- do_bindings(sp->bindings, sp->num_bindings);
- execvp(command, (char **)sp->args);
- G_warning(_("Unable to execute command '%s': %s"), command, strerror(errno));
- _exit(127);
- }
- do_signals(sp->signals, sp->num_signals, SST_POST);
- if (sp->background)
- status = (int)pid;
- else {
- pid_t n;
- do
- n = waitpid(pid, &status, 0);
- while (n == (pid_t) - 1 && errno == EINTR);
- if (n != pid)
- status = -1;
- else {
- if (WIFEXITED(status))
- status = WEXITSTATUS(status);
- else if (WIFSIGNALED(status))
- status = WTERMSIG(status);
- else
- status = -0x100;
- }
- }
- undo_signals(sp->signals, sp->num_signals, SST_POST);
- undo_signals(sp->signals, sp->num_signals, SST_PRE);
- return status;
- }
- #endif /* __MINGW32__ */
- static void begin_spawn(struct spawn *sp)
- {
- sp->num_args = 0;
- sp->num_redirects = 0;
- sp->num_signals = 0;
- sp->num_bindings = 0;
- sp->background = 0;
- sp->directory = NULL;
- }
- #define NEXT_ARG(var, type) ((type) *(var)++)
- #define NEXT_ARG_INT(var) (int)((intptr_t) *(var)++)
- static void parse_argvec(struct spawn *sp, const char **va)
- {
- for (;;) {
- const char *arg = NEXT_ARG(va, const char *);
- const char *var, *val;
- if (!arg) {
- sp->args[sp->num_args++] = NULL;
- break;
- }
- else if (arg == SF_REDIRECT_FILE) {
- sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG_INT(va);
- sp->redirects[sp->num_redirects].src_fd = -1;
- sp->redirects[sp->num_redirects].mode = NEXT_ARG_INT(va);
- sp->redirects[sp->num_redirects].file = NEXT_ARG(va, const char *);
- sp->num_redirects++;
- }
- else if (arg == SF_REDIRECT_DESCRIPTOR) {
- sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG_INT(va);
- sp->redirects[sp->num_redirects].src_fd = NEXT_ARG_INT(va);
- sp->redirects[sp->num_redirects].file = NULL;
- sp->num_redirects++;
- }
- else if (arg == SF_CLOSE_DESCRIPTOR) {
- sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG_INT(va);
- sp->redirects[sp->num_redirects].src_fd = -1;
- sp->redirects[sp->num_redirects].file = NULL;
- sp->num_redirects++;
- }
- else if (arg == SF_SIGNAL) {
- sp->signals[sp->num_signals].which = NEXT_ARG_INT(va);
- sp->signals[sp->num_signals].action = NEXT_ARG_INT(va);
- sp->signals[sp->num_signals].signum = NEXT_ARG_INT(va);
- sp->signals[sp->num_signals].valid = 0;
- sp->num_signals++;
- }
- else if (arg == SF_VARIABLE) {
- var = NEXT_ARG(va, const char *);
- val = getenv(var);
- sp->args[sp->num_args++] = val ? val : "";
- }
- else if (arg == SF_BINDING) {
- sp->bindings[sp->num_bindings].var = NEXT_ARG(va, const char *);
- sp->bindings[sp->num_bindings].val = NEXT_ARG(va, const char *);
- sp->num_bindings++;
- }
- else if (arg == SF_BACKGROUND) {
- sp->background = 1;
- }
- else if (arg == SF_DIRECTORY) {
- sp->directory = NEXT_ARG(va, const char *);
- }
- else if (arg == SF_ARGVEC) {
- parse_argvec(sp, NEXT_ARG(va, const char **));
- }
- else
- sp->args[sp->num_args++] = arg;
- }
- }
- static void parse_arglist(struct spawn *sp, va_list va)
- {
- for (;;) {
- const char *arg = va_arg(va, const char *);
- const char *var, *val;
- if (!arg) {
- sp->args[sp->num_args++] = NULL;
- break;
- }
- else if (arg == SF_REDIRECT_FILE) {
- sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
- sp->redirects[sp->num_redirects].src_fd = -1;
- sp->redirects[sp->num_redirects].mode = va_arg(va, int);
- sp->redirects[sp->num_redirects].file = va_arg(va, const char *);
- sp->num_redirects++;
- }
- else if (arg == SF_REDIRECT_DESCRIPTOR) {
- sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
- sp->redirects[sp->num_redirects].src_fd = va_arg(va, int);
- sp->redirects[sp->num_redirects].file = NULL;
- sp->num_redirects++;
- }
- else if (arg == SF_CLOSE_DESCRIPTOR) {
- sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
- sp->redirects[sp->num_redirects].src_fd = -1;
- sp->redirects[sp->num_redirects].file = NULL;
- sp->num_redirects++;
- }
- else if (arg == SF_SIGNAL) {
- sp->signals[sp->num_signals].which = va_arg(va, int);
- sp->signals[sp->num_signals].action = va_arg(va, int);
- sp->signals[sp->num_signals].signum = va_arg(va, int);
- sp->signals[sp->num_signals].valid = 0;
- sp->num_signals++;
- }
- else if (arg == SF_VARIABLE) {
- var = va_arg(va, char *);
- val = getenv(var);
- sp->args[sp->num_args++] = val ? val : "";
- }
- else if (arg == SF_BINDING) {
- sp->bindings[sp->num_bindings].var = va_arg(va, const char *);
- sp->bindings[sp->num_bindings].val = va_arg(va, const char *);
- sp->num_bindings++;
- }
- else if (arg == SF_BACKGROUND) {
- sp->background = 1;
- }
- else if (arg == SF_DIRECTORY) {
- sp->directory = va_arg(va, const char *);
- }
- else if (arg == SF_ARGVEC) {
- parse_argvec(sp, va_arg(va, const char **));
- }
- else
- sp->args[sp->num_args++] = arg;
- }
- }
- /**
- * \brief Spawn new process based on <b>command</b>.
- *
- * This is a more advanced version of G_spawn().
- *
- * \param[in] command
- * \param[in] args arguments
- * \return -1 on error
- * \return process status on success
- */
- int G_vspawn_ex(const char *command, const char **args)
- {
- struct spawn sp;
- begin_spawn(&sp);
- parse_argvec(&sp, args);
- return do_spawn(&sp, command);
- }
- /**
- * \brief Spawn new process based on <b>command</b>.
- *
- * This is a more advanced version of G_spawn().
- *
- * \param[in] command
- * \return -1 on error
- * \return process status on success
- */
- int G_spawn_ex(const char *command, ...)
- {
- struct spawn sp;
- va_list va;
- begin_spawn(&sp);
- va_start(va, command);
- parse_arglist(&sp, va);
- va_end(va);
- return do_spawn(&sp, command);
- }
- /**
- * \brief Spawn new process based on <b>command</b>.
- *
- * \param[in] command
- * \return -1 on error
- * \return process status on success
- */
- int G_spawn(const char *command, ...)
- {
- const char *args[MAX_ARGS];
- int num_args = 0, i;
- va_list va;
- int status = -1;
- va_start(va, command);
- for (i = 0; ; i++) {
- const char *arg = va_arg(va, const char *);
- args[num_args++] = arg;
- if (!arg)
- break;
- }
- va_end(va);
- status = G_spawn_ex(
- command,
- #ifndef __MINGW32__
- SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGINT,
- SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGQUIT,
- SF_SIGNAL, SST_PRE, SSA_BLOCK, SIGCHLD,
- #endif
- SF_ARGVEC, args,
- NULL);
- return status;
- }
- int G_wait(int i_pid)
- {
- #ifdef __MINGW32__
- DWORD rights = PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
- HANDLE hProcess = OpenProcess(rights, FALSE, (DWORD) i_pid);
- DWORD exitcode;
- if (!hProcess)
- return -1;
- WaitForSingleObject(hProcess, INFINITE);
- if (!GetExitCodeProcess(hProcess, &exitcode))
- exitcode = (DWORD) -1;
- CloseHandle(hProcess);
- return (int) exitcode;
- #else
- pid_t pid = (pid_t) i_pid;
- int status = -1;
- pid_t n;
- do
- n = waitpid(pid, &status, 0);
- while (n == (pid_t) - 1 && errno == EINTR);
- if (n != pid)
- return -1;
- else {
- if (WIFEXITED(status))
- return WEXITSTATUS(status);
- else if (WIFSIGNALED(status))
- return WTERMSIG(status);
- else
- return -0x100;
- }
- #endif
- }
|