nfs-ganesha 1.4

gssd_main_loop.c

Go to the documentation of this file.
00001 /*
00002   Copyright (c) 2004 The Regents of the University of Michigan.
00003   All rights reserved.
00004 
00005   Redistribution and use in source and binary forms, with or without
00006   modification, are permitted provided that the following conditions
00007   are met:
00008 
00009   1. Redistributions of source code must retain the above copyright
00010      notice, this list of conditions and the following disclaimer.
00011   2. Redistributions in binary form must reproduce the above copyright
00012      notice, this list of conditions and the following disclaimer in the
00013      documentation and/or other materials provided with the distribution.
00014   3. Neither the name of the University nor the names of its
00015      contributors may be used to endorse or promote products derived
00016      from this software without specific prior written permission.
00017 
00018   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
00019   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00020   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00021   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00022   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
00025   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00026   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00027   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 */
00030 
00031 #ifdef HAVE_CONFIG_H
00032 #include <config.h>
00033 #endif  /* HAVE_CONFIG_H */
00034 
00035 #ifndef _GNU_SOURCE
00036 #define _GNU_SOURCE
00037 #endif
00038 
00039 #include <sys/param.h>
00040 #include <sys/socket.h>
00041 #include <sys/poll.h>
00042 #include <netinet/in.h>
00043 
00044 #include <stdio.h>
00045 #include <stdlib.h>
00046 #include <string.h>
00047 #include <memory.h>
00048 #include <errno.h>
00049 #include <fcntl.h>
00050 #include <signal.h>
00051 #include <unistd.h>
00052 #include <dirent.h>
00053 
00054 #include "gssd.h"
00055 #include "err_util.h"
00056 
00057 extern struct pollfd *pollarray;
00058 extern int pollsize;
00059 
00060 #define POLL_MILLISECS  500
00061 
00062 static volatile int dir_changed = 1;
00063 
00064 static void dir_notify_handler(int sig, siginfo_t *si, void *data)
00065 {
00066         printerr(2, "dir_notify_handler: sig %d si %p data %p\n", sig, si, data);
00067 
00068         dir_changed = 1;
00069 }
00070 
00071 static void
00072 scan_poll_results(int ret)
00073 {
00074         int                     i;
00075         struct clnt_info        *clp;
00076 
00077         for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
00078         {
00079                 i = clp->gssd_poll_index;
00080                 if (i >= 0 && pollarray[i].revents) {
00081                         if (pollarray[i].revents & POLLHUP)
00082                                 dir_changed = 1;
00083                         if (pollarray[i].revents & POLLIN)
00084                                 handle_gssd_upcall(clp);
00085                         pollarray[clp->gssd_poll_index].revents = 0;
00086                         ret--;
00087                         if (!ret)
00088                                 break;
00089                 }
00090                 i = clp->krb5_poll_index;
00091                 if (i >= 0 && pollarray[i].revents) {
00092                         if (pollarray[i].revents & POLLHUP)
00093                                 dir_changed = 1;
00094                         if (pollarray[i].revents & POLLIN)
00095                                 handle_krb5_upcall(clp);
00096                         pollarray[clp->krb5_poll_index].revents = 0;
00097                         ret--;
00098                         if (!ret)
00099                                 break;
00100                 }
00101                 i = clp->spkm3_poll_index;
00102                 if (i >= 0 && pollarray[i].revents) {
00103                         if (pollarray[i].revents & POLLHUP)
00104                                 dir_changed = 1;
00105                         if (pollarray[i].revents & POLLIN)
00106                                 handle_spkm3_upcall(clp);
00107                         pollarray[clp->spkm3_poll_index].revents = 0;
00108                         ret--;
00109                         if (!ret)
00110                                 break;
00111                 }
00112         }
00113 };
00114 
00115 static int
00116 topdirs_add_entry(struct dirent *dent)
00117 {
00118         struct topdirs_info *tdi;
00119 
00120         tdi = calloc(sizeof(struct topdirs_info), 1);
00121         if (tdi == NULL) {
00122                 printerr(0, "ERROR: Couldn't allocate struct topdirs_info\n");
00123                 return -1;
00124         }
00125         tdi->dirname = malloc(PATH_MAX);
00126         if (tdi->dirname == NULL) {
00127                 printerr(0, "ERROR: Couldn't allocate directory name\n");
00128                 free(tdi);
00129                 return -1;
00130         }
00131         snprintf(tdi->dirname, PATH_MAX, "%s/%s", pipefs_dir, dent->d_name);
00132         tdi->fd = open(tdi->dirname, O_RDONLY);
00133         if (tdi->fd != -1) {
00134                 fcntl(tdi->fd, F_SETSIG, DNOTIFY_SIGNAL);
00135                 fcntl(tdi->fd, F_NOTIFY,
00136                       DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
00137         }
00138 
00139         TAILQ_INSERT_HEAD(&topdirs_list, tdi, list);
00140         return 0;
00141 }
00142 
00143 static void
00144 topdirs_free_list(void)
00145 {
00146         struct topdirs_info *tdi;
00147 
00148         TAILQ_FOREACH(tdi, &topdirs_list, list) {
00149                 free(tdi->dirname);
00150                 if (tdi->fd != -1)
00151                         close(tdi->fd);
00152                 TAILQ_REMOVE(&topdirs_list, tdi, list);
00153                 free(tdi);
00154         }
00155 }
00156 
00157 static int
00158 topdirs_init_list(void)
00159 {
00160         DIR             *pipedir;
00161         struct dirent   *dent;
00162         int             ret;
00163 
00164         TAILQ_INIT(&topdirs_list);
00165 
00166         pipedir = opendir(pipefs_dir);
00167         if (pipedir == NULL) {
00168                 printerr(0, "ERROR: could not open rpc_pipefs directory '%s': "
00169                          "%s\n", pipefs_dir, strerror(errno));
00170                 return -1;
00171         }
00172         for (dent = readdir(pipedir); dent != NULL; dent = readdir(pipedir)) {
00173                 if (dent->d_type != DT_DIR ||
00174                     strcmp(dent->d_name, ".") == 0  ||
00175                     strcmp(dent->d_name, "..") == 0) {
00176                         continue;
00177                 }
00178                 ret = topdirs_add_entry(dent);
00179                 if (ret)
00180                         goto out_err;
00181         }
00182         closedir(pipedir);
00183         return 0;
00184 out_err:
00185         topdirs_free_list();
00186         return -1;
00187 }
00188 
00189 void
00190 gssd_run()
00191 {
00192         int                     ret;
00193         struct sigaction        dn_act;
00194         sigset_t                set;
00195 
00196         /* Taken from linux/Documentation/dnotify.txt: */
00197         dn_act.sa_sigaction = dir_notify_handler;
00198         sigemptyset(&dn_act.sa_mask);
00199         dn_act.sa_flags = SA_SIGINFO;
00200         sigaction(DNOTIFY_SIGNAL, &dn_act, NULL);
00201 
00202         /* just in case the signal is blocked... */
00203         sigemptyset(&set);
00204         sigaddset(&set, DNOTIFY_SIGNAL);
00205         sigprocmask(SIG_UNBLOCK, &set, NULL);
00206 
00207         if (topdirs_init_list() != 0)
00208                 return;
00209 
00210         init_client_list();
00211 
00212         printerr(1, "beginning poll\n");
00213         while (1) {
00214                 while (dir_changed) {
00215                         dir_changed = 0;
00216                         if (update_client_list()) {
00217                                 /* Error msg is already printed */
00218                                 exit(1);
00219                         }
00220                 }
00221                 /* race condition here: dir_changed could be set before we
00222                  * enter the poll, and we'd never notice if it weren't for the
00223                  * timeout. */
00224                 ret = poll(pollarray, pollsize, POLL_MILLISECS);
00225                 if (ret < 0) {
00226                         if (errno != EINTR)
00227                                 printerr(0,
00228                                          "WARNING: error return from poll\n");
00229                 } else if (ret == 0) {
00230                         /* timeout */
00231                 } else { /* ret > 0 */
00232                         scan_poll_results(ret);
00233                 }
00234         }
00235         topdirs_free_list();
00236 
00237         return;
00238 }