GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-112dd97adf
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 __MINGW32__
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 __MINGW32__
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 __MINGW32__
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  sprintf(pathname, "%s%s%s%s", dir, *dir ? "\\" : "", pgm, ext);
216  return access(pathname, 0) == 0 ? G_store(pathname) : NULL;
217 }
218 
219 static char *find_program_ext(const char *pgm, const char *dir, char **pathext)
220 {
221  char *result;
222  int i;
223 
224  if (result = check_program(pgm, dir, ""), result)
225  return result;
226 
227  for (i = 0; pathext[i]; i++) {
228  const char *ext = pathext[i];
229 
230  if (result = check_program(pgm, dir, ext), result)
231  return result;
232  }
233 
234  return NULL;
235 }
236 
237 static char *find_program_dir_ext(const char *pgm, char **path, char **pathext)
238 {
239  char *result = NULL;
240  int i;
241 
242  if (strchr(pgm, '\\') || strchr(pgm, '/')) {
243  if (result = find_program_ext(pgm, "", pathext), result)
244  return result;
245  }
246  else {
247  if (result = find_program_ext(pgm, ".", pathext), result)
248  return result;
249 
250  for (i = 0; path[i]; i++) {
251  const char *dir = path[i];
252 
253  if (result = find_program_ext(pgm, dir, pathext), result)
254  return result;
255  }
256  }
257 
258  return NULL;
259 }
260 
261 static char *find_program(const char *pgm)
262 {
263  char **path = G_tokenize(getenv("PATH"), ";");
264  char **pathext = G_tokenize(getenv("PATHEXT"), ";");
265  char *result = find_program_dir_ext(pgm, path, pathext);
266 
268  G_free_tokens(pathext);
269  return result;
270 }
271 
272 static char *make_command_line(int shell, const char *cmd, const char **argv)
273 {
274  struct buffer result;
275  int i;
276 
277  init(&result);
278 
279  if (shell) {
280  const char *comspec = getenv("COMSPEC");
281 
282  append(&result, comspec ? comspec : "cmd.exe");
283  append(&result, " /c \"");
284  escape_arg(&result, cmd);
285  }
286 
287  for (i = shell ? 1 : 0; argv[i]; i++) {
288  if (result.len > 0)
289  append_char(&result, ' ');
290  escape_arg(&result, argv[i]);
291  }
292 
293  append(&result, "\"");
294 
295  return release(&result);
296 }
297 
298 static char *make_environment(const char **envp)
299 {
300  struct buffer result;
301  int i;
302 
303  init(&result);
304 
305  for (i = 0; envp[i]; i++) {
306  const char *env = envp[i];
307 
308  append(&result, env);
309  append_char(&result, '\0');
310  }
311 
312  return release(&result);
313 }
314 
315 static HANDLE get_handle(int fd)
316 {
317  HANDLE h1, h2;
318 
319  if (fd < 0)
320  return INVALID_HANDLE_VALUE;
321 
322  h1 = (HANDLE)_get_osfhandle(fd);
323  if (!DuplicateHandle(GetCurrentProcess(), h1, GetCurrentProcess(), &h2, 0,
324  TRUE, DUPLICATE_SAME_ACCESS))
325  return INVALID_HANDLE_VALUE;
326 
327  return h2;
328 }
329 
330 static int win_spawn(const char *cmd, const char **argv, const char **envp,
331  const char *cwd, HANDLE handles[3], int background,
332  int shell)
333 {
334  char *args = make_command_line(shell, cmd, argv);
335  char *env = make_environment(envp);
336  char *program = shell ? NULL : find_program(cmd);
337  STARTUPINFO si;
338  PROCESS_INFORMATION pi;
339  BOOL result;
340  DWORD exitcode;
341  int i;
342 
343  if (!shell) {
344  G_debug(3, "win_spawn: program = %s", program);
345 
346  if (!program) {
347  G_free(args);
348  G_free(env);
349  return -1;
350  }
351  }
352 
353  G_debug(3, "win_spawn: args = %s", args);
354 
355  memset(&si, 0, sizeof(si));
356  si.cb = sizeof(si);
357 
358  si.dwFlags |= STARTF_USESTDHANDLES;
359  si.hStdInput = handles[0];
360  si.hStdOutput = handles[1];
361  si.hStdError = handles[2];
362 
363  result = CreateProcess(program, /* lpApplicationName */
364  args, /* lpCommandLine */
365  NULL, /* lpProcessAttributes */
366  NULL, /* lpThreadAttributes */
367  1, /* bInheritHandles */
368  0, /* dwCreationFlags */
369  env, /* lpEnvironment */
370  cwd, /* lpCurrentDirectory */
371  &si, /* lpStartupInfo */
372  &pi /* lpProcessInformation */
373  );
374 
375  G_free(args);
376  G_free(env);
377  G_free(program);
378 
379  if (!result) {
380  G_warning(_("CreateProcess() failed: error = %d"), GetLastError());
381  return -1;
382  }
383 
384  CloseHandle(pi.hThread);
385 
386  for (i = 0; i < 3; i++)
387  if (handles[i] != INVALID_HANDLE_VALUE)
388  CloseHandle(handles[i]);
389 
390  if (!background) {
391  WaitForSingleObject(pi.hProcess, INFINITE);
392  if (!GetExitCodeProcess(pi.hProcess, &exitcode))
393  return -1;
394  CloseHandle(pi.hProcess);
395  return (int)exitcode;
396  }
397 
398  CloseHandle(pi.hProcess);
399 
400  return pi.dwProcessId;
401 }
402 
403 static void do_redirects(struct redirect *redirects, int num_redirects,
404  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"),
417  r->dst_fd);
418  continue;
419  }
420 
421  if (r->file) {
422  r->src_fd = open(r->file, r->mode, 0666);
423 
424  if (r->src_fd < 0) {
425  G_warning(_("G_spawn: unable to open file %s"), r->file);
426  _exit(127);
427  }
428 
429  handles[r->dst_fd] = get_handle(r->src_fd);
430 
431  close(r->src_fd);
432  }
433  else if (r->src_fd >= 0) {
434  handles[r->dst_fd] = get_handle(r->src_fd);
435  }
436  else {
437  if (r->dst_fd < 3) {
438  CloseHandle(handles[r->dst_fd]);
439  handles[r->dst_fd] = INVALID_HANDLE_VALUE;
440  }
441  close(r->dst_fd);
442  }
443  }
444 }
445 
446 static void add_binding(const char **env, int *pnum, const struct binding *b)
447 {
448  char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
449  int n = *pnum;
450  int i;
451 
452  sprintf(str, "%s=%s", b->var, b->val);
453 
454  for (i = 0; i < n; i++)
455  if (G_strcasecmp(env[i], b->var) == 0) {
456  env[i] = str;
457  return;
458  }
459 
460  env[n++] = str;
461  *pnum = n;
462 }
463 
464 static const char **do_bindings(const struct binding *bindings,
465  int num_bindings)
466 {
467  const char **newenv;
468  int i, n;
469 
470  for (i = 0; _environ[i]; i++)
471  ;
472  n = i;
473 
474  newenv = G_malloc((num_bindings + n + 1) * sizeof(char *));
475 
476  for (i = 0; i < n; i++)
477  newenv[i] = _environ[i];
478 
479  for (i = 0; i < num_bindings; i++)
480  add_binding(newenv, &n, &bindings[i]);
481 
482  newenv[num_bindings + n] = NULL;
483 
484  return newenv;
485 }
486 
487 static int do_spawn(struct spawn *sp, const char *command)
488 {
489  HANDLE handles[3];
490  const char **env;
491  int status;
492 
493  do_redirects(sp->redirects, sp->num_redirects, handles);
494  env = do_bindings(sp->bindings, sp->num_bindings);
495 
496  status = win_spawn(command, sp->args, env, sp->directory, handles,
497  sp->background, 1);
498 
499  if (!sp->background && status < 0)
500  G_warning(_("G_spawn: unable to execute command"));
501 
502  return status;
503 }
504 
505 #else /* __MINGW32__ */
506 
507 static int undo_signals(const struct signal *signals, int num_signals,
508  int which)
509 {
510  int error = 0;
511  int i;
512 
513  for (i = num_signals - 1; i >= 0; i--) {
514  const struct signal *s = &signals[i];
515 
516  if (s->which != which)
517  continue;
518 
519  if (!s->valid)
520  continue;
521 
522  switch (s->action) {
523  case SSA_IGNORE:
524  case SSA_DEFAULT:
525  if (sigaction(s->signum, &s->old_act, NULL) < 0) {
526  G_warning(_("G_spawn: unable to restore signal %d"), s->signum);
527  error = 1;
528  }
529  break;
530  case SSA_BLOCK:
531  case SSA_UNBLOCK:
532  if (sigprocmask(SIG_UNBLOCK, &s->old_mask, NULL) < 0) {
533  G_warning(_("G_spawn: unable to restore signal %d"), s->signum);
534  error = 1;
535  }
536  break;
537  }
538  }
539 
540  return !error;
541 }
542 
543 static int do_signals(struct signal *signals, int num_signals, int which)
544 {
545  struct sigaction act;
546  sigset_t mask;
547  int error = 0;
548  int i;
549 
550  sigemptyset(&act.sa_mask);
551  act.sa_flags = SA_RESTART;
552 
553  for (i = 0; i < num_signals; i++) {
554  struct signal *s = &signals[i];
555 
556  if (s->which != which)
557  continue;
558 
559  switch (s->action) {
560  case SSA_IGNORE:
561  act.sa_handler = SIG_IGN;
562  if (sigaction(s->signum, &act, &s->old_act) < 0) {
563  G_warning(_("G_spawn: unable to reset signal %d"), s->signum);
564  error = 1;
565  }
566  else
567  s->valid = 1;
568  break;
569  case SSA_DEFAULT:
570  act.sa_handler = SIG_DFL;
571  if (sigaction(s->signum, &act, &s->old_act) < 0) {
572  G_warning(_("G_spawn: unable to ignore signal %d"), s->signum);
573  error = 1;
574  }
575  else
576  s->valid = 1;
577  break;
578  case SSA_BLOCK:
579  sigemptyset(&mask);
580  sigaddset(&mask, s->signum);
581  if (sigprocmask(SIG_BLOCK, &mask, &s->old_mask) < 0) {
582  G_warning(_("G_spawn: unable to block signal %d"), s->signum);
583  error = 1;
584  }
585  break;
586  case SSA_UNBLOCK:
587  sigemptyset(&mask);
588  sigaddset(&mask, s->signum);
589  if (sigprocmask(SIG_UNBLOCK, &mask, &s->old_mask) < 0) {
590  G_warning(_("G_spawn: unable to unblock signal %d"), s->signum);
591  error = 1;
592  }
593  else
594  s->valid = 1;
595  break;
596  }
597  }
598 
599  return !error;
600 }
601 
602 static void do_redirects(struct redirect *redirects, int num_redirects)
603 {
604  int i;
605 
606  for (i = 0; i < num_redirects; i++) {
607  struct redirect *r = &redirects[i];
608 
609  if (r->file) {
610  r->src_fd = open(r->file, r->mode, 0666);
611 
612  if (r->src_fd < 0) {
613  G_warning(_("G_spawn: unable to open file %s"), r->file);
614  _exit(127);
615  }
616 
617  if (dup2(r->src_fd, r->dst_fd) < 0) {
618  G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
619  r->src_fd, r->dst_fd);
620  _exit(127);
621  }
622 
623  close(r->src_fd);
624  }
625  else if (r->src_fd >= 0) {
626  if (dup2(r->src_fd, r->dst_fd) < 0) {
627  G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
628  r->src_fd, r->dst_fd);
629  _exit(127);
630  }
631  }
632  else
633  close(r->dst_fd);
634  }
635 }
636 
637 static void do_bindings(const struct binding *bindings, int num_bindings)
638 {
639  int i;
640 
641  for (i = 0; i < num_bindings; i++) {
642  const struct binding *b = &bindings[i];
643  char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
644 
645  sprintf(str, "%s=%s", b->var, b->val);
646  putenv(str);
647  }
648 }
649 
650 static int do_spawn(struct spawn *sp, const char *command)
651 {
652  int status = -1;
653  pid_t pid;
654 
655  if (!do_signals(sp->signals, sp->num_signals, SST_PRE))
656  return status;
657 
658  pid = fork();
659  if (pid < 0) {
660  G_warning(_("Unable to create a new process: %s"), strerror(errno));
661  undo_signals(sp->signals, sp->num_signals, SST_PRE);
662 
663  return status;
664  }
665 
666  if (pid == 0) {
667  if (!undo_signals(sp->signals, sp->num_signals, SST_PRE))
668  _exit(127);
669 
670  if (!do_signals(sp->signals, sp->num_signals, SST_CHILD))
671  _exit(127);
672 
673  if (sp->directory)
674  if (chdir(sp->directory) < 0) {
675  G_warning(_("Unable to change directory to %s"), sp->directory);
676  _exit(127);
677  }
678 
679  do_redirects(sp->redirects, sp->num_redirects);
680  do_bindings(sp->bindings, sp->num_bindings);
681 
682  execvp(command, (char **)sp->args);
683  G_warning(_("Unable to execute command '%s': %s"), command,
684  strerror(errno));
685  _exit(127);
686  }
687 
688  do_signals(sp->signals, sp->num_signals, SST_POST);
689 
690  if (sp->background)
691  status = (int)pid;
692  else {
693  pid_t n;
694 
695  do
696  n = waitpid(pid, &status, 0);
697  while (n == (pid_t)-1 && errno == EINTR);
698 
699  if (n != pid)
700  status = -1;
701  else {
702  if (WIFEXITED(status))
703  status = WEXITSTATUS(status);
704  else if (WIFSIGNALED(status))
705  status = WTERMSIG(status);
706  else
707  status = -0x100;
708  }
709  }
710 
711  undo_signals(sp->signals, sp->num_signals, SST_POST);
712  undo_signals(sp->signals, sp->num_signals, SST_PRE);
713 
714  return status;
715 }
716 
717 #endif /* __MINGW32__ */
718 
719 static void begin_spawn(struct spawn *sp)
720 {
721  sp->num_args = 0;
722  sp->num_redirects = 0;
723  sp->num_signals = 0;
724  sp->num_bindings = 0;
725  sp->background = 0;
726  sp->directory = NULL;
727 }
728 
729 #define NEXT_ARG(var, type) ((type) * (var)++)
730 #define NEXT_ARG_INT(var) (int)((intptr_t) * (var)++)
731 
732 static void parse_argvec(struct spawn *sp, const char **va)
733 {
734  for (;;) {
735  const char *arg = NEXT_ARG(va, const char *);
736  const char *var, *val;
737 
738  if (!arg) {
739  sp->args[sp->num_args++] = NULL;
740  break;
741  }
742  else if (arg == SF_REDIRECT_FILE) {
743  sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG_INT(va);
744 
745  sp->redirects[sp->num_redirects].src_fd = -1;
746  sp->redirects[sp->num_redirects].mode = NEXT_ARG_INT(va);
747  sp->redirects[sp->num_redirects].file = NEXT_ARG(va, const char *);
748 
749  sp->num_redirects++;
750  }
751  else if (arg == SF_REDIRECT_DESCRIPTOR) {
752  sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG_INT(va);
753  sp->redirects[sp->num_redirects].src_fd = NEXT_ARG_INT(va);
754 
755  sp->redirects[sp->num_redirects].file = NULL;
756  sp->num_redirects++;
757  }
758  else if (arg == SF_CLOSE_DESCRIPTOR) {
759  sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG_INT(va);
760 
761  sp->redirects[sp->num_redirects].src_fd = -1;
762  sp->redirects[sp->num_redirects].file = NULL;
763  sp->num_redirects++;
764  }
765  else if (arg == SF_SIGNAL) {
766  sp->signals[sp->num_signals].which = NEXT_ARG_INT(va);
767  sp->signals[sp->num_signals].action = NEXT_ARG_INT(va);
768  sp->signals[sp->num_signals].signum = NEXT_ARG_INT(va);
769 
770  sp->signals[sp->num_signals].valid = 0;
771  sp->num_signals++;
772  }
773  else if (arg == SF_VARIABLE) {
774  var = NEXT_ARG(va, const char *);
775 
776  val = getenv(var);
777  sp->args[sp->num_args++] = val ? val : "";
778  }
779  else if (arg == SF_BINDING) {
780  sp->bindings[sp->num_bindings].var = NEXT_ARG(va, const char *);
781  sp->bindings[sp->num_bindings].val = NEXT_ARG(va, const char *);
782 
783  sp->num_bindings++;
784  }
785  else if (arg == SF_BACKGROUND) {
786  sp->background = 1;
787  }
788  else if (arg == SF_DIRECTORY) {
789  sp->directory = NEXT_ARG(va, const char *);
790  }
791  else if (arg == SF_ARGVEC) {
792  parse_argvec(sp, NEXT_ARG(va, const char **));
793  }
794  else
795  sp->args[sp->num_args++] = arg;
796  }
797 }
798 
799 static void parse_arglist(struct spawn *sp, va_list va)
800 {
801  for (;;) {
802  const char *arg = va_arg(va, const char *);
803  const char *var, *val;
804 
805  if (!arg) {
806  sp->args[sp->num_args++] = NULL;
807  break;
808  }
809  else if (arg == SF_REDIRECT_FILE) {
810  sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
811 
812  sp->redirects[sp->num_redirects].src_fd = -1;
813  sp->redirects[sp->num_redirects].mode = va_arg(va, int);
814  sp->redirects[sp->num_redirects].file = va_arg(va, const char *);
815 
816  sp->num_redirects++;
817  }
818  else if (arg == SF_REDIRECT_DESCRIPTOR) {
819  sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
820  sp->redirects[sp->num_redirects].src_fd = va_arg(va, int);
821 
822  sp->redirects[sp->num_redirects].file = NULL;
823  sp->num_redirects++;
824  }
825  else if (arg == SF_CLOSE_DESCRIPTOR) {
826  sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
827 
828  sp->redirects[sp->num_redirects].src_fd = -1;
829  sp->redirects[sp->num_redirects].file = NULL;
830  sp->num_redirects++;
831  }
832  else if (arg == SF_SIGNAL) {
833  sp->signals[sp->num_signals].which = va_arg(va, int);
834  sp->signals[sp->num_signals].action = va_arg(va, int);
835  sp->signals[sp->num_signals].signum = va_arg(va, int);
836 
837  sp->signals[sp->num_signals].valid = 0;
838  sp->num_signals++;
839  }
840  else if (arg == SF_VARIABLE) {
841  var = va_arg(va, char *);
842 
843  val = getenv(var);
844  sp->args[sp->num_args++] = val ? val : "";
845  }
846  else if (arg == SF_BINDING) {
847  sp->bindings[sp->num_bindings].var = va_arg(va, const char *);
848  sp->bindings[sp->num_bindings].val = va_arg(va, const char *);
849 
850  sp->num_bindings++;
851  }
852  else if (arg == SF_BACKGROUND) {
853  sp->background = 1;
854  }
855  else if (arg == SF_DIRECTORY) {
856  sp->directory = va_arg(va, const char *);
857  }
858  else if (arg == SF_ARGVEC) {
859  parse_argvec(sp, va_arg(va, const char **));
860  }
861  else
862  sp->args[sp->num_args++] = arg;
863  }
864 }
865 
866 /**
867  * \brief Spawn new process based on <b>command</b>.
868  *
869  * This is a more advanced version of G_spawn().
870  *
871  * \param[in] command
872  * \param[in] args arguments
873  * \return -1 on error
874  * \return process status on success
875  */
876 int G_vspawn_ex(const char *command, const char **args)
877 {
878  struct spawn sp;
879 
880  begin_spawn(&sp);
881 
882  parse_argvec(&sp, args);
883 
884  return do_spawn(&sp, command);
885 }
886 
887 /**
888  * \brief Spawn new process based on <b>command</b>.
889  *
890  * This is a more advanced version of G_spawn().
891  *
892  * \param[in] command
893  * \return -1 on error
894  * \return process status on success
895  */
896 
897 int G_spawn_ex(const char *command, ...)
898 {
899  struct spawn sp;
900  va_list va;
901 
902  begin_spawn(&sp);
903 
904  va_start(va, command);
905  parse_arglist(&sp, va);
906  va_end(va);
907 
908  return do_spawn(&sp, command);
909 }
910 
911 /**
912  * \brief Spawn new process based on <b>command</b>.
913  *
914  * \param[in] command
915  * \return -1 on error
916  * \return process status on success
917  */
918 
919 int G_spawn(const char *command, ...)
920 {
921  const char *args[MAX_ARGS];
922  int num_args = 0;
923  va_list va;
924  int status = -1;
925 
926  va_start(va, command);
927 
928  for (;;) {
929  const char *arg = va_arg(va, const char *);
930 
931  args[num_args++] = arg;
932  if (!arg)
933  break;
934  }
935 
936  va_end(va);
937 
938  status =
939  G_spawn_ex(command,
940 #ifndef __MINGW32__
942  SSA_IGNORE, SIGQUIT, SF_SIGNAL, SST_PRE, SSA_BLOCK, SIGCHLD,
943 #endif
944  SF_ARGVEC, args, NULL);
945 
946  return status;
947 }
948 
949 int G_wait(int i_pid)
950 {
951 #ifdef __MINGW32__
952  DWORD rights = PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
953  HANDLE hProcess = OpenProcess(rights, FALSE, (DWORD)i_pid);
954  DWORD exitcode;
955 
956  if (!hProcess)
957  return -1;
958 
959  WaitForSingleObject(hProcess, INFINITE);
960  if (!GetExitCodeProcess(hProcess, &exitcode))
961  exitcode = (DWORD)-1;
962 
963  CloseHandle(hProcess);
964 
965  return (int)exitcode;
966 #else
967  pid_t pid = (pid_t)i_pid;
968  int status = -1;
969  pid_t n;
970 
971  do
972  n = waitpid(pid, &status, 0);
973  while (n == (pid_t)-1 && errno == EINTR);
974 
975  if (n != pid)
976  return -1;
977  else {
978  if (WIFEXITED(status))
979  return WEXITSTATUS(status);
980  else if (WIFSIGNALED(status))
981  return WTERMSIG(status);
982  else
983  return -0x100;
984  }
985 #endif
986 }
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
#define GPATH_MAX
Definition: gis.h:194
#define TRUE
Definition: gis.h:79
#define FALSE
Definition: gis.h:83
#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:729
#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:876
int G_wait(int i_pid)
Definition: spawn.c:949
int G_spawn(const char *command,...)
Spawn new process based on command.
Definition: spawn.c:919
#define MAX_BINDINGS
Definition: spawn.c:44
int G_spawn_ex(const char *command,...)
Spawn new process based on command.
Definition: spawn.c:897
#define NEXT_ARG_INT(var)
Definition: spawn.c:730
#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