X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fnfsdcld%2Fnfsdcld.c;h=6a1eba8f7d3214ecfbd78f1dc7f6ae34bf644e58;hp=2d118681abbb5f11809898a072cbea1a5d944bf1;hb=b9f64af3b83a2916c5b6cd65fe011acc436942d4;hpb=09d9011c66e518ca7fd01d41607845b940f58c8f diff --git a/utils/nfsdcld/nfsdcld.c b/utils/nfsdcld/nfsdcld.c index 2d11868..6a1eba8 100644 --- a/utils/nfsdcld/nfsdcld.c +++ b/utils/nfsdcld/nfsdcld.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "xlog.h" #include "nfslib.h" @@ -54,6 +56,8 @@ struct cld_client { /* global variables */ static char *pipepath = DEFAULT_CLD_PATH; +static int inotify_fd = -1; +static struct event pipedir_event; static struct option longopts[] = { @@ -74,6 +78,8 @@ usage(char *progname) printf("%s [ -hFd ] [ -p pipe ] [ -s dir ]\n", progname); } +#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX) + static int cld_pipe_open(struct cld_client *clnt) { @@ -97,18 +103,149 @@ cld_pipe_open(struct cld_client *clnt) return 0; } +static void +cld_inotify_cb(int UNUSED(fd), short which, void *data) +{ + int ret; + size_t elen; + ssize_t rret; + char evbuf[INOTIFY_EVENT_MAX]; + char *dirc = NULL, *pname; + struct inotify_event *event = (struct inotify_event *)evbuf; + struct cld_client *clnt = data; + + if (which != EV_READ) + return; + + xlog(D_GENERAL, "%s: called for EV_READ", __func__); + + dirc = strndup(pipepath, PATH_MAX); + if (!dirc) { + xlog(L_ERROR, "%s: unable to allocate memory", __func__); + goto out; + } + + rret = read(inotify_fd, evbuf, INOTIFY_EVENT_MAX); + if (rret < 0) { + xlog(L_ERROR, "%s: read from inotify fd failed: %m", __func__); + goto out; + } + + /* check to see if we have a filename in the evbuf */ + if (!event->len) { + xlog(D_GENERAL, "%s: no filename in inotify event", __func__); + goto out; + } + + pname = basename(dirc); + elen = strnlen(event->name, event->len); + + /* does the filename match our pipe? */ + if (strlen(pname) != elen || memcmp(pname, event->name, elen)) { + xlog(D_GENERAL, "%s: wrong filename (%s)", __func__, + event->name); + goto out; + } + + ret = cld_pipe_open(clnt); + switch (ret) { + case 0: + /* readd the event for the cl_event pipe */ + event_add(&clnt->cl_event, NULL); + break; + case -ENOENT: + /* pipe must have disappeared, wait for it to come back */ + goto out; + default: + /* anything else is fatal */ + xlog(L_FATAL, "%s: unable to open new pipe (%d). Aborting.", + ret, __func__); + exit(ret); + } + +out: + event_add(&pipedir_event, NULL); + free(dirc); +} + +static int +cld_inotify_setup(void) +{ + int ret; + char *dirc, *dname; + + dirc = strndup(pipepath, PATH_MAX); + if (!dirc) { + xlog_err("%s: unable to allocate memory", __func__); + ret = -ENOMEM; + goto out_free; + } + + dname = dirname(dirc); + + inotify_fd = inotify_init(); + if (inotify_fd < 0) { + xlog_err("%s: inotify_init failed: %m", __func__); + ret = -errno; + goto out_free; + } + + ret = inotify_add_watch(inotify_fd, dname, IN_CREATE); + if (ret < 0) { + xlog_err("%s: inotify_add_watch failed: %m", __func__); + ret = -errno; + goto out_err; + } + +out_free: + free(dirc); + return 0; +out_err: + close(inotify_fd); + goto out_free; +} + +/* + * Set an inotify watch on the directory that should contain the pipe, and then + * try to open it. If it fails with anything but -ENOENT, return the error + * immediately. + * + * If it succeeds, then set up the pipe event handler. At that point, set up + * the inotify event handler and go ahead and return success. + */ static int cld_pipe_init(struct cld_client *clnt) { int ret; + xlog(D_GENERAL, "%s: init pipe handlers", __func__); + + ret = cld_inotify_setup(); + if (ret != 0) + goto out; + clnt->cl_fd = -1; ret = cld_pipe_open(clnt); - if (ret) - return ret; + switch (ret) { + case 0: + /* add the event and we're good to go */ + event_add(&clnt->cl_event, NULL); + break; + case -ENOENT: + /* ignore this error -- cld_inotify_cb will handle it */ + ret = 0; + break; + default: + /* anything else is fatal */ + close(inotify_fd); + goto out; + } - event_add(&clnt->cl_event, NULL); - return 0; + /* set event for inotify read */ + event_set(&pipedir_event, inotify_fd, EV_READ, cld_inotify_cb, clnt); + event_add(&pipedir_event, NULL); +out: + return ret; } static void @@ -382,6 +519,7 @@ main(int argc, char **argv) xlog(L_ERROR, "%s: event_dispatch failed: %m", __func__); close(clnt.cl_fd); + close(inotify_fd); out: free(progname); return rc;