GRASS 8 Programmer's Manual 8.6.0dev(2026)-56a9afeb9f
Loading...
Searching...
No Matches
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
59struct redirect {
60 int dst_fd;
61 int src_fd;
62 const char *file;
63 int mode;
64};
65
66struct 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
77struct binding {
78 const char *var;
79 const char *val;
80};
81
82struct 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
95static void parse_arglist(struct spawn *sp, va_list va);
96static void parse_argvec(struct spawn *sp, const char **va);
97
98#ifdef _WIN32
99
100struct buffer {
101 char *str;
102 size_t len;
103 size_t size;
104};
105
106static const int INCREMENT = 50;
107
108static void clear(struct buffer *b)
109{
110 b->len = 0;
111 b->str[b->len] = '\0';
112}
113
114static void init(struct buffer *b)
115{
116 b->str = G_malloc(1);
117 b->size = 1;
118 clear(b);
119}
120
121static 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
132static void finish(struct buffer *b)
133{
134 if (b->str)
135 G_free(b->str);
136 release(b);
137}
138
139static 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
147static 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
157static 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
165static 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
211static 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
220static 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
238static 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
262static 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
270 return result;
271}
272
273static 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
299static 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
316static HANDLE get_handle(int fd)
317{
318 HANDLE h1, h2;
319
320 if (fd < 0)
322
323 h1 = (HANDLE)_get_osfhandle(fd);
327
328 return h2;
329}
330
331static 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);
340 BOOL result;
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);
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++)
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
404static 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
447static 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
466static 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
489static 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
509static 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
545static int do_signals(struct signal *signals, int num_signals, int which)
546{
547 struct sigaction act;
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:
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:
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
604static 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
639static 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
653static 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
722static 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
735static 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
802static 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 */
879int 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 */
899int G_spawn_ex(const char *command, ...)
900{
901 struct spawn sp;
902 va_list va;
903
904 begin_spawn(&sp);
905
906 va_start(va, command);
907 parse_arglist(&sp, va);
908 va_end(va);
909
910 return do_spawn(&sp, command);
911}
912
913/**
914 * \brief Spawn new process based on <b>command</b>.
915 *
916 * \param[in] command
917 * \return -1 on error
918 * \return process status on success
919 */
920int G_spawn(const char *command, ...)
921{
922 const char *args[MAX_ARGS];
923 int num_args = 0;
924 va_list va;
925 int status = -1;
926
927 va_start(va, command);
928
929 for (;;) {
930 const char *arg = va_arg(va, const char *);
931
932 args[num_args++] = arg;
933 if (!arg)
934 break;
935 }
936
937 va_end(va);
938
939 status =
940 G_spawn_ex(command,
944#endif
945 SF_ARGVEC, args, NULL);
946
947 return status;
948}
949
950int G_wait(int i_pid)
951{
952#ifdef _WIN32
956
957 if (!hProcess)
958 return -1;
959
962 exitcode = (DWORD)-1;
963
965
966 return (int)exitcode;
967#else
968 pid_t pid = (pid_t)i_pid;
969 int status = -1;
970 pid_t n;
971
972 do
973 n = waitpid(pid, &status, 0);
974 while (n == (pid_t)-1 && errno == EINTR);
975
976 if (n != pid)
977 return -1;
978 else {
979 if (WIFEXITED(status))
980 return WEXITSTATUS(status);
981 else if (WIFSIGNALED(status))
982 return WTERMSIG(status);
983 else
984 return -0x100;
985 }
986#endif
987}
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:147
#define G_realloc(p, n)
Definition defs/gis.h:141
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition defs/gis.h:139
char ** G_tokenize(const char *, const char *)
Tokenize string.
Definition gis/token.c:47
void G_free_tokens(char **)
Free memory allocated to tokens.
Definition gis/token.c:197
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition strings.c:47
char * G_store(const char *)
Copy string to allocated memory.
Definition strings.c:87
int G_debug(int, const char *,...) __attribute__((format(printf
Header file for msvc/fcntl.c.
#define open
Definition fcntl.h:33
#define GPATH_MAX
Definition gis.h:199
#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:950
int G_spawn(const char *command,...)
Spawn new process based on command.
Definition spawn.c:920
#define MAX_BINDINGS
Definition spawn.c:44
int G_spawn_ex(const char *command,...)
Spawn new process based on command.
Definition spawn.c:899
#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