25 #include <sys/types.h>
32 #include <grass/config.h>
33 #include <grass/gis.h>
34 #include <grass/glocale.h>
35 #include <grass/spawn.h>
45 #define MAX_BINDINGS 256
46 #define MAX_SIGNALS 32
47 #define MAX_REDIRECTS 32
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)
122 b->str = G_malloc(1);
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;
149 b->str = G_realloc(b->str, b->size);
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)
219 char pathname[GPATH_MAX];
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)
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);
343 PROCESS_INFORMATION pi;
348 G_debug(3,
"win_spawn: program = %s", program);
357 G_debug(3,
"win_spawn: args = %s", args);
359 memset(&si, 0,
sizeof(si));
362 si.dwFlags |= STARTF_USESTDHANDLES;
363 si.hStdInput = handles[0];
364 si.hStdOutput = handles[1];
365 si.hStdError = handles[2];
367 result = CreateProcess(
385 G_warning(_(
"CreateProcess() failed: error = %d"), GetLastError());
389 CloseHandle(pi.hThread);
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, HANDLE handles[3])
408 for (i = 0; i < 3; i++)
409 handles[i] = get_handle(i);
411 for (i = 0; i < num_redirects; i++) {
433 else if (r->
src_fd >= 0) {
437 handles[r->
dst_fd] = INVALID_HANDLE_VALUE;
441 static void add_binding(
const char **env,
int *pnum,
const struct binding *b)
443 char *str = G_malloc(strlen(b->
var) + strlen(b->
val) + 2);
447 sprintf(str,
"%s=%s", b->
var, b->
val);
449 for (i = 0; i < n; i++)
459 static const char **do_bindings(
const struct binding *bindings,
int num_bindings)
464 for (i = 0; _environ[i]; i++)
468 newenv = G_malloc((num_bindings + n + 1) *
sizeof(
char *));
470 for (i = 0; i < n; i++)
471 newenv[i] = _environ[i];
473 for (i = 0; i < num_bindings; i++)
474 add_binding(newenv, &n, &bindings[i]);
476 newenv[num_bindings + n] =
NULL;
481 static int do_spawn(
struct spawn *sp,
const char *
command)
493 G_warning(_(
"Unable to execute command"));
500 static int undo_signals(
const struct signal *signals,
int num_signals,
int which)
505 for (i = num_signals - 1; i >= 0; i--) {
506 const struct signal *
s = &signals[i];
508 if (s->
which != which)
518 G_warning(_(
"G_spawn: unable to restore signal %d"),
526 G_warning(_(
"G_spawn: unable to restore signal %d"),
537 static int do_signals(
struct signal *signals,
int num_signals,
int which)
539 struct sigaction act;
544 sigemptyset(&act.sa_mask);
545 act.sa_flags = SA_RESTART;
547 for (i = 0; i < num_signals; i++) {
548 struct signal *s = &signals[i];
550 if (s->
which != which)
555 act.sa_handler = SIG_IGN;
564 act.sa_handler = SIG_DFL;
566 G_warning(_(
"G_spawn: unable to ignore signal %d"),
575 sigaddset(&mask, s->
signum);
576 if (sigprocmask(SIG_BLOCK, &mask, &s->
old_mask) < 0) {
583 sigaddset(&mask, s->
signum);
584 if (sigprocmask(SIG_UNBLOCK, &mask, &s->
old_mask) < 0) {
585 G_warning(_(
"G_spawn: unable to unblock signal %d"),
598 static void do_redirects(
struct redirect *redirects,
int num_redirects)
602 for (i = 0; i < num_redirects; i++) {
614 G_warning(_(
"G_spawn: unable to duplicate descriptor %d to %d"),
621 else if (r->
src_fd >= 0) {
623 G_warning(_(
"G_spawn: unable to duplicate descriptor %d to %d"),
633 static void do_bindings(
const struct binding *bindings,
int num_bindings)
637 for (i = 0; i < num_bindings; i++) {
638 const struct binding *b = &bindings[i];
639 char *str = G_malloc(strlen(b->
var) + strlen(b->
val) + 2);
641 sprintf(str,
"%s=%s", b->
var, b->
val);
646 static int do_spawn(
struct spawn *sp,
const char *command)
656 G_warning(_(
"Unable to create a new process"));
678 execvp(command, (
char **)sp->
args);
679 G_warning(_(
"Unable to execute command"));
691 n = waitpid(pid, &status, 0);
692 while (n == (pid_t) - 1 &&
errno == EINTR);
697 if (WIFEXITED(status))
698 status = WEXITSTATUS(status);
699 else if (WIFSIGNALED(status))
700 status = WTERMSIG(status);
714 static void begin_spawn(
struct spawn *sp)
724 #define NEXT_ARG(var, type) ((type) *(var)++)
726 static void parse_argvec(
struct spawn *sp,
const char **va)
729 const char *arg =
NEXT_ARG(va,
const char *);
736 else if (arg == SF_REDIRECT_FILE) {
745 else if (arg == SF_REDIRECT_DESCRIPTOR) {
752 else if (arg == SF_CLOSE_DESCRIPTOR) {
759 else if (arg == SF_SIGNAL) {
767 else if (arg == SF_VARIABLE) {
773 else if (arg == SF_BINDING) {
779 else if (arg == SF_BACKGROUND) {
782 else if (arg == SF_DIRECTORY) {
786 else if (arg == SF_ARGVEC) {
787 parse_argvec(sp,
NEXT_ARG(va,
const char **));
794 static void parse_arglist(
struct spawn *sp, va_list va)
797 const char *arg = va_arg(va,
const char *);
804 else if (arg == SF_REDIRECT_FILE) {
813 else if (arg == SF_REDIRECT_DESCRIPTOR) {
820 else if (arg == SF_CLOSE_DESCRIPTOR) {
827 else if (arg == SF_SIGNAL) {
835 else if (arg == SF_VARIABLE) {
836 var = va_arg(va,
char *);
841 else if (arg == SF_BINDING) {
847 else if (arg == SF_BACKGROUND) {
850 else if (arg == SF_DIRECTORY) {
851 sp->
directory = va_arg(va,
const char *);
853 else if (arg == SF_ARGVEC) {
854 parse_argvec(sp, va_arg(va,
const char **));
877 parse_argvec(&sp, args);
879 return do_spawn(&sp, command);
899 va_start(va, command);
900 parse_arglist(&sp, va);
903 return do_spawn(&sp, command);
921 va_start(va, command);
924 const char *arg = va_arg(va,
const char *);
925 args[num_args++] = arg;
935 SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGINT,
936 SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGQUIT,
937 SF_SIGNAL, SST_PRE, SSA_BLOCK, SIGCHLD,
948 DWORD rights = PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
949 HANDLE hProcess = OpenProcess(rights,
FALSE, (DWORD) i_pid);
955 WaitForSingleObject(hProcess, INFINITE);
956 if (!GetExitCodeProcess(hProcess, &exitcode))
957 exitcode = (DWORD) -1;
959 CloseHandle(hProcess);
961 return (
int) exitcode;
963 pid_t pid = (pid_t) i_pid;
968 n = waitpid(pid, &status, 0);
969 while (n == (pid_t) - 1 &&
errno == EINTR);
974 if (WIFEXITED(status))
975 return WEXITSTATUS(status);
976 else if (WIFSIGNALED(status))
977 return WTERMSIG(status);
struct signal signals[MAX_SIGNALS]
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
void G_free(void *buf)
Free allocated memory.
def find_program
Attempt to run a program, with optional arguments.
char * G_store(const char *s)
Copy string to allocated memory.
int G_free_tokens(char **tokens)
Free memory allocated to tokens.
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.
char ** G_tokenize(const char *buf, const char *delim)
Tokenize string.
const char * args[MAX_ARGS]
def error
Display an error message using g.message -e
int G_warning(const char *msg,...)
Print a warning message to stderr.
int G_debug(int level, const char *msg,...)
Print debugging message.
struct binding bindings[MAX_BINDINGS]
#define NEXT_ARG(var, type)
struct redirect redirects[MAX_REDIRECTS]
int G_spawn(const char *command,...)
Spawn new process based on command.