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;
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++) {
438 else if (r->
src_fd >= 0) {
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);
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)
503 G_warning(_(
"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)
528 G_warning(_(
"G_spawn: unable to restore signal %d"),
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;
574 act.sa_handler = SIG_DFL;
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) {
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++) {
624 G_warning(_(
"G_spawn: unable to duplicate descriptor %d to %d"),
631 else if (r->
src_fd >= 0) {
633 G_warning(_(
"G_spawn: unable to duplicate descriptor %d to %d"),
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);
656 static int do_spawn(
struct spawn *sp,
const char *command)
666 G_warning(_(
"Unable to create a new process"));
688 execvp(command, (
char **)sp->
args);
689 G_warning(_(
"Unable to execute command"));
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);
724 static void begin_spawn(
struct spawn *sp)
734 #define NEXT_ARG(var, type) ((type) *(var)++)
736 static void parse_argvec(
struct spawn *sp,
const char **va)
739 const char *arg =
NEXT_ARG(va,
const char *);
746 else if (arg == SF_REDIRECT_FILE) {
755 else if (arg == SF_REDIRECT_DESCRIPTOR) {
762 else if (arg == SF_CLOSE_DESCRIPTOR) {
769 else if (arg == SF_SIGNAL) {
777 else if (arg == SF_VARIABLE) {
783 else if (arg == SF_BINDING) {
789 else if (arg == SF_BACKGROUND) {
792 else if (arg == SF_DIRECTORY) {
796 else if (arg == SF_ARGVEC) {
797 parse_argvec(sp,
NEXT_ARG(va,
const char **));
804 static void parse_arglist(
struct spawn *sp, va_list va)
807 const char *arg = va_arg(va,
const char *);
814 else if (arg == SF_REDIRECT_FILE) {
823 else if (arg == SF_REDIRECT_DESCRIPTOR) {
830 else if (arg == SF_CLOSE_DESCRIPTOR) {
837 else if (arg == SF_SIGNAL) {
845 else if (arg == SF_VARIABLE) {
846 var = va_arg(va,
char *);
851 else if (arg == SF_BINDING) {
857 else if (arg == SF_BACKGROUND) {
860 else if (arg == SF_DIRECTORY) {
861 sp->
directory = va_arg(va,
const char *);
863 else if (arg == SF_ARGVEC) {
864 parse_argvec(sp, va_arg(va,
const char **));
887 parse_argvec(&sp, args);
889 return do_spawn(&sp, command);
909 va_start(va, command);
910 parse_arglist(&sp, va);
913 return do_spawn(&sp, command);
931 va_start(va, command);
934 const char *arg = va_arg(va,
const char *);
935 args[num_args++] = arg;
945 SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGINT,
946 SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGQUIT,
947 SF_SIGNAL, SST_PRE, SSA_BLOCK, SIGCHLD,
958 DWORD rights = PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
959 HANDLE hProcess = OpenProcess(rights,
FALSE, (DWORD) i_pid);
965 WaitForSingleObject(hProcess, INFINITE);
966 if (!GetExitCodeProcess(hProcess, &exitcode))
967 exitcode = (DWORD) -1;
969 CloseHandle(hProcess);
971 return (
int) exitcode;
973 pid_t pid = (pid_t) i_pid;
978 n = waitpid(pid, &status, 0);
979 while (n == (pid_t) - 1 &&
errno == EINTR);
984 if (WIFEXITED(status))
985 return WEXITSTATUS(status);
986 else if (WIFSIGNALED(status))
987 return WTERMSIG(status);
struct signal signals[MAX_SIGNALS]
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
sprintf(buf2,"%s", G3D_CATS_ELEMENT)
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
char buf[GNAME_MAX+sizeof(G3D_DIRECTORY)+2]
G_warning("category support for [%s] in mapset [%s] %s", name, mapset, type)
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.