Fix signal handling race condition.
[gnupg.git] / common / exechelp.c
blobbb9ddd5573c92d28617547e0cb1a790fa5438485
1 /* exechelp.c - fork and exec helpers
2 * Copyright (C) 2004, 2007, 2008 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 #include "util.h"
44 #include "i18n.h"
45 #include "exechelp.h"
47 /* Define to 1 do enable debugging. */
48 #define DEBUG_W32_SPAWN 1
51 #ifdef _POSIX_OPEN_MAX
52 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
53 #else
54 #define MAX_OPEN_FDS 20
55 #endif
57 /* We have the usual problem here: Some modules are linked against pth
58 and some are not. However we want to use pth_fork and pth_waitpid
59 here. Using a weak symbol works but is not portable - we should
60 provide a an explicit dummy pth module instead of using the
61 pragma. */
62 #ifndef _WIN32
63 #pragma weak pth_fork
64 #pragma weak pth_waitpid
65 #endif
67 #ifdef HAVE_W32_SYSTEM
68 /* It seems Vista doesn't grok X_OK and so fails access() tests.
69 Previous versions interpreted X_OK as F_OK anyway, so we'll just
70 use F_OK directly. */
71 #undef X_OK
72 #define X_OK F_OK
73 #endif /* HAVE_W32_SYSTEM */
76 #ifdef HAVE_W32_SYSTEM
77 /* We assume that a HANDLE can be represented by an int which should
78 be true for all i386 systems (HANDLE is defined as void *) and
79 these are the only systems for which Windows is available. Further
80 we assume that -1 denotes an invalid handle. */
81 # define fd_to_handle(a) ((HANDLE)(a))
82 # define handle_to_fd(a) ((int)(a))
83 # define pid_to_handle(a) ((HANDLE)(a))
84 # define handle_to_pid(a) ((int)(a))
85 #endif
88 #ifdef HAVE_W32_SYSTEM
89 /* Helper function to build_w32_commandline. */
90 static char *
91 build_w32_commandline_copy (char *buffer, const char *string)
93 char *p = buffer;
94 const char *s;
96 if (!*string) /* Empty string. */
97 p = stpcpy (p, "\"\"");
98 else if (strpbrk (string, " \t\n\v\f\""))
100 /* Need top do some kind of quoting. */
101 p = stpcpy (p, "\"");
102 for (s=string; *s; s++)
104 *p++ = *s;
105 if (*s == '\"')
106 *p++ = *s;
108 *p++ = '\"';
109 *p = 0;
111 else
112 p = stpcpy (p, string);
114 return p;
117 /* Build a command line for use with W32's CreateProcess. On success
118 CMDLINE gets the address of a newly allocated string. */
119 static gpg_error_t
120 build_w32_commandline (const char *pgmname, const char * const *argv,
121 char **cmdline)
123 int i, n;
124 const char *s;
125 char *buf, *p;
127 *cmdline = NULL;
128 n = 0;
129 s = pgmname;
130 n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
131 for (; *s; s++)
132 if (*s == '\"')
133 n++; /* Need to double inner quotes. */
134 for (i=0; (s=argv[i]); i++)
136 n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
137 for (; *s; s++)
138 if (*s == '\"')
139 n++; /* Need to double inner quotes. */
141 n++;
143 buf = p = xtrymalloc (n);
144 if (!buf)
145 return gpg_error_from_syserror ();
147 p = build_w32_commandline_copy (p, pgmname);
148 for (i=0; argv[i]; i++)
150 *p++ = ' ';
151 p = build_w32_commandline_copy (p, argv[i]);
154 *cmdline= buf;
155 return 0;
157 #endif /*HAVE_W32_SYSTEM*/
160 #ifdef HAVE_W32_SYSTEM
161 /* Create pipe where the write end is inheritable. */
162 static int
163 create_inheritable_pipe (int filedes[2])
165 HANDLE r, w, h;
166 SECURITY_ATTRIBUTES sec_attr;
168 memset (&sec_attr, 0, sizeof sec_attr );
169 sec_attr.nLength = sizeof sec_attr;
170 sec_attr.bInheritHandle = FALSE;
172 if (!CreatePipe (&r, &w, &sec_attr, 0))
173 return -1;
175 if (!DuplicateHandle (GetCurrentProcess(), w,
176 GetCurrentProcess(), &h, 0,
177 TRUE, DUPLICATE_SAME_ACCESS ))
179 log_error ("DuplicateHandle failed: %s\n", w32_strerror (-1));
180 CloseHandle (r);
181 CloseHandle (w);
182 return -1;
184 CloseHandle (w);
185 w = h;
187 filedes[0] = handle_to_fd (r);
188 filedes[1] = handle_to_fd (w);
189 return 0;
191 #endif /*HAVE_W32_SYSTEM*/
194 #ifdef HAVE_W32_SYSTEM
195 static HANDLE
196 w32_open_null (int for_write)
198 HANDLE hfile;
200 hfile = CreateFile ("nul",
201 for_write? GENERIC_WRITE : GENERIC_READ,
202 FILE_SHARE_READ | FILE_SHARE_WRITE,
203 NULL, OPEN_EXISTING, 0, NULL);
204 if (hfile == INVALID_HANDLE_VALUE)
205 log_debug ("can't open `nul': %s\n", w32_strerror (-1));
206 return hfile;
208 #endif /*HAVE_W32_SYSTEM*/
211 #ifndef HAVE_W32_SYSTEM
212 /* The exec core used right after the fork. This will never return. */
213 static void
214 do_exec (const char *pgmname, const char *argv[],
215 int fd_in, int fd_out, int fd_err,
216 void (*preexec)(void) )
218 char **arg_list;
219 int n, i, j;
220 int fds[3];
222 fds[0] = fd_in;
223 fds[1] = fd_out;
224 fds[2] = fd_err;
226 /* Create the command line argument array. */
227 i = 0;
228 if (argv)
229 while (argv[i])
230 i++;
231 arg_list = xcalloc (i+2, sizeof *arg_list);
232 arg_list[0] = strrchr (pgmname, '/');
233 if (arg_list[0])
234 arg_list[0]++;
235 else
236 arg_list[0] = xstrdup (pgmname);
237 if (argv)
238 for (i=0,j=1; argv[i]; i++, j++)
239 arg_list[j] = (char*)argv[i];
241 /* Connect the standard files. */
242 for (i=0; i <= 2; i++)
244 if (fds[i] == -1 )
246 fds[i] = open ("/dev/null", i? O_WRONLY : O_RDONLY);
247 if (fds[i] == -1)
248 log_fatal ("failed to open `%s': %s\n",
249 "/dev/null", strerror (errno));
251 else if (fds[i] != i && dup2 (fds[i], i) == -1)
252 log_fatal ("dup2 std%s failed: %s\n",
253 i==0?"in":i==1?"out":"err", strerror (errno));
256 /* Close all other files. */
257 n = sysconf (_SC_OPEN_MAX);
258 if (n < 0)
259 n = MAX_OPEN_FDS;
260 for (i=3; i < n; i++)
261 close(i);
262 errno = 0;
264 if (preexec)
265 preexec ();
266 execv (pgmname, arg_list);
267 /* No way to print anything, as we have closed all streams. */
268 _exit (127);
270 #endif /*!HAVE_W32_SYSTEM*/
273 /* Portable function to create a pipe. Under Windows the write end is
274 inheritable. */
275 gpg_error_t
276 gnupg_create_inbound_pipe (int filedes[2])
278 gpg_error_t err = 0;
279 #if HAVE_W32_SYSTEM
280 int fds[2];
282 filedes[0] = filedes[1] = -1;
283 err = gpg_error (GPG_ERR_GENERAL);
284 if (!create_inheritable_pipe (fds))
286 filedes[0] = _open_osfhandle (fds[0], 0);
287 if (filedes[0] == -1)
289 log_error ("failed to translate osfhandle %p\n", (void*)fds[0]);
290 CloseHandle (fd_to_handle (fds[1]));
292 else
294 filedes[1] = _open_osfhandle (fds[1], 1);
295 if (filedes[1] == -1)
297 log_error ("failed to translate osfhandle %p\n", (void*)fds[1]);
298 close (filedes[0]);
299 filedes[0] = -1;
300 CloseHandle (fd_to_handle (fds[1]));
302 else
303 err = 0;
306 #else
307 if (pipe (filedes) == -1)
309 err = gpg_error_from_syserror ();
310 filedes[0] = filedes[1] = -1;
312 #endif
313 return err;
317 /* Fork and exec the PGMNAME, connect the file descriptor of INFILE to
318 stdin, write the output to OUTFILE, return a new stream in
319 STATUSFILE for stderr and the pid of the process in PID. The
320 arguments for the process are expected in the NULL terminated array
321 ARGV. The program name itself should not be included there. If
322 PREEXEC is not NULL, that function will be called right before the
323 exec. Calling gnupg_wait_process is required.
325 FLAGS is a bit vector with just one bit defined for now:
327 Bit 7: If set the process will be started as a background process.
328 This flag is only useful under W32 systems, so that no new
329 console is created and pops up a console window when
330 starting the server
332 Returns 0 on success or an error code. */
333 gpg_error_t
334 gnupg_spawn_process (const char *pgmname, const char *argv[],
335 FILE *infile, FILE *outfile,
336 void (*preexec)(void), unsigned int flags,
337 FILE **statusfile, pid_t *pid)
339 #ifdef HAVE_W32_SYSTEM
340 gpg_error_t err;
341 SECURITY_ATTRIBUTES sec_attr;
342 PROCESS_INFORMATION pi =
344 NULL, /* Returns process handle. */
345 0, /* Returns primary thread handle. */
346 0, /* Returns pid. */
347 0 /* Returns tid. */
349 STARTUPINFO si;
350 int cr_flags;
351 char *cmdline;
352 int fd, fdout, rp[2];
354 (void)preexec;
356 /* Setup return values. */
357 *statusfile = NULL;
358 *pid = (pid_t)(-1);
359 fflush (infile);
360 rewind (infile);
361 fd = _get_osfhandle (fileno (infile));
362 fdout = _get_osfhandle (fileno (outfile));
363 if (fd == -1 || fdout == -1)
364 log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
366 /* Prepare security attributes. */
367 memset (&sec_attr, 0, sizeof sec_attr );
368 sec_attr.nLength = sizeof sec_attr;
369 sec_attr.bInheritHandle = FALSE;
371 /* Build the command line. */
372 err = build_w32_commandline (pgmname, argv, &cmdline);
373 if (err)
374 return err;
376 /* Create a pipe. */
377 if (create_inheritable_pipe (rp))
379 err = gpg_error (GPG_ERR_GENERAL);
380 log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
381 xfree (cmdline);
382 return err;
385 /* Start the process. Note that we can't run the PREEXEC function
386 because this would change our own environment. */
387 memset (&si, 0, sizeof si);
388 si.cb = sizeof (si);
389 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
390 si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
391 si.hStdInput = fd_to_handle (fd);
392 si.hStdOutput = fd_to_handle (fdout);
393 si.hStdError = fd_to_handle (rp[1]);
395 cr_flags = (CREATE_DEFAULT_ERROR_MODE
396 | ((flags & 128)? DETACHED_PROCESS : 0)
397 | GetPriorityClass (GetCurrentProcess ())
398 | CREATE_SUSPENDED);
399 /* log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline); */
400 if (!CreateProcess (pgmname, /* Program to start. */
401 cmdline, /* Command line arguments. */
402 &sec_attr, /* Process security attributes. */
403 &sec_attr, /* Thread security attributes. */
404 TRUE, /* Inherit handles. */
405 cr_flags, /* Creation flags. */
406 NULL, /* Environment. */
407 NULL, /* Use current drive/directory. */
408 &si, /* Startup information. */
409 &pi /* Returns process information. */
412 log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
413 xfree (cmdline);
414 CloseHandle (fd_to_handle (rp[0]));
415 CloseHandle (fd_to_handle (rp[1]));
416 return gpg_error (GPG_ERR_GENERAL);
418 xfree (cmdline);
419 cmdline = NULL;
421 /* Close the other end of the pipe. */
422 CloseHandle (fd_to_handle (rp[1]));
424 /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
425 /* " dwProcessID=%d dwThreadId=%d\n", */
426 /* pi.hProcess, pi.hThread, */
427 /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
429 /* Process has been created suspended; resume it now. */
430 ResumeThread (pi.hThread);
431 CloseHandle (pi.hThread);
434 int x;
436 x = _open_osfhandle (rp[0], 0);
437 if (x == -1)
438 log_error ("failed to translate osfhandle %p\n", (void*)rp[0] );
439 else
440 *statusfile = fdopen (x, "r");
442 if (!*statusfile)
444 err = gpg_error_from_syserror ();
445 log_error (_("can't fdopen pipe for reading: %s\n"), gpg_strerror (err));
446 CloseHandle (pi.hProcess);
447 return err;
450 *pid = handle_to_pid (pi.hProcess);
451 return 0;
453 #else /* !HAVE_W32_SYSTEM */
454 gpg_error_t err;
455 int fd, fdout, rp[2];
457 (void)flags; /* Currently not used. */
459 *statusfile = NULL;
460 *pid = (pid_t)(-1);
461 fflush (infile);
462 rewind (infile);
463 fd = fileno (infile);
464 fdout = fileno (outfile);
465 if (fd == -1 || fdout == -1)
466 log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
468 if (pipe (rp) == -1)
470 err = gpg_error_from_syserror ();
471 log_error (_("error creating a pipe: %s\n"), strerror (errno));
472 return err;
475 #ifdef USE_GNU_PTH
476 *pid = pth_fork? pth_fork () : fork ();
477 #else
478 *pid = fork ();
479 #endif
480 if (*pid == (pid_t)(-1))
482 err = gpg_error_from_syserror ();
483 log_error (_("error forking process: %s\n"), strerror (errno));
484 close (rp[0]);
485 close (rp[1]);
486 return err;
489 if (!*pid)
491 gcry_control (GCRYCTL_TERM_SECMEM);
492 /* Run child. */
493 do_exec (pgmname, argv, fd, fdout, rp[1], preexec);
494 /*NOTREACHED*/
497 /* Parent. */
498 close (rp[1]);
500 *statusfile = fdopen (rp[0], "r");
501 if (!*statusfile)
503 err = gpg_error_from_syserror ();
504 log_error (_("can't fdopen pipe for reading: %s\n"), strerror (errno));
505 kill (*pid, SIGTERM);
506 *pid = (pid_t)(-1);
507 return err;
510 return 0;
511 #endif /* !HAVE_W32_SYSTEM */
516 /* Simplified version of gnupg_spawn_process. This function forks and
517 then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
518 and ERRFD to stderr (any of them may be -1 to connect them to
519 /dev/null). The arguments for the process are expected in the NULL
520 terminated array ARGV. The program name itself should not be
521 included there. Calling gnupg_wait_process is required.
523 Returns 0 on success or an error code. */
524 gpg_error_t
525 gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
526 int infd, int outfd, int errfd, pid_t *pid)
528 #ifdef HAVE_W32_SYSTEM
529 gpg_error_t err;
530 SECURITY_ATTRIBUTES sec_attr;
531 PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
532 STARTUPINFO si;
533 char *cmdline;
534 int i;
535 HANDLE stdhd[3];
537 /* Setup return values. */
538 *pid = (pid_t)(-1);
540 /* Prepare security attributes. */
541 memset (&sec_attr, 0, sizeof sec_attr );
542 sec_attr.nLength = sizeof sec_attr;
543 sec_attr.bInheritHandle = FALSE;
545 /* Build the command line. */
546 err = build_w32_commandline (pgmname, argv, &cmdline);
547 if (err)
548 return err;
550 memset (&si, 0, sizeof si);
551 si.cb = sizeof (si);
552 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
553 si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
554 stdhd[0] = infd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
555 stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
556 stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
557 si.hStdInput = infd == -1? stdhd[0] : (void*)_get_osfhandle (infd);
558 si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
559 si.hStdError = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
561 /* log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline); */
562 if (!CreateProcess (pgmname, /* Program to start. */
563 cmdline, /* Command line arguments. */
564 &sec_attr, /* Process security attributes. */
565 &sec_attr, /* Thread security attributes. */
566 TRUE, /* Inherit handles. */
567 (CREATE_DEFAULT_ERROR_MODE
568 | GetPriorityClass (GetCurrentProcess ())
569 | CREATE_SUSPENDED | DETACHED_PROCESS),
570 NULL, /* Environment. */
571 NULL, /* Use current drive/directory. */
572 &si, /* Startup information. */
573 &pi /* Returns process information. */
576 log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
577 err = gpg_error (GPG_ERR_GENERAL);
579 else
580 err = 0;
581 xfree (cmdline);
582 for (i=0; i < 3; i++)
583 if (stdhd[i] != INVALID_HANDLE_VALUE)
584 CloseHandle (stdhd[i]);
585 if (err)
586 return err;
588 /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
589 /* " dwProcessID=%d dwThreadId=%d\n", */
590 /* pi.hProcess, pi.hThread, */
591 /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
593 /* Process has been created suspended; resume it now. */
594 ResumeThread (pi.hThread);
595 CloseHandle (pi.hThread);
597 *pid = handle_to_pid (pi.hProcess);
598 return 0;
600 #else /* !HAVE_W32_SYSTEM */
601 gpg_error_t err;
603 #ifdef USE_GNU_PTH
604 *pid = pth_fork? pth_fork () : fork ();
605 #else
606 *pid = fork ();
607 #endif
608 if (*pid == (pid_t)(-1))
610 err = gpg_error_from_syserror ();
611 log_error (_("error forking process: %s\n"), strerror (errno));
612 return err;
615 if (!*pid)
617 gcry_control (GCRYCTL_TERM_SECMEM);
618 /* Run child. */
619 do_exec (pgmname, argv, infd, outfd, errfd, NULL);
620 /*NOTREACHED*/
623 return 0;
624 #endif /* !HAVE_W32_SYSTEM */
628 /* Wait for the process identified by PID to terminate. PGMNAME should
629 be the same as supplied to the spawn function and is only used for
630 diagnostics. Returns 0 if the process succeeded, GPG_ERR_GENERAL
631 for any failures of the spawned program or other error codes. If
632 EXITCODE is not NULL the exit code of the process is stored at this
633 address or -1 if it could not be retrieved. */
634 gpg_error_t
635 gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
637 gpg_err_code_t ec;
639 #ifdef HAVE_W32_SYSTEM
640 HANDLE proc = fd_to_handle (pid);
641 int code;
642 DWORD exc;
644 if (exitcode)
645 *exitcode = -1;
647 if (pid == (pid_t)(-1))
648 return gpg_error (GPG_ERR_INV_VALUE);
650 /* FIXME: We should do a pth_waitpid here. However this has not yet
651 been implemented. A special W32 pth system call would even be
652 better. */
653 code = WaitForSingleObject (proc, INFINITE);
654 switch (code)
656 case WAIT_FAILED:
657 log_error (_("waiting for process %d to terminate failed: %s\n"),
658 (int)pid, w32_strerror (-1));
659 ec = GPG_ERR_GENERAL;
660 break;
662 case WAIT_OBJECT_0:
663 if (!GetExitCodeProcess (proc, &exc))
665 log_error (_("error getting exit code of process %d: %s\n"),
666 (int)pid, w32_strerror (-1) );
667 ec = GPG_ERR_GENERAL;
669 else if (exc)
671 log_error (_("error running `%s': exit status %d\n"),
672 pgmname, (int)exc );
673 if (exitcode)
674 *exitcode = (int)exc;
675 ec = GPG_ERR_GENERAL;
677 else
679 if (exitcode)
680 *exitcode = 0;
681 ec = 0;
683 CloseHandle (proc);
684 break;
686 default:
687 log_error ("WaitForSingleObject returned unexpected "
688 "code %d for pid %d\n", code, (int)pid );
689 ec = GPG_ERR_GENERAL;
690 break;
693 #else /* !HAVE_W32_SYSTEM */
694 int i, status;
696 if (exitcode)
697 *exitcode = -1;
699 if (pid == (pid_t)(-1))
700 return gpg_error (GPG_ERR_INV_VALUE);
702 #ifdef USE_GNU_PTH
703 i = pth_waitpid ? pth_waitpid (pid, &status, 0) : waitpid (pid, &status, 0);
704 #else
705 while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
707 #endif
708 if (i == (pid_t)(-1))
710 log_error (_("waiting for process %d to terminate failed: %s\n"),
711 (int)pid, strerror (errno));
712 ec = gpg_err_code_from_errno (errno);
714 else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
716 log_error (_("error running `%s': probably not installed\n"), pgmname);
717 ec = GPG_ERR_CONFIGURATION;
719 else if (WIFEXITED (status) && WEXITSTATUS (status))
721 log_error (_("error running `%s': exit status %d\n"), pgmname,
722 WEXITSTATUS (status));
723 if (exitcode)
724 *exitcode = WEXITSTATUS (status);
725 ec = GPG_ERR_GENERAL;
727 else if (!WIFEXITED (status))
729 log_error (_("error running `%s': terminated\n"), pgmname);
730 ec = GPG_ERR_GENERAL;
732 else
734 if (exitcode)
735 *exitcode = 0;
736 ec = 0;
738 #endif /* !HAVE_W32_SYSTEM */
740 return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
744 /* Spawn a new process and immediatley detach from it. The name of
745 the program to exec is PGMNAME and its arguments are in ARGV (the
746 programname is automatically passed as first argument).
747 Environment strings in ENVP are set. An error is returned if
748 pgmname is not executable; to make this work it is necessary to
749 provide an absolute file name. All standard file descriptors are
750 connected to /dev/null. */
751 gpg_error_t
752 gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
753 const char *envp[] )
755 #ifdef HAVE_W32_SYSTEM
756 gpg_error_t err;
757 SECURITY_ATTRIBUTES sec_attr;
758 PROCESS_INFORMATION pi =
760 NULL, /* Returns process handle. */
761 0, /* Returns primary thread handle. */
762 0, /* Returns pid. */
763 0 /* Returns tid. */
765 STARTUPINFO si;
766 int cr_flags;
767 char *cmdline;
770 /* FIXME: We don't make use of ENVP yet. It is currently only used
771 to pass the GPG_AGENT_INFO variable to gpg-agent. As the default
772 on windows is to use a standard socket, this does not really
773 matter. */
774 (void)envp;
776 if (access (pgmname, X_OK))
777 return gpg_error_from_syserror ();
779 /* Prepare security attributes. */
780 memset (&sec_attr, 0, sizeof sec_attr );
781 sec_attr.nLength = sizeof sec_attr;
782 sec_attr.bInheritHandle = FALSE;
784 /* Build the command line. */
785 err = build_w32_commandline (pgmname, argv, &cmdline);
786 if (err)
787 return err;
789 /* Start the process. */
790 memset (&si, 0, sizeof si);
791 si.cb = sizeof (si);
792 si.dwFlags = STARTF_USESHOWWINDOW;
793 si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
795 cr_flags = (CREATE_DEFAULT_ERROR_MODE
796 | GetPriorityClass (GetCurrentProcess ())
797 | CREATE_NEW_PROCESS_GROUP
798 | DETACHED_PROCESS);
799 /* log_debug ("CreateProcess(detached), path=`%s' cmdline=`%s'\n", */
800 /* pgmname, cmdline); */
801 if (!CreateProcess (pgmname, /* Program to start. */
802 cmdline, /* Command line arguments. */
803 &sec_attr, /* Process security attributes. */
804 &sec_attr, /* Thread security attributes. */
805 FALSE, /* Inherit handles. */
806 cr_flags, /* Creation flags. */
807 NULL, /* Environment. */
808 NULL, /* Use current drive/directory. */
809 &si, /* Startup information. */
810 &pi /* Returns process information. */
813 log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
814 xfree (cmdline);
815 return gpg_error (GPG_ERR_GENERAL);
817 xfree (cmdline);
818 cmdline = NULL;
820 /* log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
821 /* " dwProcessID=%d dwThreadId=%d\n", */
822 /* pi.hProcess, pi.hThread, */
823 /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
825 CloseHandle (pi.hThread);
827 return 0;
829 #else
830 pid_t pid;
831 int i;
833 if (getuid() != geteuid())
834 return gpg_error (GPG_ERR_BUG);
836 if (access (pgmname, X_OK))
837 return gpg_error_from_syserror ();
839 #ifdef USE_GNU_PTH
840 pid = pth_fork? pth_fork () : fork ();
841 #else
842 pid = fork ();
843 #endif
844 if (pid == (pid_t)(-1))
846 log_error (_("error forking process: %s\n"), strerror (errno));
847 return gpg_error_from_syserror ();
849 if (!pid)
851 gcry_control (GCRYCTL_TERM_SECMEM);
852 if (setsid() == -1 || chdir ("/"))
853 _exit (1);
854 pid = fork (); /* Double fork to let init takes over the new child. */
855 if (pid == (pid_t)(-1))
856 _exit (1);
857 if (pid)
858 _exit (0); /* Let the parent exit immediately. */
860 if (envp)
861 for (i=0; envp[i]; i++)
862 putenv (xstrdup (envp[i]));
864 do_exec (pgmname, argv, -1, -1, -1, NULL);
866 /*NOTREACHED*/
869 if (waitpid (pid, NULL, 0) == -1)
870 log_error ("waitpid failed in gnupg_spawn_process_detached: %s",
871 strerror (errno));
873 return 0;
874 #endif /* !HAVE_W32_SYSTEM*/