2009-05-15 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / exechelp.c
blob7019ae7a0c4bea07a41ae1e159b7114abc100134
1 /* exechelp.c - fork and exec helpers
2 * Copyright (C) 2004, 2007, 2008, 2009 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <signal.h>
28 #include <unistd.h>
29 #include <fcntl.h>
31 #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */
32 #undef HAVE_PTH
33 #undef USE_GNU_PTH
34 #endif
36 #ifdef USE_GNU_PTH
37 #include <pth.h>
38 #endif
39 #ifndef HAVE_W32_SYSTEM
40 #include <sys/wait.h>
41 #endif
43 #ifdef HAVE_GETRLIMIT
44 #include <sys/time.h>
45 #include <sys/resource.h>
46 #endif /*HAVE_GETRLIMIT*/
48 #ifdef HAVE_STAT
49 # include <sys/stat.h>
50 #endif
53 #include "util.h"
54 #include "i18n.h"
55 #include "sysutils.h"
56 #include "exechelp.h"
58 /* Define to 1 do enable debugging. */
59 #define DEBUG_W32_SPAWN 1
62 /* We have the usual problem here: Some modules are linked against pth
63 and some are not. However we want to use pth_fork and pth_waitpid
64 here. Using a weak symbol works but is not portable - we should
65 provide a an explicit dummy pth module instead of using the
66 pragma. */
67 #ifndef _WIN32
68 #pragma weak pth_fork
69 #pragma weak pth_waitpid
70 #endif
72 #ifdef HAVE_W32_SYSTEM
73 /* It seems Vista doesn't grok X_OK and so fails access() tests.
74 Previous versions interpreted X_OK as F_OK anyway, so we'll just
75 use F_OK directly. */
76 #undef X_OK
77 #define X_OK F_OK
78 #endif /* HAVE_W32_SYSTEM */
81 #ifdef HAVE_W32_SYSTEM
82 /* We assume that a HANDLE can be represented by an int which should
83 be true for all i386 systems (HANDLE is defined as void *) and
84 these are the only systems for which Windows is available. Further
85 we assume that -1 denotes an invalid handle. */
86 # define fd_to_handle(a) ((HANDLE)(a))
87 # define handle_to_fd(a) ((int)(a))
88 # define pid_to_handle(a) ((HANDLE)(a))
89 # define handle_to_pid(a) ((int)(a))
90 #endif
93 /* Return the maximum number of currently allowed open file
94 descriptors. Only useful on POSIX systems but returns a value on
95 other systems too. */
96 int
97 get_max_fds (void)
99 int max_fds = -1;
100 #ifdef HAVE_GETRLIMIT
101 struct rlimit rl;
103 # ifdef RLIMIT_NOFILE
104 if (!getrlimit (RLIMIT_NOFILE, &rl))
105 max_fds = rl.rlim_max;
106 # endif
108 # ifdef RLIMIT_OFILE
109 if (max_fds == -1 && !getrlimit (RLIMIT_OFILE, &rl))
110 max_fds = rl.rlim_max;
112 # endif
113 #endif /*HAVE_GETRLIMIT*/
115 #ifdef _SC_OPEN_MAX
116 if (max_fds == -1)
118 long int scres = sysconf (_SC_OPEN_MAX);
119 if (scres >= 0)
120 max_fds = scres;
122 #endif
124 #ifdef _POSIX_OPEN_MAX
125 if (max_fds == -1)
126 max_fds = _POSIX_OPEN_MAX;
127 #endif
129 #ifdef OPEN_MAX
130 if (max_fds == -1)
131 max_fds = OPEN_MAX;
132 #endif
134 if (max_fds == -1)
135 max_fds = 256; /* Arbitrary limit. */
137 return max_fds;
141 /* Close all file descriptors starting with descriptor FIRST. If
142 EXCEPT is not NULL, it is expected to be a list of file descriptors
143 which shall not be closed. This list shall be sorted in ascending
144 order with the end marked by -1. */
145 void
146 close_all_fds (int first, int *except)
148 int max_fd = get_max_fds ();
149 int fd, i, except_start;
151 if (except)
153 except_start = 0;
154 for (fd=first; fd < max_fd; fd++)
156 for (i=except_start; except[i] != -1; i++)
158 if (except[i] == fd)
160 /* If we found the descriptor in the exception list
161 we can start the next compare run at the next
162 index because the exception list is ordered. */
163 except_start = i + 1;
164 break;
167 if (except[i] == -1)
168 close (fd);
171 else
173 for (fd=first; fd < max_fd; fd++)
174 close (fd);
177 errno = 0;
181 /* Returns an array with all currently open file descriptors. The end
182 of the array is marked by -1. The caller needs to release this
183 array using the *standard free* and not with xfree. This allow the
184 use of this fucntion right at startup even before libgcrypt has
185 been initialized. Returns NULL on error and sets ERRNO
186 accordingly. */
187 int *
188 get_all_open_fds (void)
190 int *array;
191 size_t narray;
192 int fd, max_fd, idx;
193 #ifndef HAVE_STAT
194 array = calloc (1, sizeof *array);
195 if (array)
196 array[0] = -1;
197 #else /*HAVE_STAT*/
198 struct stat statbuf;
200 max_fd = get_max_fds ();
201 narray = 32; /* If you change this change also t-exechelp.c. */
202 array = calloc (narray, sizeof *array);
203 if (!array)
204 return NULL;
206 /* Note: The list we return is ordered. */
207 for (idx=0, fd=0; fd < max_fd; fd++)
208 if (!(fstat (fd, &statbuf) == -1 && errno == EBADF))
210 if (idx+1 >= narray)
212 int *tmp;
214 narray += (narray < 256)? 32:256;
215 tmp = realloc (array, narray * sizeof *array);
216 if (!tmp)
218 free (array);
219 return NULL;
221 array = tmp;
223 array[idx++] = fd;
225 array[idx] = -1;
226 #endif /*HAVE_STAT*/
227 return array;
232 #ifdef HAVE_W32_SYSTEM
233 /* Helper function to build_w32_commandline. */
234 static char *
235 build_w32_commandline_copy (char *buffer, const char *string)
237 char *p = buffer;
238 const char *s;
240 if (!*string) /* Empty string. */
241 p = stpcpy (p, "\"\"");
242 else if (strpbrk (string, " \t\n\v\f\""))
244 /* Need top do some kind of quoting. */
245 p = stpcpy (p, "\"");
246 for (s=string; *s; s++)
248 *p++ = *s;
249 if (*s == '\"')
250 *p++ = *s;
252 *p++ = '\"';
253 *p = 0;
255 else
256 p = stpcpy (p, string);
258 return p;
261 /* Build a command line for use with W32's CreateProcess. On success
262 CMDLINE gets the address of a newly allocated string. */
263 static gpg_error_t
264 build_w32_commandline (const char *pgmname, const char * const *argv,
265 char **cmdline)
267 int i, n;
268 const char *s;
269 char *buf, *p;
271 *cmdline = NULL;
272 n = 0;
273 s = pgmname;
274 n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
275 for (; *s; s++)
276 if (*s == '\"')
277 n++; /* Need to double inner quotes. */
278 for (i=0; (s=argv[i]); i++)
280 n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
281 for (; *s; s++)
282 if (*s == '\"')
283 n++; /* Need to double inner quotes. */
285 n++;
287 buf = p = xtrymalloc (n);
288 if (!buf)
289 return gpg_error_from_syserror ();
291 p = build_w32_commandline_copy (p, pgmname);
292 for (i=0; argv[i]; i++)
294 *p++ = ' ';
295 p = build_w32_commandline_copy (p, argv[i]);
298 *cmdline= buf;
299 return 0;
301 #endif /*HAVE_W32_SYSTEM*/
304 #ifdef HAVE_W32_SYSTEM
305 /* Create pipe where the write end is inheritable. */
306 static int
307 create_inheritable_pipe (int filedes[2])
309 HANDLE r, w, h;
310 SECURITY_ATTRIBUTES sec_attr;
312 memset (&sec_attr, 0, sizeof sec_attr );
313 sec_attr.nLength = sizeof sec_attr;
314 sec_attr.bInheritHandle = FALSE;
316 if (!CreatePipe (&r, &w, &sec_attr, 0))
317 return -1;
319 if (!DuplicateHandle (GetCurrentProcess(), w,
320 GetCurrentProcess(), &h, 0,
321 TRUE, DUPLICATE_SAME_ACCESS ))
323 log_error ("DuplicateHandle failed: %s\n", w32_strerror (-1));
324 CloseHandle (r);
325 CloseHandle (w);
326 return -1;
328 CloseHandle (w);
329 w = h;
331 filedes[0] = handle_to_fd (r);
332 filedes[1] = handle_to_fd (w);
333 return 0;
335 #endif /*HAVE_W32_SYSTEM*/
338 #ifdef HAVE_W32_SYSTEM
339 static HANDLE
340 w32_open_null (int for_write)
342 HANDLE hfile;
344 hfile = CreateFile ("nul",
345 for_write? GENERIC_WRITE : GENERIC_READ,
346 FILE_SHARE_READ | FILE_SHARE_WRITE,
347 NULL, OPEN_EXISTING, 0, NULL);
348 if (hfile == INVALID_HANDLE_VALUE)
349 log_debug ("can't open `nul': %s\n", w32_strerror (-1));
350 return hfile;
352 #endif /*HAVE_W32_SYSTEM*/
355 #ifndef HAVE_W32_SYSTEM
356 /* The exec core used right after the fork. This will never return. */
357 static void
358 do_exec (const char *pgmname, const char *argv[],
359 int fd_in, int fd_out, int fd_err,
360 void (*preexec)(void) )
362 char **arg_list;
363 int i, j;
364 int fds[3];
366 fds[0] = fd_in;
367 fds[1] = fd_out;
368 fds[2] = fd_err;
370 /* Create the command line argument array. */
371 i = 0;
372 if (argv)
373 while (argv[i])
374 i++;
375 arg_list = xcalloc (i+2, sizeof *arg_list);
376 arg_list[0] = strrchr (pgmname, '/');
377 if (arg_list[0])
378 arg_list[0]++;
379 else
380 arg_list[0] = xstrdup (pgmname);
381 if (argv)
382 for (i=0,j=1; argv[i]; i++, j++)
383 arg_list[j] = (char*)argv[i];
385 /* Assign /dev/null to unused FDs. */
386 for (i=0; i <= 2; i++)
388 if (fds[i] == -1 )
390 fds[i] = open ("/dev/null", i? O_WRONLY : O_RDONLY);
391 if (fds[i] == -1)
392 log_fatal ("failed to open `%s': %s\n",
393 "/dev/null", strerror (errno));
397 /* Connect the standard files. */
398 for (i=0; i <= 2; i++)
400 if (fds[i] != i && dup2 (fds[i], i) == -1)
401 log_fatal ("dup2 std%s failed: %s\n",
402 i==0?"in":i==1?"out":"err", strerror (errno));
405 /* Close all other files. */
406 close_all_fds (3, NULL);
408 if (preexec)
409 preexec ();
410 execv (pgmname, arg_list);
411 /* No way to print anything, as we have closed all streams. */
412 _exit (127);
414 #endif /*!HAVE_W32_SYSTEM*/
417 /* Portable function to create a pipe. Under Windows the write end is
418 inheritable. */
419 gpg_error_t
420 gnupg_create_inbound_pipe (int filedes[2])
422 gpg_error_t err = 0;
423 #if HAVE_W32_SYSTEM
424 int fds[2];
426 filedes[0] = filedes[1] = -1;
427 err = gpg_error (GPG_ERR_GENERAL);
428 if (!create_inheritable_pipe (fds))
430 filedes[0] = _open_osfhandle (fds[0], 0);
431 if (filedes[0] == -1)
433 log_error ("failed to translate osfhandle %p\n", (void*)fds[0]);
434 CloseHandle (fd_to_handle (fds[1]));
436 else
438 filedes[1] = _open_osfhandle (fds[1], 1);
439 if (filedes[1] == -1)
441 log_error ("failed to translate osfhandle %p\n", (void*)fds[1]);
442 close (filedes[0]);
443 filedes[0] = -1;
444 CloseHandle (fd_to_handle (fds[1]));
446 else
447 err = 0;
450 #else
451 if (pipe (filedes) == -1)
453 err = gpg_error_from_syserror ();
454 filedes[0] = filedes[1] = -1;
456 #endif
457 return err;
461 /* Fork and exec the PGMNAME, connect the file descriptor of INFILE to
462 stdin, write the output to OUTFILE, return a new stream in
463 STATUSFILE for stderr and the pid of the process in PID. The
464 arguments for the process are expected in the NULL terminated array
465 ARGV. The program name itself should not be included there. If
466 PREEXEC is not NULL, that function will be called right before the
467 exec. Calling gnupg_wait_process is required.
469 FLAGS is a bit vector with just one bit defined for now:
471 Bit 7: If set the process will be started as a background process.
472 This flag is only useful under W32 systems, so that no new
473 console is created and pops up a console window when
474 starting the server
476 Bit 6: On W32 run AllowSetForegroundWindow for the child. Due to
477 error problems this actually allows SetForegroundWindow for
478 childs of this process.
480 Returns 0 on success or an error code. */
481 gpg_error_t
482 gnupg_spawn_process (const char *pgmname, const char *argv[],
483 FILE *infile, FILE *outfile,
484 void (*preexec)(void), unsigned int flags,
485 FILE **statusfile, pid_t *pid)
487 #ifdef HAVE_W32_SYSTEM
488 gpg_error_t err;
489 SECURITY_ATTRIBUTES sec_attr;
490 PROCESS_INFORMATION pi =
492 NULL, /* Returns process handle. */
493 0, /* Returns primary thread handle. */
494 0, /* Returns pid. */
495 0 /* Returns tid. */
497 STARTUPINFO si;
498 int cr_flags;
499 char *cmdline;
500 int fd, fdout, rp[2];
502 (void)preexec;
504 /* Setup return values. */
505 *statusfile = NULL;
506 *pid = (pid_t)(-1);
507 fflush (infile);
508 rewind (infile);
509 fd = _get_osfhandle (fileno (infile));
510 fdout = _get_osfhandle (fileno (outfile));
511 if (fd == -1 || fdout == -1)
512 log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
514 /* Prepare security attributes. */
515 memset (&sec_attr, 0, sizeof sec_attr );
516 sec_attr.nLength = sizeof sec_attr;
517 sec_attr.bInheritHandle = FALSE;
519 /* Build the command line. */
520 err = build_w32_commandline (pgmname, argv, &cmdline);
521 if (err)
522 return err;
524 /* Create a pipe. */
525 if (create_inheritable_pipe (rp))
527 err = gpg_error (GPG_ERR_GENERAL);
528 log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
529 xfree (cmdline);
530 return err;
533 /* Start the process. Note that we can't run the PREEXEC function
534 because this would change our own environment. */
535 memset (&si, 0, sizeof si);
536 si.cb = sizeof (si);
537 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
538 si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
539 si.hStdInput = fd_to_handle (fd);
540 si.hStdOutput = fd_to_handle (fdout);
541 si.hStdError = fd_to_handle (rp[1]);
543 cr_flags = (CREATE_DEFAULT_ERROR_MODE
544 | ((flags & 128)? DETACHED_PROCESS : 0)
545 | GetPriorityClass (GetCurrentProcess ())
546 | CREATE_SUSPENDED);
547 /* log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline); */
548 if (!CreateProcess (pgmname, /* Program to start. */
549 cmdline, /* Command line arguments. */
550 &sec_attr, /* Process security attributes. */
551 &sec_attr, /* Thread security attributes. */
552 TRUE, /* Inherit handles. */
553 cr_flags, /* Creation flags. */
554 NULL, /* Environment. */
555 NULL, /* Use current drive/directory. */
556 &si, /* Startup information. */
557 &pi /* Returns process information. */
560 log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
561 xfree (cmdline);
562 CloseHandle (fd_to_handle (rp[0]));
563 CloseHandle (fd_to_handle (rp[1]));
564 return gpg_error (GPG_ERR_GENERAL);
566 xfree (cmdline);
567 cmdline = NULL;
569 /* Close the other end of the pipe. */
570 CloseHandle (fd_to_handle (rp[1]));
572 /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
573 /* " dwProcessID=%d dwThreadId=%d\n", */
574 /* pi.hProcess, pi.hThread, */
575 /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
577 /* Fixme: For unknown reasons AllowSetForegroundWindow returns an
578 invalid argument error if we pass the the correct processID to
579 it. As a workaround we use -1 (ASFW_ANY). */
580 if ( (flags & 64) )
581 gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/);
583 /* Process has been created suspended; resume it now. */
584 ResumeThread (pi.hThread);
585 CloseHandle (pi.hThread);
588 int x;
590 x = _open_osfhandle (rp[0], 0);
591 if (x == -1)
592 log_error ("failed to translate osfhandle %p\n", (void*)rp[0] );
593 else
594 *statusfile = fdopen (x, "r");
596 if (!*statusfile)
598 err = gpg_error_from_syserror ();
599 log_error (_("can't fdopen pipe for reading: %s\n"), gpg_strerror (err));
600 CloseHandle (pi.hProcess);
601 return err;
604 *pid = handle_to_pid (pi.hProcess);
605 return 0;
607 #else /* !HAVE_W32_SYSTEM */
608 gpg_error_t err;
609 int fd, fdout, rp[2];
611 (void)flags; /* Currently not used. */
613 *statusfile = NULL;
614 *pid = (pid_t)(-1);
615 fflush (infile);
616 rewind (infile);
617 fd = fileno (infile);
618 fdout = fileno (outfile);
619 if (fd == -1 || fdout == -1)
620 log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
622 if (pipe (rp) == -1)
624 err = gpg_error_from_syserror ();
625 log_error (_("error creating a pipe: %s\n"), strerror (errno));
626 return err;
629 #ifdef USE_GNU_PTH
630 *pid = pth_fork? pth_fork () : fork ();
631 #else
632 *pid = fork ();
633 #endif
634 if (*pid == (pid_t)(-1))
636 err = gpg_error_from_syserror ();
637 log_error (_("error forking process: %s\n"), strerror (errno));
638 close (rp[0]);
639 close (rp[1]);
640 return err;
643 if (!*pid)
645 gcry_control (GCRYCTL_TERM_SECMEM);
646 /* Run child. */
647 do_exec (pgmname, argv, fd, fdout, rp[1], preexec);
648 /*NOTREACHED*/
651 /* Parent. */
652 close (rp[1]);
654 *statusfile = fdopen (rp[0], "r");
655 if (!*statusfile)
657 err = gpg_error_from_syserror ();
658 log_error (_("can't fdopen pipe for reading: %s\n"), strerror (errno));
659 kill (*pid, SIGTERM);
660 *pid = (pid_t)(-1);
661 return err;
664 return 0;
665 #endif /* !HAVE_W32_SYSTEM */
670 /* Simplified version of gnupg_spawn_process. This function forks and
671 then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
672 and ERRFD to stderr (any of them may be -1 to connect them to
673 /dev/null). The arguments for the process are expected in the NULL
674 terminated array ARGV. The program name itself should not be
675 included there. Calling gnupg_wait_process is required.
677 Returns 0 on success or an error code. */
678 gpg_error_t
679 gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
680 int infd, int outfd, int errfd, pid_t *pid)
682 #ifdef HAVE_W32_SYSTEM
683 gpg_error_t err;
684 SECURITY_ATTRIBUTES sec_attr;
685 PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
686 STARTUPINFO si;
687 char *cmdline;
688 int i;
689 HANDLE stdhd[3];
691 /* Setup return values. */
692 *pid = (pid_t)(-1);
694 /* Prepare security attributes. */
695 memset (&sec_attr, 0, sizeof sec_attr );
696 sec_attr.nLength = sizeof sec_attr;
697 sec_attr.bInheritHandle = FALSE;
699 /* Build the command line. */
700 err = build_w32_commandline (pgmname, argv, &cmdline);
701 if (err)
702 return err;
704 memset (&si, 0, sizeof si);
705 si.cb = sizeof (si);
706 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
707 si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
708 stdhd[0] = infd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
709 stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
710 stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
711 si.hStdInput = infd == -1? stdhd[0] : (void*)_get_osfhandle (infd);
712 si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
713 si.hStdError = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
715 /* log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline); */
716 if (!CreateProcess (pgmname, /* Program to start. */
717 cmdline, /* Command line arguments. */
718 &sec_attr, /* Process security attributes. */
719 &sec_attr, /* Thread security attributes. */
720 TRUE, /* Inherit handles. */
721 (CREATE_DEFAULT_ERROR_MODE
722 | GetPriorityClass (GetCurrentProcess ())
723 | CREATE_SUSPENDED | DETACHED_PROCESS),
724 NULL, /* Environment. */
725 NULL, /* Use current drive/directory. */
726 &si, /* Startup information. */
727 &pi /* Returns process information. */
730 log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
731 err = gpg_error (GPG_ERR_GENERAL);
733 else
734 err = 0;
735 xfree (cmdline);
736 for (i=0; i < 3; i++)
737 if (stdhd[i] != INVALID_HANDLE_VALUE)
738 CloseHandle (stdhd[i]);
739 if (err)
740 return err;
742 /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
743 /* " dwProcessID=%d dwThreadId=%d\n", */
744 /* pi.hProcess, pi.hThread, */
745 /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
747 /* Process has been created suspended; resume it now. */
748 ResumeThread (pi.hThread);
749 CloseHandle (pi.hThread);
751 *pid = handle_to_pid (pi.hProcess);
752 return 0;
754 #else /* !HAVE_W32_SYSTEM */
755 gpg_error_t err;
757 #ifdef USE_GNU_PTH
758 *pid = pth_fork? pth_fork () : fork ();
759 #else
760 *pid = fork ();
761 #endif
762 if (*pid == (pid_t)(-1))
764 err = gpg_error_from_syserror ();
765 log_error (_("error forking process: %s\n"), strerror (errno));
766 return err;
769 if (!*pid)
771 gcry_control (GCRYCTL_TERM_SECMEM);
772 /* Run child. */
773 do_exec (pgmname, argv, infd, outfd, errfd, NULL);
774 /*NOTREACHED*/
777 return 0;
778 #endif /* !HAVE_W32_SYSTEM */
782 /* Wait for the process identified by PID to terminate. PGMNAME should
783 be the same as supplied to the spawn function and is only used for
784 diagnostics. Returns 0 if the process succeeded, GPG_ERR_GENERAL
785 for any failures of the spawned program or other error codes. If
786 EXITCODE is not NULL the exit code of the process is stored at this
787 address or -1 if it could not be retrieved. */
788 gpg_error_t
789 gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
791 gpg_err_code_t ec;
793 #ifdef HAVE_W32_SYSTEM
794 HANDLE proc = fd_to_handle (pid);
795 int code;
796 DWORD exc;
798 if (exitcode)
799 *exitcode = -1;
801 if (pid == (pid_t)(-1))
802 return gpg_error (GPG_ERR_INV_VALUE);
804 /* FIXME: We should do a pth_waitpid here. However this has not yet
805 been implemented. A special W32 pth system call would even be
806 better. */
807 code = WaitForSingleObject (proc, INFINITE);
808 switch (code)
810 case WAIT_FAILED:
811 log_error (_("waiting for process %d to terminate failed: %s\n"),
812 (int)pid, w32_strerror (-1));
813 ec = GPG_ERR_GENERAL;
814 break;
816 case WAIT_OBJECT_0:
817 if (!GetExitCodeProcess (proc, &exc))
819 log_error (_("error getting exit code of process %d: %s\n"),
820 (int)pid, w32_strerror (-1) );
821 ec = GPG_ERR_GENERAL;
823 else if (exc)
825 log_error (_("error running `%s': exit status %d\n"),
826 pgmname, (int)exc );
827 if (exitcode)
828 *exitcode = (int)exc;
829 ec = GPG_ERR_GENERAL;
831 else
833 if (exitcode)
834 *exitcode = 0;
835 ec = 0;
837 CloseHandle (proc);
838 break;
840 default:
841 log_error ("WaitForSingleObject returned unexpected "
842 "code %d for pid %d\n", code, (int)pid );
843 ec = GPG_ERR_GENERAL;
844 break;
847 #else /* !HAVE_W32_SYSTEM */
848 int i, status;
850 if (exitcode)
851 *exitcode = -1;
853 if (pid == (pid_t)(-1))
854 return gpg_error (GPG_ERR_INV_VALUE);
856 #ifdef USE_GNU_PTH
857 i = pth_waitpid ? pth_waitpid (pid, &status, 0) : waitpid (pid, &status, 0);
858 #else
859 while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
861 #endif
862 if (i == (pid_t)(-1))
864 log_error (_("waiting for process %d to terminate failed: %s\n"),
865 (int)pid, strerror (errno));
866 ec = gpg_err_code_from_errno (errno);
868 else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
870 log_error (_("error running `%s': probably not installed\n"), pgmname);
871 ec = GPG_ERR_CONFIGURATION;
873 else if (WIFEXITED (status) && WEXITSTATUS (status))
875 log_error (_("error running `%s': exit status %d\n"), pgmname,
876 WEXITSTATUS (status));
877 if (exitcode)
878 *exitcode = WEXITSTATUS (status);
879 ec = GPG_ERR_GENERAL;
881 else if (!WIFEXITED (status))
883 log_error (_("error running `%s': terminated\n"), pgmname);
884 ec = GPG_ERR_GENERAL;
886 else
888 if (exitcode)
889 *exitcode = 0;
890 ec = 0;
892 #endif /* !HAVE_W32_SYSTEM */
894 return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
898 /* Spawn a new process and immediatley detach from it. The name of
899 the program to exec is PGMNAME and its arguments are in ARGV (the
900 programname is automatically passed as first argument).
901 Environment strings in ENVP are set. An error is returned if
902 pgmname is not executable; to make this work it is necessary to
903 provide an absolute file name. All standard file descriptors are
904 connected to /dev/null. */
905 gpg_error_t
906 gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
907 const char *envp[] )
909 #ifdef HAVE_W32_SYSTEM
910 gpg_error_t err;
911 SECURITY_ATTRIBUTES sec_attr;
912 PROCESS_INFORMATION pi =
914 NULL, /* Returns process handle. */
915 0, /* Returns primary thread handle. */
916 0, /* Returns pid. */
917 0 /* Returns tid. */
919 STARTUPINFO si;
920 int cr_flags;
921 char *cmdline;
924 /* FIXME: We don't make use of ENVP yet. It is currently only used
925 to pass the GPG_AGENT_INFO variable to gpg-agent. As the default
926 on windows is to use a standard socket, this does not really
927 matter. */
928 (void)envp;
930 if (access (pgmname, X_OK))
931 return gpg_error_from_syserror ();
933 /* Prepare security attributes. */
934 memset (&sec_attr, 0, sizeof sec_attr );
935 sec_attr.nLength = sizeof sec_attr;
936 sec_attr.bInheritHandle = FALSE;
938 /* Build the command line. */
939 err = build_w32_commandline (pgmname, argv, &cmdline);
940 if (err)
941 return err;
943 /* Start the process. */
944 memset (&si, 0, sizeof si);
945 si.cb = sizeof (si);
946 si.dwFlags = STARTF_USESHOWWINDOW;
947 si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
949 cr_flags = (CREATE_DEFAULT_ERROR_MODE
950 | GetPriorityClass (GetCurrentProcess ())
951 | CREATE_NEW_PROCESS_GROUP
952 | DETACHED_PROCESS);
953 /* log_debug ("CreateProcess(detached), path=`%s' cmdline=`%s'\n", */
954 /* pgmname, cmdline); */
955 if (!CreateProcess (pgmname, /* Program to start. */
956 cmdline, /* Command line arguments. */
957 &sec_attr, /* Process security attributes. */
958 &sec_attr, /* Thread security attributes. */
959 FALSE, /* Inherit handles. */
960 cr_flags, /* Creation flags. */
961 NULL, /* Environment. */
962 NULL, /* Use current drive/directory. */
963 &si, /* Startup information. */
964 &pi /* Returns process information. */
967 log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
968 xfree (cmdline);
969 return gpg_error (GPG_ERR_GENERAL);
971 xfree (cmdline);
972 cmdline = NULL;
974 /* log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
975 /* " dwProcessID=%d dwThreadId=%d\n", */
976 /* pi.hProcess, pi.hThread, */
977 /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
979 CloseHandle (pi.hThread);
981 return 0;
983 #else
984 pid_t pid;
985 int i;
987 if (getuid() != geteuid())
988 return gpg_error (GPG_ERR_BUG);
990 if (access (pgmname, X_OK))
991 return gpg_error_from_syserror ();
993 #ifdef USE_GNU_PTH
994 pid = pth_fork? pth_fork () : fork ();
995 #else
996 pid = fork ();
997 #endif
998 if (pid == (pid_t)(-1))
1000 log_error (_("error forking process: %s\n"), strerror (errno));
1001 return gpg_error_from_syserror ();
1003 if (!pid)
1005 gcry_control (GCRYCTL_TERM_SECMEM);
1006 if (setsid() == -1 || chdir ("/"))
1007 _exit (1);
1008 pid = fork (); /* Double fork to let init takes over the new child. */
1009 if (pid == (pid_t)(-1))
1010 _exit (1);
1011 if (pid)
1012 _exit (0); /* Let the parent exit immediately. */
1014 if (envp)
1015 for (i=0; envp[i]; i++)
1016 putenv (xstrdup (envp[i]));
1018 do_exec (pgmname, argv, -1, -1, -1, NULL);
1020 /*NOTREACHED*/
1023 if (waitpid (pid, NULL, 0) == -1)
1024 log_error ("waitpid failed in gnupg_spawn_process_detached: %s",
1025 strerror (errno));
1027 return 0;
1028 #endif /* !HAVE_W32_SYSTEM*/