diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-11-30 18:49:48 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-11-30 18:49:48 +0200 |
commit | 23404fbf27b67bd1767998918548aee3235f201c (patch) | |
tree | d3557c6336910a53f9f8dc83568195e383d10b4d | |
parent | 42e0f735b48ab0f05e80eeec335684b25a93c4a3 (diff) | |
download | mailutils-23404fbf27b67bd1767998918548aee3235f201c.tar.gz mailutils-23404fbf27b67bd1767998918548aee3235f201c.tar.bz2 |
New functions for closing all fds and daemonizing
* configure.ac: Select a suitable interface for closing all file
descriptors greater than or equal to a chosen one.
* include/mailutils/daemon.h (mu_daemon): New proto.
* include/mailutils/util.h (mu_close_fds): New proto.
* lib/daemon.c: Removed.
* lib/Makefile.am: Remove daemon.c
* libmailutils/base/Makefile.am: Add closefds.c
* libmailutils/base/closefds.c: New file.
* libmailutils/base/daemon.c: Rename to libmailutils/base/pidfile.c
* libmailutils/base/daemon.c: New file.
* libmailutils/diag/bt.c: Use mu_close_fds.
* libmailutils/server/acl.c: Likewise.
* mh/mh_whatnow.c: Likewise.
* libmailutils/stream/prog_stream.c: Likewise.
* libmailutils/server/msrv.c: Use mu_daemon.
* mh/send.c: Likewise.
* mda/lib/util.c (mda_close_fds): Remove.
-rw-r--r-- | configure.ac | 29 | ||||
-rw-r--r-- | include/mailutils/daemon.h | 5 | ||||
-rw-r--r-- | include/mailutils/util.h | 3 | ||||
-rw-r--r-- | lib/Makefile.am | 1 | ||||
-rw-r--r-- | lib/daemon.c | 198 | ||||
-rw-r--r-- | libmailutils/base/Makefile.am | 2 | ||||
-rw-r--r-- | libmailutils/base/closefds.c | 129 | ||||
-rw-r--r-- | libmailutils/base/daemon.c | 220 | ||||
-rw-r--r-- | libmailutils/base/pidfile.c | 187 | ||||
-rw-r--r-- | libmailutils/diag/bt.c | 4 | ||||
-rw-r--r-- | libmailutils/server/acl.c | 7 | ||||
-rw-r--r-- | libmailutils/server/msrv.c | 4 | ||||
-rw-r--r-- | libmailutils/stream/prog_stream.c | 3 | ||||
-rw-r--r-- | mda/lib/util.c | 9 | ||||
-rw-r--r-- | mh/mh_whatnow.c | 4 | ||||
-rw-r--r-- | mh/send.c | 4 |
16 files changed, 423 insertions, 386 deletions
diff --git a/configure.ac b/configure.ac index ae80fd9c2..3e3625db8 100644 --- a/configure.ac +++ b/configure.ac @@ -329,6 +329,35 @@ AH_BOTTOM( # define MU_PATH_MAILDIR PATH_MAILDIR #endif]) +################################## +# Select interface used to close file descriptors greater than or +# equal to the given one. +# +# Variants: +# 1. closefrom call (FreeBSD) +# 2. F_CLOSEM fcntl (NetBSD, AIX, IRIX) +# 3. proc_pidinfo call (Darwin) +# 4. /proc/self/fd filesystem (Linux) +# 5. Brute force +# +# The defines created here direct conditionalal compilation in +# libmailutils/base/closefds.c + +AC_CHECK_FUNCS([closefrom]) +AC_CHECK_DECL([F_CLOSEM], + AC_DEFINE([HAVE_FCNTL_CLOSEM], [1], + [Use F_CLOSEM fcntl for mu_close_fds]), + [], + [#include <limits.h> + #include <fcntl.h> +]) + +AC_CHECK_HEADERS([libproc.h]) +AC_CHECK_FUNCS([proc_pidinfo]) + +if test -d "/proc/self/fd" ; then + AC_DEFINE([HAVE_PROC_SELF_FD], [1], [Define if you have /proc/self/fd]) +fi ################################## # DBM Support ################################## diff --git a/include/mailutils/daemon.h b/include/mailutils/daemon.h index cd368e157..c9c1d2424 100644 --- a/include/mailutils/daemon.h +++ b/include/mailutils/daemon.h @@ -28,8 +28,9 @@ extern "C" { #define MODE_INTERACTIVE 0 #define MODE_DAEMON 1 -extern int mu_daemon_create_pidfile (const char *); -extern void mu_daemon_remove_pidfile (void); +int mu_daemon_create_pidfile (const char *); +void mu_daemon_remove_pidfile (void); +int mu_daemon (void); #ifdef __cplusplus } diff --git a/include/mailutils/util.h b/include/mailutils/util.h index 7c12aadec..e0aa0d167 100644 --- a/include/mailutils/util.h +++ b/include/mailutils/util.h @@ -248,6 +248,9 @@ int mu_remove_file (const char *path); int mu_file_name_is_safe (char const *str); int mu_getmaxfd (void); +void mu_close_fds (int minfd); +int mu_daemon (void); + /* Get the host name, doing a gethostbyname() if possible. */ int mu_get_host_name (char **host); int mu_spawnvp (const char *prog, char *av[], int *stat); diff --git a/lib/Makefile.am b/lib/Makefile.am index a1d8ea79c..12a7c2b0b 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -27,7 +27,6 @@ lib_LTLIBRARIES = libmuaux.la noinst_LIBRARIES = libmuscript.a libmutcpwrap.a libmuaux_la_SOURCES = \ - daemon.c\ mailcap.c\ manlock.c\ mdecode.c\ diff --git a/lib/daemon.c b/lib/daemon.c deleted file mode 100644 index 3709f4dcb..000000000 --- a/lib/daemon.c +++ /dev/null @@ -1,198 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif -#include <stdio.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdlib.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/wait.h> - -#include <confpaths.h> - -#ifndef PATH_DEVNULL -# define PATH_DEVNULL "/dev/null" -#endif - -/* - According to Unix-FAQ maintained by Andrew Gierth: - - 1.fork() so the parent can exit, this returns control to the command - line or shell invoking your program. This step is required so that the - new process is guaranteed not to be a process group leader. The next - step, setsid(), fails if you're a process group leader. - - 2.setsid() to become a process group and session group leader. Since a - controlling terminal is associated with a session, and this new session - has not yet acquired a controlling terminal our process now has no - controlling terminal, which is a Good Thing for daemons. - - 3.fork() again so the parent, (the session group leader), can exit. This - means that we, as a non-session group leader, can never regain a - controlling terminal. - - 4.chdir("/") to ensure that our process doesn't keep any directory in use. - Failure to do this could make it so that an administrator couldn't unmount - a filesystem, because it was our current directory. - [Equivalently, we could change to any directory containing files important - to the daemon's operation.] - - 5.umask(0) so that we have complete control over the permissions of - anything we write. We don't know what umask we may have inherited. - [This step is optional] - - 6.close() fds 0, 1, and 2. This releases the standard in, out, and error - we inherited from our parent process. We have no way of knowing where - these fds might have been redirected to. Note that many daemons use - sysconf() to determine the limit _SC_OPEN_MAX. _SC_OPEN_MAX tells you the - maximun open files/process. Then in a loop, the daemon can close all - possible file descriptors. You have to decide if you need to do this or not. - If you think that there might be file-descriptors open you should close - them, since there's a limit on number of concurrent file descriptors. - - 7.Establish new open descriptors for stdin, stdout and stderr. Even if - you don't plan to use them, it is still a good idea to have them open. - The precise handling of these is a matter of taste; if you have a logfile, - for example, you might wish to open it as stdout or stderr, and open - `/dev/null' as stdin; alternatively, you could open `/dev/console' as - stderr and/or stdout, and `/dev/null' as stdin, or any other combination - that makes sense for your particular daemon. */ - -#define MAXFD 64 - -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) -# define __attribute__(x) -#endif - -void -waitdaemon_timeout (int signo __attribute__ ((__unused__))) -{ - int left; - - left = alarm (0); - signal (SIGALRM, SIG_DFL); - if (left == 0) - { - fprintf (stderr, "timed out waiting for child\n"); - exit (1); - } -} - -/* waitdaemon is like daemon, but optionally the parent pause up - until maxwait before exiting. Return -1, on error, otherwise - waitdaemon will return the pid of the parent. */ - -int -waitdaemon (int nochdir, int noclose, int maxwait) -{ - int fd; - pid_t childpid; - pid_t ppid; - - ppid = getpid (); - - switch (childpid = fork ()) - { - case -1: /* Something went wrong. */ - return (-1); - - case 0: /* In the child. */ - break; - - default: /* In the parent. */ - if (maxwait > 0) - { - signal (SIGALRM, waitdaemon_timeout); - alarm (maxwait); - pause (); - } - _exit(0); - } - - if (setsid () == -1) - return -1; - - /* SIGHUP is ignore because when the session leader terminates - all process in the session (the second child) are sent the SIGHUP. */ - signal (SIGHUP, SIG_IGN); - - switch (fork ()) - { - case 0: - break; - - case -1: - return -1; - - default: - _exit (0); - } - - if (!nochdir) - chdir ("/"); - - if (!noclose) - { - int i; - long fdlimit = -1; - -#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX) - fdlimit = sysconf (_SC_OPEN_MAX); -#elif defined (HAVE_GETDTABLESIZE) - fdlimit = getdtablesize (); -#endif - - if (fdlimit == -1) - fdlimit = MAXFD; - - for (i = 0; i < fdlimit; i++) - close (i); - - fd = open (PATH_DEVNULL, O_RDWR, 0); - if (fd != -1) - { - dup2 (fd, STDIN_FILENO); - dup2 (fd, STDOUT_FILENO); - dup2 (fd, STDERR_FILENO); - if (fd > 2) - close (fd); - } - } - return ppid; -} - -int -daemon (int nochdir, int noclose) -{ - return (waitdaemon (nochdir, noclose, 0) == -1) ? -1 : 0; -} diff --git a/libmailutils/base/Makefile.am b/libmailutils/base/Makefile.am index 3d6820c77..d56938751 100644 --- a/libmailutils/base/Makefile.am +++ b/libmailutils/base/Makefile.am @@ -24,6 +24,7 @@ libbase_la_SOURCES = \ argcvjoin.c\ argcvrem.c\ assoc.c\ + closefds.c\ coord.c\ copyfile.c\ ctparse.c\ @@ -55,6 +56,7 @@ libbase_la_SOURCES = \ onexit.c\ opool.c\ permstr.c\ + pidfile.c\ registrar.c\ refcount.c\ renamefile.c\ diff --git a/libmailutils/base/closefds.c b/libmailutils/base/closefds.c new file mode 100644 index 000000000..49c024fb1 --- /dev/null +++ b/libmailutils/base/closefds.c @@ -0,0 +1,129 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2019-2020 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, 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ +#include <config.h> +#include <stdlib.h> +#include <unistd.h> +#include <mailutils/util.h> + +#if defined (HAVE_FUNC_CLOSEFROM) +# include <unistd.h> + +static int +close_fds_sys (int minfd) +{ + closefrom (minfd); + return 0; +} + +#elif defined (HAVE_FCNTL_CLOSEM) +# include <fcntl.h> + +static int +close_fds_sys (int minfd) +{ + fcntl (minfd, F_CLOSEM, 0); + return 0; +} + +#elif defined (HAVE_LIBPROC_H) && defined (HAVE_FUNC_PROC_PIDINFO) +#include <libproc.h> + +static int +close_fds_sys (int minfd) +{ + pid_t pid = getpid (); + struct proc_fdinfo *fdinfo; + int i, n, size; + + size = proc_pidinfo (pid, PROC_PIDLISTFDS, 0, NULL, 0); + if (size == 0) + return 0; + else if (size < 0) + return -1; + + fdinfo = calloc (size, sizeof (fdinfo[0])); + if (!fdinfo) + return -1; + + n = proc_pidinfo (pid, PROC_PIDLISTFDS, 0, fdinfo, size); + if (n <= 0) + { + free (fdinfo); + return -1; + } + + n /= PROC_PIDLISTFD_SIZE; + + for (i = minfd; i < n; i++) + { + close (fdinfo_buf[i].proc_fd); + } + + free (fdinfo); + return 0; +} + +#elif defined (HAVE_PROC_SELF_FD) +# include <sys/types.h> +# include <dirent.h> +# include <limits.h> + +static int +close_fds_sys (int minfd) +{ + DIR *dir; + struct dirent *ent; + + dir = opendir ("/proc/self/fd"); + if (!dir) + return -1; + while ((ent = readdir (dir)) != NULL) + { + long n; + char *p; + + if (ent->d_name[0] == '.') + continue; + + n = strtol (ent->d_name, &p, 10); + if (n >= minfd && n < INT_MAX && *p == 0) + close ((int) n); + } + closedir (dir); + return 0; +} + +#else +# define close_fds_sys(fd) (-1) +#endif + +static int +close_fds_bruteforce (int minfd) +{ + int i, n = mu_getmaxfd (); + + for (i = minfd; i < n; i++) + close (i); + + return 0; +} + +void +mu_close_fds (int minfd) +{ + if (close_fds_sys (minfd)) + close_fds_bruteforce (minfd); +} diff --git a/libmailutils/base/daemon.c b/libmailutils/base/daemon.c index a2a3252ca..d7ca0c6cd 100644 --- a/libmailutils/base/daemon.c +++ b/libmailutils/base/daemon.c @@ -1,187 +1,87 @@ /* GNU Mailutils -- a suite of utilities for electronic mail - Copyright (C) 2004-2020 Free Software Foundation, Inc. + Copyright (C) 2019-2020 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 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, 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. + 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 - <http://www.gnu.org/licenses/>. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> + You should have received a copy of the GNU Lesser General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ +#include <config.h> +#include <confpaths.h> #include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <string.h> - +#include <unistd.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <mailutils/util.h> #include <mailutils/daemon.h> -#include <mailutils/errno.h> -#include <mailutils/error.h> -#include <mailutils/nls.h> - -static char *pidfile; -static pid_t current_pid; - -/* Return 0 if DIR is writable for EUID/EGID. - Otherwise, return error code. */ -static int -ewraccess (const char *dir) -{ - struct stat st; - if (stat (dir, &st)) - return errno; - if ((st.st_mode & S_IWOTH) - || (st.st_gid == getegid () && (st.st_mode & S_IWGRP)) - || (st.st_uid == geteuid () && (st.st_mode & S_IWUSR))) - return 0; - else - return EACCES; -} - -/* Return 0 if DIR is writable. If necessary and possible, raise to - EUID 0, in that case return prior EUID in the memory location pointed to - by PUID. */ -static int -access_dir (const char *dir, uid_t *puid) -{ - int ec = ewraccess (dir); - if (ec) - { - if (ec == EACCES && access (dir, W_OK) == 0) - { - uid_t uid = geteuid (); - /* See if we can become root */ - if (uid && getuid () == 0 && seteuid (0) == 0) - { - *puid = uid; - return 0; - } - } - } - return ec; -} int -mu_daemon_create_pidfile (const char *filename) +mu_daemon (void) { - char *p; int fd; - uid_t uid = 0; - int rc; - if (filename[0] != '/') - return EINVAL; + switch (fork ()) + { + case 0: + break; - if (pidfile) - free (pidfile); - pidfile = strdup (filename); - if (!pidfile) - return ENOMEM; + case -1: + return errno; - /* Determine the hosting directory name */ - p = strrchr (pidfile, '/'); - if (pidfile == p) - { - free (pidfile); - pidfile = NULL; - /* Sorry, pidfiles in root dir are not allowed */ - return EINVAL; - } - /* Check if we have write access to the directory */ - *p = 0; - rc = access_dir (pidfile, &uid); - if (rc) - { - /* Nope, clean up and return */ - free (pidfile); - pidfile = NULL; - return rc; + default: + _exit (0); } - /* Restore directory separator */ - *p = '/'; - - unlink (pidfile); - current_pid = getpid (); + if (setsid () == (pid_t) -1) + return errno; + + signal (SIGHUP, SIG_IGN); - if ((fd = open (pidfile, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644)) != -1) + switch (fork ()) { - FILE *fp = fdopen (fd, "w"); - if (!fp) - { - rc = errno; - free (pidfile); - close (fd); - } - else - { - fprintf (fp, "%lu", (unsigned long) current_pid); - fclose (fp); - atexit (mu_daemon_remove_pidfile); - } - } - else - { - rc = errno; - free (pidfile); - pidfile = NULL; - } + case 0: + break; - /* Restore previous EUID value. */ - if (uid) - seteuid (uid); - - return rc; -} + case -1: + return errno; -void -mu_daemon_remove_pidfile (void) -{ - if (getpid () == current_pid) - { - int rc; - uid_t uid = 0; + default: + _exit (0); + } - /* Determine the hosting directory name */ - char *p = strrchr (pidfile, '/'); - if (pidfile == p) - { - /* Should not happen */ - abort (); - } - /* Check if we have write access to the directory */ - *p = 0; - rc = access_dir (pidfile, &uid); - *p = '/'; - if (rc == 0) - { - if (unlink (pidfile) && errno != ENOENT) - rc = errno; - else - rc = 0; - } - - if (rc) - mu_error (_("cannot remove pidfile %s: %s"), - pidfile, mu_strerror (rc)); + chdir ("/"); + mu_close_fds (0); - free (pidfile); - pidfile = NULL; + fd = open (PATH_DEVNULL, O_RDWR); + if (fd == 0) + { + dup2 (fd, 1); + dup2 (fd, 2); + } + else if (fd > 0) + { + /* This means that mu_close_fds failed to close stdin. + Shouldn't happen, but just in case ... */ + dup2 (fd, 0); + dup2 (fd, 1); + dup2 (fd, 2); + close (fd); } + + return 0; } - + + + + + diff --git a/libmailutils/base/pidfile.c b/libmailutils/base/pidfile.c new file mode 100644 index 000000000..a2a3252ca --- /dev/null +++ b/libmailutils/base/pidfile.c @@ -0,0 +1,187 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2004-2020 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 + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> + +#include <mailutils/daemon.h> +#include <mailutils/errno.h> +#include <mailutils/error.h> +#include <mailutils/nls.h> + +static char *pidfile; +static pid_t current_pid; + +/* Return 0 if DIR is writable for EUID/EGID. + Otherwise, return error code. */ +static int +ewraccess (const char *dir) +{ + struct stat st; + if (stat (dir, &st)) + return errno; + if ((st.st_mode & S_IWOTH) + || (st.st_gid == getegid () && (st.st_mode & S_IWGRP)) + || (st.st_uid == geteuid () && (st.st_mode & S_IWUSR))) + return 0; + else + return EACCES; +} + +/* Return 0 if DIR is writable. If necessary and possible, raise to + EUID 0, in that case return prior EUID in the memory location pointed to + by PUID. */ +static int +access_dir (const char *dir, uid_t *puid) +{ + int ec = ewraccess (dir); + if (ec) + { + if (ec == EACCES && access (dir, W_OK) == 0) + { + uid_t uid = geteuid (); + /* See if we can become root */ + if (uid && getuid () == 0 && seteuid (0) == 0) + { + *puid = uid; + return 0; + } + } + } + return ec; +} + +int +mu_daemon_create_pidfile (const char *filename) +{ + char *p; + int fd; + uid_t uid = 0; + int rc; + + if (filename[0] != '/') + return EINVAL; + + if (pidfile) + free (pidfile); + pidfile = strdup (filename); + if (!pidfile) + return ENOMEM; + + /* Determine the hosting directory name */ + p = strrchr (pidfile, '/'); + if (pidfile == p) + { + free (pidfile); + pidfile = NULL; + /* Sorry, pidfiles in root dir are not allowed */ + return EINVAL; + } + /* Check if we have write access to the directory */ + *p = 0; + rc = access_dir (pidfile, &uid); + if (rc) + { + /* Nope, clean up and return */ + free (pidfile); + pidfile = NULL; + return rc; + } + + /* Restore directory separator */ + *p = '/'; + + unlink (pidfile); + current_pid = getpid (); + + if ((fd = open (pidfile, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644)) != -1) + { + FILE *fp = fdopen (fd, "w"); + if (!fp) + { + rc = errno; + free (pidfile); + close (fd); + } + else + { + fprintf (fp, "%lu", (unsigned long) current_pid); + fclose (fp); + atexit (mu_daemon_remove_pidfile); + } + } + else + { + rc = errno; + free (pidfile); + pidfile = NULL; + } + + /* Restore previous EUID value. */ + if (uid) + seteuid (uid); + + return rc; +} + +void +mu_daemon_remove_pidfile (void) +{ + if (getpid () == current_pid) + { + int rc; + uid_t uid = 0; + + /* Determine the hosting directory name */ + char *p = strrchr (pidfile, '/'); + if (pidfile == p) + { + /* Should not happen */ + abort (); + } + /* Check if we have write access to the directory */ + *p = 0; + rc = access_dir (pidfile, &uid); + *p = '/'; + if (rc == 0) + { + if (unlink (pidfile) && errno != ENOENT) + rc = errno; + else + rc = 0; + } + + if (rc) + mu_error (_("cannot remove pidfile %s: %s"), + pidfile, mu_strerror (rc)); + + free (pidfile); + pidfile = NULL; + } +} + + + diff --git a/libmailutils/diag/bt.c b/libmailutils/diag/bt.c index c27634ef2..3b43dcd21 100644 --- a/libmailutils/diag/bt.c +++ b/libmailutils/diag/bt.c @@ -36,7 +36,6 @@ void mu_gdb_bt () { - int i; pid_t master_pid = getpid (); pid_t pid; static char buf[1024]; @@ -58,8 +57,7 @@ mu_gdb_bt () abort (); } - for (i = mu_getmaxfd (); i >= 0; i--) - close (i); + mu_close_fds (0); fd = open (fname, O_WRONLY|O_CREAT, 0600); if (fd == -1) diff --git a/libmailutils/server/acl.c b/libmailutils/server/acl.c index f209d6929..5f71d2bce 100644 --- a/libmailutils/server/acl.c +++ b/libmailutils/server/acl.c @@ -410,7 +410,6 @@ spawn_prog (const char *cmdline, int *pstatus, struct run_closure *rp) pid = fork (); if (pid == 0) { - int i; struct mu_wordsplit ws; if (mu_wordsplit (s, &ws, MU_WRDSF_DEFFLAGS)) @@ -419,9 +418,9 @@ spawn_prog (const char *cmdline, int *pstatus, struct run_closure *rp) mu_wordsplit_strerror (&ws)); _exit (127); } - - for (i = mu_getmaxfd (); i > 2; i--) - close (i); + + mu_close_fds (3); + execvp (ws.ws_wordv[0], ws.ws_wordv); _exit (127); } diff --git a/libmailutils/server/msrv.c b/libmailutils/server/msrv.c index 088f4d8b3..6203ae71c 100644 --- a/libmailutils/server/msrv.c +++ b/libmailutils/server/msrv.c @@ -522,9 +522,9 @@ mu_m_server_begin (mu_m_server_t msrv) { /* Become a daemon. Take care to close inherited fds and to hold first three one, in, out, err */ - if (daemon (0, 0) < 0) + if ((rc = mu_daemon ()) != 0) { - mu_error (_("failed to become a daemon: %s"), mu_strerror (errno)); + mu_error (_("failed to become a daemon: %s"), mu_strerror (rc)); exit (EXIT_FAILURE); } mu_onexit_reset (); diff --git a/libmailutils/stream/prog_stream.c b/libmailutils/stream/prog_stream.c index 08a19af2a..61ccfd39a 100644 --- a/libmailutils/stream/prog_stream.c +++ b/libmailutils/stream/prog_stream.c @@ -252,8 +252,7 @@ start_program_filter (int *p, struct _mu_prog_stream *fs, int flags) } /* Close unneded descripitors */ - for (i = mu_getmaxfd (); i > 2; i--) - close (i); + mu_close_fds (3); /*FIXME: Switch to other uid/gid if desired */ execvp (fs->progname, fs->argv); diff --git a/mda/lib/util.c b/mda/lib/util.c index 5e7fff4ab..ac20a405c 100644 --- a/mda/lib/util.c +++ b/mda/lib/util.c @@ -18,15 +18,6 @@ int exit_code; -void -mda_close_fds (void) -{ - int i; - long fdlimit = sysconf (_SC_OPEN_MAX); - for (i = 3; i < fdlimit; i++) - close (i); -} - int mda_switch_user_id (struct mu_auth_data *auth, int user) { diff --git a/mh/mh_whatnow.c b/mh/mh_whatnow.c index 09ed83031..547980fe9 100644 --- a/mh/mh_whatnow.c +++ b/mh/mh_whatnow.c @@ -688,7 +688,6 @@ mh_whatnowproc (struct mh_whatnow_env *wh, int initial_edit, const char *prog) if (pid == 0) { struct mu_wordsplit ws; - int i; if (mu_wordsplit (prog, &ws, MU_WRDSF_DEFFLAGS & ~MU_WRDSF_CESCAPES)) @@ -700,8 +699,7 @@ mh_whatnowproc (struct mh_whatnow_env *wh, int initial_edit, const char *prog) set_default_editor (wh); mh_whatnow_env_to_environ (wh); - for (i = mu_getmaxfd (); i > 2; i--) - close (i); + mu_close_fds (3); execvp (ws.ws_wordv[0], ws.ws_wordv); mu_diag_funcall (MU_DIAG_ERROR, "execvp", prog, errno); _exit (127); |