diff options
Diffstat (limited to 'libmailutils/base/daemon.c')
-rw-r--r-- | libmailutils/base/daemon.c | 220 |
1 files changed, 60 insertions, 160 deletions
diff --git a/libmailutils/base/daemon.c b/libmailutils/base/daemon.c index e9ff80980..4052aae48 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-2019 Free Software Foundation, Inc. + Copyright (C) 2019-2024 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; } - + + + + + |