nbd-proxy: replace hook dir with a single executable
A future change will run the executable asynchronously. With a directory
of hooks, this gets overly complicated.
Replace the directory-of-hooks concept with a single hook. The hook
itself can then spawn multiple hooks if required (eg, with run-parts).
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
diff --git a/README b/README
index 0d3030e..d7e1ec7 100644
--- a/README
+++ b/README
@@ -54,12 +54,12 @@
websocket proxy should implement proper authentication before nbd-proxy is
connected to the websocket endpoint.
-State hooks
------------
+State hook
+----------
-The nbd-proxy has a facility to run hooks on state change. When a
-nbd session is established or shut down, the proxy will run any executables
-found under the hook path (by default, /etc/nbd-proxy/state.d/).
+The nbd-proxy has a facility to run an program on state change. When a nbd
+session is established or shut down, the proxy will run the executable at
+/etc/nbd-proxy/state.
-These hooks are called with two arguments: the action ("start" or "stop"),
+This executable is called with two arguments: the action ("start" or "stop"),
and the name of the configuration (as specified in the config.json file).
diff --git a/nbd-proxy.c b/nbd-proxy.c
index 6e932ad..2db70df 100644
--- a/nbd-proxy.c
+++ b/nbd-proxy.c
@@ -69,14 +69,12 @@
};
static const char *conf_path = SYSCONFDIR "/nbd-proxy/config.json";
-static const char *state_hook_path = SYSCONFDIR "/nbd-proxy/state.d";
+static const char *state_hook_path = SYSCONFDIR "/nbd-proxy/state";
static const char *sockpath_tmpl = RUNSTATEDIR "/nbd.%d.sock";
static const size_t bufsize = 0x20000;
static const int nbd_timeout_default = 30;
-#define BUILD_ASSERT_OR_ZERO(c) (sizeof(struct {int:-!(c);}))
-
static int open_nbd_socket(struct ctx *ctx)
{
struct sockaddr_un addr;
@@ -352,40 +350,29 @@
return 0;
}
-#define join_paths(p1, p2, r) \
- (BUILD_ASSERT_OR_ZERO(sizeof(r) > PATH_MAX) + __join_paths(p1, p2, r))
-static int __join_paths(const char *p1, const char *p2, char res[])
-{
- size_t len;
- char *pos;
-
- len = strlen(p1) + 1 + strlen(p2);
- if (len > PATH_MAX)
- return -1;
-
- pos = res;
- strcpy(pos, p1);
- pos += strlen(p1);
- *pos = '/';
- pos++;
- strcpy(pos, p2);
-
- return 0;
-}
-
-static int run_state_hook(struct ctx *ctx,
- const char *path, const char *name, const char *action)
+static int run_state_hook(struct ctx *ctx, const char *action)
{
int status, rc, fd;
pid_t pid;
+ /* if the hook isn't present or executable, that's not necessarily
+ * an error condition */
+ if (!access(state_hook_path, X_OK))
+ return 0;
+
pid = fork();
if (pid < 0) {
- warn("can't fork to execute hook %s", name);
+ warn("can't fork to execute hook %s", state_hook_path);
return -1;
}
if (!pid) {
+ const char *argv0;
+
+ argv0 = strchr(state_hook_path, '/');
+ if (!argv0)
+ argv0 = state_hook_path;
+
fd = open("/dev/null", O_RDWR | O_CLOEXEC);
if (fd < 0)
exit(EXIT_FAILURE);
@@ -393,7 +380,7 @@
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
- execl(path, name, action, ctx->config->name, NULL);
+ execl(state_hook_path, argv0, action, ctx->config->name, NULL);
exit(EXIT_FAILURE);
}
@@ -404,60 +391,13 @@
}
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- warnx("hook %s failed", name);
+ warnx("hook %s failed", state_hook_path);
return -1;
}
return 0;
}
-static int run_state_hooks(struct ctx *ctx, const char *action)
-{
- struct dirent *dirent;
- DIR *dir;
- int rc;
-
- dir = opendir(state_hook_path);
- if (!dir)
- return 0;
-
- rc = 0;
-
- for (dirent = readdir(dir); dirent; dirent = readdir(dir)) {
- char full_path[PATH_MAX+1];
- struct stat statbuf;
-
- if (dirent->d_name[0] == '.')
- continue;
-
- rc = fstatat(dirfd(dir), dirent->d_name, &statbuf, 0);
- if (rc) {
- rc = 0;
- continue;
- }
-
- if (!(S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)))
- continue;
-
- if (faccessat(dirfd(dir), dirent->d_name, X_OK, 0))
- continue;
-
- rc = join_paths(state_hook_path, dirent->d_name, full_path);
- if (rc) {
- rc = 0;
- continue;
- }
-
- rc = run_state_hook(ctx, full_path, dirent->d_name, action);
- if (rc)
- break;
- }
-
- closedir(dir);
-
- return rc;
-}
-
static int udev_init(struct ctx *ctx)
{
int rc;
@@ -536,7 +476,7 @@
ctx->monitor = NULL;
ctx->udev = NULL;
- rc = run_state_hooks(ctx, "start");
+ rc = run_state_hook(ctx, "start");
return rc;
}
@@ -886,7 +826,7 @@
if (ctx->udev)
udev_free(ctx);
- run_state_hooks(ctx, "stop");
+ run_state_hook(ctx, "stop");
out_stop_client:
/* we cleanup signals before stopping the client, because we