X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fgssd%2Fgssd_main_loop.c;h=ccf7fe534009fad885ce404d82178ba2b6426b7c;hp=84f04e96eda218cc236e835067b8e0728f27191c;hb=41f32cd96eca95a2730603ebc539440c48a1dda5;hpb=ca5f2d1e16a6451c1df203bccfd8944ee84c728f diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c index 84f04e9..ccf7fe5 100644 --- a/utils/gssd/gssd_main_loop.c +++ b/utils/gssd/gssd_main_loop.c @@ -28,9 +28,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif + #include #include #include @@ -44,18 +49,19 @@ #include #include #include +#include #include "gssd.h" #include "err_util.h" extern struct pollfd *pollarray; -extern int pollsize; +extern unsigned long pollsize; #define POLL_MILLISECS 500 static volatile int dir_changed = 1; -static void dir_notify_handler(int sig, siginfo_t *si, void *data) +static void dir_notify_handler(__attribute__((unused))int sig) { dir_changed = 1; } @@ -68,51 +74,166 @@ scan_poll_results(int ret) for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) { - i = clp->krb5_poll_index; + i = clp->gssd_poll_index; if (i >= 0 && pollarray[i].revents) { - if (pollarray[i].revents & POLLHUP) + if (pollarray[i].revents & POLLHUP) { + clp->gssd_close_me = 1; dir_changed = 1; + } if (pollarray[i].revents & POLLIN) - handle_krb5_upcall(clp); - pollarray[clp->krb5_poll_index].revents = 0; + handle_gssd_upcall(clp); + pollarray[clp->gssd_poll_index].revents = 0; ret--; if (!ret) break; } - i = clp->spkm3_poll_index; + i = clp->krb5_poll_index; if (i >= 0 && pollarray[i].revents) { - if (pollarray[i].revents & POLLHUP) + if (pollarray[i].revents & POLLHUP) { + clp->krb5_close_me = 1; dir_changed = 1; + } if (pollarray[i].revents & POLLIN) - handle_spkm3_upcall(clp); - pollarray[clp->spkm3_poll_index].revents = 0; + handle_krb5_upcall(clp); + pollarray[clp->krb5_poll_index].revents = 0; ret--; if (!ret) break; } } -}; +} + +static int +topdirs_add_entry(struct dirent *dent) +{ + struct topdirs_info *tdi; + + tdi = calloc(sizeof(struct topdirs_info), 1); + if (tdi == NULL) { + printerr(0, "ERROR: Couldn't allocate struct topdirs_info\n"); + return -1; + } + tdi->dirname = malloc(PATH_MAX); + if (tdi->dirname == NULL) { + printerr(0, "ERROR: Couldn't allocate directory name\n"); + free(tdi); + return -1; + } + snprintf(tdi->dirname, PATH_MAX, "%s/%s", pipefs_dir, dent->d_name); + tdi->fd = open(tdi->dirname, O_RDONLY); + if (tdi->fd == -1) { + printerr(0, "ERROR: failed to open %s\n", tdi->dirname); + free(tdi); + return -1; + } + fcntl(tdi->fd, F_SETSIG, DNOTIFY_SIGNAL); + fcntl(tdi->fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT); + + TAILQ_INSERT_HEAD(&topdirs_list, tdi, list); + return 0; +} + +static void +topdirs_free_list(void) +{ + struct topdirs_info *tdi; + + TAILQ_FOREACH(tdi, &topdirs_list, list) { + free(tdi->dirname); + if (tdi->fd != -1) + close(tdi->fd); + TAILQ_REMOVE(&topdirs_list, tdi, list); + free(tdi); + } +} + +static int +topdirs_init_list(void) +{ + DIR *pipedir; + struct dirent *dent; + int ret; + + TAILQ_INIT(&topdirs_list); + + pipedir = opendir(pipefs_dir); + if (pipedir == NULL) { + printerr(0, "ERROR: could not open rpc_pipefs directory '%s': " + "%s\n", pipefs_dir, strerror(errno)); + return -1; + } + for (dent = readdir(pipedir); dent != NULL; dent = readdir(pipedir)) { + if (dent->d_type != DT_DIR || + strcmp(dent->d_name, ".") == 0 || + strcmp(dent->d_name, "..") == 0) { + continue; + } + ret = topdirs_add_entry(dent); + if (ret) + goto out_err; + } + closedir(pipedir); + return 0; +out_err: + topdirs_free_list(); + return -1; +} + +#ifdef HAVE_PPOLL +static void gssd_poll(struct pollfd *fds, unsigned long nfds) +{ + sigset_t emptyset; + int ret; + + sigemptyset(&emptyset); + ret = ppoll(fds, nfds, NULL, &emptyset); + if (ret < 0) { + if (errno != EINTR) + printerr(0, "WARNING: error return from poll\n"); + } else if (ret == 0) { + printerr(0, "WARNING: unexpected timeout\n"); + } else { + scan_poll_results(ret); + } +} +#else /* !HAVE_PPOLL */ +static void gssd_poll(struct pollfd *fds, unsigned long nfds) +{ + int ret; + + /* race condition here: dir_changed could be set before we + * enter the poll, and we'd never notice if it weren't for the + * timeout. */ + ret = poll(fds, nfds, POLL_MILLISECS); + if (ret < 0) { + if (errno != EINTR) + printerr(0, "WARNING: error return from poll\n"); + } else if (ret == 0) { + /* timeout */ + } else { /* ret > 0 */ + scan_poll_results(ret); + } +} +#endif /* !HAVE_PPOLL */ void gssd_run() { - int ret; - struct sigaction dn_act; - int fd; + struct sigaction dn_act = { + .sa_handler = dir_notify_handler + }; + sigset_t set; - /* Taken from linux/Documentation/dnotify.txt: */ - dn_act.sa_sigaction = dir_notify_handler; sigemptyset(&dn_act.sa_mask); - dn_act.sa_flags = SA_SIGINFO; sigaction(DNOTIFY_SIGNAL, &dn_act, NULL); - if ((fd = open(pipefs_nfsdir, O_RDONLY)) == -1) { - printerr(0, "ERROR: failed to open %s: %s\n", - pipefs_nfsdir, strerror(errno)); - exit(1); - } - fcntl(fd, F_SETSIG, DNOTIFY_SIGNAL); - fcntl(fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT); + /* just in case the signal is blocked... */ + sigemptyset(&set); + sigaddset(&set, DNOTIFY_SIGNAL); + sigprocmask(SIG_UNBLOCK, &set, NULL); + + if (topdirs_init_list() != 0) + return; init_client_list(); @@ -121,25 +242,13 @@ gssd_run() while (dir_changed) { dir_changed = 0; if (update_client_list()) { - printerr(0, "ERROR: couldn't update " - "client list\n"); + /* Error msg is already printed */ exit(1); } } - /* race condition here: dir_changed could be set before we - * enter the poll, and we'd never notice if it weren't for the - * timeout. */ - ret = poll(pollarray, pollsize, POLL_MILLISECS); - if (ret < 0) { - if (errno != EINTR) - printerr(0, - "WARNING: error return from poll\n"); - } else if (ret == 0) { - /* timeout */ - } else { /* ret > 0 */ - scan_poll_results(ret); - } + gssd_poll(pollarray, pollsize); } - close(fd); + topdirs_free_list(); + return; }