changeset 6396:1b21dfee7bd7 HEAD

Calculate needed fd count better. Make sure we have one unused fd available when exec()ing so it doesn't fail.
author Timo Sirainen <tss@iki.fi>
date Sat, 15 Sep 2007 16:58:18 +0300
parents 1622e332c8ae
children 08eaa53f1aaa
files src/master/login-process.c
diffstat 1 files changed, 14 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/src/master/login-process.c	Sat Sep 15 16:57:11 2007 +0300
+++ b/src/master/login-process.c	Sat Sep 15 16:58:18 2007 +0300
@@ -589,8 +589,8 @@
 	const char *prefix;
 	pid_t pid;
 	ARRAY_TYPE(dup2) dups;
-	unsigned int i, listen_count = 0, ssl_listen_count = 0;
-	int fd[2], log_fd, cur_fd;
+	unsigned int i, fd_limit, listen_count = 0, ssl_listen_count = 0;
+	int fd[2], log_fd, cur_fd, tmp_fd;
 
 	if (group->set->login_uid == 0)
 		i_fatal("Login process must not run as root");
@@ -664,8 +664,8 @@
 		i_fatal("Failed to dup2() fds");
 
 	/* don't close any of these */
-	while (cur_fd >= 0)
-		fd_close_on_exec(cur_fd--, FALSE);
+	for (tmp_fd = 0; tmp_fd <= cur_fd; tmp_fd++)
+		fd_close_on_exec(tmp_fd, FALSE);
 
 	(void)close(fd[0]);
 	(void)close(fd[1]);
@@ -684,15 +684,21 @@
 	}
 
 	restrict_process_size(group->set->login_process_size, (unsigned int)-1);
-	if (group->set->login_process_per_connection)
-		restrict_fd_limit(16 + 2);
-	else
-		restrict_fd_limit(16 + 2*group->set->login_max_connections);
+	fd_limit = 16 + listen_count + ssl_listen_count +
+		2 * (group->set->login_process_per_connection ? 1 :
+		     group->set->login_max_connections);
+	restrict_fd_limit(fd_limit);
 
 	/* make sure we don't leak syslog fd, but do it last so that
 	   any errors above will be logged */
 	closelog();
 
+	/* execv() needs at least one file descriptor. we might have all fds
+	   up to fd_limit used already, so close one we don't care about.
+	   either it succeeds or fails with EBADF, doesn't matter. */
+	i_assert(fd_limit > (unsigned int)cur_fd+1);
+	(void)close(cur_fd+1);
+
 	client_process_exec(group->set->login_executable, "");
 	i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m",
 		       group->set->login_executable);