nfs-ganesha 1.4
|
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 }