From 69adbb0ce3bb9d5bd569c13aaa3ac8f390c1586a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 31 Jan 2002 23:26:12 +0000 Subject: Fix from Michael Steffens to make signal processing work correctly in winbindd. This is a really good patch that gives full select semantics to the Samba modified select. Jeremy. (This used to be commit 3af16ade173cac24c1ac5eff4a36b439f16ac036) --- source3/client/client.c | 2 +- source3/lib/readline.c | 2 +- source3/lib/select.c | 76 ++++++++++++++++++++++++++++++++------------- source3/lib/util.c | 2 +- source3/lib/util_sock.c | 4 +-- source3/libsmb/nmblib.c | 2 +- source3/nmbd/nmbd_packets.c | 2 +- source3/nsswitch/winbindd.c | 5 ++- source3/smbd/oplock.c | 2 +- source3/smbd/process.c | 2 +- source3/smbd/server.c | 2 +- source3/utils/smbfilter.c | 4 +-- source3/wrepld/server.c | 2 +- 13 files changed, 71 insertions(+), 36 deletions(-) diff --git a/source3/client/client.c b/source3/client/client.c index c491efd194..1daba28b98 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -2169,7 +2169,7 @@ static void readline_callback(void) timeout.tv_sec = 0; timeout.tv_usec = 0; - sys_select_intr(cli->fd+1,&fds,&timeout); + sys_select_intr(cli->fd+1,&fds,NULL,NULL,&timeout); /* We deliberately use receive_smb instead of client_receive_smb as we want to receive diff --git a/source3/lib/readline.c b/source3/lib/readline.c index 013b8516f8..d80c571dd3 100644 --- a/source3/lib/readline.c +++ b/source3/lib/readline.c @@ -51,7 +51,7 @@ static char *smb_readline_replacement(char *prompt, void (*callback)(void), FD_ZERO(&fds); FD_SET(fd,&fds); - if (sys_select_intr(fd+1,&fds,&timeout) == 1) { + if (sys_select_intr(fd+1,&fds,NULL,NULL,&timeout) == 1) { ret = fgets(line, sizeof(line), stdin); return ret; } diff --git a/source3/lib/select.c b/source3/lib/select.c index 5e85d11351..f70268b7ce 100644 --- a/source3/lib/select.c +++ b/source3/lib/select.c @@ -1,5 +1,6 @@ /* - Unix SMB/CIFS implementation. + Unix SMB/Netbios implementation. + Version 3.0 Samba select/poll implementation Copyright (C) Andrew Tridgell 1992-1998 @@ -20,22 +21,23 @@ #include "includes.h" -/* this is here because it allows us to avoid a nasty race in signal handling. +/* This is here because it allows us to avoid a nasty race in signal handling. We need to guarantee that when we get a signal we get out of a select immediately but doing that involves a race condition. We can avoid the race by getting the signal handler to write to a pipe that is in the select/poll list - this means all Samba signal handlers should call sys_select_signal() + This means all Samba signal handlers should call sys_select_signal(). */ + static pid_t initialised; static int select_pipe[2]; static VOLATILE unsigned pipe_written, pipe_read; - /******************************************************************* -call this from all Samba signal handlers if you want to avoid a -nasty signal race condition + Call this from all Samba signal handlers if you want to avoid a + nasty signal race condition. ********************************************************************/ + void sys_select_signal(void) { char c = 1; @@ -47,13 +49,15 @@ void sys_select_signal(void) } /******************************************************************* -like select() but avoids the signal race using a pipe -it also guarantees that fds on return only ever contains bits set -for file descriptors that were readable + Like select() but avoids the signal race using a pipe + it also guuarantees that fds on return only ever contains bits set + for file descriptors that were readable. ********************************************************************/ -int sys_select(int maxfd, fd_set *fds,struct timeval *tval) + +int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval) { int ret, saved_errno; + fd_set *readfds2, readfds_buf; if (initialised != sys_getpid()) { pipe(select_pipe); @@ -76,16 +80,29 @@ int sys_select(int maxfd, fd_set *fds,struct timeval *tval) } maxfd = MAX(select_pipe[0]+1, maxfd); - FD_SET(select_pipe[0], fds); + + /* If readfds is NULL we need to provide our own set. */ + if (readfds) { + readfds2 = readfds; + } else { + readfds2 = &readfds_buf; + FD_ZERO(readfds2); + } + FD_SET(select_pipe[0], readfds2); + errno = 0; - ret = select(maxfd,fds,NULL,NULL,tval); + ret = select(maxfd,readfds2,writefds,errorfds,tval); if (ret <= 0) { - FD_ZERO(fds); + FD_ZERO(readfds2); + if (writefds) + FD_ZERO(writefds); + if (errorfds) + FD_ZERO(errorfds); } - if (FD_ISSET(select_pipe[0], fds)) { - FD_CLR(select_pipe[0], fds); + if (FD_ISSET(select_pipe[0], readfds2)) { + FD_CLR(select_pipe[0], readfds2); ret--; if (ret == 0) { ret = -1; @@ -109,20 +126,35 @@ int sys_select(int maxfd, fd_set *fds,struct timeval *tval) } /******************************************************************* -similar to sys_select() but catch EINTR and continue -this is what sys_select() used to do in Samba + Similar to sys_select() but catch EINTR and continue. + This is what sys_select() used to do in Samba. ********************************************************************/ -int sys_select_intr(int maxfd, fd_set *fds,struct timeval *tval) + +int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval) { int ret; - fd_set fds2; + fd_set *readfds2, readfds_buf, *writefds2, writefds_buf, *errorfds2, errorfds_buf; + + readfds2 = (readfds ? &readfds_buf : NULL); + writefds2 = (writefds ? &writefds_buf : NULL); + errorfds2 = (errorfds ? &errorfds_buf : NULL); do { - fds2 = *fds; - ret = sys_select(maxfd, &fds2, tval); + if (readfds) + readfds_buf = *readfds; + if (writefds) + writefds_buf = *writefds; + if (errorfds) + errorfds_buf = *errorfds; + ret = sys_select(maxfd, readfds2, writefds2, errorfds2, tval); } while (ret == -1 && errno == EINTR); - *fds = fds2; + if (readfds) + *readfds = readfds_buf; + if (writefds) + *writefds = writefds_buf; + if (errorfds) + *errorfds = errorfds_buf; return ret; } diff --git a/source3/lib/util.c b/source3/lib/util.c index 9d000c80f0..8867d37d57 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -642,7 +642,7 @@ void msleep(int t) FD_ZERO(&fds); errno = 0; - sys_select_intr(0,&fds,&tval); + sys_select_intr(0,&fds,NULL,NULL,&tval); GetTimeOfDay(&t2); tdiff = TvalDiff(&t1,&t2); diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index 3d32d77000..daab7933da 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -208,7 +208,7 @@ int read_data_outstanding(int fd, unsigned int time_out) timeout.tv_sec = (time_t) (time_out / 1000); timeout.tv_usec = (long)(1000 * (time_out % 1000)); - selrtn = sys_select_intr(fd + 1, &fds, &timeout); + selrtn = sys_select_intr(fd + 1, &fds, NULL, NULL, &timeout); if (selrtn <= 0) { @@ -283,7 +283,7 @@ static ssize_t read_socket_with_timeout(int fd,char *buf,size_t mincnt,size_t ma FD_ZERO(&fds); FD_SET(fd,&fds); - selrtn = sys_select_intr(fd+1,&fds,&timeout); + selrtn = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout); /* Check if error */ if (selrtn == -1) { diff --git a/source3/libsmb/nmblib.c b/source3/libsmb/nmblib.c index 0d14461547..c78946fa09 100644 --- a/source3/libsmb/nmblib.c +++ b/source3/libsmb/nmblib.c @@ -952,7 +952,7 @@ struct packet_struct *receive_packet(int fd,enum packet_type type,int t) timeout.tv_sec = t/1000; timeout.tv_usec = 1000*(t%1000); - if ((ret = sys_select_intr(fd+1,&fds,&timeout)) == -1) { + if ((ret = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout)) == -1) { /* errno should be EBADF or EINVAL. */ DEBUG(0,("select returned -1, errno = %s (%d)\n", strerror(errno), errno)); return NULL; diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c index 6e5487ae44..a11b30b1dc 100644 --- a/source3/nmbd/nmbd_packets.c +++ b/source3/nmbd/nmbd_packets.c @@ -1817,7 +1817,7 @@ BOOL listen_for_packets(BOOL run_election) BlockSignals(False, SIGTERM); - selrtn = sys_select(FD_SETSIZE,&fds,&timeout); + selrtn = sys_select(FD_SETSIZE,&fds,NULL,NULL,&timeout); /* We can only take signals when we are in the select - block them again here. */ diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c index debe7f716f..02bd3dd877 100644 --- a/source3/nsswitch/winbindd.c +++ b/source3/nsswitch/winbindd.c @@ -168,6 +168,7 @@ static BOOL do_sigterm; static void termination_handler(int signum) { do_sigterm = True; + sys_select_signal(); } static BOOL do_sigusr2; @@ -175,6 +176,7 @@ static BOOL do_sigusr2; static void sigusr2_handler(int signum) { do_sigusr2 = True; + sys_select_signal(); } static BOOL do_sighup; @@ -182,6 +184,7 @@ static BOOL do_sighup; static void sighup_handler(int signum) { do_sighup = True; + sys_select_signal(); } /* Create winbindd socket */ @@ -553,7 +556,7 @@ static void process_loop(int accept_sock) /* Call select */ - selret = select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout); + selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout); if (selret == 0) continue; diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index 16c7db6645..39bcb558f1 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -93,7 +93,7 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou to.tv_sec = timeout / 1000; to.tv_usec = (timeout % 1000) * 1000; - selrtn = sys_select(maxfd+1,fds,&to); + selrtn = sys_select(maxfd+1,fds,NULL,NULL,&to); if (selrtn == -1 && errno == EINTR) { /* could be a kernel oplock interrupt */ diff --git a/source3/smbd/process.c b/source3/smbd/process.c index e7a9d0b644..bf1a1ca9a7 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -193,7 +193,7 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) to.tv_sec = timeout / 1000; to.tv_usec = (timeout % 1000) * 1000; - selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,timeout>0?&to:NULL); + selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,timeout>0?&to:NULL); /* if we get EINTR then maybe we have received an oplock signal - treat this as select returning 1. This is ugly, but diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 3b40cb6191..50f09cf6e6 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -239,7 +239,7 @@ max can be %d\n", memcpy((char *)&lfds, (char *)&listen_set, sizeof(listen_set)); - num = sys_select(FD_SETSIZE,&lfds,NULL); + num = sys_select(FD_SETSIZE,&lfds,NULL,NULL,NULL); if (num == -1 && errno == EINTR) { extern VOLATILE sig_atomic_t reload_after_sighup; diff --git a/source3/utils/smbfilter.c b/source3/utils/smbfilter.c index b05427724e..5a2d394706 100644 --- a/source3/utils/smbfilter.c +++ b/source3/utils/smbfilter.c @@ -137,7 +137,7 @@ static void filter_child(int c, struct in_addr dest_ip) if (s != -1) FD_SET(s, &fds); if (c != -1) FD_SET(c, &fds); - num = sys_select_intr(MAX(s+1, c+1),&fds,NULL); + num = sys_select_intr(MAX(s+1, c+1),&fds,NULL,NULL,NULL); if (num <= 0) continue; if (c != -1 && FD_ISSET(c, &fds)) { @@ -201,7 +201,7 @@ static void start_filter(char *desthost) FD_ZERO(&fds); FD_SET(s, &fds); - num = sys_select_intr(s+1,&fds,NULL); + num = sys_select_intr(s+1,&fds,NULL,NULL,NULL); if (num > 0) { c = accept(s, &addr, &in_addrlen); if (c != -1) { diff --git a/source3/wrepld/server.c b/source3/wrepld/server.c index 8925802e58..d078a833ae 100644 --- a/source3/wrepld/server.c +++ b/source3/wrepld/server.c @@ -380,7 +380,7 @@ static BOOL listen_for_wins_packets(void) BlockSignals(False, SIGTERM); - num = sys_select(FD_SETSIZE, &fds, &timeout); + num = sys_select(FD_SETSIZE, &fds, NULL, NULL, &timeout); /* We can only take signals when we are in the select - block them again here. */ -- cgit