ctdb-daemon: Add helper process to execute event scripts
authorAmitay Isaacs <amitay@gmail.com>
Mon, 16 Dec 2013 04:40:01 +0000 (15:40 +1100)
committerMartin Schwenke <martin@meltin.net>
Thu, 16 Jan 2014 01:11:37 +0000 (12:11 +1100)
Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Reviewed-by: Martin Schwenke <martin@meltin.net>
ctdb/Makefile.in
ctdb/packaging/RPM/ctdb.spec.in
ctdb/server/ctdb_event_helper.c [new file with mode: 0644]

index 92bd56f2ca2a201eabc5795f03cc76123b461a01..94904bda04e10ff69fa4ebe42e51848d46c61e2a 100755 (executable)
@@ -120,7 +120,7 @@ TEST_BINS=tests/bin/ctdb_bench tests/bin/ctdb_fetch tests/bin/ctdb_fetch_one \
        @INFINIBAND_BINS@
 
 BINS = bin/ctdb @CTDB_SCSI_IO@ bin/smnotify bin/ping_pong bin/ltdbtool \
-       bin/ctdb_lock_helper @CTDB_PMDA@
+       bin/ctdb_lock_helper bin/ctdb_event_helper @CTDB_PMDA@
 
 SBINS = bin/ctdbd
 
@@ -178,6 +178,10 @@ bin/ctdb_lock_helper: server/ctdb_lock_helper.o lib/util/util_file.o $(CTDB_EXTE
        @echo Linking $@
        $(WRAPPER) $(CC) $(CFLAGS) -o $@ server/ctdb_lock_helper.o lib/util/util_file.o $(CTDB_EXTERNAL_OBJ) $(TDB_LIBS) $(LIB_FLAGS)
 
+bin/ctdb_event_helper: server/ctdb_event_helper.o $(SOCKET_WRAPPER_OBJ)
+       @echo Linking $@
+       $(WRAPPER) $(CC) $(CFLAGS) -o $@ server/ctdb_event_helper.o  $(SOCKET_WRAPPER_OBJ) $(LIB_FLAGS)
+
 bin/smnotify: utils/smnotify/gen_xdr.o utils/smnotify/gen_smnotify.o utils/smnotify/smnotify.o $(POPT_OBJ)
        @echo Linking $@
        $(WRAPPER) $(CC) $(CFLAGS) -o $@ utils/smnotify/smnotify.o utils/smnotify/gen_xdr.o utils/smnotify/gen_smnotify.o $(POPT_OBJ) $(LIB_FLAGS)
@@ -332,6 +336,7 @@ install: all manpages $(PMDA_INSTALL)
        $(INSTALLCMD) -m 755 bin/ping_pong $(DESTDIR)$(bindir)
        $(INSTALLCMD) -m 755 bin/ltdbtool $(DESTDIR)$(bindir)
        $(INSTALLCMD) -m 755 bin/ctdb_lock_helper $(DESTDIR)$(bindir)
+       $(INSTALLCMD) -m 755 bin/ctdb_event_helper $(DESTDIR)$(bindir)
        ${INSTALLCMD} -m 644 include/ctdb.h $(DESTDIR)$(includedir)
        ${INSTALLCMD} -m 644 include/ctdb_client.h $(DESTDIR)$(includedir)
        ${INSTALLCMD} -m 644 include/ctdb_protocol.h $(DESTDIR)$(includedir)
index e3a34869327bf9af0f065c6c8e480eb1adff8d5f..b2520c369337a5b76ec1d636e8307f984e7d7986 100644 (file)
@@ -192,6 +192,7 @@ rm -rf $RPM_BUILD_ROOT
 %{_sbindir}/ctdbd_wrapper
 %{_bindir}/ctdb
 %{_bindir}/ctdb_lock_helper
+%{_bindir}/ctdb_event_helper
 %{_bindir}/smnotify
 %{_bindir}/ping_pong
 %{_bindir}/ltdbtool
diff --git a/ctdb/server/ctdb_event_helper.c b/ctdb/server/ctdb_event_helper.c
new file mode 100644 (file)
index 0000000..4c62e41
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+   ctdb event script helper
+
+   Copyright (C) Amitay Isaacs  2013
+
+   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/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+
+static char *progname = NULL;
+
+
+/* CTDB sends SIGTERM, when process must die */
+static void sigterm(int sig)
+{
+       pid_t pid;
+
+       /* all the child processes are running in the same process group */
+       pid = getpgrp();
+       if (pid == -1) {
+               kill(-getpid(), SIGKILL);
+       } else {
+               kill(-pid, SIGKILL);
+       }
+       _exit(0);
+}
+
+static void set_close_on_exec(int fd)
+{
+       int v;
+
+       v = fcntl(fd, F_GETFD, 0);
+       if (v == -1) {
+               return;
+       }
+       fcntl(fd, F_SETFD, v | FD_CLOEXEC);
+}
+
+static int check_executable(const char *path)
+{
+       struct stat st;
+
+       if (stat(path, &st) != 0) {
+               fprintf(stderr, "Failed to access '%s' - %s\n",
+                       path, strerror(errno));
+               return errno;
+       }
+
+       if (!(st.st_mode & S_IXUSR)) {
+               return ENOEXEC;
+       }
+
+       return 0;
+}
+
+static void usage(void)
+{
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Usage: %s <log-fd> <output-fd> <script_path> <event> [<args>]\n",
+               progname);
+}
+
+int main(int argc, char *argv[])
+{
+       int log_fd, write_fd;
+       pid_t pid;
+       int status, output;
+
+       progname = argv[0];
+
+       if (argc < 5) {
+               usage();
+               exit(1);
+       }
+
+       log_fd = atoi(argv[1]);
+       write_fd = atoi(argv[2]);
+
+       set_close_on_exec(write_fd);
+
+       close(STDOUT_FILENO);
+       close(STDERR_FILENO);
+       dup2(log_fd, STDOUT_FILENO);
+       dup2(log_fd, STDERR_FILENO);
+       close(log_fd);
+
+       if (setpgid(0, 0) != 0) {
+               fprintf(stderr, "Failed to create process group for event script - %s\n",
+                       strerror(errno));
+               exit(1);
+       }
+
+       signal(SIGTERM, sigterm);
+
+       pid = fork();
+       if (pid < 0) {
+               fprintf(stderr, "Failed to fork - %s\n", strerror(errno));
+               exit(errno);
+       }
+
+       if (pid == 0) {
+               int save_errno;
+
+               execv(argv[3], &argv[3]);
+               if (errno == EACCES) {
+                       save_errno = check_executable(argv[3]);
+               } else {
+                       save_errno = errno;
+                       fprintf(stderr, "Error executing '%s' - %s\n",
+                               argv[3], strerror(errno));
+               }
+               _exit(save_errno);
+       }
+
+       waitpid(pid, &status, 0);
+       if (WIFEXITED(status)) {
+               output = -WEXITSTATUS(status);
+               write(write_fd, &output, sizeof(output));
+               exit(output);
+       }
+
+       exit(1);
+}