diff --git a/plugins/pidfile.c b/plugins/pidfile.c index ad5b6241..753ba07a 100644 --- a/plugins/pidfile.c +++ b/plugins/pidfile.c @@ -25,8 +25,6 @@ #include #include #include -#include -#include #include "finit.h" #include "cond.h" @@ -34,28 +32,15 @@ #include "pid.h" #include "plugin.h" #include "service.h" - -struct iwatch_path { - TAILQ_ENTRY(iwatch_path) link; - char *path; - int wd; -}; - -struct iwatch { - int fd; - TAILQ_HEAD(, iwatch_path) iwp_list; -}; +#include "iwatch.h" static struct iwatch iw_pidfile; -static int iwatch_add(struct iwatch *iw, char *path) -{ - struct iwatch_path *iwp; - uint32_t mask = IN_ONLYDIR | IN_CREATE | IN_ATTRIB | IN_DELETE | IN_MODIFY | IN_MOVED_TO; - char *ptr; - int wd; - _d("pidfile: Adding new watcher for path %s", path); +static int pidfile_add_path(struct iwatch *iw, char *path) +{ + char *ptr; + ptr = strstr(path, "run/"); if (ptr) { char *slash; @@ -66,44 +51,16 @@ static int iwatch_add(struct iwatch *iw, char *path) ptr = slash++; slash = strchr(ptr, '/'); if (slash) { - _d("pidfile: Path too deep, skipping."); + _d("Path too deep, skipping."); return -1; } } } - wd = inotify_add_watch(iw->fd, path, mask); - if (wd < 0) { - _pe("inotify_add_watch()"); - return -1; - } - - iwp = malloc(sizeof(struct iwatch_path)); - if (!iwp) { - _pe("Failed allocating new `struct iwatch_path`"); - inotify_rm_watch(iw->fd, wd); - return -1; - } - - iwp->path = path; - iwp->wd = wd; - TAILQ_INSERT_HEAD(&iw->iwp_list, iwp, link); - - return 0; + return iwatch_add(iw, path, IN_ONLYDIR); } -static int iwatch_del(struct iwatch *iw, struct iwatch_path *iwp) -{ - _d("pidfile: Removing watcher for removed path %s", iwp->path); - TAILQ_REMOVE(&iw->iwp_list, iwp, link); - inotify_rm_watch(iw->fd, iwp->wd); - free(iwp->path); - free(iwp); - - return 0; -} - -static void update_conds(char *dir, char *name, uint32_t mask) +static void pidfile_update_conds(char *dir, char *name, uint32_t mask) { char cond[MAX_COND_LEN]; char fn[PATH_MAX]; @@ -114,11 +71,11 @@ static void update_conds(char *dir, char *name, uint32_t mask) svc = svc_find_by_pidfile(fn); if (!svc) { - _d("pidfile: No matching svc for %s", fn); + _d("No matching svc for %s", fn); return; } - _d("pidfile: Found svc %s for %s with pid %d", svc->name, fn, svc->pid); + _d("Found svc %s for %s with pid %d", svc->name, fn, svc->pid); mkcond(svc, cond, sizeof(cond)); if (mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) { @@ -138,7 +95,7 @@ static void update_conds(char *dir, char *name, uint32_t mask) } /* synthesize events in case of new run dirs */ -static void scan_for_pidfiles(struct iwatch *iw, char *dir, int len) +static void pidfile_scandir(struct iwatch *iw, char *dir, int len) { glob_t gl; size_t i; @@ -157,47 +114,33 @@ static void scan_for_pidfiles(struct iwatch *iw, char *dir, int len) for (i = 0; i < gl.gl_pathc; i++) { _d("scan found %s", gl.gl_pathv[i]); - update_conds(dir, gl.gl_pathv[i], IN_CREATE); + pidfile_update_conds(dir, gl.gl_pathv[i], IN_CREATE); } globfree(&gl); } -static void handle_dir(struct iwatch *iw, struct iwatch_path *iwp, char *name, int mask) +/* + * create/remove sub-directory in monitored directory + */ +static void pidfile_handle_dir(struct iwatch *iw, char *dir, char *name, int mask) { - char *path; - int plen; - int exist = 0; + char path[strlen(dir) + strlen(name) + 2]; + struct iwatch_path *iwp; - plen = snprintf(NULL, 0, "%s/%s", iwp->path, name) + 1; - path = malloc(plen); - if (!path) { - _pe("Failed allocating path buffer for watcher"); - return; - } - snprintf(path, plen, "%s/%s", iwp->path, name); - _d("pidfile: path is %s", path); + snprintf(path, sizeof(path), "%s/%s", dir, name); + _d("path: %s", path); - TAILQ_FOREACH(iwp, &iw->iwp_list, link) { - if (!strcmp(iwp->path, path)) { - exist = 1; - break; - } - } + iwp = iwatch_find_by_path(iw, path); if (mask & IN_CREATE) { - if (!exist) { - int rc = iwatch_add(iw, path); - - scan_for_pidfiles(iw, path, plen); - if (!rc) - return; + if (!iwp) { + pidfile_add_path(iw, path); + pidfile_scandir(iw, path, sizeof(path)); } } else if (mask & IN_DELETE) { - if (exist) + if (iwp) iwatch_del(&iw_pidfile, iwp); } - - free(path); } static void pidfile_callback(void *arg, int fd, int events) @@ -213,14 +156,14 @@ static void pidfile_callback(void *arg, int fd, int events) return; } - _d("pidfile: Entering ... reading %zu bytes into ev_buf[]", buflen - 1); + _d("Entering ... reading %zu bytes into ev_buf[]", buflen - 1); sz = read(fd, buf, buflen - 1); if (sz <= 0) { _pe("invalid inotify event"); goto done; } buf[sz] = 0; - _d("pidfile: Read %zd bytes, processing ...", sz); + _d("Read %zd bytes, processing ...", sz); off = 0; for (off = 0; off < sz; off += sizeof(*ev) + ev->len) { @@ -228,18 +171,17 @@ static void pidfile_callback(void *arg, int fd, int events) ev = (struct inotify_event *)&buf[off]; - _d("pidfile: path %s, event: 0x%08x", ev->name, ev->mask); + _d("path %s, event: 0x%08x", ev->name, ev->mask); if (!ev->mask) continue; /* Find base path for this event */ - TAILQ_FOREACH(iwp, &iw_pidfile.iwp_list, link) { - if (iwp->wd == ev->wd) - break; - } + iwp = iwatch_find_by_wd(&iw_pidfile, ev->wd); + if (!iwp) + continue; if (ev->mask & IN_ISDIR) { - handle_dir(&iw_pidfile, iwp, ev->name, ev->mask); + pidfile_handle_dir(&iw_pidfile, iwp->path, ev->name, ev->mask); continue; } @@ -249,7 +191,7 @@ static void pidfile_callback(void *arg, int fd, int events) } if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) - update_conds(iwp->path, ev->name, ev->mask); + pidfile_update_conds(iwp->path, ev->name, ev->mask); } done: free(buf); @@ -305,14 +247,10 @@ static void pidfile_init(void *arg) return; } - TAILQ_INIT(&iw_pidfile.iwp_list); - if (iwatch_add(&iw_pidfile, path)) - close(iw_pidfile.fd); - _d("pidfile monitor active"); + if (pidfile_add_path(&iw_pidfile, path)) + iwatch_exit(&iw_pidfile); } -static struct iwatch iw_pidfile; - /* * When performing an `initctl reload` with one (unchanged) service * depending on, e.g. `net/iface/lo`, its condition will not be set @@ -340,27 +278,19 @@ static plugin_t plugin = { PLUGIN_INIT(plugin_init) { - iw_pidfile.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); - if (iw_pidfile.fd < 0) { - _pe("inotify_init()"); - return; - } + int fd; - plugin.io.fd = iw_pidfile.fd; + fd = iwatch_init(&iw_pidfile); + if (fd < 0) + return; + + plugin.io.fd = fd; plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { - struct iwatch_path *iwp, *tmp; - - TAILQ_FOREACH_SAFE(iwp, &iw_pidfile.iwp_list, link, tmp) { - inotify_rm_watch(iw_pidfile.fd, iwp->wd); - free(iwp->path); - free(iwp); - } - close(iw_pidfile.fd); - + iwatch_exit(&iw_pidfile); plugin_unregister(&plugin); } diff --git a/src/Makefile.am b/src/Makefile.am index 491efa6c..c3198a80 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,6 +26,7 @@ finit_SOURCES = api.c cgroup.c cgroup.h \ exec.c finit.c finit.h \ getty.c stty.c \ helpers.c helpers.h \ + iwatch.c iwatch.h \ log.c log.h \ mdadm.c mount.c \ pid.c pid.h \ diff --git a/src/iwatch.c b/src/iwatch.c new file mode 100644 index 00000000..41cc18fd --- /dev/null +++ b/src/iwatch.c @@ -0,0 +1,118 @@ +#include + +#include "finit.h" +#include "iwatch.h" +#include "log.h" + + +int iwatch_init(struct iwatch *iw) +{ + if (!iw) { + errno = EINVAL; + return -1; + } + + TAILQ_INIT(&iw->iwp_list); + + iw->fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (iw->fd < 0) { + _pe("inotify_init()"); + return -1; + } + + return iw->fd; +} + +void iwatch_exit(struct iwatch *iw) +{ + struct iwatch_path *iwp, *tmp; + + TAILQ_FOREACH_SAFE(iwp, &iw->iwp_list, link, tmp) { + TAILQ_REMOVE(&iw->iwp_list, iwp, link); + inotify_rm_watch(iw->fd, iwp->wd); + free(iwp->path); + free(iwp); + } + + close(iw->fd); +} + +int iwatch_add(struct iwatch *iw, char *file, uint32_t mask) +{ + struct iwatch_path *iwp; + char *path; + int wd; + + _d("Adding new watcher for path %s", file); + + path = strdup(file); + if (!path) { + _pe("Out of memory"); + return -1; + } + + wd = inotify_add_watch(iw->fd, path, IWATCH_MASK | mask); + if (wd < 0) { + _pe("inotify_add_watch(%s)", path); + free(path); + return -1; + } + + iwp = malloc(sizeof(struct iwatch_path)); + if (!iwp) { + _pe("Failed allocating new `struct iwatch_path`"); + inotify_rm_watch(iw->fd, wd); + free(path); + return -1; + } + + iwp->path = path; + iwp->wd = wd; + TAILQ_INSERT_HEAD(&iw->iwp_list, iwp, link); + + return 0; +} + +int iwatch_del(struct iwatch *iw, struct iwatch_path *iwp) +{ + _d("Removing watcher for removed path %s", iwp->path); + + TAILQ_REMOVE(&iw->iwp_list, iwp, link); + inotify_rm_watch(iw->fd, iwp->wd); + free(iwp->path); + free(iwp); + + return 0; +} + +struct iwatch_path *iwatch_find_by_wd(struct iwatch *iw, int wd) +{ + struct iwatch_path *iwp; + + TAILQ_FOREACH(iwp, &iw->iwp_list, link) { + if (iwp->wd == wd) + return iwp; + } + + return NULL; +} + +struct iwatch_path *iwatch_find_by_path(struct iwatch *iw, const char *path) +{ + struct iwatch_path *iwp; + + TAILQ_FOREACH(iwp, &iw->iwp_list, link) { + if (!strcmp(iwp->path, path)) + return iwp; + } + + return NULL; +} + +/** + * Local Variables: + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */ + diff --git a/src/iwatch.h b/src/iwatch.h new file mode 100644 index 00000000..b59c3fb9 --- /dev/null +++ b/src/iwatch.h @@ -0,0 +1,64 @@ +/* inotify watcher for files or directories + * + * Copyright (c) 2015-2016 Tobias Waldekranz + * Copyright (c) 2016-2021 Joachim Wiberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef FINIT_IWATCH_H_ +#define FINIT_IWATCH_H_ + +#include +#include +#include + + +/* Monitors changes to both directories and files by default */ +#define IWATCH_MASK (IN_CREATE | IN_DELETE | IN_MODIFY | IN_ATTRIB | IN_MOVE) + +struct iwatch_path { + TAILQ_ENTRY(iwatch_path) link; + char *path; + int wd; +}; + +struct iwatch { + int fd; + TAILQ_HEAD(, iwatch_path) iwp_list; +}; + + +int iwatch_init (struct iwatch *iw); +void iwatch_exit (struct iwatch *iw); + +int iwatch_add (struct iwatch *iw, char *file, uint32_t mask); +int iwatch_del (struct iwatch *iw, struct iwatch_path *iwp); + +struct iwatch_path *iwatch_find_by_wd (struct iwatch *iw, int wd); +struct iwatch_path *iwatch_find_by_path (struct iwatch *iw, const char *path); + +#endif /* FINIT_IWATCH_H_ */ + +/** + * Local Variables: + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */