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