From 7b1212f653f6b4886d7c6536c554343bcb3cc625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se> Date: Sat, 29 Apr 2006 21:54:56 +0200 Subject: [PATCH] (daemon_pidfile): Deleted #if:ed out file locking code. (daemon_started_by_init, daemon_started_by_inetd): Made static. (daemon_detect): New function, split out from daemon_init. (daemon_dup_null): Likewise. (getdtablesize): New function, for systems that don't have it in libc. (daemon_close_fds): New function. (daemon_init): New argument with the daemon mode. Split handling of fd:s to the new functions daemon_dup_null and daemon_close_fds. Rev: src/daemon.c:1.14 --- src/daemon.c | 395 ++++++++++++++++----------------------------------- 1 file changed, 119 insertions(+), 276 deletions(-) diff --git a/src/daemon.c b/src/daemon.c index 8005ea524..410421bc1 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -67,22 +67,10 @@ #define PID_SUFFIX ".pid" #endif -/* -** struct lsh_string *daemon_pidfile(const char *name) -** -** Creates a pid file for a daemon and locks it. -** The file has one line containing the process id of the daemon. -** The well-known location for the file is defined in PID_DIR -** ("/var/run" by default). The name of the file is the name of -** the daemon (given by the name argument) followed by ".pid". -** -** Returns 1 on success or 0 on failure (with errno set -** appropriately). Reasons for failure are: ENAMETOOLONG If the pid -** file's path is longer than the system path limit. open(2). -** fcntl(2). write(2). */ - - -int daemon_pidfile(const char *name) +/* Creates a pid file for a daemon. For now, only O_EXCL style + locking. Returns 1 on success or 0 on failure. */ +int +daemon_pidfile(const char *name) { int fd; @@ -100,90 +88,9 @@ int daemon_pidfile(const char *name) return 0; } + /* FIXME: We could try to detect and ignore stale pid files. */ werror("Pid file '%z' already exists.\n", name); return 0; - - /* FIXME: Various trickery to detect and ignore stale pid files. - * Disabled for now. */ -#if 0 - /* Attempt to lock and read the file */ - { - struct flock lock; - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - - int fd = open(name, O_RDWR); - - if (fcntl(fd, F_SETLK, &lock) < 0) - { - werror("pid file '%z' exists and is locked.\n"); - return 0; - } - } - fd = open(name, O_RDONLY); - if (fd < 0) - { - werror("Pid file '%z' already exists, and is unreadable %e\n", - name, errno); - return 0; - } - { - /* Read some characters */ -#define BUF_SIZE 20 - char buffer[BUF_SIZE]; - - int length = read(fd, buffer, BUF_SIZE); - close(fd); - - if (length < 0) - { - werror("Pid file '%z' already exists, but read failed %e\n", - name, errno); - return 0; - } - if ( !length|| !buffer[0] || (length == BUF_SIZE) ) - { - werror("Pid file '%z' already exists, but contents is garbled.\n", - name); - return 0; - } - - buffer[length] = '\0'; - - { - long other; - char *end; - - /* FIXME: strtol is somewhat inconvenient, too forgiving, - * and possibly locale dependent. */ - other = strtol(buffer, &end, 10); - errno = 0; - - if ( (errno == ERANGE) || (end != buffer + length) - || (other <= 0) || (other != (pid_t) other)) - { - werror("Pid file '%z' already exists, but contents is garbled.\n", - name); - return 0; - } - - if ( (kill((pid_t) other, 0) < 0) - && (errno == SRCH)) - { - werror("pid lock '%z' owned by process %i, which appear to be dead.\n", - name, other); - /* We could try to be clever and delete the file in this - * case, but then we get into race conditions if two - * processes tries to do that simultaneously. */ - } - else - werror("pid lock '%z' owned by process %i, which appears to be alive.\n"); - return 0; - } - } -#endif } else { @@ -211,32 +118,23 @@ int daemon_pidfile(const char *name) } } -/* -** int daemon_started_by_init(void) -** -** Determines whether or not this process was started by init(8). -** If it was, we might be getting respawned so fork(2) and exit(2) -** would be a big mistake. -*/ - -int daemon_started_by_init(void) +/* Determines whether or not this process was started by init(8). If + it was, we might be getting respawned so fork(2) and exit(2) would + be a big mistake. */ +static int +daemon_started_by_init(void) { return (getppid() == 1); } -/* -** int daemon_started_by_inetd(void) -** -** Determines whether or not this process was started by inetd(8). -** If it was, stdin, stdout and stderr would be opened to a socket. -** Closing them would be a big mistake. We also wouldn't need to -** fork(2) and exec(2) because there isn't a controlling terminal -** in sight. -*/ +/* Determines whether or not this process was started by inetd(8). If + it was, stdin, stdout and stderr would be opened to a socket. + Closing stdin and stdout. We also wouldn't need to fork(2) and + exec(2) because there isn't a controlling terminal in sight. */ /* FIXME: Do we need to detect if the socket is listening or connected * to a peer? */ -int +static int daemon_started_by_inetd(void) { int optval; @@ -247,6 +145,17 @@ daemon_started_by_inetd(void) return res == 0; } +enum daemon_mode +daemon_detect(void) +{ + if (daemon_started_by_init()) + return DAEMON_INIT; + else if (daemon_started_by_inetd()) + return DAEMON_INETD; + else + return DAEMON_NORMAL; +} + /* Disable core files */ int daemon_disable_core(void) @@ -268,51 +177,89 @@ daemon_disable_core(void) return 1; } -/* -** int daemon_init(void) -** -** Initialises a daemon: -** Disables core files to prevent security holes. -** If the process wasn't started by init(8) or inetd(8): -** Backgrounds the process to lose process group leadership. -** Becomes a process session leader. -** When SVR4 is defined: -** Backgrounds the process again to lose process group leadership. -** This prevents the process from gaining a controlling terminal. -** Under BSD, you must still include O_NOCTTY when opening terminals -** to prevent the process from gaining a controlling terminal. -** Changes directory to the root directory so as not to hamper umounts. -** Clears the umask to enable explicit file modes. -** If the process wasn't started by inetd(8): -** Closes all files (as determined by sysconf(2)). -** Opens stdin, stdout and stderr to /dev/null in case something needs them. -** If the hup parameter is non-null, -** Registers a SIGHUP handler. -** If the term parameter is non-null, -** Registers a SIGTERM handler. -** If the name parameter is non-null, -** Places the process id in the file system and locks it. -** -** Returns DAEMON_NORMAL, DAEMON_INIT or DAEMON_INETD on success, 0 on -** error (with errno set appropriately). -** -** Reasons for failure are: getrlimit(2), setrlimit(2), fork(2), chdir(2), -** sysconf(2), open(2), dup2(2), daemon_pidfile(), sigemptyset(2), -** sigaddset(2), sigaction(2). */ - -int daemon_init(void) +int +daemon_dup_null(int fd) { - int mode = DAEMON_NORMAL; + int null = open("/dev/null", O_RDWR); + if (null < 0) + { + werror("Opening /dev/null failed: %e\n", errno); + return 0; + } + if (dup2(null, fd) < 0) + { + werror("Failed to redirect fd %i to /dev/null: %e\n", errno); + close(null); + return 0; + } - if (daemon_started_by_init()) - mode = DAEMON_INIT; - else if (daemon_started_by_inetd()) - mode = DAEMON_INETD; - - /* - ** Don't setup a daemon-friendly process context - ** if started by init(8) or inetd(8). - */ + close(null); + return 1; +} + +#if !HAVE_GETDTABLESIZE +#define MAX_CLOSE_FD 1024; +int +getdtablesize(void) +{ + long open_max = sysconf(_SC_OPEN_MAX); + if (open_max < 0 || open_max > MAX_INT) + { + werror("No limit on number of openfiles. Some high fd:s might be left open.\n"); + return MAX_CLOSE_FD; + } + else + return open_max; +} +#endif /* !HAVE_GETDTABLESIZE */ + +/* Try to close all fd:s above stderr. There shouldn't be any open + file descriptors left over by startup scripts and the like, but if + there are anyway, they should be closed so that they aren't + inherited by user processes started by lshd. */ +void +daemon_close_fds(void) +{ + int fd = getdtablesize(); + + while (--fd > 2) + { + int res; + + do + res = close(fd); + while (res < 0 && errno == EINTR); + + if (res == 0) + werror("Closed spurious fd %i\n", fd); + else if (errno != EBADF) + werror("Closing spurious fd %i failed: %e\n", fd, errno); + } +} + +/* Initialises a daemon: + + If the process wasn't started by init(8) or inetd(8): + + Backgrounds the process to lose process group leadership. + + Becomes a process session leader. + + Backgrounds the process again to lose process group leadership. + This prevents the process from gaining a controlling terminal. + Under BSD, you must still include O_NOCTTY when opening terminals + to prevent the process from gaining a controlling terminal. + + Changes directory to the root directory so as not to hamper umounts. + + Clears the umask to enable explicit file modes. +*/ + +int +daemon_init(enum daemon_mode mode) +{ + /* Don't setup a daemon-friendly process context if started by + init(8) or inetd(8). */ if (mode == DAEMON_NORMAL) { @@ -334,17 +281,16 @@ int daemon_init(void) /* Parent */ exit(0); } - /* - ** Become a process session leader. - */ + /* Become a process session leader. */ if (setsid() < 0) - fatal("daemon_init: setsid failed.\n"); + { + werror("daemon_init: setsid failed.\n"); + return 0; + } - /* - ** Lose process session leadership - ** to prevent gaining a controlling - ** terminal in SVR4. + /* Lose process session leadership to prevent gaining a + controlling terminal in SVR4. */ switch (child = fork()) { @@ -378,123 +324,20 @@ int daemon_init(void) } } - /* - ** Enter the root directory to prevent hampering umounts. - */ + /* Enter the root directory to prevent hampering umounts. */ if (chdir(ROOT_DIR) == -1) return 0; - /* - ** Clear umask to enable explicit file modes. - */ - + /* Clear umask to enable explicit file modes. */ umask(0); - { - int fd; - - fd = open("/dev/null", O_RDWR); - - if (fd < 0) - return 0; - - /* Don't close stdin if we are started from inetd. */ - - if ( (mode != DAEMON_INETD) - && (dup2(fd, STDIN_FILENO) < 0)) - { - werror("daemon_init: Failed to redirect stdin to /dev/null.\n"); - close(fd); - return 0; - } - - if ( (dup2(fd, STDOUT_FILENO) < 0) - || (dup2(fd, STDERR_FILENO) < 0) ) - { - werror("daemon_init: Failed to redirect stdout and stderr to /dev/null.\n"); - close(fd); - return 0; - } - - close(fd); - - /* It seems unfriendly to try toclose all fds (and on some - * systems, e.g. the HURD, there are no limits to the number of - * open files. It should be good enough to take care of stdio. */ - -#if 0 - /* - ** Close all open files. - ** Don't forget to open any future - ** tty devices with O_NOCTTY so as - ** to prevent gaining a controlling - ** terminal (not necessary with SVR4). - */ - - if ((nopen = limit_open()) == -1) - return -1; - - for (fd = 0; fd < nopen; ++fd) - close(fd); - - /* - ** Open stdin, stdout and stderr to /dev/null - ** just in case someone expects them to be open. - */ - - if ((fd = open("/dev/null", O_RDWR)) == -1) - return -1; - - /* - ** This is only needed for very strange - ** (hypothetical) posix implementations - ** where STDIN_FILENO != 0 or STDOUT_FILE != 1 - ** or STERR_FILENO != 2 (yeah, right). - */ - - if (fd != STDIN_FILENO) - { - if (dup2(fd, STDIN_FILENO) == -1) - return -1; - - close(fd); - } - - if (dup2(STDIN_FILENO, STDOUT_FILENO) == -1) - return -1; - - if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) - return -1; -#endif - } - -#if 0 - /* - ** Register a SIGHUP handler, if required. - */ - - if (hup && signal_set_handler(SIGHUP, 0, hup) == -1) - return -1; - - /* - ** Register a SIGTERM handler, if required. - */ - - if (term && signal_set_handler(SIGTERM, 0, term) == -1) - return -1; -#endif - return 1; } -/* -** int daemon_close() -** -** Unlinks the daemon's (locked) process id file. -*/ - -int daemon_close(const char *name) +/* Unlinks the daemon's (locked) process id file. */ +int +daemon_close(const char *name) { if (unlink(name) < 0) { -- GitLab