GRASS Programmer's Manual  6.4.3(2013)-r
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Pages
spawn.c
Go to the documentation of this file.
1 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <signal.h>
21 #include <stdarg.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <sys/types.h>
26 
27 #ifndef __MINGW32__
28 #include <sys/wait.h>
29 #else
30 #include <windows.h>
31 #endif
32 #include <grass/config.h>
33 #include <grass/gis.h>
34 #include <grass/glocale.h>
35 #include <grass/spawn.h>
36 
44 #define MAX_ARGS 256
45 #define MAX_BINDINGS 256
46 #define MAX_SIGNALS 32
47 #define MAX_REDIRECTS 32
48 
49 
61 struct redirect
62 {
63  int dst_fd;
64  int src_fd;
65  const char *file;
66  int mode;
67 };
68 
69 struct signal
70 {
71  int which;
72  int action;
73  int signum;
74  int valid;
75 #ifndef __MINGW32__
76  struct sigaction old_act;
77  sigset_t old_mask;
78 #endif
79 };
80 
81 struct binding
82 {
83  const char *var;
84  const char *val;
85 };
86 
87 struct spawn
88 {
89  const char *args[MAX_ARGS];
90  int num_args;
98  const char *directory;
99 };
100 
101 static void parse_arglist(struct spawn *sp, va_list va);
102 static void parse_argvec(struct spawn *sp, const char **va);
103 
104 #ifdef __MINGW32__
105 
106 struct buffer {
107  char *str;
108  size_t len;
109  size_t size;
110 };
111 
112 static const int INCREMENT = 50;
113 
114 static void clear(struct buffer *b)
115 {
116  b->len = 0;
117  b->str[b->len] = '\0';
118 }
119 
120 static void init(struct buffer *b)
121 {
122  b->str = G_malloc(1);
123  b->size = 1;
124  clear(b);
125 }
126 
127 static char *release(struct buffer *b)
128 {
129  char *p = b->str;
130 
131  b->str = NULL;
132  b->size = 0;
133  b->len = 0;
134 
135  return p;
136 }
137 
138 static void finish(struct buffer *b)
139 {
140  if (b->str)
141  G_free(b->str);
142  release(b);
143 }
144 
145 static void ensure(struct buffer *b, size_t n)
146 {
147  if (b->size <= b->len + n + 1) {
148  b->size = b->len + n + INCREMENT;
149  b->str = G_realloc(b->str, b->size);
150  }
151 }
152 
153 static void append(struct buffer *b, const char *str)
154 {
155  size_t n = strlen(str);
156 
157  ensure(b, n);
158  memcpy(&b->str[b->len], str, n);
159  b->len += n;
160  b->str[b->len] = '\0';
161 }
162 
163 static void append_char(struct buffer *b, char c)
164 {
165  ensure(b, 1);
166  b->str[b->len] = c;
167  b->len++;
168  b->str[b->len] = '\0';
169 }
170 
171 static void escape_arg(struct buffer *result, const char *arg)
172 {
173  struct buffer buf;
174  int quote, j;
175 
176  init(&buf);
177 
178  quote = arg[0] == '\0' || strchr(arg, ' ') || strchr(arg, '\t');
179 
180  if (quote)
181  append_char(result, '\"');
182 
183  for (j = 0; arg[j]; j++) {
184  int c = arg[j];
185  int k;
186 
187  switch (c) {
188  case '\\':
189  append_char(&buf, '\\');
190  break;
191  case '\"':
192  for (k = 0; k < buf.len; k++)
193  append(result, "\\\\");
194  clear(&buf);
195  append(result, "\\\"");
196  break;
197  default:
198  if (buf.len > 0) {
199  append(result, buf.str);
200  clear(&buf);
201  }
202  append_char(result, c);
203  }
204  }
205 
206  if (buf.len > 0)
207  append(result, buf.str);
208 
209  if (quote) {
210  append(result, buf.str);
211  append_char(result, '\"');
212  }
213 
214  finish(&buf);
215 }
216 
217 static char *check_program(const char *pgm, const char *dir, const char *ext)
218 {
219  char pathname[GPATH_MAX];
220 
221  sprintf(pathname, "%s%s%s%s", dir, *dir ? "\\" : "", pgm, ext);
222  return access(pathname, 0) == 0
223  ? G_store(pathname)
224  : NULL;
225 }
226 
227 static char *find_program_ext(const char *pgm, const char *dir, char **pathext)
228 {
229  char *result;
230  int i;
231 
232  if (result = check_program(pgm, dir, ""), result)
233  return result;
234 
235  for (i = 0; pathext[i]; i++) {
236  const char *ext = pathext[i];
237  if (result = check_program(pgm, dir, ext), result)
238  return result;
239  }
240 
241  return NULL;
242 }
243 
244 static char *find_program_dir_ext(const char *pgm, char **path, char **pathext)
245 {
246  char *result = NULL;
247  int i;
248 
249  if (strchr(pgm, '\\') || strchr(pgm, '/')) {
250  if (result = find_program_ext(pgm, "", pathext), result)
251  return result;
252  }
253  else {
254  if (result = find_program_ext(pgm, ".", pathext), result)
255  return result;
256 
257  for (i = 0; path[i]; i++) {
258  const char *dir = path[i];
259  if (result = find_program_ext(pgm, dir, pathext), result)
260  return result;
261  }
262  }
263 
264  return NULL;
265 }
266 
267 static char *find_program(const char *pgm)
268 {
269  char **path = G_tokenize(getenv("PATH"), ";");
270  char **pathext = G_tokenize(getenv("PATHEXT"), ";");
271  char *result = find_program_dir_ext(pgm, path, pathext);
272  G_free_tokens(path);
273  G_free_tokens(pathext);
274  return result;
275 }
276 
277 static char *make_command_line(int shell, const char *cmd, const char **argv)
278 {
279  struct buffer result;
280  int i;
281 
282  init(&result);
283 
284  if (shell) {
285  const char *comspec = getenv("COMSPEC");
286  append(&result, comspec ? comspec : "cmd.exe");
287  append(&result, " /c \"");
288  escape_arg(&result, cmd);
289  }
290 
291  for (i = shell ? 1 : 0; argv[i]; i++) {
292  if (result.len > 0)
293  append_char(&result, ' ');
294  escape_arg(&result, argv[i]);
295  }
296 
297  append(&result, "\"");
298 
299  return release(&result);
300 }
301 
302 static char *make_environment(const char **envp)
303 {
304  struct buffer result;
305  int i;
306 
307  init(&result);
308 
309  for (i = 0; envp[i]; i++) {
310  const char *env = envp[i];
311 
312  append(&result, env);
313  append_char(&result, '\0');
314  }
315 
316  return release(&result);
317 }
318 
319 static HANDLE get_handle(int fd)
320 {
321  HANDLE h1, h2;
322 
323  if (fd < 0)
324  return INVALID_HANDLE_VALUE;
325 
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;
331 
332  return h2;
333 }
334 
335 static int win_spawn(const char *cmd, const char **argv, const char **envp,
336  const char *cwd, HANDLE handles[3], int background,
337  int shell)
338 {
339  char *args = make_command_line(shell, cmd, argv);
340  char *env = make_environment(envp);
341  char *program = shell ? NULL : find_program(cmd);
342  STARTUPINFO si;
343  PROCESS_INFORMATION pi;
344  BOOL result;
345  DWORD exitcode;
346 
347  if (!shell) {
348  G_debug(3, "win_spawn: program = %s", program);
349 
350  if (!program) {
351  G_free(args);
352  G_free(env);
353  return -1;
354  }
355  }
356 
357  G_debug(3, "win_spawn: args = %s", args);
358 
359  memset(&si, 0, sizeof(si));
360  si.cb = sizeof(si);
361 
362  si.dwFlags |= STARTF_USESTDHANDLES;
363  si.hStdInput = handles[0];
364  si.hStdOutput = handles[1];
365  si.hStdError = handles[2];
366 
367  result = CreateProcess(
368  program, /* lpApplicationName */
369  args, /* lpCommandLine */
370  NULL, /* lpProcessAttributes */
371  NULL, /* lpThreadAttributes */
372  1, /* bInheritHandles */
373  0, /* dwCreationFlags */
374  env, /* lpEnvironment */
375  cwd, /* lpCurrentDirectory */
376  &si, /* lpStartupInfo */
377  &pi /* lpProcessInformation */
378  );
379 
380  G_free(args);
381  G_free(env);
382  G_free(program);
383 
384  if (!result) {
385  G_warning(_("CreateProcess() failed: error = %d"), GetLastError());
386  return -1;
387  }
388 
389  CloseHandle(pi.hThread);
390 
391  if (!background) {
392  WaitForSingleObject(pi.hProcess, INFINITE);
393  if (!GetExitCodeProcess(pi.hProcess, &exitcode))
394  return -1;
395  CloseHandle(pi.hProcess);
396  return (int) exitcode;
397  }
398 
399  CloseHandle(pi.hProcess);
400 
401  return pi.dwProcessId;
402 }
403 
404 static void do_redirects(struct redirect *redirects, int num_redirects, HANDLE handles[3])
405 {
406  int i;
407 
408  for (i = 0; i < 3; i++)
409  handles[i] = get_handle(i);
410 
411  for (i = 0; i < num_redirects; i++) {
412  struct redirect *r = &redirects[i];
413 
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"), r->dst_fd);
417  continue;
418  }
419 
420  if (r->file) {
421  r->src_fd = open(r->file, r->mode, 0666);
422 
423  if (r->src_fd < 0) {
424  G_warning(_("G_spawn: unable to open file %s"), r->file);
425  _exit(127);
426  }
427 
428  handles[r->dst_fd] = get_handle(r->src_fd);
429 
430  close(r->src_fd);
431 
432  }
433  else if (r->src_fd >= 0) {
434  handles[r->dst_fd] = get_handle(r->src_fd);
435  }
436  else
437  handles[r->dst_fd] = INVALID_HANDLE_VALUE;
438  }
439 }
440 
441 static void add_binding(const char **env, int *pnum, const struct binding *b)
442 {
443  char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
444  int n = *pnum;
445  int i;
446 
447  sprintf(str, "%s=%s", b->var, b->val);
448 
449  for (i = 0; i < n; i++)
450  if (G_strcasecmp(env[i], b->var) == 0) {
451  env[i] = str;
452  return;
453  }
454 
455  env[n++] = str;
456  *pnum = n;
457 }
458 
459 static const char **do_bindings(const struct binding *bindings, int num_bindings)
460 {
461  const char **newenv;
462  int i, n;
463 
464  for (i = 0; _environ[i]; i++)
465  ;
466  n = i;
467 
468  newenv = G_malloc((num_bindings + n + 1) * sizeof(char *));
469 
470  for (i = 0; i < n; i++)
471  newenv[i] = _environ[i];
472 
473  for (i = 0; i < num_bindings; i++)
474  add_binding(newenv, &n, &bindings[i]);
475 
476  newenv[num_bindings + n] = NULL;
477 
478  return newenv;
479 }
480 
481 static int do_spawn(struct spawn *sp, const char *command)
482 {
483  HANDLE handles[3];
484  const char **env;
485  int status;
486 
487  do_redirects(sp->redirects, sp->num_redirects, handles);
488  env = do_bindings(sp->bindings, sp->num_bindings);
489 
490  status = win_spawn(command, sp->args, env, sp->directory, handles, sp->background, 1);
491 
492  if (!sp->background && status < 0)
493  G_warning(_("Unable to execute command"));
494 
495  return status;
496 }
497 
498 #else /* __MINGW32__ */
499 
500 static int undo_signals(const struct signal *signals, int num_signals, int which)
501 {
502  int error = 0;
503  int i;
504 
505  for (i = num_signals - 1; i >= 0; i--) {
506  const struct signal *s = &signals[i];
507 
508  if (s->which != which)
509  continue;
510 
511  if (!s->valid)
512  continue;
513 
514  switch (s->action) {
515  case SSA_IGNORE:
516  case SSA_DEFAULT:
517  if (sigaction(s->signum, &s->old_act, NULL) < 0) {
518  G_warning(_("G_spawn: unable to restore signal %d"),
519  s->signum);
520  error = 1;
521  }
522  break;
523  case SSA_BLOCK:
524  case SSA_UNBLOCK:
525  if (sigprocmask(SIG_UNBLOCK, &s->old_mask, NULL) < 0) {
526  G_warning(_("G_spawn: unable to restore signal %d"),
527  s->signum);
528  error = 1;
529  }
530  break;
531  }
532  }
533 
534  return !error;
535 }
536 
537 static int do_signals(struct signal *signals, int num_signals, int which)
538 {
539  struct sigaction act;
540  sigset_t mask;
541  int error = 0;
542  int i;
543 
544  sigemptyset(&act.sa_mask);
545  act.sa_flags = SA_RESTART;
546 
547  for (i = 0; i < num_signals; i++) {
548  struct signal *s = &signals[i];
549 
550  if (s->which != which)
551  continue;
552 
553  switch (s->action) {
554  case SSA_IGNORE:
555  act.sa_handler = SIG_IGN;
556  if (sigaction(s->signum, &act, &s->old_act) < 0) {
557  G_warning(_("G_spawn: unable to reset signal %d"), s->signum);
558  error = 1;
559  }
560  else
561  s->valid = 1;
562  break;
563  case SSA_DEFAULT:
564  act.sa_handler = SIG_DFL;
565  if (sigaction(s->signum, &act, &s->old_act) < 0) {
566  G_warning(_("G_spawn: unable to ignore signal %d"),
567  s->signum);
568  error = 1;
569  }
570  else
571  s->valid = 1;
572  break;
573  case SSA_BLOCK:
574  sigemptyset(&mask);
575  sigaddset(&mask, s->signum);
576  if (sigprocmask(SIG_BLOCK, &mask, &s->old_mask) < 0) {
577  G_warning(_("G_spawn: unable to block signal %d"), s->signum);
578  error = 1;
579  }
580  break;
581  case SSA_UNBLOCK:
582  sigemptyset(&mask);
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"),
586  s->signum);
587  error = 1;
588  }
589  else
590  s->valid = 1;
591  break;
592  }
593  }
594 
595  return !error;
596 }
597 
598 static void do_redirects(struct redirect *redirects, int num_redirects)
599 {
600  int i;
601 
602  for (i = 0; i < num_redirects; i++) {
603  struct redirect *r = &redirects[i];
604 
605  if (r->file) {
606  r->src_fd = open(r->file, r->mode, 0666);
607 
608  if (r->src_fd < 0) {
609  G_warning(_("G_spawn: unable to open file %s"), r->file);
610  _exit(127);
611  }
612 
613  if (dup2(r->src_fd, r->dst_fd) < 0) {
614  G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
615  r->src_fd, r->dst_fd);
616  _exit(127);
617  }
618 
619  close(r->src_fd);
620  }
621  else if (r->src_fd >= 0) {
622  if (dup2(r->src_fd, r->dst_fd) < 0) {
623  G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
624  r->src_fd, r->dst_fd);
625  _exit(127);
626  }
627  }
628  else
629  close(r->dst_fd);
630  }
631 }
632 
633 static void do_bindings(const struct binding *bindings, int num_bindings)
634 {
635  int i;
636 
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);
640 
641  sprintf(str, "%s=%s", b->var, b->val);
642  putenv(str);
643  }
644 }
645 
646 static int do_spawn(struct spawn *sp, const char *command)
647 {
648  int status = -1;
649  pid_t pid;
650 
651  if (!do_signals(sp->signals, sp->num_signals, SST_PRE))
652  return status;
653 
654  pid = fork();
655  if (pid < 0) {
656  G_warning(_("Unable to create a new process"));
657  undo_signals(sp->signals, sp->num_signals, SST_PRE);
658 
659  return status;
660  }
661 
662  if (pid == 0) {
663  if (!undo_signals(sp->signals, sp->num_signals, SST_PRE))
664  _exit(127);
665 
666  if (!do_signals(sp->signals, sp->num_signals, SST_CHILD))
667  _exit(127);
668 
669  if (sp->directory)
670  if (chdir(sp->directory) < 0) {
671  G_warning(_("Unable to change directory to %s"), sp->directory);
672  _exit(127);
673  }
674 
675  do_redirects(sp->redirects, sp->num_redirects);
676  do_bindings(sp->bindings, sp->num_bindings);
677 
678  execvp(command, (char **)sp->args);
679  G_warning(_("Unable to execute command"));
680  _exit(127);
681  }
682 
683  do_signals(sp->signals, sp->num_signals, SST_POST);
684 
685  if (sp->background)
686  status = (int)pid;
687  else {
688  pid_t n;
689 
690  do
691  n = waitpid(pid, &status, 0);
692  while (n == (pid_t) - 1 && errno == EINTR);
693 
694  if (n != pid)
695  status = -1;
696  else {
697  if (WIFEXITED(status))
698  status = WEXITSTATUS(status);
699  else if (WIFSIGNALED(status))
700  status = WTERMSIG(status);
701  else
702  status = -0x100;
703  }
704  }
705 
706  undo_signals(sp->signals, sp->num_signals, SST_POST);
707  undo_signals(sp->signals, sp->num_signals, SST_PRE);
708 
709  return status;
710 }
711 
712 #endif /* __MINGW32__ */
713 
714 static void begin_spawn(struct spawn *sp)
715 {
716  sp->num_args = 0;
717  sp->num_redirects = 0;
718  sp->num_signals = 0;
719  sp->num_bindings = 0;
720  sp->background = 0;
721  sp->directory = NULL;
722 }
723 
724 #define NEXT_ARG(var, type) ((type) *(var)++)
725 
726 static void parse_argvec(struct spawn *sp, const char **va)
727 {
728  for (;;) {
729  const char *arg = NEXT_ARG(va, const char *);
730  const char *var, *val;
731 
732  if (!arg) {
733  sp->args[sp->num_args++] = NULL;
734  break;
735  }
736  else if (arg == SF_REDIRECT_FILE) {
737  sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
738 
739  sp->redirects[sp->num_redirects].src_fd = -1;
740  sp->redirects[sp->num_redirects].mode = NEXT_ARG(va, int);
741  sp->redirects[sp->num_redirects].file = NEXT_ARG(va, const char *);
742 
743  sp->num_redirects++;
744  }
745  else if (arg == SF_REDIRECT_DESCRIPTOR) {
746  sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
747  sp->redirects[sp->num_redirects].src_fd = NEXT_ARG(va, int);
748 
749  sp->redirects[sp->num_redirects].file = NULL;
750  sp->num_redirects++;
751  }
752  else if (arg == SF_CLOSE_DESCRIPTOR) {
753  sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
754 
755  sp->redirects[sp->num_redirects].src_fd = -1;
756  sp->redirects[sp->num_redirects].file = NULL;
757  sp->num_redirects++;
758  }
759  else if (arg == SF_SIGNAL) {
760  sp->signals[sp->num_signals].which = NEXT_ARG(va, int);
761  sp->signals[sp->num_signals].action = NEXT_ARG(va, int);
762  sp->signals[sp->num_signals].signum = NEXT_ARG(va, int);
763 
764  sp->signals[sp->num_signals].valid = 0;
765  sp->num_signals++;
766  }
767  else if (arg == SF_VARIABLE) {
768  var = NEXT_ARG(va, const char *);
769 
770  val = getenv(var);
771  sp->args[sp->num_args++] = val ? val : "";
772  }
773  else if (arg == SF_BINDING) {
774  sp->bindings[sp->num_bindings].var = NEXT_ARG(va, const char *);
775  sp->bindings[sp->num_bindings].val = NEXT_ARG(va, const char *);
776 
777  sp->num_bindings++;
778  }
779  else if (arg == SF_BACKGROUND) {
780  sp->background = 1;
781  }
782  else if (arg == SF_DIRECTORY) {
783  sp->directory = NEXT_ARG(va, const char *);
784 
785  }
786  else if (arg == SF_ARGVEC) {
787  parse_argvec(sp, NEXT_ARG(va, const char **));
788  }
789  else
790  sp->args[sp->num_args++] = arg;
791  }
792 }
793 
794 static void parse_arglist(struct spawn *sp, va_list va)
795 {
796  for (;;) {
797  const char *arg = va_arg(va, const char *);
798  const char *var, *val;
799 
800  if (!arg) {
801  sp->args[sp->num_args++] = NULL;
802  break;
803  }
804  else if (arg == SF_REDIRECT_FILE) {
805  sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
806 
807  sp->redirects[sp->num_redirects].src_fd = -1;
808  sp->redirects[sp->num_redirects].mode = va_arg(va, int);
809  sp->redirects[sp->num_redirects].file = va_arg(va, const char *);
810 
811  sp->num_redirects++;
812  }
813  else if (arg == SF_REDIRECT_DESCRIPTOR) {
814  sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
815  sp->redirects[sp->num_redirects].src_fd = va_arg(va, int);
816 
817  sp->redirects[sp->num_redirects].file = NULL;
818  sp->num_redirects++;
819  }
820  else if (arg == SF_CLOSE_DESCRIPTOR) {
821  sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
822 
823  sp->redirects[sp->num_redirects].src_fd = -1;
824  sp->redirects[sp->num_redirects].file = NULL;
825  sp->num_redirects++;
826  }
827  else if (arg == SF_SIGNAL) {
828  sp->signals[sp->num_signals].which = va_arg(va, int);
829  sp->signals[sp->num_signals].action = va_arg(va, int);
830  sp->signals[sp->num_signals].signum = va_arg(va, int);
831 
832  sp->signals[sp->num_signals].valid = 0;
833  sp->num_signals++;
834  }
835  else if (arg == SF_VARIABLE) {
836  var = va_arg(va, char *);
837 
838  val = getenv(var);
839  sp->args[sp->num_args++] = val ? val : "";
840  }
841  else if (arg == SF_BINDING) {
842  sp->bindings[sp->num_bindings].var = va_arg(va, const char *);
843  sp->bindings[sp->num_bindings].val = va_arg(va, const char *);
844 
845  sp->num_bindings++;
846  }
847  else if (arg == SF_BACKGROUND) {
848  sp->background = 1;
849  }
850  else if (arg == SF_DIRECTORY) {
851  sp->directory = va_arg(va, const char *);
852  }
853  else if (arg == SF_ARGVEC) {
854  parse_argvec(sp, va_arg(va, const char **));
855  }
856  else
857  sp->args[sp->num_args++] = arg;
858  }
859 }
860 
871 int G_vspawn_ex(const char *command, const char **args)
872 {
873  struct spawn sp;
874 
875  begin_spawn(&sp);
876 
877  parse_argvec(&sp, args);
878 
879  return do_spawn(&sp, command);
880 }
881 
892 int G_spawn_ex(const char *command, ...)
893 {
894  struct spawn sp;
895  va_list va;
896 
897  begin_spawn(&sp);
898 
899  va_start(va, command);
900  parse_arglist(&sp, va);
901  va_end(va);
902 
903  return do_spawn(&sp, command);
904 }
905 
914 int G_spawn(const char *command, ...)
915 {
916  const char *args[MAX_ARGS];
917  int num_args = 0, i;
918  va_list va;
919  int status = -1;
920 
921  va_start(va, command);
922 
923  for (i = 0; ; i++) {
924  const char *arg = va_arg(va, const char *);
925  args[num_args++] = arg;
926  if (!arg)
927  break;
928  }
929 
930  va_end(va);
931 
932  status = G_spawn_ex(
933  command,
934 #ifndef __MINGW32__
935  SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGINT,
936  SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGQUIT,
937  SF_SIGNAL, SST_PRE, SSA_BLOCK, SIGCHLD,
938 #endif
939  SF_ARGVEC, args,
940  NULL);
941 
942  return status;
943 }
944 
945 int G_wait(int i_pid)
946 {
947 #ifdef __MINGW32__
948  DWORD rights = PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
949  HANDLE hProcess = OpenProcess(rights, FALSE, (DWORD) i_pid);
950  DWORD exitcode;
951 
952  if (!hProcess)
953  return -1;
954 
955  WaitForSingleObject(hProcess, INFINITE);
956  if (!GetExitCodeProcess(hProcess, &exitcode))
957  exitcode = (DWORD) -1;
958 
959  CloseHandle(hProcess);
960 
961  return (int) exitcode;
962 #else
963  pid_t pid = (pid_t) i_pid;
964  int status = -1;
965  pid_t n;
966 
967  do
968  n = waitpid(pid, &status, 0);
969  while (n == (pid_t) - 1 && errno == EINTR);
970 
971  if (n != pid)
972  return -1;
973  else {
974  if (WIFEXITED(status))
975  return WEXITSTATUS(status);
976  else if (WIFSIGNALED(status))
977  return WTERMSIG(status);
978  else
979  return -0x100;
980  }
981 #endif
982 }
983 
int num_signals
Definition: spawn.c:94
int G_wait(int i_pid)
Definition: spawn.c:945
struct signal signals[MAX_SIGNALS]
Definition: spawn.c:93
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
Definition: strings.c:192
sprintf(buf2,"%s", G3D_CATS_ELEMENT)
void G_free(void *buf)
Free allocated memory.
Definition: gis/alloc.c:142
int which
Definition: spawn.c:71
float b
Definition: named_colr.c:8
def find_program
Attempt to run a program, with optional arguments.
Definition: core.py:972
char * G_store(const char *s)
Copy string to allocated memory.
Definition: store.c:32
const char * file
Definition: spawn.c:65
int G_free_tokens(char **tokens)
Free memory allocated to tokens.
Definition: gis/token.c:98
#define FALSE
Definition: dbfopen.c:117
int
Definition: y.tab.c:1344
tuple cmd
Definition: forms.py:2019
FILE * fd
Definition: g3dcolor.c:368
int G_spawn_ex(const char *command,...)
Spawn new process based on command.
Definition: spawn.c:892
int G_vspawn_ex(const char *command, const char **args)
Spawn new process based on command.
Definition: spawn.c:871
float r
Definition: named_colr.c:8
int background
Definition: spawn.c:97
char ** G_tokenize(const char *buf, const char *delim)
Tokenize string.
Definition: gis/token.c:33
const char * args[MAX_ARGS]
Definition: spawn.c:89
def error
Display an error message using g.message -e
Definition: core.py:370
tuple env
list command
Definition: render.py:1306
#define MAX_BINDINGS
Definition: spawn.c:45
sigset_t old_mask
Definition: spawn.c:77
tuple size
value.Bind(wx.EVT_TEXT, self.OnVolumeIsosurfMap)
Definition: tools.py:2329
char * getenv()
int dst_fd
Definition: spawn.c:63
int num_args
Definition: spawn.c:90
const char * var
Definition: spawn.c:83
#define MAX_REDIRECTS
Definition: spawn.c:47
const char * directory
Definition: spawn.c:98
#define TRUE
Definition: dbfopen.c:118
unsigned int background
int action
Definition: spawn.c:72
#define MAX_ARGS
Definition: spawn.c:44
Spawns a new process.
Definition: spawn.c:61
int num_bindings
Definition: spawn.c:96
const char * val
Definition: spawn.c:84
char buf[GNAME_MAX+sizeof(G3D_DIRECTORY)+2]
Definition: g3drange.c:62
return NULL
Definition: dbfopen.c:1394
G_warning("category support for [%s] in mapset [%s] %s", name, mapset, type)
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: gis/debug.c:51
struct sigaction old_act
Definition: spawn.c:76
int num_redirects
Definition: spawn.c:92
Definition: spawn.c:81
int errno
int signum
Definition: spawn.c:73
Definition: spawn.c:69
int valid
Definition: spawn.c:74
struct binding bindings[MAX_BINDINGS]
Definition: spawn.c:95
int src_fd
Definition: spawn.c:64
int mode
Definition: spawn.c:66
int n
Definition: dataquad.c:291
#define NEXT_ARG(var, type)
Definition: spawn.c:724
Definition: spawn.c:87
#define MAX_SIGNALS
Definition: spawn.c:46
void init(double work[])
Definition: as177.c:65
struct redirect redirects[MAX_REDIRECTS]
Definition: spawn.c:91
int G_spawn(const char *command,...)
Spawn new process based on command.
Definition: spawn.c:914