diff options
Diffstat (limited to 'src/hooks.c')
-rw-r--r-- | src/hooks.c | 101 |
1 files changed, 76 insertions, 25 deletions
diff --git a/src/hooks.c b/src/hooks.c index be02b18..96f6f83 100644 --- a/src/hooks.c +++ b/src/hooks.c @@ -111,6 +111,45 @@ open_hooks_dir(const char **path_out, char **pathbuf_out) /** + * Run hook file + * + * @param path The path to the hook file + * @param argv `NULL` terminated list of command line arguments + * for the hooks; must contain an unused initial slot, + * which the function will use to provide the zeroth + * argument + */ +static void +run_hook(const char *path, const char *argv[]) +{ +#ifdef WINDOWS + /* TODO [Windows] hooks are not support on Windows */ +#else + switch (fork()) { + case -1: + weprintf("fork:"); + break; + + case 0: + if (dup2(STDOUT_FILENO, STDERR_FILENO) != STDERR_FILENO) { + weprintf("dup2 <stdout> <stderr>:"); + _exit(1); + } + argv[0] = path; + execv(path, (const void *)argv); + if (errno != EACCES) + weprintf("execv %s:", path); + _exit(1); + + default: + /* SIGCHLD is ignored */ + break; + } +#endif +} + + +/** * Run hooks * * @param argv `NULL` terminated list of command line arguments @@ -122,13 +161,44 @@ static void run_hooks(const char *argv[]) { static int looked_up_dir = 0; + static int hook_file_is_regular = 0; + static int hook_file_checked = 0; DIR *dir; struct dirent *f; size_t required; const char *dirpath_static; - if (!looked_up_dir) { + if (hook_file_is_regular) { + goto run_hook_file; + + } else if (hook_file) { + if (!hook_file_checked) { + hook_file_checked = 1; + if (!strcmp(hook_file, "/dev/null") || + !strcmp(hook_file, "/var/empty") || + !strcmp(hook_file, "/var/empty/")) + goto no_hooks; + } + + dir = opendir(hook_file); + if (!dir) { + if (errno == ENOTDIR) { + hook_file_is_regular = 1; + run_hook_file: + run_hook(hook_file, argv); + return; + } + weprintf("opendir %s:", hook_file); + no_hooks: + free(hook_file); + hook_file = NULL; + looked_up_dir = 1; + dirpath = NULL; + return; + } + + } else if (!looked_up_dir) { looked_up_dir = 1; dir = open_hooks_dir(&dirpath_static, &dirpath); if (!dir) @@ -137,6 +207,7 @@ run_hooks(const char *argv[]) dirpath = estrdup(dirpath_static); dirpathsize = dirpathlen = strlen(dirpath); atexit(&cleanup); + } else if (dirpath) { dir = opendir(dirpath); if (!dir) { @@ -144,6 +215,7 @@ run_hooks(const char *argv[]) cleanup(); return; } + } else { return; } @@ -155,32 +227,11 @@ run_hooks(const char *argv[]) required = dirpathlen + sizeof("/") + strlen(f->d_name); if (required > dirpathsize) dirpath = erealloc(dirpath, dirpathsize = required); + stpcpy(stpcpy(&dirpath[dirpathlen], "/"), f->d_name); -#ifdef WINDOWS - /* TODO [Windows] hooks are not support on Windows */ -#else - switch (fork()) { - case -1: - weprintf("fork:"); - break; - - case 0: - if (dup2(STDOUT_FILENO, STDERR_FILENO) != STDERR_FILENO) { - weprintf("dup2 <stdout> <stderr>:"); - _exit(1); - } - stpcpy(stpcpy(&dirpath[dirpathlen], "/"), f->d_name); - argv[0] = dirpath; - execv(dirpath, (const void *)argv); - if (errno != EACCES) - weprintf("execv %s:", dirpath); - _exit(1); + run_hook(dirpath, argv); - default: - /* SIGCHLD is ignored */ - break; - } -#endif + dirpath[dirpathlen] = '\0'; } if (errno) |