/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011 Free Software Foundation, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #if HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include /* See Advanced Programming in the UNIX Environment, Stevens, * program 10.20 for the rational for the signal handling. I * had to look it up, so if somebody else is curious, thats where * to find it. */ int mu_spawnvp (const char *prog, char *av[], int *stat) { pid_t pid; int err = 0; int progstat; struct sigaction ignore; struct sigaction saveintr; struct sigaction savequit; sigset_t chldmask; sigset_t savemask; if (!prog || !av) return EINVAL; ignore.sa_handler = SIG_IGN; /* ignore SIGINT and SIGQUIT */ ignore.sa_flags = 0; sigemptyset (&ignore.sa_mask); if (sigaction (SIGINT, &ignore, &saveintr) < 0) return errno; if (sigaction (SIGQUIT, &ignore, &savequit) < 0) { sigaction (SIGINT, &saveintr, NULL); return errno; } sigemptyset (&chldmask); /* now block SIGCHLD */ sigaddset (&chldmask, SIGCHLD); if (sigprocmask (SIG_BLOCK, &chldmask, &savemask) < 0) { sigaction (SIGINT, &saveintr, NULL); sigaction (SIGQUIT, &savequit, NULL); return errno; } pid = fork (); if (pid < 0) { err = errno; } else if (pid == 0) { /* child */ /* restore previous signal actions & reset signal mask */ sigaction (SIGINT, &saveintr, NULL); sigaction (SIGQUIT, &savequit, NULL); sigprocmask (SIG_SETMASK, &savemask, NULL); execvp (prog, av); _exit (127); /* exec error */ } else { /* parent */ while (waitpid (pid, &progstat, 0) < 0) if (errno != EINTR) { err = errno; /* error other than EINTR from waitpid() */ break; } if (err == 0 && stat) *stat = progstat; } /* restore previous signal actions & reset signal mask */ /* preserve first error number, but still try and reset the signals */ if (sigaction (SIGINT, &saveintr, NULL) < 0) err = err ? err : errno; if (sigaction (SIGQUIT, &savequit, NULL) < 0) err = err ? err : errno; if (sigprocmask (SIG_SETMASK, &savemask, NULL) < 0) err = err ? err : errno; return err; }