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>
44 #define PIPEFS_DIR NFS_STATEDIR "/rpc_pipefs"
47 #define DEFAULT_CLD_PATH PIPEFS_DIR "/nfsd/cld"
49 #define UPCALL_VERSION 1
51 /* private data structures */
54 struct event cl_event;
55 struct cld_msg cl_msg;
58 /* global variables */
59 static char *pipepath = DEFAULT_CLD_PATH;
60 static int inotify_fd = -1;
61 static struct event pipedir_event;
63 static struct option longopts[] =
65 { "help", 0, NULL, 'h' },
66 { "foreground", 0, NULL, 'F' },
67 { "debug", 0, NULL, 'd' },
68 { "pipe", 1, NULL, 'p' },
69 { "storagedir", 1, NULL, 's' },
73 /* forward declarations */
74 static void cldcb(int UNUSED(fd), short which, void *data);
79 printf("%s [ -hFd ] [ -p pipe ] [ -s dir ]\n", progname);
82 #define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX)
85 cld_pipe_open(struct cld_client *clnt)
89 xlog(D_GENERAL, "%s: opening upcall pipe %s", __func__, pipepath);
90 fd = open(pipepath, O_RDWR, 0);
92 xlog(L_ERROR, "%s: open of %s failed: %m", __func__, pipepath);
96 if (clnt->cl_event.ev_flags & EVLIST_INIT)
97 event_del(&clnt->cl_event);
102 event_set(&clnt->cl_event, clnt->cl_fd, EV_READ, cldcb, clnt);
103 /* event_add is done by the caller */
108 cld_inotify_cb(int UNUSED(fd), short which, void *data)
113 char evbuf[INOTIFY_EVENT_MAX];
114 char *dirc = NULL, *pname;
115 struct inotify_event *event = (struct inotify_event *)evbuf;
116 struct cld_client *clnt = data;
118 if (which != EV_READ)
121 xlog(D_GENERAL, "%s: called for EV_READ", __func__);
123 dirc = strndup(pipepath, PATH_MAX);
125 xlog(L_ERROR, "%s: unable to allocate memory", __func__);
129 rret = read(inotify_fd, evbuf, INOTIFY_EVENT_MAX);
131 xlog(L_ERROR, "%s: read from inotify fd failed: %m", __func__);
135 /* check to see if we have a filename in the evbuf */
137 xlog(D_GENERAL, "%s: no filename in inotify event", __func__);
141 pname = basename(dirc);
142 elen = strnlen(event->name, event->len);
144 /* does the filename match our pipe? */
145 if (strlen(pname) != elen || memcmp(pname, event->name, elen)) {
146 xlog(D_GENERAL, "%s: wrong filename (%s)", __func__,
151 ret = cld_pipe_open(clnt);
154 /* readd the event for the cl_event pipe */
155 event_add(&clnt->cl_event, NULL);
158 /* pipe must have disappeared, wait for it to come back */
161 /* anything else is fatal */
162 xlog(L_FATAL, "%s: unable to open new pipe (%d). Aborting.",
168 event_add(&pipedir_event, NULL);
173 cld_inotify_setup(void)
178 dirc = strndup(pipepath, PATH_MAX);
180 xlog_err("%s: unable to allocate memory", __func__);
185 dname = dirname(dirc);
187 inotify_fd = inotify_init();
188 if (inotify_fd < 0) {
189 xlog_err("%s: inotify_init failed: %m", __func__);
194 ret = inotify_add_watch(inotify_fd, dname, IN_CREATE);
196 xlog_err("%s: inotify_add_watch failed: %m", __func__);
210 * Set an inotify watch on the directory that should contain the pipe, and then
211 * try to open it. If it fails with anything but -ENOENT, return the error
214 * If it succeeds, then set up the pipe event handler. At that point, set up
215 * the inotify event handler and go ahead and return success.
218 cld_pipe_init(struct cld_client *clnt)
222 xlog(D_GENERAL, "%s: init pipe handlers", __func__);
224 ret = cld_inotify_setup();
229 ret = cld_pipe_open(clnt);
232 /* add the event and we're good to go */
233 event_add(&clnt->cl_event, NULL);
236 /* ignore this error -- cld_inotify_cb will handle it */
240 /* anything else is fatal */
245 /* set event for inotify read */
246 event_set(&pipedir_event, inotify_fd, EV_READ, cld_inotify_cb, clnt);
247 event_add(&pipedir_event, NULL);
253 cld_not_implemented(struct cld_client *clnt)
256 ssize_t bsize, wsize;
257 struct cld_msg *cmsg = &clnt->cl_msg;
259 xlog(D_GENERAL, "%s: downcalling with not implemented error", __func__);
262 cmsg->cm_status = -EOPNOTSUPP;
264 bsize = sizeof(*cmsg);
266 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
268 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
271 /* reopen pipe, just to be sure */
272 ret = cld_pipe_open(clnt);
274 xlog(L_FATAL, "%s: unable to reopen pipe: %d", __func__, ret);
280 cld_create(struct cld_client *clnt)
283 ssize_t bsize, wsize;
284 struct cld_msg *cmsg = &clnt->cl_msg;
286 xlog(D_GENERAL, "%s: create client record.", __func__);
288 ret = sqlite_insert_client(cmsg->cm_u.cm_name.cn_id,
289 cmsg->cm_u.cm_name.cn_len);
291 cmsg->cm_status = ret ? -EREMOTEIO : ret;
293 bsize = sizeof(*cmsg);
295 xlog(D_GENERAL, "Doing downcall with status %d", cmsg->cm_status);
296 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
297 if (wsize != bsize) {
298 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
300 ret = cld_pipe_open(clnt);
302 xlog(L_FATAL, "%s: unable to reopen pipe: %d",
310 cld_remove(struct cld_client *clnt)
313 ssize_t bsize, wsize;
314 struct cld_msg *cmsg = &clnt->cl_msg;
316 xlog(D_GENERAL, "%s: remove client record.", __func__);
318 ret = sqlite_remove_client(cmsg->cm_u.cm_name.cn_id,
319 cmsg->cm_u.cm_name.cn_len);
321 cmsg->cm_status = ret ? -EREMOTEIO : ret;
323 bsize = sizeof(*cmsg);
325 xlog(D_GENERAL, "%s: downcall with status %d", __func__,
327 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
328 if (wsize != bsize) {
329 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
331 ret = cld_pipe_open(clnt);
333 xlog(L_FATAL, "%s: unable to reopen pipe: %d",
341 cld_check(struct cld_client *clnt)
344 ssize_t bsize, wsize;
345 struct cld_msg *cmsg = &clnt->cl_msg;
347 xlog(D_GENERAL, "%s: check client record", __func__);
349 ret = sqlite_check_client(cmsg->cm_u.cm_name.cn_id,
350 cmsg->cm_u.cm_name.cn_len);
353 cmsg->cm_status = ret ? -EACCES : ret;
355 bsize = sizeof(*cmsg);
357 xlog(D_GENERAL, "%s: downcall with status %d", __func__,
359 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
360 if (wsize != bsize) {
361 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
363 ret = cld_pipe_open(clnt);
365 xlog(L_FATAL, "%s: unable to reopen pipe: %d",
373 cld_gracedone(struct cld_client *clnt)
376 ssize_t bsize, wsize;
377 struct cld_msg *cmsg = &clnt->cl_msg;
379 xlog(D_GENERAL, "%s: grace done. cm_gracetime=%ld", __func__,
380 cmsg->cm_u.cm_gracetime);
382 ret = sqlite_remove_unreclaimed(cmsg->cm_u.cm_gracetime);
384 /* set up reply: downcall with 0 status */
385 cmsg->cm_status = ret ? -EREMOTEIO : ret;
387 bsize = sizeof(*cmsg);
389 xlog(D_GENERAL, "Doing downcall with status %d", cmsg->cm_status);
390 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
391 if (wsize != bsize) {
392 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
394 ret = cld_pipe_open(clnt);
396 xlog(L_FATAL, "%s: unable to reopen pipe: %d",
404 cldcb(int UNUSED(fd), short which, void *data)
407 struct cld_client *clnt = data;
408 struct cld_msg *cmsg = &clnt->cl_msg;
410 if (which != EV_READ)
413 len = atomicio(read, clnt->cl_fd, cmsg, sizeof(*cmsg));
415 xlog(L_ERROR, "%s: pipe read failed: %m", __func__);
420 if (cmsg->cm_vers != UPCALL_VERSION) {
421 xlog(L_ERROR, "%s: unsupported upcall version: %hu",
427 switch(cmsg->cm_cmd) {
441 xlog(L_WARNING, "%s: command %u is not yet implemented",
442 __func__, cmsg->cm_cmd);
443 cld_not_implemented(clnt);
446 event_add(&clnt->cl_event, NULL);
450 main(int argc, char **argv)
454 bool foreground = false;
456 char *storagedir = NULL;
457 struct cld_client clnt;
459 memset(&clnt, 0, sizeof(clnt));
461 progname = strdup(basename(argv[0]));
463 fprintf(stderr, "%s: unable to allocate memory.\n", argv[0]);
471 /* process command-line options */
472 while ((arg = getopt_long(argc, argv, "hdFp:s:", longopts,
476 xlog_config(D_ALL, 1);
500 xlog(L_ERROR, "Unable to daemonize: %m");
505 /* set up storage db */
506 rc = sqlite_maindb_init(storagedir);
508 xlog(L_ERROR, "Failed to open main database: %d", rc);
512 /* set up event handler */
513 rc = cld_pipe_init(&clnt);
517 xlog(D_GENERAL, "%s: Starting event dispatch handler.", __func__);
518 rc = event_dispatch();
520 xlog(L_ERROR, "%s: event_dispatch failed: %m", __func__);