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 sprintf(pathname,
"%s%s%s%s", dir, *dir ?
"\\" :
"", pgm, ext);
216 return access(pathname, 0) == 0 ?
G_store(pathname) :
NULL;
219 static char *find_program_ext(
const char *pgm,
const char *dir,
char **pathext)
224 if (result = check_program(pgm, dir,
""), result)
227 for (i = 0; pathext[i]; i++) {
228 const char *ext = pathext[i];
230 if (result = check_program(pgm, dir, ext), result)
237 static char *find_program_dir_ext(
const char *pgm,
char **
path,
char **pathext)
242 if (strchr(pgm,
'\\') || strchr(pgm,
'/')) {
243 if (result = find_program_ext(pgm,
"", pathext), result)
247 if (result = find_program_ext(pgm,
".", pathext), result)
250 for (i = 0;
path[i]; i++) {
251 const char *dir =
path[i];
253 if (result = find_program_ext(pgm, dir, pathext), result)
261 static char *find_program(
const char *pgm)
264 char **pathext =
G_tokenize(getenv(
"PATHEXT"),
";");
265 char *result = find_program_dir_ext(pgm,
path, pathext);
272 static char *make_command_line(
int shell,
const char *cmd,
const char **argv)
274 struct buffer result;
280 const char *comspec = getenv(
"COMSPEC");
282 append(&result, comspec ? comspec :
"cmd.exe");
283 append(&result,
" /c \"");
284 escape_arg(&result, cmd);
287 for (i = shell ? 1 : 0; argv[i]; i++) {
289 append_char(&result,
' ');
290 escape_arg(&result, argv[i]);
293 append(&result,
"\"");
295 return release(&result);
298 static char *make_environment(
const char **envp)
300 struct buffer result;
305 for (i = 0; envp[i]; i++) {
306 const char *env = envp[i];
308 append(&result, env);
309 append_char(&result,
'\0');
312 return release(&result);
315 static HANDLE get_handle(
int fd)
320 return INVALID_HANDLE_VALUE;
322 h1 = (HANDLE)_get_osfhandle(fd);
323 if (!DuplicateHandle(GetCurrentProcess(), h1, GetCurrentProcess(), &h2, 0,
324 TRUE, DUPLICATE_SAME_ACCESS))
325 return INVALID_HANDLE_VALUE;
330 static int win_spawn(
const char *cmd,
const char **argv,
const char **envp,
331 const char *cwd, HANDLE handles[3],
int background,
334 char *args = make_command_line(shell, cmd, argv);
335 char *env = make_environment(envp);
336 char *program = shell ?
NULL : find_program(cmd);
338 PROCESS_INFORMATION pi;
344 G_debug(3,
"win_spawn: program = %s", program);
353 G_debug(3,
"win_spawn: args = %s", args);
355 memset(&si, 0,
sizeof(si));
358 si.dwFlags |= STARTF_USESTDHANDLES;
359 si.hStdInput = handles[0];
360 si.hStdOutput = handles[1];
361 si.hStdError = handles[2];
363 result = CreateProcess(program,
380 G_warning(
_(
"CreateProcess() failed: error = %d"), GetLastError());
384 CloseHandle(pi.hThread);
386 for (i = 0; i < 3; i++)
387 if (handles[i] != INVALID_HANDLE_VALUE)
388 CloseHandle(handles[i]);
391 WaitForSingleObject(pi.hProcess, INFINITE);
392 if (!GetExitCodeProcess(pi.hProcess, &exitcode))
394 CloseHandle(pi.hProcess);
395 return (
int)exitcode;
398 CloseHandle(pi.hProcess);
400 return pi.dwProcessId;
403 static void do_redirects(
struct redirect *redirects,
int num_redirects,
408 for (i = 0; i < 3; i++)
409 handles[i] = get_handle(i);
411 for (i = 0; i < num_redirects; i++) {
412 struct redirect *
r = &redirects[i];
414 if (
r->dst_fd < 0 ||
r->dst_fd > 2) {
415 if (
r->file ||
r->src_fd >= 0)
416 G_warning(
_(
"G_spawn: unable to redirect descriptor %d"),
422 r->src_fd = open(
r->file,
r->mode, 0666);
425 G_warning(
_(
"G_spawn: unable to open file %s"),
r->file);
429 handles[
r->dst_fd] = get_handle(
r->src_fd);
433 else if (
r->src_fd >= 0) {
434 handles[
r->dst_fd] = get_handle(
r->src_fd);
438 CloseHandle(handles[
r->dst_fd]);
439 handles[
r->dst_fd] = INVALID_HANDLE_VALUE;
446 static void add_binding(
const char **env,
int *pnum,
const struct binding *
b)
448 char *str =
G_malloc(strlen(
b->var) + strlen(
b->val) + 2);
452 sprintf(str,
"%s=%s",
b->var,
b->val);
454 for (i = 0; i < n; i++)
464 static const char **do_bindings(
const struct binding *bindings,
470 for (i = 0; _environ[i]; i++)
474 newenv =
G_malloc((num_bindings + n + 1) *
sizeof(
char *));
476 for (i = 0; i < n; i++)
477 newenv[i] = _environ[i];
479 for (i = 0; i < num_bindings; i++)
480 add_binding(newenv, &n, &bindings[i]);
482 newenv[num_bindings + n] =
NULL;
487 static int do_spawn(
struct spawn *sp,
const char *command)
493 do_redirects(sp->redirects, sp->num_redirects, handles);
494 env = do_bindings(sp->bindings, sp->num_bindings);
496 status = win_spawn(command, sp->args, env, sp->directory, handles,
499 if (!sp->background && status < 0)
500 G_warning(
_(
"G_spawn: unable to execute command"));
507 static int undo_signals(
const struct signal *signals,
int num_signals,
513 for (i = num_signals - 1; i >= 0; i--) {
514 const struct signal *s = &signals[i];
516 if (s->which != which)
525 if (sigaction(s->signum, &s->old_act,
NULL) < 0) {
526 G_warning(
_(
"G_spawn: unable to restore signal %d"), s->signum);
532 if (sigprocmask(SIG_UNBLOCK, &s->old_mask,
NULL) < 0) {
533 G_warning(
_(
"G_spawn: unable to restore signal %d"), s->signum);
543 static int do_signals(
struct signal *signals,
int num_signals,
int which)
545 struct sigaction act;
550 sigemptyset(&act.sa_mask);
551 act.sa_flags = SA_RESTART;
553 for (i = 0; i < num_signals; i++) {
554 struct signal *s = &signals[i];
556 if (s->which != which)
561 act.sa_handler = SIG_IGN;
562 if (sigaction(s->signum, &act, &s->old_act) < 0) {
563 G_warning(
_(
"G_spawn: unable to reset signal %d"), s->signum);
570 act.sa_handler = SIG_DFL;
571 if (sigaction(s->signum, &act, &s->old_act) < 0) {
572 G_warning(
_(
"G_spawn: unable to ignore signal %d"), s->signum);
580 sigaddset(&mask, s->signum);
581 if (sigprocmask(SIG_BLOCK, &mask, &s->old_mask) < 0) {
582 G_warning(
_(
"G_spawn: unable to block signal %d"), s->signum);
588 sigaddset(&mask, s->signum);
589 if (sigprocmask(SIG_UNBLOCK, &mask, &s->old_mask) < 0) {
590 G_warning(
_(
"G_spawn: unable to unblock signal %d"), s->signum);
602 static void do_redirects(
struct redirect *redirects,
int num_redirects)
606 for (i = 0; i < num_redirects; i++) {
607 struct redirect *
r = &redirects[i];
610 r->src_fd = open(
r->file,
r->mode, 0666);
613 G_warning(
_(
"G_spawn: unable to open file %s"),
r->file);
617 if (dup2(
r->src_fd,
r->dst_fd) < 0) {
618 G_warning(
_(
"G_spawn: unable to duplicate descriptor %d to %d"),
619 r->src_fd,
r->dst_fd);
625 else if (
r->src_fd >= 0) {
626 if (dup2(
r->src_fd,
r->dst_fd) < 0) {
627 G_warning(
_(
"G_spawn: unable to duplicate descriptor %d to %d"),
628 r->src_fd,
r->dst_fd);
637 static void do_bindings(
const struct binding *bindings,
int num_bindings)
641 for (i = 0; i < num_bindings; i++) {
642 const struct binding *
b = &bindings[i];
643 char *str =
G_malloc(strlen(
b->var) + strlen(
b->val) + 2);
645 sprintf(str,
"%s=%s",
b->var,
b->val);
650 static int do_spawn(
struct spawn *sp,
const char *command)
655 if (!do_signals(sp->signals, sp->num_signals,
SST_PRE))
660 G_warning(
_(
"Unable to create a new process: %s"), strerror(errno));
661 undo_signals(sp->signals, sp->num_signals,
SST_PRE);
667 if (!undo_signals(sp->signals, sp->num_signals,
SST_PRE))
670 if (!do_signals(sp->signals, sp->num_signals,
SST_CHILD))
674 if (chdir(sp->directory) < 0) {
675 G_warning(
_(
"Unable to change directory to %s"), sp->directory);
679 do_redirects(sp->redirects, sp->num_redirects);
680 do_bindings(sp->bindings, sp->num_bindings);
682 execvp(command, (
char **)sp->args);
683 G_warning(
_(
"Unable to execute command '%s': %s"), command,
688 do_signals(sp->signals, sp->num_signals,
SST_POST);
696 n = waitpid(pid, &status, 0);
697 while (n == (pid_t)-1 && errno == EINTR);
702 if (WIFEXITED(status))
703 status = WEXITSTATUS(status);
704 else if (WIFSIGNALED(status))
705 status = WTERMSIG(status);
711 undo_signals(sp->signals, sp->num_signals,
SST_POST);
712 undo_signals(sp->signals, sp->num_signals,
SST_PRE);
719 static void begin_spawn(
struct spawn *sp)
722 sp->num_redirects = 0;
724 sp->num_bindings = 0;
726 sp->directory =
NULL;
729 #define NEXT_ARG(var, type) ((type) * (var)++)
730 #define NEXT_ARG_INT(var) (int)((intptr_t) * (var)++)
732 static void parse_argvec(
struct spawn *sp,
const char **va)
735 const char *arg =
NEXT_ARG(va,
const char *);
736 const char *
var, *val;
739 sp->args[sp->num_args++] =
NULL;
743 sp->redirects[sp->num_redirects].dst_fd =
NEXT_ARG_INT(va);
745 sp->redirects[sp->num_redirects].src_fd = -1;
746 sp->redirects[sp->num_redirects].mode =
NEXT_ARG_INT(va);
747 sp->redirects[sp->num_redirects].file =
NEXT_ARG(va,
const char *);
752 sp->redirects[sp->num_redirects].dst_fd =
NEXT_ARG_INT(va);
753 sp->redirects[sp->num_redirects].src_fd =
NEXT_ARG_INT(va);
755 sp->redirects[sp->num_redirects].file =
NULL;
759 sp->redirects[sp->num_redirects].dst_fd =
NEXT_ARG_INT(va);
761 sp->redirects[sp->num_redirects].src_fd = -1;
762 sp->redirects[sp->num_redirects].file =
NULL;
770 sp->signals[sp->num_signals].valid = 0;
777 sp->args[sp->num_args++] = val ? val :
"";
780 sp->bindings[sp->num_bindings].var =
NEXT_ARG(va,
const char *);
781 sp->bindings[sp->num_bindings].val =
NEXT_ARG(va,
const char *);
789 sp->directory =
NEXT_ARG(va,
const char *);
792 parse_argvec(sp,
NEXT_ARG(va,
const char **));
795 sp->args[sp->num_args++] = arg;
799 static void parse_arglist(
struct spawn *sp, va_list va)
802 const char *arg = va_arg(va,
const char *);
803 const char *
var, *val;
806 sp->args[sp->num_args++] =
NULL;
810 sp->redirects[sp->num_redirects].dst_fd = va_arg(va,
int);
812 sp->redirects[sp->num_redirects].src_fd = -1;
813 sp->redirects[sp->num_redirects].mode = va_arg(va,
int);
814 sp->redirects[sp->num_redirects].file = va_arg(va,
const char *);
819 sp->redirects[sp->num_redirects].dst_fd = va_arg(va,
int);
820 sp->redirects[sp->num_redirects].src_fd = va_arg(va,
int);
822 sp->redirects[sp->num_redirects].file =
NULL;
826 sp->redirects[sp->num_redirects].dst_fd = va_arg(va,
int);
828 sp->redirects[sp->num_redirects].src_fd = -1;
829 sp->redirects[sp->num_redirects].file =
NULL;
833 sp->signals[sp->num_signals].which = va_arg(va,
int);
834 sp->signals[sp->num_signals].action = va_arg(va,
int);
835 sp->signals[sp->num_signals].signum = va_arg(va,
int);
837 sp->signals[sp->num_signals].valid = 0;
841 var = va_arg(va,
char *);
844 sp->args[sp->num_args++] = val ? val :
"";
847 sp->bindings[sp->num_bindings].var = va_arg(va,
const char *);
848 sp->bindings[sp->num_bindings].val = va_arg(va,
const char *);
856 sp->directory = va_arg(va,
const char *);
859 parse_argvec(sp, va_arg(va,
const char **));
862 sp->args[sp->num_args++] = arg;
882 parse_argvec(&sp, args);
884 return do_spawn(&sp, command);
904 va_start(va, command);
905 parse_arglist(&sp, va);
908 return do_spawn(&sp, command);
926 va_start(va, command);
929 const char *arg = va_arg(va,
const char *);
931 args[num_args++] = arg;
952 DWORD rights = PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
953 HANDLE hProcess = OpenProcess(rights,
FALSE, (DWORD)i_pid);
959 WaitForSingleObject(hProcess, INFINITE);
960 if (!GetExitCodeProcess(hProcess, &exitcode))
961 exitcode = (DWORD)-1;
963 CloseHandle(hProcess);
965 return (
int)exitcode;
967 pid_t pid = (pid_t)i_pid;
972 n = waitpid(pid, &status, 0);
973 while (n == (pid_t)-1 && errno == EINTR);
978 if (WIFEXITED(status))
979 return WEXITSTATUS(status);
980 else if (WIFSIGNALED(status))
981 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.
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