The branch, master has been updated
       via  8d818e1 ctdb-tools: Always exit with positive return value
       via  a64a83f ctdb-eventd: Avoid passing NULL pointer to printf( %s )
       via  b0293ce ctdb-eventd: Use run_event abstraction
       via  98ee7e7 ctdb-common: Add run_event abstraction
       via  16c188c ctdb-common: Update run_proc api to re-assign stdin
      from  15367ce s4/torture: add a leases test with stat open

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 8d818e18c2ba0385b96e0fd9385dc77b23cf43b1
Author: Amitay Isaacs <ami...@gmail.com>
Date:   Tue Mar 7 16:44:08 2017 +1100

    ctdb-tools: Always exit with positive return value
    
    Signed-off-by: Amitay Isaacs <ami...@gmail.com>
    Reviewed-by: Martin Schwenke <mar...@meltin.net>
    
    Autobuild-User(master): Martin Schwenke <mart...@samba.org>
    Autobuild-Date(master): Tue May 30 08:05:56 CEST 2017 on sn-devel-144

commit a64a83f08a09fbafa0c86171a0f639cc7d4c03f5
Author: Amitay Isaacs <ami...@gmail.com>
Date:   Mon May 29 12:36:11 2017 +1000

    ctdb-eventd: Avoid passing NULL pointer to printf( %s )
    
    Signed-off-by: Amitay Isaacs <ami...@gmail.com>
    Reviewed-by: Martin Schwenke <mar...@meltin.net>

commit b0293ce826e307e3af9750f174355c08815edf6e
Author: Amitay Isaacs <ami...@gmail.com>
Date:   Mon Feb 27 15:00:42 2017 +1100

    ctdb-eventd: Use run_event abstraction
    
    Signed-off-by: Amitay Isaacs <ami...@gmail.com>
    Reviewed-by: Martin Schwenke <mar...@meltin.net>

commit 98ee7e799171c270460d966a4d4700072eb41ed0
Author: Amitay Isaacs <ami...@gmail.com>
Date:   Thu Feb 23 18:40:48 2017 +1100

    ctdb-common: Add run_event abstraction
    
    Signed-off-by: Amitay Isaacs <ami...@gmail.com>
    Reviewed-by: Martin Schwenke <mar...@meltin.net>

commit 16c188c7f8e335e5c8c191148be2f8347020178a
Author: Amitay Isaacs <ami...@gmail.com>
Date:   Sat May 6 02:47:00 2017 +1000

    ctdb-common: Update run_proc api to re-assign stdin
    
    This allows to pass data to a child process via stdin.
    
    Signed-off-by: Amitay Isaacs <ami...@gmail.com>
    Reviewed-by: Martin Schwenke <mar...@meltin.net>

-----------------------------------------------------------------------

Summary of changes:
 ctdb/common/run_event.c           | 796 ++++++++++++++++++++++++++++++++++++
 ctdb/common/run_event.h           | 148 +++++++
 ctdb/common/run_proc.c            |  13 +-
 ctdb/common/run_proc.h            |   3 +-
 ctdb/server/ctdb_eventd.c         | 835 ++++++--------------------------------
 ctdb/tests/cunit/run_event_001.sh | 134 ++++++
 ctdb/tests/cunit/run_proc_001.sh  |  38 +-
 ctdb/tests/src/run_event_test.c   | 205 ++++++++++
 ctdb/tests/src/run_proc_test.c    |  14 +-
 ctdb/tools/ctdb_event.c           |   3 +-
 ctdb/wscript                      |   5 +-
 11 files changed, 1468 insertions(+), 726 deletions(-)
 create mode 100644 ctdb/common/run_event.c
 create mode 100644 ctdb/common/run_event.h
 create mode 100755 ctdb/tests/cunit/run_event_001.sh
 create mode 100644 ctdb/tests/src/run_event_test.c


Changeset truncated at 500 lines:

diff --git a/ctdb/common/run_event.c b/ctdb/common/run_event.c
new file mode 100644
index 0000000..e5d562c
--- /dev/null
+++ b/ctdb/common/run_event.c
@@ -0,0 +1,796 @@
+/*
+   Run scripts in a directory with specific event arguments
+
+   Copyright (C) Amitay Isaacs  2017
+
+   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 "replace.h"
+#include "system/filesys.h"
+#include "system/dir.h"
+#include "system/locale.h"
+#include "system/wait.h"
+
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/tevent_unix.h"
+#include "lib/util/debug.h"
+
+#include "common/logging.h"
+#include "common/run_proc.h"
+#include "common/run_event.h"
+
+/*
+ * Utility functions
+ */
+
+static int script_filter(const struct dirent *de)
+{
+       size_t namelen = strlen(de->d_name);
+       char *ptr;
+
+       /* Ignore . and .. */
+       if (namelen < 3) {
+               return 0;
+       }
+
+       /* Skip filenames with ~ */
+       ptr = strchr(de->d_name, '~');
+       if (ptr != NULL) {
+               return 0;
+       }
+
+       /* Filename should start with [0-9][0-9]. */
+       if ((! isdigit(de->d_name[0])) ||
+           (! isdigit(de->d_name[1])) ||
+           (de->d_name[2] != '.')) {
+               return 0;
+       }
+
+       return 1;
+}
+
+static int get_script_list(TALLOC_CTX *mem_ctx,
+                          const char *script_dir,
+                          struct run_event_script_list **out)
+{
+       struct dirent **namelist = NULL;
+       struct run_event_script_list *script_list;
+       int count, ret;
+       int i;
+
+       count = scandir(script_dir, &namelist, script_filter, alphasort);
+       if (count == -1) {
+               ret = errno;
+               if (ret == ENOENT) {
+                       D_WARNING("event script dir %s removed\n", script_dir);
+               } else {
+                       D_WARNING("scandir() failed on %s, ret=%d\n",
+                                 script_dir, ret);
+               }
+               *out = NULL;
+               ret = 0;
+               goto done;
+       }
+
+       if (count == 0) {
+               *out = NULL;
+               ret = 0;
+               goto done;
+       }
+
+       script_list = talloc_zero(mem_ctx, struct run_event_script_list);
+       if (script_list == NULL) {
+               return ENOMEM;
+       }
+
+       script_list->num_scripts = count;
+       script_list->script = talloc_zero_array(script_list,
+                                               struct run_event_script,
+                                               count);
+       if (script_list->script == NULL) {
+               ret = ENOMEM;
+               talloc_free(script_list);
+               goto done;
+       }
+
+       for (i=0; i<count; i++) {
+               struct run_event_script *s = &script_list->script[i];
+
+               s->name = talloc_strdup(script_list, namelist[i]->d_name);
+               if (s->name == NULL) {
+                       ret = ENOMEM;
+                       talloc_free(script_list);
+                       goto done;
+               }
+       }
+
+       *out = script_list;
+       ret = 0;
+
+done:
+       if (namelist != NULL && count != -1) {
+               for (i=0; i<count; i++) {
+                       free(namelist[i]);
+               }
+               free(namelist);
+       }
+       return ret;
+}
+
+static int script_chmod(TALLOC_CTX *mem_ctx, const char *script_dir,
+                       const char *script_name, bool enable)
+{
+       DIR *dirp;
+       struct dirent *de;
+       int ret, new_mode;
+       char *filename;
+       struct stat st;
+       bool found;
+       int fd = -1;
+
+       dirp = opendir(script_dir);
+       if (dirp == NULL) {
+               return errno;
+       }
+
+       found = false;
+       while ((de = readdir(dirp)) != NULL) {
+               if (strcmp(de->d_name, script_name) == 0) {
+
+                       /* check for valid script names */
+                       ret = script_filter(de);
+                       if (ret == 0) {
+                               closedir(dirp);
+                               return EINVAL;
+                       }
+
+                       found = true;
+                       break;
+               }
+       }
+       closedir(dirp);
+
+       if (! found) {
+               return ENOENT;
+       }
+
+       filename = talloc_asprintf(mem_ctx, "%s/%s", script_dir, script_name);
+       if (filename == NULL) {
+               return ENOMEM;
+       }
+
+       fd = open(filename, O_RDWR);
+       if (fd == -1) {
+               ret = errno;
+               goto done;
+       }
+
+       ret = fstat(fd, &st);
+       if (ret != 0) {
+               ret = errno;
+               goto done;
+       }
+
+       if (enable) {
+               new_mode = st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH);
+       } else {
+               new_mode = st.st_mode & ~(S_IXUSR | S_IXGRP | S_IXOTH);
+       }
+
+       ret = fchmod(fd, new_mode);
+       if (ret != 0) {
+               ret = errno;
+               goto done;
+       }
+
+done:
+       if (fd != -1) {
+               close(fd);
+       }
+       talloc_free(filename);
+       return ret;
+}
+
+static int script_args(TALLOC_CTX *mem_ctx, const char *event_str,
+                      const char *arg_str, const char ***out)
+{
+       const char **argv;
+       int argc;
+       size_t len;
+
+       /* Preallocate argv array to avoid reallocation. */
+       len = 8;
+       argv = talloc_array(mem_ctx, const char *, len);
+       if (argv == NULL) {
+               return ENOMEM;
+       }
+
+       argv[0] = NULL; /* script name */
+       argv[1] = event_str;
+       argc = 2;
+
+       if (arg_str != NULL) {
+               char *str, *t, *tok;
+
+               str = talloc_strdup(argv, arg_str);
+               if (str == NULL) {
+                       return ENOMEM;
+               }
+
+               t = str;
+               while ((tok = strtok(t, " ")) != NULL) {
+                       argv[argc] = talloc_strdup(argv, tok);
+                       if (argv[argc] == NULL) {
+                               talloc_free(argv);
+                               return ENOMEM;
+                       }
+                       argc += 1;
+                       if (argc >= len) {
+                               argv = talloc_realloc(mem_ctx, argv,
+                                                     const char *, len + 8);
+                               if (argv == NULL) {
+                                       return ENOMEM;
+                               }
+                               len += 8;
+                       }
+                       t = NULL;
+               }
+
+               talloc_free(str);
+       }
+
+       argv[argc] = NULL;
+       argc += 1;
+
+       *out = argv;
+       return 0;
+}
+
+struct run_event_context {
+       struct run_proc_context *run_proc_ctx;
+       const char *script_dir;
+       const char *debug_prog;
+       bool debug_running;
+};
+
+
+int run_event_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+                  const char *script_dir, const char *debug_prog,
+                  struct run_event_context **out)
+{
+       struct run_event_context *run_ctx;
+       struct stat st;
+       int ret;
+
+       run_ctx = talloc_zero(mem_ctx, struct run_event_context);
+       if (run_ctx == NULL) {
+               return ENOMEM;
+       }
+
+       ret = run_proc_init(run_ctx, ev, &run_ctx->run_proc_ctx);
+       if (ret != 0) {
+               talloc_free(run_ctx);
+               return ret;
+       }
+
+       ret = stat(script_dir, &st);
+       if (ret != 0) {
+               ret = errno;
+               talloc_free(run_ctx);
+               return ret;
+       }
+
+       if (! S_ISDIR(st.st_mode)) {
+               talloc_free(run_ctx);
+               return EINVAL;
+       }
+
+       run_ctx->script_dir = talloc_strdup(run_ctx, script_dir);
+       if (run_ctx->script_dir == NULL) {
+               talloc_free(run_ctx);
+               return ENOMEM;
+       }
+
+       if (debug_prog != NULL) {
+               run_ctx->debug_prog = talloc_strdup(run_ctx, debug_prog);
+               if (run_ctx->debug_prog == NULL) {
+                       talloc_free(run_ctx);
+                       return ENOMEM;
+               }
+       }
+
+       run_ctx->debug_running = false;
+
+       *out = run_ctx;
+       return 0;
+}
+
+static struct run_proc_context *
+run_event_run_proc_context(struct run_event_context *run_ctx)
+{
+       return run_ctx->run_proc_ctx;
+}
+
+static const char *run_event_script_dir(struct run_event_context *run_ctx)
+{
+       return run_ctx->script_dir;
+}
+
+static const char *run_event_debug_prog(struct run_event_context *run_ctx)
+{
+       return run_ctx->debug_prog;
+}
+
+static int run_event_script_status(struct run_event_script *script)
+{
+       int ret;
+
+       if (script->result.sig > 0) {
+               ret = -EINTR;
+       } else if (script->result.err > 0) {
+               if (script->result.err == EACCES) {
+                       /* Map EACCESS to ENOEXEC */
+                       ret = -ENOEXEC;
+               } else {
+                       ret = -script->result.err;
+               }
+       } else {
+               ret = script->result.status;
+       }
+
+       return ret;
+}
+
+int run_event_script_list(struct run_event_context *run_ctx,
+                         TALLOC_CTX *mem_ctx,
+                         struct run_event_script_list **output)
+{
+       struct run_event_script_list *script_list;
+       int ret, i;
+
+       ret = get_script_list(mem_ctx, run_event_script_dir(run_ctx),
+                             &script_list);
+       if (ret != 0) {
+               return ret;
+       }
+
+       if (script_list == NULL) {
+               *output = NULL;
+               return 0;
+       }
+
+       for (i=0; i<script_list->num_scripts; i++) {
+               struct run_event_script *script = &script_list->script[i];
+               struct stat st;
+               char *path = NULL;
+
+               path = talloc_asprintf(mem_ctx, "%s/%s",
+                                      run_event_script_dir(run_ctx),
+                                      script->name);
+               if (path == NULL) {
+                       continue;
+               }
+
+               ret = stat(path, &st);
+               if (ret != 0) {
+                       TALLOC_FREE(path);
+                       continue;
+               }
+
+               if (! (st.st_mode & S_IXUSR)) {
+                       script->summary = -ENOEXEC;
+               }
+
+               TALLOC_FREE(path);
+       }
+
+       *output = script_list;
+       return 0;
+}
+
+int run_event_script_enable(struct run_event_context *run_ctx,
+                           const char *script_name)
+{
+       return script_chmod(run_ctx, run_event_script_dir(run_ctx),
+                           script_name, true);
+}
+
+int run_event_script_disable(struct run_event_context *run_ctx,
+                            const char *script_name)
+{
+       return script_chmod(run_ctx, run_event_script_dir(run_ctx),
+                           script_name, false);
+}
+
+/*
+ * Run debug program to diagnose hung scripts
+ */
+
+static int debug_args(TALLOC_CTX *mem_ctx, const char *path,
+                     const char *event_str, pid_t pid, const char ***out)
+{
+       const char **argv;
+
+       argv = talloc_array(mem_ctx, const char *, 4);
+       if (argv == NULL) {
+               return ENOMEM;
+       }
+
+       argv[0] = path;
+       argv[1] = talloc_asprintf(argv, "%d", pid);
+       argv[2] = event_str;
+       if (argv[1] == NULL) {
+               talloc_free(argv);
+               return ENOMEM;
+       }
+       argv[3] = NULL;
+
+       *out = argv;
+       return 0;
+}
+
+static void debug_log(int loglevel, const char *output, const char *log_prefix)
+{
+       char *line, *s;
+
+       s = strdup(output);
+       if (s == NULL) {
+               DEBUG(loglevel, ("%s: %s\n", log_prefix, output));
+               return;
+       }
+
+       line = strtok(s, "\n");
+       while (line != NULL) {
+               DEBUG(loglevel, ("%s: %s\n", log_prefix, line));
+               line = strtok(NULL, "\n");
+       }
+       free(s);
+}
+
+struct run_debug_state {
+       struct run_event_context *run_ctx;
+       pid_t pid;
+};
+
+static void run_debug_done(struct tevent_req *subreq);
+
+static struct tevent_req *run_debug_send(TALLOC_CTX *mem_ctx,
+                                        struct tevent_context *ev,
+                                        struct run_event_context *run_ctx,
+                                        const char *event_str, pid_t pid)
+{
+       struct tevent_req *req, *subreq;
+       struct run_debug_state *state;
+       const char **argv;
+       const char *debug_prog;
+       int ret;
+
+       req = tevent_req_create(mem_ctx, &state, struct run_debug_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       state->run_ctx = run_ctx;
+       state->pid = pid;
+
+       debug_prog = run_event_debug_prog(run_ctx);
+       if (debug_prog == NULL) {
+               tevent_req_done(req);
+               return tevent_req_post(req, ev);
+       }


-- 
Samba Shared Repository

Reply via email to