]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/gssd/gssd_main_loop.c
Release 1.2.5
[nfs-utils.git] / utils / gssd / gssd_main_loop.c
1 /*
2   Copyright (c) 2004 The Regents of the University of Michigan.
3   All rights reserved.
4
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions
7   are met:
8
9   1. Redistributions of source code must retain the above copyright
10      notice, this list of conditions and the following disclaimer.
11   2. Redistributions in binary form must reproduce the above copyright
12      notice, this list of conditions and the following disclaimer in the
13      documentation and/or other materials provided with the distribution.
14   3. Neither the name of the University nor the names of its
15      contributors may be used to endorse or promote products derived
16      from this software without specific prior written permission.
17
18   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif  /* HAVE_CONFIG_H */
34
35 #ifndef _GNU_SOURCE
36 #define _GNU_SOURCE
37 #endif
38
39 #include <sys/param.h>
40 #include <sys/socket.h>
41 #include <sys/poll.h>
42 #include <netinet/in.h>
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <memory.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <signal.h>
51 #include <unistd.h>
52 #include <dirent.h>
53
54 #include "gssd.h"
55 #include "err_util.h"
56
57 extern struct pollfd *pollarray;
58 extern int pollsize;
59
60 #define POLL_MILLISECS  500
61
62 static volatile int dir_changed = 1;
63
64 static void dir_notify_handler(int sig, siginfo_t *si, void *data)
65 {
66         printerr(2, "dir_notify_handler: sig %d si %p data %p\n", sig, si, data);
67
68         dir_changed = 1;
69 }
70
71 static void
72 scan_poll_results(int ret)
73 {
74         int                     i;
75         struct clnt_info        *clp;
76
77         for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
78         {
79                 i = clp->gssd_poll_index;
80                 if (i >= 0 && pollarray[i].revents) {
81                         if (pollarray[i].revents & POLLHUP)
82                                 dir_changed = 1;
83                         if (pollarray[i].revents & POLLIN)
84                                 handle_gssd_upcall(clp);
85                         pollarray[clp->gssd_poll_index].revents = 0;
86                         ret--;
87                         if (!ret)
88                                 break;
89                 }
90                 i = clp->krb5_poll_index;
91                 if (i >= 0 && pollarray[i].revents) {
92                         if (pollarray[i].revents & POLLHUP)
93                                 dir_changed = 1;
94                         if (pollarray[i].revents & POLLIN)
95                                 handle_krb5_upcall(clp);
96                         pollarray[clp->krb5_poll_index].revents = 0;
97                         ret--;
98                         if (!ret)
99                                 break;
100                 }
101                 i = clp->spkm3_poll_index;
102                 if (i >= 0 && pollarray[i].revents) {
103                         if (pollarray[i].revents & POLLHUP)
104                                 dir_changed = 1;
105                         if (pollarray[i].revents & POLLIN)
106                                 handle_spkm3_upcall(clp);
107                         pollarray[clp->spkm3_poll_index].revents = 0;
108                         ret--;
109                         if (!ret)
110                                 break;
111                 }
112         }
113 };
114
115 static int
116 topdirs_add_entry(struct dirent *dent)
117 {
118         struct topdirs_info *tdi;
119
120         tdi = calloc(sizeof(struct topdirs_info), 1);
121         if (tdi == NULL) {
122                 printerr(0, "ERROR: Couldn't allocate struct topdirs_info\n");
123                 return -1;
124         }
125         tdi->dirname = malloc(PATH_MAX);
126         if (tdi->dirname == NULL) {
127                 printerr(0, "ERROR: Couldn't allocate directory name\n");
128                 free(tdi);
129                 return -1;
130         }
131         snprintf(tdi->dirname, PATH_MAX, "%s/%s", pipefs_dir, dent->d_name);
132         tdi->fd = open(tdi->dirname, O_RDONLY);
133         if (tdi->fd != -1) {
134                 fcntl(tdi->fd, F_SETSIG, DNOTIFY_SIGNAL);
135                 fcntl(tdi->fd, F_NOTIFY,
136                       DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
137         }
138
139         TAILQ_INSERT_HEAD(&topdirs_list, tdi, list);
140         return 0;
141 }
142
143 static void
144 topdirs_free_list(void)
145 {
146         struct topdirs_info *tdi;
147
148         TAILQ_FOREACH(tdi, &topdirs_list, list) {
149                 free(tdi->dirname);
150                 if (tdi->fd != -1)
151                         close(tdi->fd);
152                 TAILQ_REMOVE(&topdirs_list, tdi, list);
153                 free(tdi);
154         }
155 }
156
157 static int
158 topdirs_init_list(void)
159 {
160         DIR             *pipedir;
161         struct dirent   *dent;
162         int             ret;
163
164         TAILQ_INIT(&topdirs_list);
165
166         pipedir = opendir(pipefs_dir);
167         if (pipedir == NULL) {
168                 printerr(0, "ERROR: could not open rpc_pipefs directory '%s': "
169                          "%s\n", pipefs_dir, strerror(errno));
170                 return -1;
171         }
172         for (dent = readdir(pipedir); dent != NULL; dent = readdir(pipedir)) {
173                 if (dent->d_type != DT_DIR ||
174                     strcmp(dent->d_name, ".") == 0  ||
175                     strcmp(dent->d_name, "..") == 0) {
176                         continue;
177                 }
178                 ret = topdirs_add_entry(dent);
179                 if (ret)
180                         goto out_err;
181         }
182         closedir(pipedir);
183         return 0;
184 out_err:
185         topdirs_free_list();
186         return -1;
187 }
188
189 void
190 gssd_run()
191 {
192         int                     ret;
193         struct sigaction        dn_act;
194         sigset_t                set;
195
196         /* Taken from linux/Documentation/dnotify.txt: */
197         dn_act.sa_sigaction = dir_notify_handler;
198         sigemptyset(&dn_act.sa_mask);
199         dn_act.sa_flags = SA_SIGINFO;
200         sigaction(DNOTIFY_SIGNAL, &dn_act, NULL);
201
202         /* just in case the signal is blocked... */
203         sigemptyset(&set);
204         sigaddset(&set, DNOTIFY_SIGNAL);
205         sigprocmask(SIG_UNBLOCK, &set, NULL);
206
207         if (topdirs_init_list() != 0)
208                 return;
209
210         init_client_list();
211
212         printerr(1, "beginning poll\n");
213         while (1) {
214                 while (dir_changed) {
215                         dir_changed = 0;
216                         if (update_client_list()) {
217                                 /* Error msg is already printed */
218                                 exit(1);
219                         }
220                 }
221                 /* race condition here: dir_changed could be set before we
222                  * enter the poll, and we'd never notice if it weren't for the
223                  * timeout. */
224                 ret = poll(pollarray, pollsize, POLL_MILLISECS);
225                 if (ret < 0) {
226                         if (errno != EINTR)
227                                 printerr(0,
228                                          "WARNING: error return from poll\n");
229                 } else if (ret == 0) {
230                         /* timeout */
231                 } else { /* ret > 0 */
232                         scan_poll_results(ret);
233                 }
234         }
235         topdirs_free_list();
236
237         return;
238 }