25 #include <sys/types.h> 45 #define MAX_BINDINGS 256 46 #define MAX_SIGNALS 32 47 #define MAX_REDIRECTS 32 76 struct sigaction old_act;
91 struct redirect redirects[MAX_REDIRECTS];
93 struct signal signals[MAX_SIGNALS];
95 struct binding bindings[MAX_BINDINGS];
98 const char *directory;
101 static void parse_arglist(
struct spawn *sp, va_list va);
102 static void parse_argvec(
struct spawn *sp,
const char **va);
112 static const int INCREMENT = 50;
114 static void clear(
struct buffer *
b)
117 b->str[b->len] =
'\0';
120 static void init(
struct buffer *b)
127 static char *release(
struct buffer *b)
138 static void finish(
struct buffer *b)
145 static void ensure(
struct buffer *b,
size_t n)
147 if (b->size <= b->len + n + 1) {
148 b->size = b->len + n + INCREMENT;
153 static void append(
struct buffer *b,
const char *str)
155 size_t n = strlen(str);
158 memcpy(&b->str[b->len], str, n);
160 b->str[b->len] =
'\0';
163 static void append_char(
struct buffer *b,
char c)
168 b->str[b->len] =
'\0';
171 static void escape_arg(
struct buffer *result,
const char *arg)
178 quote = arg[0] ==
'\0' || strchr(arg,
' ') || strchr(arg,
'\t');
181 append_char(result,
'\"');
183 for (j = 0; arg[j]; j++) {
189 append_char(&buf,
'\\');
192 for (k = 0; k < buf.len; k++)
193 append(result,
"\\\\");
195 append(result,
"\\\"");
199 append(result, buf.str);
202 append_char(result, c);
207 append(result, buf.str);
210 append(result, buf.str);
211 append_char(result,
'\"');
217 static char *check_program(
const char *pgm,
const char *dir,
const char *ext)
221 sprintf(pathname,
"%s%s%s%s", dir, *dir ?
"\\" :
"", pgm, ext);
222 return access(pathname, 0) == 0
227 static char *find_program_ext(
const char *pgm,
const char *dir,
char **pathext)
232 if (result = check_program(pgm, dir,
""), result)
235 for (i = 0; pathext[i]; i++) {
236 const char *ext = pathext[i];
237 if (result = check_program(pgm, dir, ext), result)
244 static char *find_program_dir_ext(
const char *pgm,
char **
path,
char **pathext)
249 if (strchr(pgm,
'\\') || strchr(pgm,
'/')) {
250 if (result = find_program_ext(pgm,
"", pathext), result)
254 if (result = find_program_ext(pgm,
".", pathext), result)
257 for (i = 0;
path[i]; i++) {
258 const char *dir =
path[i];
259 if (result = find_program_ext(pgm, dir, pathext), result)
267 static char *find_program(
const char *pgm)
271 char *result = find_program_dir_ext(pgm, path, pathext);
277 static char *make_command_line(
int shell,
const char *cmd,
const char **argv)
279 struct buffer result;
285 const char *comspec =
getenv(
"COMSPEC");
286 append(&result, comspec ? comspec :
"cmd.exe");
287 append(&result,
" /c \"");
288 escape_arg(&result, cmd);
291 for (i = shell ? 1 : 0; argv[i]; i++) {
293 append_char(&result,
' ');
294 escape_arg(&result, argv[i]);
297 append(&result,
"\"");
299 return release(&result);
302 static char *make_environment(
const char **envp)
304 struct buffer result;
309 for (i = 0; envp[i]; i++) {
310 const char *env = envp[i];
312 append(&result, env);
313 append_char(&result,
'\0');
316 return release(&result);
319 static HANDLE get_handle(
int fd)
324 return INVALID_HANDLE_VALUE;
326 h1 = (HANDLE) _get_osfhandle(fd);
327 if (!DuplicateHandle(GetCurrentProcess(), h1,
328 GetCurrentProcess(), &h2,
329 0,
TRUE, DUPLICATE_SAME_ACCESS))
330 return INVALID_HANDLE_VALUE;
335 static int win_spawn(
const char *cmd,
const char **argv,
const char **envp,
336 const char *cwd, HANDLE handles[3],
int background,
339 char *args = make_command_line(shell, cmd, argv);
340 char *env = make_environment(envp);
341 char *program = shell ?
NULL : find_program(cmd);
343 PROCESS_INFORMATION pi;
349 G_debug(3,
"win_spawn: program = %s", program);
358 G_debug(3,
"win_spawn: args = %s", args);
360 memset(&si, 0,
sizeof(si));
363 si.dwFlags |= STARTF_USESTDHANDLES;
364 si.hStdInput = handles[0];
365 si.hStdOutput = handles[1];
366 si.hStdError = handles[2];
368 result = CreateProcess(
386 G_warning(
_(
"CreateProcess() failed: error = %d"), GetLastError());
390 CloseHandle(pi.hThread);
392 for (i = 0; i < 3; i++)
393 if (handles[i] != INVALID_HANDLE_VALUE)
394 CloseHandle(handles[i]);
397 WaitForSingleObject(pi.hProcess, INFINITE);
398 if (!GetExitCodeProcess(pi.hProcess, &exitcode))
400 CloseHandle(pi.hProcess);
401 return (
int) exitcode;
404 CloseHandle(pi.hProcess);
406 return pi.dwProcessId;
409 static void do_redirects(
struct redirect *redirects,
int num_redirects, HANDLE handles[3])
413 for (i = 0; i < 3; i++)
414 handles[i] = get_handle(i);
416 for (i = 0; i < num_redirects; i++) {
417 struct redirect *
r = &redirects[i];
419 if (r->dst_fd < 0 || r->dst_fd > 2) {
420 if (r->file || r->src_fd >= 0)
421 G_warning(
_(
"G_spawn: unable to redirect descriptor %d"), r->dst_fd);
426 r->src_fd = open(r->file, r->mode, 0666);
429 G_warning(
_(
"G_spawn: unable to open file %s"), r->file);
433 handles[r->dst_fd] = get_handle(r->src_fd);
438 else if (r->src_fd >= 0) {
439 handles[r->dst_fd] = get_handle(r->src_fd);
443 CloseHandle(handles[r->dst_fd]);
444 handles[r->dst_fd] = INVALID_HANDLE_VALUE;
451 static void add_binding(
const char **env,
int *pnum,
const struct binding *b)
453 char *str =
G_malloc(strlen(b->var) + strlen(b->val) + 2);
457 sprintf(str,
"%s=%s", b->var, b->val);
459 for (i = 0; i < n; i++)
469 static const char **do_bindings(
const struct binding *bindings,
int num_bindings)
474 for (i = 0; _environ[i]; i++)
478 newenv =
G_malloc((num_bindings + n + 1) *
sizeof(
char *));
480 for (i = 0; i < n; i++)
481 newenv[i] = _environ[i];
483 for (i = 0; i < num_bindings; i++)
484 add_binding(newenv, &n, &bindings[i]);
486 newenv[num_bindings + n] =
NULL;
491 static int do_spawn(
struct spawn *sp,
const char *command)
497 do_redirects(sp->redirects, sp->num_redirects, handles);
498 env = do_bindings(sp->bindings, sp->num_bindings);
500 status = win_spawn(command, sp->args, env, sp->directory, handles, sp->background, 1);
502 if (!sp->background && status < 0)
503 G_warning(
_(
"G_spawn: unable to execute command"));
510 static int undo_signals(
const struct signal *signals,
int num_signals,
int which)
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"),
535 if (sigprocmask(SIG_UNBLOCK, &s->old_mask,
NULL) < 0) {
536 G_warning(
_(
"G_spawn: unable to restore signal %d"),
547 static int do_signals(
struct signal *signals,
int num_signals,
int which)
549 struct sigaction act;
554 sigemptyset(&act.sa_mask);
555 act.sa_flags = SA_RESTART;
557 for (i = 0; i < num_signals; i++) {
558 struct signal *s = &signals[i];
560 if (s->which != which)
565 act.sa_handler = SIG_IGN;
566 if (sigaction(s->signum, &act, &s->old_act) < 0) {
567 G_warning(
_(
"G_spawn: unable to reset signal %d"), s->signum);
574 act.sa_handler = SIG_DFL;
575 if (sigaction(s->signum, &act, &s->old_act) < 0) {
576 G_warning(
_(
"G_spawn: unable to ignore signal %d"),
585 sigaddset(&mask, s->signum);
586 if (sigprocmask(SIG_BLOCK, &mask, &s->old_mask) < 0) {
587 G_warning(
_(
"G_spawn: unable to block signal %d"), s->signum);
593 sigaddset(&mask, s->signum);
594 if (sigprocmask(SIG_UNBLOCK, &mask, &s->old_mask) < 0) {
595 G_warning(
_(
"G_spawn: unable to unblock signal %d"),
608 static void do_redirects(
struct redirect *redirects,
int num_redirects)
612 for (i = 0; i < num_redirects; i++) {
613 struct redirect *
r = &redirects[i];
616 r->src_fd = open(r->file, r->mode, 0666);
619 G_warning(
_(
"G_spawn: unable to open file %s"), r->file);
623 if (dup2(r->src_fd, r->dst_fd) < 0) {
624 G_warning(
_(
"G_spawn: unable to duplicate descriptor %d to %d"),
625 r->src_fd, r->dst_fd);
631 else if (r->src_fd >= 0) {
632 if (dup2(r->src_fd, r->dst_fd) < 0) {
633 G_warning(
_(
"G_spawn: unable to duplicate descriptor %d to %d"),
634 r->src_fd, r->dst_fd);
643 static void do_bindings(
const struct binding *bindings,
int num_bindings)
647 for (i = 0; i < num_bindings; i++) {
648 const struct binding *b = &bindings[i];
649 char *str =
G_malloc(strlen(b->var) + strlen(b->val) + 2);
651 sprintf(str,
"%s=%s", b->var, b->val);
656 static int do_spawn(
struct spawn *sp,
const char *command)
661 if (!do_signals(sp->signals, sp->num_signals,
SST_PRE))
666 G_warning(
_(
"Unable to create a new process: %s"), strerror(errno));
667 undo_signals(sp->signals, sp->num_signals,
SST_PRE);
673 if (!undo_signals(sp->signals, sp->num_signals,
SST_PRE))
676 if (!do_signals(sp->signals, sp->num_signals,
SST_CHILD))
680 if (chdir(sp->directory) < 0) {
681 G_warning(
_(
"Unable to change directory to %s"), sp->directory);
685 do_redirects(sp->redirects, sp->num_redirects);
686 do_bindings(sp->bindings, sp->num_bindings);
688 execvp(command, (
char **)sp->args);
689 G_warning(
_(
"Unable to execute command '%s': %s"), command, strerror(errno));
693 do_signals(sp->signals, sp->num_signals,
SST_POST);
701 n = waitpid(pid, &status, 0);
702 while (n == (pid_t) - 1 && errno == EINTR);
707 if (WIFEXITED(status))
708 status = WEXITSTATUS(status);
709 else if (WIFSIGNALED(status))
710 status = WTERMSIG(status);
716 undo_signals(sp->signals, sp->num_signals,
SST_POST);
717 undo_signals(sp->signals, sp->num_signals,
SST_PRE);
724 static void begin_spawn(
struct spawn *sp)
727 sp->num_redirects = 0;
729 sp->num_bindings = 0;
731 sp->directory =
NULL;
734 #define NEXT_ARG(var, type) ((type) *(var)++) 735 #define NEXT_ARG_INT(var) (int)((intptr_t) *(var)++) 737 static void parse_argvec(
struct spawn *sp,
const char **va)
740 const char *arg =
NEXT_ARG(va,
const char *);
741 const char *
var, *val;
744 sp->args[sp->num_args++] =
NULL;
748 sp->redirects[sp->num_redirects].dst_fd =
NEXT_ARG_INT(va);
750 sp->redirects[sp->num_redirects].src_fd = -1;
751 sp->redirects[sp->num_redirects].mode =
NEXT_ARG_INT(va);
752 sp->redirects[sp->num_redirects].file =
NEXT_ARG(va,
const char *);
757 sp->redirects[sp->num_redirects].dst_fd =
NEXT_ARG_INT(va);
758 sp->redirects[sp->num_redirects].src_fd =
NEXT_ARG_INT(va);
760 sp->redirects[sp->num_redirects].file =
NULL;
764 sp->redirects[sp->num_redirects].dst_fd =
NEXT_ARG_INT(va);
766 sp->redirects[sp->num_redirects].src_fd = -1;
767 sp->redirects[sp->num_redirects].file =
NULL;
775 sp->signals[sp->num_signals].valid = 0;
782 sp->args[sp->num_args++] = val ? val :
"";
785 sp->bindings[sp->num_bindings].var =
NEXT_ARG(va,
const char *);
786 sp->bindings[sp->num_bindings].val =
NEXT_ARG(va,
const char *);
794 sp->directory =
NEXT_ARG(va,
const char *);
798 parse_argvec(sp,
NEXT_ARG(va,
const char **));
801 sp->args[sp->num_args++] = arg;
805 static void parse_arglist(
struct spawn *sp, va_list va)
808 const char *arg = va_arg(va,
const char *);
809 const char *
var, *val;
812 sp->args[sp->num_args++] =
NULL;
816 sp->redirects[sp->num_redirects].dst_fd = va_arg(va,
int);
818 sp->redirects[sp->num_redirects].src_fd = -1;
819 sp->redirects[sp->num_redirects].mode = va_arg(va,
int);
820 sp->redirects[sp->num_redirects].file = va_arg(va,
const char *);
825 sp->redirects[sp->num_redirects].dst_fd = va_arg(va,
int);
826 sp->redirects[sp->num_redirects].src_fd = va_arg(va,
int);
828 sp->redirects[sp->num_redirects].file =
NULL;
832 sp->redirects[sp->num_redirects].dst_fd = va_arg(va,
int);
834 sp->redirects[sp->num_redirects].src_fd = -1;
835 sp->redirects[sp->num_redirects].file =
NULL;
839 sp->signals[sp->num_signals].which = va_arg(va,
int);
840 sp->signals[sp->num_signals].action = va_arg(va,
int);
841 sp->signals[sp->num_signals].signum = va_arg(va,
int);
843 sp->signals[sp->num_signals].valid = 0;
847 var = va_arg(va,
char *);
850 sp->args[sp->num_args++] = val ? val :
"";
853 sp->bindings[sp->num_bindings].var = va_arg(va,
const char *);
854 sp->bindings[sp->num_bindings].val = va_arg(va,
const char *);
862 sp->directory = va_arg(va,
const char *);
865 parse_argvec(sp, va_arg(va,
const char **));
868 sp->args[sp->num_args++] = arg;
888 parse_argvec(&sp, args);
890 return do_spawn(&sp, command);
910 va_start(va, command);
911 parse_arglist(&sp, va);
914 return do_spawn(&sp, command);
932 va_start(va, command);
935 const char *arg = va_arg(va,
const char *);
936 args[num_args++] = arg;
959 DWORD rights = PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
960 HANDLE hProcess = OpenProcess(rights,
FALSE, (DWORD) i_pid);
966 WaitForSingleObject(hProcess, INFINITE);
967 if (!GetExitCodeProcess(hProcess, &exitcode))
968 exitcode = (DWORD) -1;
970 CloseHandle(hProcess);
972 return (
int) exitcode;
974 pid_t pid = (pid_t) i_pid;
979 n = waitpid(pid, &status, 0);
980 while (n == (pid_t) - 1 && errno == EINTR);
985 if (WIFEXITED(status))
986 return WEXITSTATUS(status);
987 else if (WIFSIGNALED(status))
988 return WTERMSIG(status);
int G_spawn_ex(const char *command,...)
Spawn new process based on command.
int G_vspawn_ex(const char *command, const char **args)
Spawn new process based on command.
void G_free(void *)
Free allocated memory.
#define SF_REDIRECT_DESCRIPTOR
char ** G_tokenize(const char *, const char *)
Tokenize string.
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
float var(IClass_statistics *statistics, int band1, int band2)
Helper function for computing variance.
void G_free_tokens(char **)
Free memory allocated to tokens.
void G_warning(const char *,...) __attribute__((format(printf
#define SF_CLOSE_DESCRIPTOR
#define NEXT_ARG_INT(var)
char * G_store(const char *)
Copy string to allocated memory.
int G_debug(int, const char *,...) __attribute__((format(printf
#define NEXT_ARG(var, type)
int G_spawn(const char *command,...)
Spawn new process based on command.