GRASS GIS 7 Programmer's Manual  7.5.svn(2018)-r72636
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
spawn.c
Go to the documentation of this file.
1 
2 /*!
3  * \file lib/gis/spawn.c
4  *
5  * \brief GIS Library - Handles process spawning.
6  *
7  * (C) 2001-2014 by the GRASS Development Team
8  *
9  * This program is free software under the GNU General Public License
10  * (>=v2). Read the file COPYING that comes with GRASS for details.
11  *
12  * \author Glynn Clements
13  *
14  * \date 2004-2006
15  */
16 
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 
37 /** \def MAX_ARGS Maximum number of arguments */
38 
39 /** \def MAX_BINDINGS Maximum number of bindings */
40 
41 /** \def MAX_SIGNALS Maximum number of signals */
42 
43 /** \def MAX_REDIRECTS Maximum number of redirects */
44 #define MAX_ARGS 256
45 #define MAX_BINDINGS 256
46 #define MAX_SIGNALS 32
47 #define MAX_REDIRECTS 32
48 
49 
50 /**
51  * \brief Spawns a new process.
52  *
53  * A more useful alternative to G_system(), which takes the
54  * arguments of <b>command</b> as parameters.
55  *
56  * \param[in] command command to execute
57  * \return -1 on error
58  * \return process status on success
59  */
60 
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;
91  struct redirect redirects[MAX_REDIRECTS];
92  int num_redirects;
93  struct signal signals[MAX_SIGNALS];
94  int num_signals;
95  struct binding bindings[MAX_BINDINGS];
96  int num_bindings;
97  int background;
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  int i;
347 
348  if (!shell) {
349  G_debug(3, "win_spawn: program = %s", program);
350 
351  if (!program) {
352  G_free(args);
353  G_free(env);
354  return -1;
355  }
356  }
357 
358  G_debug(3, "win_spawn: args = %s", args);
359 
360  memset(&si, 0, sizeof(si));
361  si.cb = sizeof(si);
362 
363  si.dwFlags |= STARTF_USESTDHANDLES;
364  si.hStdInput = handles[0];
365  si.hStdOutput = handles[1];
366  si.hStdError = handles[2];
367 
368  result = CreateProcess(
369  program, /* lpApplicationName */
370  args, /* lpCommandLine */
371  NULL, /* lpProcessAttributes */
372  NULL, /* lpThreadAttributes */
373  1, /* bInheritHandles */
374  0, /* dwCreationFlags */
375  env, /* lpEnvironment */
376  cwd, /* lpCurrentDirectory */
377  &si, /* lpStartupInfo */
378  &pi /* lpProcessInformation */
379  );
380 
381  G_free(args);
382  G_free(env);
383  G_free(program);
384 
385  if (!result) {
386  G_warning(_("CreateProcess() failed: error = %d"), GetLastError());
387  return -1;
388  }
389 
390  CloseHandle(pi.hThread);
391 
392  for (i = 0; i < 3; i++)
393  if (handles[i] != INVALID_HANDLE_VALUE)
394  CloseHandle(handles[i]);
395 
396  if (!background) {
397  WaitForSingleObject(pi.hProcess, INFINITE);
398  if (!GetExitCodeProcess(pi.hProcess, &exitcode))
399  return -1;
400  CloseHandle(pi.hProcess);
401  return (int) exitcode;
402  }
403 
404  CloseHandle(pi.hProcess);
405 
406  return pi.dwProcessId;
407 }
408 
409 static void do_redirects(struct redirect *redirects, int num_redirects, HANDLE handles[3])
410 {
411  int i;
412 
413  for (i = 0; i < 3; i++)
414  handles[i] = get_handle(i);
415 
416  for (i = 0; i < num_redirects; i++) {
417  struct redirect *r = &redirects[i];
418 
419  if (r->dst_fd < 0 || r->dst_fd > 2) {
420  if (r->file || r->src_fd >= 0)
421  G_warning(_("G_spawn: unable to redirect descriptor %d"), r->dst_fd);
422  continue;
423  }
424 
425  if (r->file) {
426  r->src_fd = open(r->file, r->mode, 0666);
427 
428  if (r->src_fd < 0) {
429  G_warning(_("G_spawn: unable to open file %s"), r->file);
430  _exit(127);
431  }
432 
433  handles[r->dst_fd] = get_handle(r->src_fd);
434 
435  close(r->src_fd);
436 
437  }
438  else if (r->src_fd >= 0) {
439  handles[r->dst_fd] = get_handle(r->src_fd);
440  }
441  else {
442  if (r->dst_fd < 3) {
443  CloseHandle(handles[r->dst_fd]);
444  handles[r->dst_fd] = INVALID_HANDLE_VALUE;
445  }
446  close(r->dst_fd);
447  }
448  }
449 }
450 
451 static void add_binding(const char **env, int *pnum, const struct binding *b)
452 {
453  char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
454  int n = *pnum;
455  int i;
456 
457  sprintf(str, "%s=%s", b->var, b->val);
458 
459  for (i = 0; i < n; i++)
460  if (G_strcasecmp(env[i], b->var) == 0) {
461  env[i] = str;
462  return;
463  }
464 
465  env[n++] = str;
466  *pnum = n;
467 }
468 
469 static const char **do_bindings(const struct binding *bindings, int num_bindings)
470 {
471  const char **newenv;
472  int i, n;
473 
474  for (i = 0; _environ[i]; i++)
475  ;
476  n = i;
477 
478  newenv = G_malloc((num_bindings + n + 1) * sizeof(char *));
479 
480  for (i = 0; i < n; i++)
481  newenv[i] = _environ[i];
482 
483  for (i = 0; i < num_bindings; i++)
484  add_binding(newenv, &n, &bindings[i]);
485 
486  newenv[num_bindings + n] = NULL;
487 
488  return newenv;
489 }
490 
491 static int do_spawn(struct spawn *sp, const char *command)
492 {
493  HANDLE handles[3];
494  const char **env;
495  int status;
496 
497  do_redirects(sp->redirects, sp->num_redirects, handles);
498  env = do_bindings(sp->bindings, sp->num_bindings);
499 
500  status = win_spawn(command, sp->args, env, sp->directory, handles, sp->background, 1);
501 
502  if (!sp->background && status < 0)
503  G_warning(_("G_spawn: unable to execute command"));
504 
505  return status;
506 }
507 
508 #else /* __MINGW32__ */
509 
510 static int undo_signals(const struct signal *signals, int num_signals, 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"),
529  s->signum);
530  error = 1;
531  }
532  break;
533  case SSA_BLOCK:
534  case SSA_UNBLOCK:
535  if (sigprocmask(SIG_UNBLOCK, &s->old_mask, NULL) < 0) {
536  G_warning(_("G_spawn: unable to restore signal %d"),
537  s->signum);
538  error = 1;
539  }
540  break;
541  }
542  }
543 
544  return !error;
545 }
546 
547 static int do_signals(struct signal *signals, int num_signals, int which)
548 {
549  struct sigaction act;
550  sigset_t mask;
551  int error = 0;
552  int i;
553 
554  sigemptyset(&act.sa_mask);
555  act.sa_flags = SA_RESTART;
556 
557  for (i = 0; i < num_signals; i++) {
558  struct signal *s = &signals[i];
559 
560  if (s->which != which)
561  continue;
562 
563  switch (s->action) {
564  case SSA_IGNORE:
565  act.sa_handler = SIG_IGN;
566  if (sigaction(s->signum, &act, &s->old_act) < 0) {
567  G_warning(_("G_spawn: unable to reset signal %d"), s->signum);
568  error = 1;
569  }
570  else
571  s->valid = 1;
572  break;
573  case SSA_DEFAULT:
574  act.sa_handler = SIG_DFL;
575  if (sigaction(s->signum, &act, &s->old_act) < 0) {
576  G_warning(_("G_spawn: unable to ignore signal %d"),
577  s->signum);
578  error = 1;
579  }
580  else
581  s->valid = 1;
582  break;
583  case SSA_BLOCK:
584  sigemptyset(&mask);
585  sigaddset(&mask, s->signum);
586  if (sigprocmask(SIG_BLOCK, &mask, &s->old_mask) < 0) {
587  G_warning(_("G_spawn: unable to block signal %d"), s->signum);
588  error = 1;
589  }
590  break;
591  case SSA_UNBLOCK:
592  sigemptyset(&mask);
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"),
596  s->signum);
597  error = 1;
598  }
599  else
600  s->valid = 1;
601  break;
602  }
603  }
604 
605  return !error;
606 }
607 
608 static void do_redirects(struct redirect *redirects, int num_redirects)
609 {
610  int i;
611 
612  for (i = 0; i < num_redirects; i++) {
613  struct redirect *r = &redirects[i];
614 
615  if (r->file) {
616  r->src_fd = open(r->file, r->mode, 0666);
617 
618  if (r->src_fd < 0) {
619  G_warning(_("G_spawn: unable to open file %s"), r->file);
620  _exit(127);
621  }
622 
623  if (dup2(r->src_fd, r->dst_fd) < 0) {
624  G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
625  r->src_fd, r->dst_fd);
626  _exit(127);
627  }
628 
629  close(r->src_fd);
630  }
631  else if (r->src_fd >= 0) {
632  if (dup2(r->src_fd, r->dst_fd) < 0) {
633  G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
634  r->src_fd, r->dst_fd);
635  _exit(127);
636  }
637  }
638  else
639  close(r->dst_fd);
640  }
641 }
642 
643 static void do_bindings(const struct binding *bindings, int num_bindings)
644 {
645  int i;
646 
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);
650 
651  sprintf(str, "%s=%s", b->var, b->val);
652  putenv(str);
653  }
654 }
655 
656 static int do_spawn(struct spawn *sp, const char *command)
657 {
658  int status = -1;
659  pid_t pid;
660 
661  if (!do_signals(sp->signals, sp->num_signals, SST_PRE))
662  return status;
663 
664  pid = fork();
665  if (pid < 0) {
666  G_warning(_("Unable to create a new process: %s"), strerror(errno));
667  undo_signals(sp->signals, sp->num_signals, SST_PRE);
668 
669  return status;
670  }
671 
672  if (pid == 0) {
673  if (!undo_signals(sp->signals, sp->num_signals, SST_PRE))
674  _exit(127);
675 
676  if (!do_signals(sp->signals, sp->num_signals, SST_CHILD))
677  _exit(127);
678 
679  if (sp->directory)
680  if (chdir(sp->directory) < 0) {
681  G_warning(_("Unable to change directory to %s"), sp->directory);
682  _exit(127);
683  }
684 
685  do_redirects(sp->redirects, sp->num_redirects);
686  do_bindings(sp->bindings, sp->num_bindings);
687 
688  execvp(command, (char **)sp->args);
689  G_warning(_("Unable to execute command"));
690  _exit(127);
691  }
692 
693  do_signals(sp->signals, sp->num_signals, SST_POST);
694 
695  if (sp->background)
696  status = (int)pid;
697  else {
698  pid_t n;
699 
700  do
701  n = waitpid(pid, &status, 0);
702  while (n == (pid_t) - 1 && errno == EINTR);
703 
704  if (n != pid)
705  status = -1;
706  else {
707  if (WIFEXITED(status))
708  status = WEXITSTATUS(status);
709  else if (WIFSIGNALED(status))
710  status = WTERMSIG(status);
711  else
712  status = -0x100;
713  }
714  }
715 
716  undo_signals(sp->signals, sp->num_signals, SST_POST);
717  undo_signals(sp->signals, sp->num_signals, SST_PRE);
718 
719  return status;
720 }
721 
722 #endif /* __MINGW32__ */
723 
724 static void begin_spawn(struct spawn *sp)
725 {
726  sp->num_args = 0;
727  sp->num_redirects = 0;
728  sp->num_signals = 0;
729  sp->num_bindings = 0;
730  sp->background = 0;
731  sp->directory = NULL;
732 }
733 
734 #define NEXT_ARG(var, type) ((type) *(var)++)
735 
736 static void parse_argvec(struct spawn *sp, const char **va)
737 {
738  for (;;) {
739  const char *arg = NEXT_ARG(va, const char *);
740  const char *var, *val;
741 
742  if (!arg) {
743  sp->args[sp->num_args++] = NULL;
744  break;
745  }
746  else if (arg == SF_REDIRECT_FILE) {
747  sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
748 
749  sp->redirects[sp->num_redirects].src_fd = -1;
750  sp->redirects[sp->num_redirects].mode = NEXT_ARG(va, int);
751  sp->redirects[sp->num_redirects].file = NEXT_ARG(va, const char *);
752 
753  sp->num_redirects++;
754  }
755  else if (arg == SF_REDIRECT_DESCRIPTOR) {
756  sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
757  sp->redirects[sp->num_redirects].src_fd = NEXT_ARG(va, int);
758 
759  sp->redirects[sp->num_redirects].file = NULL;
760  sp->num_redirects++;
761  }
762  else if (arg == SF_CLOSE_DESCRIPTOR) {
763  sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
764 
765  sp->redirects[sp->num_redirects].src_fd = -1;
766  sp->redirects[sp->num_redirects].file = NULL;
767  sp->num_redirects++;
768  }
769  else if (arg == SF_SIGNAL) {
770  sp->signals[sp->num_signals].which = NEXT_ARG(va, int);
771  sp->signals[sp->num_signals].action = NEXT_ARG(va, int);
772  sp->signals[sp->num_signals].signum = NEXT_ARG(va, int);
773 
774  sp->signals[sp->num_signals].valid = 0;
775  sp->num_signals++;
776  }
777  else if (arg == SF_VARIABLE) {
778  var = NEXT_ARG(va, const char *);
779 
780  val = getenv(var);
781  sp->args[sp->num_args++] = val ? val : "";
782  }
783  else if (arg == SF_BINDING) {
784  sp->bindings[sp->num_bindings].var = NEXT_ARG(va, const char *);
785  sp->bindings[sp->num_bindings].val = NEXT_ARG(va, const char *);
786 
787  sp->num_bindings++;
788  }
789  else if (arg == SF_BACKGROUND) {
790  sp->background = 1;
791  }
792  else if (arg == SF_DIRECTORY) {
793  sp->directory = NEXT_ARG(va, const char *);
794 
795  }
796  else if (arg == SF_ARGVEC) {
797  parse_argvec(sp, NEXT_ARG(va, const char **));
798  }
799  else
800  sp->args[sp->num_args++] = arg;
801  }
802 }
803 
804 static void parse_arglist(struct spawn *sp, va_list va)
805 {
806  for (;;) {
807  const char *arg = va_arg(va, const char *);
808  const char *var, *val;
809 
810  if (!arg) {
811  sp->args[sp->num_args++] = NULL;
812  break;
813  }
814  else if (arg == SF_REDIRECT_FILE) {
815  sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
816 
817  sp->redirects[sp->num_redirects].src_fd = -1;
818  sp->redirects[sp->num_redirects].mode = va_arg(va, int);
819  sp->redirects[sp->num_redirects].file = va_arg(va, const char *);
820 
821  sp->num_redirects++;
822  }
823  else if (arg == SF_REDIRECT_DESCRIPTOR) {
824  sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
825  sp->redirects[sp->num_redirects].src_fd = va_arg(va, int);
826 
827  sp->redirects[sp->num_redirects].file = NULL;
828  sp->num_redirects++;
829  }
830  else if (arg == SF_CLOSE_DESCRIPTOR) {
831  sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
832 
833  sp->redirects[sp->num_redirects].src_fd = -1;
834  sp->redirects[sp->num_redirects].file = NULL;
835  sp->num_redirects++;
836  }
837  else if (arg == SF_SIGNAL) {
838  sp->signals[sp->num_signals].which = va_arg(va, int);
839  sp->signals[sp->num_signals].action = va_arg(va, int);
840  sp->signals[sp->num_signals].signum = va_arg(va, int);
841 
842  sp->signals[sp->num_signals].valid = 0;
843  sp->num_signals++;
844  }
845  else if (arg == SF_VARIABLE) {
846  var = va_arg(va, char *);
847 
848  val = getenv(var);
849  sp->args[sp->num_args++] = val ? val : "";
850  }
851  else if (arg == SF_BINDING) {
852  sp->bindings[sp->num_bindings].var = va_arg(va, const char *);
853  sp->bindings[sp->num_bindings].val = va_arg(va, const char *);
854 
855  sp->num_bindings++;
856  }
857  else if (arg == SF_BACKGROUND) {
858  sp->background = 1;
859  }
860  else if (arg == SF_DIRECTORY) {
861  sp->directory = va_arg(va, const char *);
862  }
863  else if (arg == SF_ARGVEC) {
864  parse_argvec(sp, va_arg(va, const char **));
865  }
866  else
867  sp->args[sp->num_args++] = arg;
868  }
869 }
870 
871 /**
872  * \brief Spawn new process based on <b>command</b>.
873  *
874  * This is a more advanced version of G_spawn().
875  *
876  * \param[in] command
877  * \param[in] args arguments
878  * \return -1 on error
879  * \return process status on success
880  */
881 int G_vspawn_ex(const char *command, const char **args)
882 {
883  struct spawn sp;
884 
885  begin_spawn(&sp);
886 
887  parse_argvec(&sp, args);
888 
889  return do_spawn(&sp, command);
890 }
891 
892 /**
893  * \brief Spawn new process based on <b>command</b>.
894  *
895  * This is a more advanced version of G_spawn().
896  *
897  * \param[in] command
898  * \return -1 on error
899  * \return process status on success
900  */
901 
902 int G_spawn_ex(const char *command, ...)
903 {
904  struct spawn sp;
905  va_list va;
906 
907  begin_spawn(&sp);
908 
909  va_start(va, command);
910  parse_arglist(&sp, va);
911  va_end(va);
912 
913  return do_spawn(&sp, command);
914 }
915 
916 /**
917  * \brief Spawn new process based on <b>command</b>.
918  *
919  * \param[in] command
920  * \return -1 on error
921  * \return process status on success
922  */
923 
924 int G_spawn(const char *command, ...)
925 {
926  const char *args[MAX_ARGS];
927  int num_args = 0, i;
928  va_list va;
929  int status = -1;
930 
931  va_start(va, command);
932 
933  for (i = 0; ; i++) {
934  const char *arg = va_arg(va, const char *);
935  args[num_args++] = arg;
936  if (!arg)
937  break;
938  }
939 
940  va_end(va);
941 
942  status = G_spawn_ex(
943  command,
944 #ifndef __MINGW32__
945  SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGINT,
946  SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGQUIT,
947  SF_SIGNAL, SST_PRE, SSA_BLOCK, SIGCHLD,
948 #endif
949  SF_ARGVEC, args,
950  NULL);
951 
952  return status;
953 }
954 
955 int G_wait(int i_pid)
956 {
957 #ifdef __MINGW32__
958  DWORD rights = PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
959  HANDLE hProcess = OpenProcess(rights, FALSE, (DWORD) i_pid);
960  DWORD exitcode;
961 
962  if (!hProcess)
963  return -1;
964 
965  WaitForSingleObject(hProcess, INFINITE);
966  if (!GetExitCodeProcess(hProcess, &exitcode))
967  exitcode = (DWORD) -1;
968 
969  CloseHandle(hProcess);
970 
971  return (int) exitcode;
972 #else
973  pid_t pid = (pid_t) i_pid;
974  int status = -1;
975  pid_t n;
976 
977  do
978  n = waitpid(pid, &status, 0);
979  while (n == (pid_t) - 1 && errno == EINTR);
980 
981  if (n != pid)
982  return -1;
983  else {
984  if (WIFEXITED(status))
985  return WEXITSTATUS(status);
986  else if (WIFSIGNALED(status))
987  return WTERMSIG(status);
988  else
989  return -0x100;
990  }
991 #endif
992 }
993 
int G_wait(int i_pid)
Definition: spawn.c:955
#define TRUE
Definition: gis.h:49
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
Definition: strings.c:46
void G_free(void *buf)
Free allocated memory.
Definition: gis/alloc.c:149
Definition: spawn.h:39
#define SF_SIGNAL
Definition: spawn.h:20
int G_spawn_ex(const char *command,...)
Spawn new process based on command.
Definition: spawn.c:902
int G_vspawn_ex(const char *command, const char **args)
Spawn new process based on command.
Definition: spawn.c:881
#define SF_REDIRECT_FILE
Definition: spawn.h:17
char ** G_tokenize(const char *buf, const char *delim)
Tokenize string.
Definition: gis/token.c:48
#define SF_ARGVEC
Definition: spawn.h:25
char * G_store(const char *s)
Copy string to allocated memory.
Definition: strings.c:86
#define SF_REDIRECT_DESCRIPTOR
Definition: spawn.h:18
#define NULL
Definition: ccmath.h:32
#define SF_BACKGROUND
Definition: spawn.h:23
#define MAX_BINDINGS
Definition: spawn.c:45
fd
Definition: d/range.c:69
#define MAX_REDIRECTS
Definition: spawn.c:47
double b
Definition: r_raster.c:39
#define FALSE
Definition: gis.h:53
#define SF_BINDING
Definition: spawn.h:22
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: debug.c:65
#define GPATH_MAX
Definition: gis.h:151
#define MAX_ARGS
Definition: spawn.c:44
float var(IClass_statistics *statistics, int band1, int band2)
Helper function for computing variance.
Definition: path.h:16
#define file
void G_free_tokens(char **tokens)
Free memory allocated to tokens.
Definition: gis/token.c:204
#define SF_DIRECTORY
Definition: spawn.h:24
#define _(str)
Definition: glocale.h:13
#define SF_CLOSE_DESCRIPTOR
Definition: spawn.h:19
close(fd)
int
Reads the categories file for map name in mapset and stores the categories in the pcats structure...
char * getenv()
#define SF_VARIABLE
Definition: spawn.h:21
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition: gis/error.c:204
Definition: spawn.h:38
double r
Definition: r_raster.c:39
#define NEXT_ARG(var, type)
Definition: spawn.c:734
#define MAX_SIGNALS
Definition: spawn.c:46
void init(double work[])
Definition: as177.c:65
int G_spawn(const char *command,...)
Spawn new process based on command.
Definition: spawn.c:924