GRASS 8 Programmer's Manual 8.6.0dev(2026)-1878fdfec5
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 * SPDX-FileCopyrightText: 2001-2014 GRASS Development Team
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 *
9 * \author Glynn Clements
10 *
11 * \date 2004-2006
12 */
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <signal.h>
18#include <stdarg.h>
19#include <unistd.h>
20#include <fcntl.h>
21#include <errno.h>
22#include <sys/types.h>
23
24#ifndef _WIN32
25#include <sys/wait.h>
26#else
27#include <windows.h>
28#endif
29#include <grass/config.h>
30#include <grass/gis.h>
31#include <grass/glocale.h>
32#include <grass/spawn.h>
33
34/** \def MAX_ARGS Maximum number of arguments */
35
36/** \def MAX_BINDINGS Maximum number of bindings */
37
38/** \def MAX_SIGNALS Maximum number of signals */
39
40/** \def MAX_REDIRECTS Maximum number of redirects */
41#define MAX_ARGS 256
42#define MAX_BINDINGS 256
43#define MAX_SIGNALS 32
44#define MAX_REDIRECTS 32
45
46/**
47 * \brief Spawns a new process.
48 *
49 * A more useful alternative to G_system(), which takes the
50 * arguments of <b>command</b> as parameters.
51 *
52 * \param[in] command command to execute
53 * \return -1 on error
54 * \return process status on success
55 */
56
57struct redirect {
58 int dst_fd;
59 int src_fd;
60 const char *file;
61 int mode;
62};
63
64struct signal {
65 int which;
66 int action;
67 int signum;
68 int valid;
69#ifndef _WIN32
70 struct sigaction old_act;
71 sigset_t old_mask;
72#endif
73};
74
75struct binding {
76 const char *var;
77 const char *val;
78};
79
80struct spawn {
81 const char *args[MAX_ARGS];
82 int num_args;
83 struct redirect redirects[MAX_REDIRECTS];
84 int num_redirects;
85 struct signal signals[MAX_SIGNALS];
86 int num_signals;
87 struct binding bindings[MAX_BINDINGS];
88 int num_bindings;
89 int background;
90 const char *directory;
91};
92
93static void parse_arglist(struct spawn *sp, va_list va);
94static void parse_argvec(struct spawn *sp, const char **va);
95
96#ifdef _WIN32
97
98struct buffer {
99 char *str;
100 size_t len;
101 size_t size;
102};
103
104static const int INCREMENT = 50;
105
106static void clear(struct buffer *b)
107{
108 b->len = 0;
109 b->str[b->len] = '\0';
110}
111
112static void init(struct buffer *b)
113{
114 b->str = G_malloc(1);
115 b->size = 1;
116 clear(b);
117}
118
119static char *release(struct buffer *b)
120{
121 char *p = b->str;
122
123 b->str = NULL;
124 b->size = 0;
125 b->len = 0;
126
127 return p;
128}
129
130static void finish(struct buffer *b)
131{
132 if (b->str)
133 G_free(b->str);
134 release(b);
135}
136
137static void ensure(struct buffer *b, size_t n)
138{
139 if (b->size <= b->len + n + 1) {
140 b->size = b->len + n + INCREMENT;
141 b->str = G_realloc(b->str, b->size);
142 }
143}
144
145static void append(struct buffer *b, const char *str)
146{
147 size_t n = strlen(str);
148
149 ensure(b, n);
150 memcpy(&b->str[b->len], str, n);
151 b->len += n;
152 b->str[b->len] = '\0';
153}
154
155static void append_char(struct buffer *b, char c)
156{
157 ensure(b, 1);
158 b->str[b->len] = c;
159 b->len++;
160 b->str[b->len] = '\0';
161}
162
163static void escape_arg(struct buffer *result, const char *arg)
164{
165 struct buffer buf;
166 int quote, j;
167
168 init(&buf);
169
170 quote = arg[0] == '\0' || strchr(arg, ' ') || strchr(arg, '\t');
171
172 if (quote)
173 append_char(result, '\"');
174
175 for (j = 0; arg[j]; j++) {
176 int c = arg[j];
177 int k;
178
179 switch (c) {
180 case '\\':
181 append_char(&buf, '\\');
182 break;
183 case '\"':
184 for (k = 0; k < buf.len; k++)
185 append(result, "\\\\");
186 clear(&buf);
187 append(result, "\\\"");
188 break;
189 default:
190 if (buf.len > 0) {
191 append(result, buf.str);
192 clear(&buf);
193 }
194 append_char(result, c);
195 }
196 }
197
198 if (buf.len > 0)
199 append(result, buf.str);
200
201 if (quote) {
202 append(result, buf.str);
203 append_char(result, '\"');
204 }
205
206 finish(&buf);
207}
208
209static char *check_program(const char *pgm, const char *dir, const char *ext)
210{
211 char pathname[GPATH_MAX];
212
213 snprintf(pathname, sizeof(pathname), "%s%s%s%s", dir, *dir ? "\\" : "", pgm,
214 ext);
215 return access(pathname, 0) == 0 ? G_store(pathname) : NULL;
216}
217
218static char *find_program_ext(const char *pgm, const char *dir, char **pathext)
219{
220 char *result;
221 int i;
222
223 if (result = check_program(pgm, dir, ""), result)
224 return result;
225
226 for (i = 0; pathext[i]; i++) {
227 const char *ext = pathext[i];
228
229 if (result = check_program(pgm, dir, ext), result)
230 return result;
231 }
232
233 return NULL;
234}
235
236static char *find_program_dir_ext(const char *pgm, char **path, char **pathext)
237{
238 char *result = NULL;
239 int i;
240
241 if (strchr(pgm, '\\') || strchr(pgm, '/')) {
242 if (result = find_program_ext(pgm, "", pathext), result)
243 return result;
244 }
245 else {
246 if (result = find_program_ext(pgm, ".", pathext), result)
247 return result;
248
249 for (i = 0; path[i]; i++) {
250 const char *dir = path[i];
251
252 if (result = find_program_ext(pgm, dir, pathext), result)
253 return result;
254 }
255 }
256
257 return NULL;
258}
259
260static char *find_program(const char *pgm)
261{
262 char **path = G_tokenize(getenv("PATH"), ";");
263 char **pathext = G_tokenize(getenv("PATHEXT"), ";");
264 char *result = find_program_dir_ext(pgm, path, pathext);
265
268 return result;
269}
270
271static char *make_command_line(int shell, const char *cmd, const char **argv)
272{
273 struct buffer result;
274 int i;
275
276 init(&result);
277
278 if (shell) {
279 const char *comspec = getenv("COMSPEC");
280
281 append(&result, comspec ? comspec : "cmd.exe");
282 append(&result, " /c \"");
283 escape_arg(&result, cmd);
284 }
285
286 for (i = shell ? 1 : 0; argv[i]; i++) {
287 if (result.len > 0)
288 append_char(&result, ' ');
289 escape_arg(&result, argv[i]);
290 }
291
292 append(&result, "\"");
293
294 return release(&result);
295}
296
297static char *make_environment(const char **envp)
298{
299 struct buffer result;
300 int i;
301
302 init(&result);
303
304 for (i = 0; envp[i]; i++) {
305 const char *env = envp[i];
306
307 append(&result, env);
308 append_char(&result, '\0');
309 }
310
311 return release(&result);
312}
313
314static HANDLE get_handle(int fd)
315{
316 HANDLE h1, h2;
317
318 if (fd < 0)
320
321 h1 = (HANDLE)_get_osfhandle(fd);
325
326 return h2;
327}
328
329static int win_spawn(const char *cmd, const char **argv, const char **envp,
330 const char *cwd, HANDLE handles[3], int background,
331 int shell)
332{
333 char *args = make_command_line(shell, cmd, argv);
334 char *env = make_environment(envp);
335 char *program = shell ? NULL : find_program(cmd);
338 BOOL result;
340 int i;
341
342 if (!shell) {
343 G_debug(3, "win_spawn: program = %s", program);
344
345 if (!program) {
346 G_free(args);
347 G_free(env);
348 return -1;
349 }
350 }
351
352 G_debug(3, "win_spawn: args = %s", args);
353
354 memset(&si, 0, sizeof(si));
355 si.cb = sizeof(si);
356
357 si.dwFlags |= STARTF_USESTDHANDLES;
358 si.hStdInput = handles[0];
359 si.hStdOutput = handles[1];
360 si.hStdError = handles[2];
361
362 result = CreateProcess(program, /* lpApplicationName */
363 args, /* lpCommandLine */
364 NULL, /* lpProcessAttributes */
365 NULL, /* lpThreadAttributes */
366 1, /* bInheritHandles */
367 0, /* dwCreationFlags */
368 env, /* lpEnvironment */
369 cwd, /* lpCurrentDirectory */
370 &si, /* lpStartupInfo */
371 &pi /* lpProcessInformation */
372 );
373
374 G_free(args);
375 G_free(env);
377
378 if (!result) {
379 G_warning(_("CreateProcess() failed: error = %d"), GetLastError());
380 return -1;
381 }
382
383 CloseHandle(pi.hThread);
384
385 for (i = 0; i < 3; i++)
388
389 if (!background) {
390 WaitForSingleObject(pi.hProcess, INFINITE);
391 if (!GetExitCodeProcess(pi.hProcess, &exitcode))
392 return -1;
393 CloseHandle(pi.hProcess);
394 return (int)exitcode;
395 }
396
397 CloseHandle(pi.hProcess);
398
399 return pi.dwProcessId;
400}
401
402static void do_redirects(struct redirect *redirects, int num_redirects,
403 HANDLE handles[3])
404{
405 int i;
406
407 for (i = 0; i < 3; i++)
408 handles[i] = get_handle(i);
409
410 for (i = 0; i < num_redirects; i++) {
411 struct redirect *r = &redirects[i];
412
413 if (r->dst_fd < 0 || r->dst_fd > 2) {
414 if (r->file || r->src_fd >= 0)
415 G_warning(_("G_spawn: unable to redirect descriptor %d"),
416 r->dst_fd);
417 continue;
418 }
419
420 if (r->file) {
421 r->src_fd = open(r->file, r->mode, 0666);
422
423 if (r->src_fd < 0) {
424 G_warning(_("G_spawn: unable to open file %s"), r->file);
425 _exit(127);
426 }
427
428 handles[r->dst_fd] = get_handle(r->src_fd);
429
430 close(r->src_fd);
431 }
432 else if (r->src_fd >= 0) {
433 handles[r->dst_fd] = get_handle(r->src_fd);
434 }
435 else {
436 if (r->dst_fd < 3) {
437 CloseHandle(handles[r->dst_fd]);
438 handles[r->dst_fd] = INVALID_HANDLE_VALUE;
439 }
440 close(r->dst_fd);
441 }
442 }
443}
444
445static void add_binding(const char **env, int *pnum, const struct binding *b)
446{
447 size_t bufsize = strlen(b->var) + strlen(b->val) + 2;
448 char *str = G_malloc(bufsize);
449 int n = *pnum;
450 int i;
451
452 snprintf(str, bufsize, "%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
464static 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
487static 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
507static 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
543static int do_signals(struct signal *signals, int num_signals, int which)
544{
545 struct sigaction act;
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:
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:
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
602static 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
637static 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 size_t bufsize = strlen(b->var) + strlen(b->val) + 2;
644 char *str = G_malloc(bufsize);
645
646 snprintf(str, bufsize, "%s=%s", b->var, b->val);
647 putenv(str);
648 }
649}
650
651static int do_spawn(struct spawn *sp, const char *command)
652{
653 int status = -1;
654 pid_t pid;
655
656 if (!do_signals(sp->signals, sp->num_signals, SST_PRE))
657 return status;
658
659 pid = fork();
660 if (pid < 0) {
661 G_warning(_("Unable to create a new process: %s"), strerror(errno));
662 undo_signals(sp->signals, sp->num_signals, SST_PRE);
663
664 return status;
665 }
666
667 if (pid == 0) {
668 if (!undo_signals(sp->signals, sp->num_signals, SST_PRE))
669 _exit(127);
670
671 if (!do_signals(sp->signals, sp->num_signals, SST_CHILD))
672 _exit(127);
673
674 if (sp->directory)
675 if (chdir(sp->directory) < 0) {
676 G_warning(_("Unable to change directory to %s"), sp->directory);
677 _exit(127);
678 }
679
680 do_redirects(sp->redirects, sp->num_redirects);
681 do_bindings(sp->bindings, sp->num_bindings);
682
683 execvp(command, (char **)sp->args);
684 G_warning(_("Unable to execute command '%s': %s"), command,
685 strerror(errno));
686 _exit(127);
687 }
688
689 do_signals(sp->signals, sp->num_signals, SST_POST);
690
691 if (sp->background)
692 status = (int)pid;
693 else {
694 pid_t n;
695
696 do
697 n = waitpid(pid, &status, 0);
698 while (n == (pid_t)-1 && errno == EINTR);
699
700 if (n != pid)
701 status = -1;
702 else {
703 if (WIFEXITED(status))
704 status = WEXITSTATUS(status);
705 else if (WIFSIGNALED(status))
706 status = WTERMSIG(status);
707 else
708 status = -0x100;
709 }
710 }
711
712 undo_signals(sp->signals, sp->num_signals, SST_POST);
713 undo_signals(sp->signals, sp->num_signals, SST_PRE);
714
715 return status;
716}
717
718#endif /* __MINGW32__ */
719
720static void begin_spawn(struct spawn *sp)
721{
722 sp->num_args = 0;
723 sp->num_redirects = 0;
724 sp->num_signals = 0;
725 sp->num_bindings = 0;
726 sp->background = 0;
727 sp->directory = NULL;
728}
729
730#define NEXT_ARG(var, type) ((type) * (var)++)
731#define NEXT_ARG_INT(var) (int)((intptr_t)*(var)++)
732
733static void parse_argvec(struct spawn *sp, const char **va)
734{
735 for (;;) {
736 const char *arg = NEXT_ARG(va, const char *);
737 const char *var, *val;
738
739 if (!arg) {
740 sp->args[sp->num_args++] = NULL;
741 break;
742 }
743 else if (arg == SF_REDIRECT_FILE) {
744 sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG_INT(va);
745
746 sp->redirects[sp->num_redirects].src_fd = -1;
747 sp->redirects[sp->num_redirects].mode = NEXT_ARG_INT(va);
748 sp->redirects[sp->num_redirects].file = NEXT_ARG(va, const char *);
749
750 sp->num_redirects++;
751 }
752 else if (arg == SF_REDIRECT_DESCRIPTOR) {
753 sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG_INT(va);
754 sp->redirects[sp->num_redirects].src_fd = NEXT_ARG_INT(va);
755
756 sp->redirects[sp->num_redirects].file = NULL;
757 sp->num_redirects++;
758 }
759 else if (arg == SF_CLOSE_DESCRIPTOR) {
760 sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG_INT(va);
761
762 sp->redirects[sp->num_redirects].src_fd = -1;
763 sp->redirects[sp->num_redirects].file = NULL;
764 sp->num_redirects++;
765 }
766 else if (arg == SF_SIGNAL) {
767 sp->signals[sp->num_signals].which = NEXT_ARG_INT(va);
768 sp->signals[sp->num_signals].action = NEXT_ARG_INT(va);
769 sp->signals[sp->num_signals].signum = NEXT_ARG_INT(va);
770
771 sp->signals[sp->num_signals].valid = 0;
772 sp->num_signals++;
773 }
774 else if (arg == SF_VARIABLE) {
775 var = NEXT_ARG(va, const char *);
776
777 val = getenv(var);
778 sp->args[sp->num_args++] = val ? val : "";
779 }
780 else if (arg == SF_BINDING) {
781 sp->bindings[sp->num_bindings].var = NEXT_ARG(va, const char *);
782 sp->bindings[sp->num_bindings].val = NEXT_ARG(va, const char *);
783
784 sp->num_bindings++;
785 }
786 else if (arg == SF_BACKGROUND) {
787 sp->background = 1;
788 }
789 else if (arg == SF_DIRECTORY) {
790 sp->directory = NEXT_ARG(va, const char *);
791 }
792 else if (arg == SF_ARGVEC) {
793 parse_argvec(sp, NEXT_ARG(va, const char **));
794 }
795 else
796 sp->args[sp->num_args++] = arg;
797 }
798}
799
800static void parse_arglist(struct spawn *sp, va_list va)
801{
802 for (;;) {
803 const char *arg = va_arg(va, const char *);
804 const char *var, *val;
805
806 if (!arg) {
807 sp->args[sp->num_args++] = NULL;
808 break;
809 }
810 else if (arg == SF_REDIRECT_FILE) {
811 sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
812
813 sp->redirects[sp->num_redirects].src_fd = -1;
814 sp->redirects[sp->num_redirects].mode = va_arg(va, int);
815 sp->redirects[sp->num_redirects].file = va_arg(va, const char *);
816
817 sp->num_redirects++;
818 }
819 else if (arg == SF_REDIRECT_DESCRIPTOR) {
820 sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
821 sp->redirects[sp->num_redirects].src_fd = va_arg(va, int);
822
823 sp->redirects[sp->num_redirects].file = NULL;
824 sp->num_redirects++;
825 }
826 else if (arg == SF_CLOSE_DESCRIPTOR) {
827 sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
828
829 sp->redirects[sp->num_redirects].src_fd = -1;
830 sp->redirects[sp->num_redirects].file = NULL;
831 sp->num_redirects++;
832 }
833 else if (arg == SF_SIGNAL) {
834 sp->signals[sp->num_signals].which = va_arg(va, int);
835 sp->signals[sp->num_signals].action = va_arg(va, int);
836 sp->signals[sp->num_signals].signum = va_arg(va, int);
837
838 sp->signals[sp->num_signals].valid = 0;
839 sp->num_signals++;
840 }
841 else if (arg == SF_VARIABLE) {
842 var = va_arg(va, char *);
843
844 val = getenv(var);
845 sp->args[sp->num_args++] = val ? val : "";
846 }
847 else if (arg == SF_BINDING) {
848 sp->bindings[sp->num_bindings].var = va_arg(va, const char *);
849 sp->bindings[sp->num_bindings].val = va_arg(va, const char *);
850
851 sp->num_bindings++;
852 }
853 else if (arg == SF_BACKGROUND) {
854 sp->background = 1;
855 }
856 else if (arg == SF_DIRECTORY) {
857 sp->directory = va_arg(va, const char *);
858 }
859 else if (arg == SF_ARGVEC) {
860 parse_argvec(sp, va_arg(va, const char **));
861 }
862 else
863 sp->args[sp->num_args++] = arg;
864 }
865}
866
867/**
868 * \brief Spawn new process based on <b>command</b>.
869 *
870 * This is a more advanced version of G_spawn().
871 *
872 * \param[in] command
873 * \param[in] args arguments
874 * \return -1 on error
875 * \return process status on success
876 */
877int G_vspawn_ex(const char *command, const char **args)
878{
879 struct spawn sp;
880
881 begin_spawn(&sp);
882
883 parse_argvec(&sp, args);
884
885 return do_spawn(&sp, command);
886}
887
888/**
889 * \brief Spawn new process based on <b>command</b>.
890 *
891 * This is a more advanced version of G_spawn().
892 *
893 * \param[in] command
894 * \return -1 on error
895 * \return process status on success
896 */
897int 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 */
918int G_spawn(const char *command, ...)
919{
920 const char *args[MAX_ARGS];
921 int num_args = 0;
922 va_list va;
923 int status = -1;
924
925 va_start(va, command);
926
927 for (;;) {
928 const char *arg = va_arg(va, const char *);
929
930 args[num_args++] = arg;
931 if (!arg)
932 break;
933 }
934
935 va_end(va);
936
937 status =
938 G_spawn_ex(command,
942#endif
943 SF_ARGVEC, args, NULL);
944
945 return status;
946}
947
948int G_wait(int i_pid)
949{
950#ifdef _WIN32
954
955 if (!hProcess)
956 return -1;
957
960 exitcode = (DWORD)-1;
961
963
964 return (int)exitcode;
965#else
966 pid_t pid = (pid_t)i_pid;
967 int status = -1;
968 pid_t n;
969
970 do
971 n = waitpid(pid, &status, 0);
972 while (n == (pid_t)-1 && errno == EINTR);
973
974 if (n != pid)
975 return -1;
976 else {
977 if (WIFEXITED(status))
978 return WEXITSTATUS(status);
979 else if (WIFSIGNALED(status))
980 return WTERMSIG(status);
981 else
982 return -0x100;
983 }
984#endif
985}
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:145
#define G_realloc(p, n)
Definition defs/gis.h:138
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition defs/gis.h:136
char ** G_tokenize(const char *, const char *)
Tokenize string.
Definition gis/token.c:45
void G_free_tokens(char **)
Free memory allocated to tokens.
Definition gis/token.c:195
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition strings.c:45
char * G_store(const char *)
Copy string to allocated memory.
Definition strings.c:85
int G_debug(int, const char *,...) __attribute__((format(printf
Header file for msvc/fcntl.c.
#define open
Definition fcntl.h:32
#define GPATH_MAX
Definition gis.h:196
#define TRUE
Definition gis.h:75
#define FALSE
Definition gis.h:79
#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:37
double r
Definition r_raster.c:37
#define NEXT_ARG(var, type)
Definition spawn.c:730
#define MAX_ARGS
Definition spawn.c:41
int G_vspawn_ex(const char *command, const char **args)
Spawn new process based on command.
Definition spawn.c:877
int G_wait(int i_pid)
Definition spawn.c:948
int G_spawn(const char *command,...)
Spawn new process based on command.
Definition spawn.c:918
#define MAX_BINDINGS
Definition spawn.c:42
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:731
#define MAX_REDIRECTS
Definition spawn.c:44
#define MAX_SIGNALS
Definition spawn.c:43
#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