24 #include <sys/types.h>
44 #define MAX_BINDINGS 256
45 #define MAX_SIGNALS 32
46 #define MAX_REDIRECTS 32
72 struct sigaction old_act;
92 const char *directory;
95 static void parse_arglist(
struct spawn *sp, va_list va);
96 static void parse_argvec(
struct spawn *sp,
const char **va);
106 static const int INCREMENT = 50;
108 static void clear(
struct buffer *
b)
111 b->str[
b->len] =
'\0';
114 static void init(
struct buffer *
b)
121 static char *release(
struct buffer *
b)
132 static void finish(
struct buffer *
b)
139 static void ensure(
struct buffer *
b,
size_t n)
141 if (
b->size <=
b->len + n + 1) {
142 b->size =
b->len + n + INCREMENT;
147 static void append(
struct buffer *
b,
const char *str)
149 size_t n = strlen(str);
152 memcpy(&
b->str[
b->len], str, n);
154 b->str[
b->len] =
'\0';
157 static void append_char(
struct buffer *
b,
char c)
162 b->str[
b->len] =
'\0';
165 static void escape_arg(
struct buffer *result,
const char *arg)
172 quote = arg[0] ==
'\0' || strchr(arg,
' ') || strchr(arg,
'\t');
175 append_char(result,
'\"');
177 for (j = 0; arg[j]; j++) {
183 append_char(&buf,
'\\');
186 for (k = 0; k < buf.len; k++)
187 append(result,
"\\\\");
189 append(result,
"\\\"");
193 append(result, buf.str);
196 append_char(result, c);
201 append(result, buf.str);
204 append(result, buf.str);
205 append_char(result,
'\"');
211 static char *check_program(
const char *pgm,
const char *dir,
const char *ext)
215 snprintf(pathname,
sizeof(pathname),
"%s%s%s%s", dir, *dir ?
"\\" :
"", pgm,
220 static char *find_program_ext(
const char *pgm,
const char *dir,
char **pathext)
225 if (result = check_program(pgm, dir,
""), result)
228 for (i = 0; pathext[i]; i++) {
229 const char *ext = pathext[i];
231 if (result = check_program(pgm, dir, ext), result)
238 static char *find_program_dir_ext(
const char *pgm,
char **
path,
char **pathext)
243 if (strchr(pgm,
'\\') || strchr(pgm,
'/')) {
244 if (result = find_program_ext(pgm,
"", pathext), result)
248 if (result = find_program_ext(pgm,
".", pathext), result)
251 for (i = 0;
path[i]; i++) {
252 const char *dir =
path[i];
254 if (result = find_program_ext(pgm, dir, pathext), result)
262 static char *find_program(
const char *pgm)
265 char **pathext =
G_tokenize(getenv(
"PATHEXT"),
";");
266 char *result = find_program_dir_ext(pgm,
path, pathext);
273 static char *make_command_line(
int shell,
const char *cmd,
const char **argv)
275 struct buffer result;
281 const char *comspec = getenv(
"COMSPEC");
283 append(&result, comspec ? comspec :
"cmd.exe");
284 append(&result,
" /c \"");
285 escape_arg(&result, cmd);
288 for (i = shell ? 1 : 0; argv[i]; i++) {
290 append_char(&result,
' ');
291 escape_arg(&result, argv[i]);
294 append(&result,
"\"");
296 return release(&result);
299 static char *make_environment(
const char **envp)
301 struct buffer result;
306 for (i = 0; envp[i]; i++) {
307 const char *env = envp[i];
309 append(&result, env);
310 append_char(&result,
'\0');
313 return release(&result);
316 static HANDLE get_handle(
int fd)
321 return INVALID_HANDLE_VALUE;
323 h1 = (HANDLE)_get_osfhandle(fd);
324 if (!DuplicateHandle(GetCurrentProcess(), h1, GetCurrentProcess(), &h2, 0,
325 TRUE, DUPLICATE_SAME_ACCESS))
326 return INVALID_HANDLE_VALUE;
331 static int win_spawn(
const char *cmd,
const char **argv,
const char **envp,
332 const char *cwd, HANDLE handles[3],
int background,
335 char *args = make_command_line(shell, cmd, argv);
336 char *env = make_environment(envp);
337 char *program = shell ?
NULL : find_program(cmd);
339 PROCESS_INFORMATION pi;
345 G_debug(3,
"win_spawn: program = %s", program);
354 G_debug(3,
"win_spawn: args = %s", args);
356 memset(&si, 0,
sizeof(si));
359 si.dwFlags |= STARTF_USESTDHANDLES;
360 si.hStdInput = handles[0];
361 si.hStdOutput = handles[1];
362 si.hStdError = handles[2];
364 result = CreateProcess(program,
381 G_warning(
_(
"CreateProcess() failed: error = %d"), GetLastError());
385 CloseHandle(pi.hThread);
387 for (i = 0; i < 3; i++)
388 if (handles[i] != INVALID_HANDLE_VALUE)
389 CloseHandle(handles[i]);
392 WaitForSingleObject(pi.hProcess, INFINITE);
393 if (!GetExitCodeProcess(pi.hProcess, &exitcode))
395 CloseHandle(pi.hProcess);
396 return (
int)exitcode;
399 CloseHandle(pi.hProcess);
401 return pi.dwProcessId;
404 static void do_redirects(
struct redirect *redirects,
int num_redirects,
409 for (i = 0; i < 3; i++)
410 handles[i] = get_handle(i);
412 for (i = 0; i < num_redirects; i++) {
413 struct redirect *
r = &redirects[i];
415 if (
r->dst_fd < 0 ||
r->dst_fd > 2) {
416 if (
r->file ||
r->src_fd >= 0)
417 G_warning(
_(
"G_spawn: unable to redirect descriptor %d"),
423 r->src_fd =
open(
r->file,
r->mode, 0666);
426 G_warning(
_(
"G_spawn: unable to open file %s"),
r->file);
430 handles[
r->dst_fd] = get_handle(
r->src_fd);
434 else if (
r->src_fd >= 0) {
435 handles[
r->dst_fd] = get_handle(
r->src_fd);
439 CloseHandle(handles[
r->dst_fd]);
440 handles[
r->dst_fd] = INVALID_HANDLE_VALUE;
447 static void add_binding(
const char **env,
int *pnum,
const struct binding *
b)
449 size_t bufsize = strlen(
b->var) + strlen(
b->val) + 2;
454 snprintf(str, bufsize,
"%s=%s",
b->var,
b->val);
456 for (i = 0; i < n; i++)
466 static const char **do_bindings(
const struct binding *bindings,
472 for (i = 0; _environ[i]; i++)
476 newenv =
G_malloc((num_bindings + n + 1) *
sizeof(
char *));
478 for (i = 0; i < n; i++)
479 newenv[i] = _environ[i];
481 for (i = 0; i < num_bindings; i++)
482 add_binding(newenv, &n, &bindings[i]);
484 newenv[num_bindings + n] =
NULL;
489 static int do_spawn(
struct spawn *sp,
const char *command)
495 do_redirects(sp->redirects, sp->num_redirects, handles);
496 env = do_bindings(sp->bindings, sp->num_bindings);
498 status = win_spawn(command, sp->args, env, sp->directory, handles,
501 if (!sp->background && status < 0)
502 G_warning(
_(
"G_spawn: unable to execute command"));
509 static int undo_signals(
const struct signal *signals,
int num_signals,
515 for (i = num_signals - 1; i >= 0; i--) {
516 const struct signal *s = &signals[i];
518 if (s->which != which)
527 if (sigaction(s->signum, &s->old_act,
NULL) < 0) {
528 G_warning(
_(
"G_spawn: unable to restore signal %d"), s->signum);
534 if (sigprocmask(SIG_UNBLOCK, &s->old_mask,
NULL) < 0) {
535 G_warning(
_(
"G_spawn: unable to restore signal %d"), s->signum);
545 static int do_signals(
struct signal *signals,
int num_signals,
int which)
547 struct sigaction act;
552 sigemptyset(&act.sa_mask);
553 act.sa_flags = SA_RESTART;
555 for (i = 0; i < num_signals; i++) {
556 struct signal *s = &signals[i];
558 if (s->which != which)
563 act.sa_handler = SIG_IGN;
564 if (sigaction(s->signum, &act, &s->old_act) < 0) {
565 G_warning(
_(
"G_spawn: unable to reset signal %d"), s->signum);
572 act.sa_handler = SIG_DFL;
573 if (sigaction(s->signum, &act, &s->old_act) < 0) {
574 G_warning(
_(
"G_spawn: unable to ignore signal %d"), s->signum);
582 sigaddset(&mask, s->signum);
583 if (sigprocmask(SIG_BLOCK, &mask, &s->old_mask) < 0) {
584 G_warning(
_(
"G_spawn: unable to block signal %d"), s->signum);
590 sigaddset(&mask, s->signum);
591 if (sigprocmask(SIG_UNBLOCK, &mask, &s->old_mask) < 0) {
592 G_warning(
_(
"G_spawn: unable to unblock signal %d"), s->signum);
604 static void do_redirects(
struct redirect *redirects,
int num_redirects)
608 for (i = 0; i < num_redirects; i++) {
609 struct redirect *
r = &redirects[i];
612 r->src_fd =
open(
r->file,
r->mode, 0666);
615 G_warning(
_(
"G_spawn: unable to open file %s"),
r->file);
619 if (
dup2(
r->src_fd,
r->dst_fd) < 0) {
620 G_warning(
_(
"G_spawn: unable to duplicate descriptor %d to %d"),
621 r->src_fd,
r->dst_fd);
627 else if (
r->src_fd >= 0) {
628 if (
dup2(
r->src_fd,
r->dst_fd) < 0) {
629 G_warning(
_(
"G_spawn: unable to duplicate descriptor %d to %d"),
630 r->src_fd,
r->dst_fd);
639 static void do_bindings(
const struct binding *bindings,
int num_bindings)
643 for (i = 0; i < num_bindings; i++) {
644 const struct binding *
b = &bindings[i];
645 size_t bufsize = strlen(
b->var) + strlen(
b->val) + 2;
648 snprintf(str, bufsize,
"%s=%s",
b->var,
b->val);
653 static int do_spawn(
struct spawn *sp,
const char *command)
658 if (!do_signals(sp->signals, sp->num_signals,
SST_PRE))
663 G_warning(
_(
"Unable to create a new process: %s"), strerror(errno));
664 undo_signals(sp->signals, sp->num_signals,
SST_PRE);
670 if (!undo_signals(sp->signals, sp->num_signals,
SST_PRE))
673 if (!do_signals(sp->signals, sp->num_signals,
SST_CHILD))
677 if (
chdir(sp->directory) < 0) {
678 G_warning(
_(
"Unable to change directory to %s"), sp->directory);
682 do_redirects(sp->redirects, sp->num_redirects);
683 do_bindings(sp->bindings, sp->num_bindings);
685 execvp(command, (
char **)sp->args);
686 G_warning(
_(
"Unable to execute command '%s': %s"), command,
691 do_signals(sp->signals, sp->num_signals,
SST_POST);
699 n = waitpid(pid, &status, 0);
700 while (n == (pid_t)-1 && errno == EINTR);
705 if (WIFEXITED(status))
706 status = WEXITSTATUS(status);
707 else if (WIFSIGNALED(status))
708 status = WTERMSIG(status);
714 undo_signals(sp->signals, sp->num_signals,
SST_POST);
715 undo_signals(sp->signals, sp->num_signals,
SST_PRE);
722 static void begin_spawn(
struct spawn *sp)
725 sp->num_redirects = 0;
727 sp->num_bindings = 0;
729 sp->directory =
NULL;
732 #define NEXT_ARG(var, type) ((type) * (var)++)
733 #define NEXT_ARG_INT(var) (int)((intptr_t) * (var)++)
735 static void parse_argvec(
struct spawn *sp,
const char **va)
738 const char *arg =
NEXT_ARG(va,
const char *);
739 const char *
var, *val;
742 sp->args[sp->num_args++] =
NULL;
746 sp->redirects[sp->num_redirects].dst_fd =
NEXT_ARG_INT(va);
748 sp->redirects[sp->num_redirects].src_fd = -1;
749 sp->redirects[sp->num_redirects].mode =
NEXT_ARG_INT(va);
750 sp->redirects[sp->num_redirects].file =
NEXT_ARG(va,
const char *);
755 sp->redirects[sp->num_redirects].dst_fd =
NEXT_ARG_INT(va);
756 sp->redirects[sp->num_redirects].src_fd =
NEXT_ARG_INT(va);
758 sp->redirects[sp->num_redirects].file =
NULL;
762 sp->redirects[sp->num_redirects].dst_fd =
NEXT_ARG_INT(va);
764 sp->redirects[sp->num_redirects].src_fd = -1;
765 sp->redirects[sp->num_redirects].file =
NULL;
773 sp->signals[sp->num_signals].valid = 0;
780 sp->args[sp->num_args++] = val ? val :
"";
783 sp->bindings[sp->num_bindings].var =
NEXT_ARG(va,
const char *);
784 sp->bindings[sp->num_bindings].val =
NEXT_ARG(va,
const char *);
792 sp->directory =
NEXT_ARG(va,
const char *);
795 parse_argvec(sp,
NEXT_ARG(va,
const char **));
798 sp->args[sp->num_args++] = arg;
802 static void parse_arglist(
struct spawn *sp, va_list va)
805 const char *arg = va_arg(va,
const char *);
806 const char *
var, *val;
809 sp->args[sp->num_args++] =
NULL;
813 sp->redirects[sp->num_redirects].dst_fd = va_arg(va,
int);
815 sp->redirects[sp->num_redirects].src_fd = -1;
816 sp->redirects[sp->num_redirects].mode = va_arg(va,
int);
817 sp->redirects[sp->num_redirects].file = va_arg(va,
const char *);
822 sp->redirects[sp->num_redirects].dst_fd = va_arg(va,
int);
823 sp->redirects[sp->num_redirects].src_fd = va_arg(va,
int);
825 sp->redirects[sp->num_redirects].file =
NULL;
829 sp->redirects[sp->num_redirects].dst_fd = va_arg(va,
int);
831 sp->redirects[sp->num_redirects].src_fd = -1;
832 sp->redirects[sp->num_redirects].file =
NULL;
836 sp->signals[sp->num_signals].which = va_arg(va,
int);
837 sp->signals[sp->num_signals].action = va_arg(va,
int);
838 sp->signals[sp->num_signals].signum = va_arg(va,
int);
840 sp->signals[sp->num_signals].valid = 0;
844 var = va_arg(va,
char *);
847 sp->args[sp->num_args++] = val ? val :
"";
850 sp->bindings[sp->num_bindings].var = va_arg(va,
const char *);
851 sp->bindings[sp->num_bindings].val = va_arg(va,
const char *);
859 sp->directory = va_arg(va,
const char *);
862 parse_argvec(sp, va_arg(va,
const char **));
865 sp->args[sp->num_args++] = arg;
885 parse_argvec(&sp, args);
887 return do_spawn(&sp, command);
907 va_start(va, command);
908 parse_arglist(&sp, va);
911 return do_spawn(&sp, command);
929 va_start(va, command);
932 const char *arg = va_arg(va,
const char *);
934 args[num_args++] = arg;
955 DWORD rights = PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
956 HANDLE hProcess = OpenProcess(rights,
FALSE, (DWORD)i_pid);
962 WaitForSingleObject(hProcess, INFINITE);
963 if (!GetExitCodeProcess(hProcess, &exitcode))
964 exitcode = (DWORD)-1;
966 CloseHandle(hProcess);
968 return (
int)exitcode;
970 pid_t pid = (pid_t)i_pid;
975 n = waitpid(pid, &status, 0);
976 while (n == (pid_t)-1 && errno == EINTR);
981 if (WIFEXITED(status))
982 return WEXITSTATUS(status);
983 else if (WIFSIGNALED(status))
984 return WTERMSIG(status);
void G_free(void *)
Free allocated memory.
void G_warning(const char *,...) __attribute__((format(printf
void G_free_tokens(char **)
Free memory allocated to tokens.
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
int G_debug(int, const char *,...) __attribute__((format(printf
char * G_store(const char *)
Copy string to allocated memory.
char ** G_tokenize(const char *, const char *)
Tokenize string.
Header file for msvc/open.c and msvc/creat.c.
float var(IClass_statistics *statistics, int band1, int band2)
Helper function for computing variance.
#define NEXT_ARG(var, type)
int G_vspawn_ex(const char *command, const char **args)
Spawn new process based on command.
int G_spawn(const char *command,...)
Spawn new process based on command.
int G_spawn_ex(const char *command,...)
Spawn new process based on command.
#define NEXT_ARG_INT(var)
#define SF_CLOSE_DESCRIPTOR
#define SF_REDIRECT_DESCRIPTOR