Quoth Jani Nikula on Dec 09 at 12:48 am: > Add mechanism for running user defined hooks. Hooks are executables or > symlinks to executables stored under the new notmuch hooks directory, > <database-path>/.notmuch/hooks. > > No hooks are introduced here, but adding support for a hook is now a simple > matter of calling the new notmuch_run_hook() function at an appropriate > location with the hook name. > > Signed-off-by: Jani Nikula <jani@nikula.org> > --- > Makefile.local | 1 + > hooks.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > notmuch-client.h | 3 ++ > 3 files changed, 97 insertions(+), 0 deletions(-) > create mode 100644 hooks.c > > diff --git a/Makefile.local b/Makefile.local > index 15e6d88..88365da 100644 > --- a/Makefile.local > +++ b/Makefile.local > @@ -298,6 +298,7 @@ notmuch_client_srcs = \ > debugger.c \ > gmime-filter-reply.c \ > gmime-filter-headers.c \ > + hooks.c \ > notmuch.c \ > notmuch-config.c \ > notmuch-count.c \ > diff --git a/hooks.c b/hooks.c > new file mode 100644 > index 0000000..44ee419 > --- /dev/null > +++ b/hooks.c > @@ -0,0 +1,93 @@ > +/* notmuch - Not much of an email program, (just index and search) > + * > + * This file is part of notmuch. > + * > + * Copyright © 2011 Jani Nikula > + * > + * This program is free software: you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation, either version 3 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program. If not, see http://www.gnu.org/licenses/ . > + * > + * Author: Jani Nikula <jani@nikula.org> > + */ > + > +#include "notmuch-client.h" > +#include <sys/wait.h> > + > +int > +notmuch_run_hook (const char *db_path, const char *hook) > +{ > + char *hook_path; > + int status = 0; > + pid_t pid; > + > + hook_path = talloc_asprintf (NULL, "%s/%s/%s/%s", db_path, ".notmuch", > + "hooks", hook); > + if (hook_path == NULL) { > + fprintf (stderr, "Out of memory\n"); > + return 1; > + } > + > + /* Check access before fork() for speed and simplicity of error handling. */ > + if (access (hook_path, X_OK) == -1) { > + /* Ignore ENOENT. It's okay not to have a hook, hook dir, or even > + * notmuch dir. Dangling symbolic links also result in ENOENT, but > + * we'll ignore that too for simplicity. */ > + if (errno != ENOENT) { > + fprintf (stderr, "Error: %s hook access failed: %s\n", hook, > + strerror (errno)); > + status = 1; > + } Is it the intent that a present but non-executable hook (errno == EACCES) will print the above error message and return with a failure? I'm pretty sure this differs from the behavior of git hooks. Other than this, this patch looks good to me. > + goto DONE; > + } > + > + pid = fork(); > + if (pid == -1) { > + fprintf (stderr, "Error: %s hook fork failed: %s\n", hook, > + strerror (errno)); > + status = 1; > + goto DONE; > + } else if (pid == 0) { > + execl (hook_path, hook_path, NULL); > + /* Same as above for ENOENT, but unlikely now. Indicate all other errors > + * to parent through non-zero exit status. */ > + if (errno != ENOENT) { > + fprintf (stderr, "Error: %s hook execution failed: %s\n", hook, > + strerror (errno)); > + status = 1; > + } > + exit (status); > + } > + > + if (waitpid (pid, &status, 0) == -1) { > + fprintf (stderr, "Error: %s hook wait failed: %s\n", hook, > + strerror (errno)); > + status = 1; > + goto DONE; > + } > + > + if (!WIFEXITED (status) || WEXITSTATUS (status)) { > + if (WIFEXITED (status)) { > + fprintf (stderr, "Error: %s hook failed with status %d\n", > + hook, WEXITSTATUS (status)); > + } else if (WIFSIGNALED (status)) { > + fprintf (stderr, "Error: %s hook terminated with signal %d\n", > + hook, WTERMSIG (status)); > + } > + status = 1; > + } > + > + DONE: > + talloc_free (hook_path); > + > + return status; > +} > diff --git a/notmuch-client.h b/notmuch-client.h > index b50cb38..a91ad6c 100644 > --- a/notmuch-client.h > +++ b/notmuch-client.h > @@ -235,6 +235,9 @@ void > notmuch_config_set_maildir_synchronize_flags (notmuch_config_t *config, > notmuch_bool_t synchronize_flags); > > +int > +notmuch_run_hook (const char *db_path, const char *hook); > + > notmuch_bool_t > debugger_is_active (void);