2 * nfsdcld.c -- NFSv4 client name tracking daemon
4 * Copyright (C) 2011 Red Hat, Jeff Layton <jlayton@redhat.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
24 #endif /* HAVE_CONFIG_H */
32 #include <sys/types.h>
36 #include <sys/inotify.h>
43 #define PIPEFS_DIR NFS_STATEDIR "/rpc_pipefs"
46 #define DEFAULT_CLD_PATH PIPEFS_DIR "/nfsd/cld"
48 #define UPCALL_VERSION 1
50 /* private data structures */
53 struct event cl_event;
54 struct cld_msg cl_msg;
57 /* global variables */
58 static char *pipepath = DEFAULT_CLD_PATH;
59 static int inotify_fd = -1;
60 static struct event pipedir_event;
62 static struct option longopts[] =
64 { "help", 0, NULL, 'h' },
65 { "foreground", 0, NULL, 'F' },
66 { "debug", 0, NULL, 'd' },
67 { "pipe", 1, NULL, 'p' },
68 { "storagedir", 1, NULL, 's' },
72 /* forward declarations */
73 static void cldcb(int UNUSED(fd), short which, void *data);
78 printf("%s [ -hFd ] [ -p pipe ] [ -s dir ]\n", progname);
81 #define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX)
84 cld_pipe_open(struct cld_client *clnt)
88 xlog(D_GENERAL, "%s: opening upcall pipe %s", __func__, pipepath);
89 fd = open(pipepath, O_RDWR, 0);
91 xlog(L_ERROR, "%s: open of %s failed: %m", __func__, pipepath);
95 if (clnt->cl_event.ev_flags & EVLIST_INIT)
96 event_del(&clnt->cl_event);
101 event_set(&clnt->cl_event, clnt->cl_fd, EV_READ, cldcb, clnt);
102 /* event_add is done by the caller */
107 cld_inotify_cb(int UNUSED(fd), short which, void *data)
112 char evbuf[INOTIFY_EVENT_MAX];
113 char *dirc = NULL, *pname;
114 struct inotify_event *event = (struct inotify_event *)evbuf;
115 struct cld_client *clnt = data;
117 if (which != EV_READ)
120 xlog(D_GENERAL, "%s: called for EV_READ", __func__);
122 dirc = strndup(pipepath, PATH_MAX);
124 xlog(L_ERROR, "%s: unable to allocate memory", __func__);
128 rret = read(inotify_fd, evbuf, INOTIFY_EVENT_MAX);
130 xlog(L_ERROR, "%s: read from inotify fd failed: %m", __func__);
134 /* check to see if we have a filename in the evbuf */
136 xlog(D_GENERAL, "%s: no filename in inotify event", __func__);
140 pname = basename(dirc);
141 elen = strnlen(event->name, event->len);
143 /* does the filename match our pipe? */
144 if (strlen(pname) != elen || memcmp(pname, event->name, elen)) {
145 xlog(D_GENERAL, "%s: wrong filename (%s)", __func__,
150 ret = cld_pipe_open(clnt);
153 /* readd the event for the cl_event pipe */
154 event_add(&clnt->cl_event, NULL);
157 /* pipe must have disappeared, wait for it to come back */
160 /* anything else is fatal */
161 xlog(L_FATAL, "%s: unable to open new pipe (%d). Aborting.",
167 event_add(&pipedir_event, NULL);
172 cld_inotify_setup(void)
177 dirc = strndup(pipepath, PATH_MAX);
179 xlog_err("%s: unable to allocate memory", __func__);
184 dname = dirname(dirc);
186 inotify_fd = inotify_init();
187 if (inotify_fd < 0) {
188 xlog_err("%s: inotify_init failed: %m", __func__);
193 ret = inotify_add_watch(inotify_fd, dname, IN_CREATE);
195 xlog_err("%s: inotify_add_watch failed: %m", __func__);
209 * Set an inotify watch on the directory that should contain the pipe, and then
210 * try to open it. If it fails with anything but -ENOENT, return the error
213 * If it succeeds, then set up the pipe event handler. At that point, set up
214 * the inotify event handler and go ahead and return success.
217 cld_pipe_init(struct cld_client *clnt)
221 xlog(D_GENERAL, "%s: init pipe handlers", __func__);
223 ret = cld_inotify_setup();
228 ret = cld_pipe_open(clnt);
231 /* add the event and we're good to go */
232 event_add(&clnt->cl_event, NULL);
235 /* ignore this error -- cld_inotify_cb will handle it */
239 /* anything else is fatal */
244 /* set event for inotify read */
245 event_set(&pipedir_event, inotify_fd, EV_READ, cld_inotify_cb, clnt);
246 event_add(&pipedir_event, NULL);
252 cld_not_implemented(struct cld_client *clnt)
255 ssize_t bsize, wsize;
256 struct cld_msg *cmsg = &clnt->cl_msg;
258 xlog(D_GENERAL, "%s: downcalling with not implemented error", __func__);
261 cmsg->cm_status = -EOPNOTSUPP;
263 bsize = sizeof(*cmsg);
265 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
267 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
270 /* reopen pipe, just to be sure */
271 ret = cld_pipe_open(clnt);
273 xlog(L_FATAL, "%s: unable to reopen pipe: %d", __func__, ret);
279 cld_create(struct cld_client *clnt)
282 ssize_t bsize, wsize;
283 struct cld_msg *cmsg = &clnt->cl_msg;
285 xlog(D_GENERAL, "%s: create client record.", __func__);
287 ret = sqlite_insert_client(cmsg->cm_u.cm_name.cn_id,
288 cmsg->cm_u.cm_name.cn_len);
290 cmsg->cm_status = ret ? -EREMOTEIO : ret;
292 bsize = sizeof(*cmsg);
294 xlog(D_GENERAL, "Doing downcall with status %d", cmsg->cm_status);
295 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
296 if (wsize != bsize) {
297 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
299 ret = cld_pipe_open(clnt);
301 xlog(L_FATAL, "%s: unable to reopen pipe: %d",
309 cld_remove(struct cld_client *clnt)
312 ssize_t bsize, wsize;
313 struct cld_msg *cmsg = &clnt->cl_msg;
315 xlog(D_GENERAL, "%s: remove client record.", __func__);
317 ret = sqlite_remove_client(cmsg->cm_u.cm_name.cn_id,
318 cmsg->cm_u.cm_name.cn_len);
320 cmsg->cm_status = ret ? -EREMOTEIO : ret;
322 bsize = sizeof(*cmsg);
324 xlog(D_GENERAL, "%s: downcall with status %d", __func__,
326 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
327 if (wsize != bsize) {
328 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
330 ret = cld_pipe_open(clnt);
332 xlog(L_FATAL, "%s: unable to reopen pipe: %d",
340 cld_check(struct cld_client *clnt)
343 ssize_t bsize, wsize;
344 struct cld_msg *cmsg = &clnt->cl_msg;
346 xlog(D_GENERAL, "%s: check client record", __func__);
348 ret = sqlite_check_client(cmsg->cm_u.cm_name.cn_id,
349 cmsg->cm_u.cm_name.cn_len);
352 cmsg->cm_status = ret ? -EACCES : ret;
354 bsize = sizeof(*cmsg);
356 xlog(D_GENERAL, "%s: downcall with status %d", __func__,
358 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
359 if (wsize != bsize) {
360 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
362 ret = cld_pipe_open(clnt);
364 xlog(L_FATAL, "%s: unable to reopen pipe: %d",
372 cld_gracedone(struct cld_client *clnt)
375 ssize_t bsize, wsize;
376 struct cld_msg *cmsg = &clnt->cl_msg;
378 xlog(D_GENERAL, "%s: grace done. cm_gracetime=%ld", __func__,
379 cmsg->cm_u.cm_gracetime);
381 ret = sqlite_remove_unreclaimed(cmsg->cm_u.cm_gracetime);
383 /* set up reply: downcall with 0 status */
384 cmsg->cm_status = ret ? -EREMOTEIO : ret;
386 bsize = sizeof(*cmsg);
388 xlog(D_GENERAL, "Doing downcall with status %d", cmsg->cm_status);
389 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
390 if (wsize != bsize) {
391 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
393 ret = cld_pipe_open(clnt);
395 xlog(L_FATAL, "%s: unable to reopen pipe: %d",
403 cldcb(int UNUSED(fd), short which, void *data)
406 struct cld_client *clnt = data;
407 struct cld_msg *cmsg = &clnt->cl_msg;
409 if (which != EV_READ)
412 len = atomicio(read, clnt->cl_fd, cmsg, sizeof(*cmsg));
414 xlog(L_ERROR, "%s: pipe read failed: %m", __func__);
419 if (cmsg->cm_vers != UPCALL_VERSION) {
420 xlog(L_ERROR, "%s: unsupported upcall version: %hu",
426 switch(cmsg->cm_cmd) {
440 xlog(L_WARNING, "%s: command %u is not yet implemented",
441 __func__, cmsg->cm_cmd);
442 cld_not_implemented(clnt);
445 event_add(&clnt->cl_event, NULL);
449 main(int argc, char **argv)
453 bool foreground = false;
455 char *storagedir = NULL;
456 struct cld_client clnt;
458 memset(&clnt, 0, sizeof(clnt));
460 progname = strdup(basename(argv[0]));
462 fprintf(stderr, "%s: unable to allocate memory.\n", argv[0]);
470 /* process command-line options */
471 while ((arg = getopt_long(argc, argv, "hdFp:s:", longopts,
475 xlog_config(D_ALL, 1);
499 xlog(L_ERROR, "Unable to daemonize: %m");
504 /* set up storage db */
505 rc = sqlite_maindb_init(storagedir);
507 xlog(L_ERROR, "Failed to open main database: %d", rc);
511 /* set up event handler */
512 rc = cld_pipe_init(&clnt);
516 xlog(D_GENERAL, "%s: Starting event dispatch handler.", __func__);
517 rc = event_dispatch();
519 xlog(L_ERROR, "%s: event_dispatch failed: %m", __func__);