The branch, master has been updated via e3ce1a2 ctdb-docs: Update documentation for "ctdb event" command via 5017325 ctdb-event: Implement event tool "script list" command via 295826f ctdb-event: Change event-tool script enable/disable to chmod file directly via 82e6248 ctdb-common: Use script abstraction in run_event via a7a4ee4 ctdb-common: Factor out basic script abstraction via 56e248d ctdb-event: Fix "ctdb event status" usage message from a44e698 ctdb-docs: Replace obsolete reference to CTDB_DEBUG_HUNG_SCRIPT option
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit e3ce1a2dfc4cbba4bf22381b91e9a14c8f240f5d Author: Martin Schwenke <mar...@meltin.net> Date: Mon Jul 23 14:07:08 2018 +1000 ctdb-docs: Update documentation for "ctdb event" command BUG: https://bugzilla.samba.org/show_bug.cgi?id=13551 Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> Autobuild-User(master): Amitay Isaacs <ami...@samba.org> Autobuild-Date(master): Sat Jul 28 20:03:52 CEST 2018 on sn-devel-144 commit 5017325c2ef84b10ccd23328f5d62ac5b246bbb3 Author: Martin Schwenke <mar...@meltin.net> Date: Thu Jul 12 13:47:51 2018 +1000 ctdb-event: Implement event tool "script list" command BUG: https://bugzilla.samba.org/show_bug.cgi?id=13551 Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 295826f1b83b6e59d24e4da43b290242c17f44af Author: Martin Schwenke <mar...@meltin.net> Date: Thu Jul 12 13:27:16 2018 +1000 ctdb-event: Change event-tool script enable/disable to chmod file directly They no longer go over the socket to eventd to enable and disable scripts. Use the event script abstraction to chmod them directly. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13551 Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 82e62488027302e541739628210292c2d95717e1 Author: Martin Schwenke <mar...@meltin.net> Date: Thu Jul 12 13:26:27 2018 +1000 ctdb-common: Use script abstraction in run_event BUG: https://bugzilla.samba.org/show_bug.cgi?id=13551 Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit a7a4ee439dc1cf262b4da9fbcb38a2f69c62744c Author: Martin Schwenke <mar...@meltin.net> Date: Thu Jul 12 13:20:55 2018 +1000 ctdb-common: Factor out basic script abstraction Provides for listing of scripts and chmod enable/disable. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13551 Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> commit 56e248de6072063308786ea83282aaecc8d7e62a Author: Martin Schwenke <mar...@meltin.net> Date: Thu Jul 12 10:44:20 2018 +1000 ctdb-event: Fix "ctdb event status" usage message BUG: https://bugzilla.samba.org/show_bug.cgi?id=13551 Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> ----------------------------------------------------------------------- Summary of changes: ctdb/common/event_script.c | 246 +++++++++++++++++++++ ctdb/common/event_script.h | 72 ++++++ ctdb/common/run_event.c | 217 +++++------------- ctdb/doc/ctdb.1.xml | 95 ++++---- ctdb/event/event_tool.c | 228 ++++++++++++++++--- ctdb/tests/cunit/event_script_test_001.sh | 125 +++++++++++ .../01.disabled.script => data/03.notalink.script} | 1 - .../data/{01.dummy.script => 02.disabled.script} | 0 .../etc-ctdb/{ => share}/events/empty/README | 0 .../{ => share}/events/random/01.disabled.script | 0 .../{ => share}/events/random/02.enabled.script | 0 .../{ => share}/events/random/README.script | 0 .../etc-ctdb/{ => share}/events/random/a.script | 0 ctdb/tests/eventd/eventd_001.sh | 5 + ctdb/tests/eventd/eventd_002.sh | 2 + ctdb/tests/eventd/eventd_003.sh | 9 + ctdb/tests/eventd/eventd_009.sh | 116 ++++++++++ ctdb/tests/src/event_script_test.c | 119 ++++++++++ ctdb/tests/src/run_event_test.c | 1 + ctdb/wscript | 4 +- 20 files changed, 1000 insertions(+), 240 deletions(-) create mode 100644 ctdb/common/event_script.c create mode 100644 ctdb/common/event_script.h create mode 100755 ctdb/tests/cunit/event_script_test_001.sh copy ctdb/tests/eventd/etc-ctdb/events/{random/01.disabled.script => data/03.notalink.script} (94%) copy ctdb/tests/eventd/etc-ctdb/share/events/data/{01.dummy.script => 02.disabled.script} (100%) copy ctdb/tests/eventd/etc-ctdb/{ => share}/events/empty/README (100%) copy ctdb/tests/eventd/etc-ctdb/{ => share}/events/random/01.disabled.script (100%) copy ctdb/tests/eventd/etc-ctdb/{ => share}/events/random/02.enabled.script (100%) copy ctdb/tests/eventd/etc-ctdb/{ => share}/events/random/README.script (100%) copy ctdb/tests/eventd/etc-ctdb/{ => share}/events/random/a.script (100%) create mode 100644 ctdb/tests/src/event_script_test.c Changeset truncated at 500 lines: diff --git a/ctdb/common/event_script.c b/ctdb/common/event_script.c new file mode 100644 index 0000000..8978d14 --- /dev/null +++ b/ctdb/common/event_script.c @@ -0,0 +1,246 @@ +/* + Low level event script handling + + Copyright (C) Amitay Isaacs 2017 + Copyright (C) Martin Schwenke 2018 + + 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/glob.h" + +#include <talloc.h> + +#include "common/event_script.h" + +static int script_filter(const struct dirent *de) +{ + int ret; + + /* Match a script pattern */ + ret = fnmatch("[0-9][0-9].*.script", de->d_name, 0); + if (ret == 0) { + return 1; + } + + return 0; +} + +int event_script_get_list(TALLOC_CTX *mem_ctx, + const char *script_dir, + struct event_script_list **out) +{ + struct dirent **namelist = NULL; + struct event_script_list *script_list = NULL; + size_t ds_len; + int count, ret; + int i; + + count = scandir(script_dir, &namelist, script_filter, alphasort); + if (count == -1) { + ret = errno; + goto done; + } + + script_list = talloc_zero(mem_ctx, struct event_script_list); + if (script_list == NULL) { + goto nomem; + } + + if (count == 0) { + ret = 0; + *out = script_list; + goto done; + } + + script_list->num_scripts = count; + script_list->script = talloc_zero_array(script_list, + struct event_script *, + count); + if (script_list->script == NULL) { + goto nomem; + } + + ds_len = strlen(".script"); + for (i = 0; i < count; i++) { + struct event_script *s; + struct stat statbuf; + + s = talloc_zero(script_list->script, struct event_script); + if (s == NULL) { + goto nomem; + } + + script_list->script[i] = s; + + s->name = talloc_strndup(script_list->script, + namelist[i]->d_name, + strlen(namelist[i]->d_name) - ds_len); + if (s->name == NULL) { + goto nomem; + } + + s->path = talloc_asprintf(script_list->script, + "%s/%s", + script_dir, + namelist[i]->d_name); + if (s->path == NULL) { + goto nomem; + } + + ret = stat(s->path, &statbuf); + if (ret == 0) { + /* + * If ret != 0 this is either a dangling + * symlink or it has just disappeared. Either + * way, it isn't executable. See the note + * below about things that have disappeared. + */ + if (statbuf.st_mode & S_IXUSR) { + s->enabled = true; + } + } + } + + *out = script_list; + return 0; + +nomem: + ret = ENOMEM; + talloc_free(script_list); + +done: + if (namelist != NULL && count != -1) { + for (i=0; i<count; i++) { + free(namelist[i]); + } + free(namelist); + } + + return ret; +} + +int event_script_chmod(const char *script_dir, + const char *script_name, + bool enable) +{ + const char *dot_script = ".script"; + size_t ds_len = strlen(dot_script); + size_t sn_len = strlen(script_name); + DIR *dirp; + struct dirent *de; + char buf[PATH_MAX]; + const char *script_file; + int ret, new_mode; + char filename[PATH_MAX]; + struct stat st; + bool found; + ino_t found_inode; + int fd = -1; + + /* Allow script_name to already have ".script" suffix */ + if (sn_len > ds_len && + strcmp(&script_name[sn_len - ds_len], dot_script) == 0) { + script_file = script_name; + } else { + ret = snprintf(buf, sizeof(buf), "%s.script", script_name); + if (ret >= sizeof(buf)) { + return ENAMETOOLONG; + } + script_file = buf; + } + + dirp = opendir(script_dir); + if (dirp == NULL) { + return errno; + } + + found = false; + while ((de = readdir(dirp)) != NULL) { + if (strcmp(de->d_name, script_file) == 0) { + /* check for valid script names */ + ret = script_filter(de); + if (ret == 0) { + closedir(dirp); + return EINVAL; + } + + found = true; + found_inode = de->d_ino; + break; + } + } + closedir(dirp); + + if (! found) { + return ENOENT; + } + + ret = snprintf(filename, + sizeof(filename), + "%s/%s", + script_dir, + script_file); + if (ret >= sizeof(filename)) { + return ENAMETOOLONG; + } + + fd = open(filename, O_RDWR); + if (fd == -1) { + ret = errno; + goto done; + } + + ret = fstat(fd, &st); + if (ret != 0) { + ret = errno; + goto done; + } + + /* + * If the directory entry inode number doesn't match the one + * returned by fstat() then this is probably a symlink, so the + * caller should not be calling this function. Note that this + * is a cheap sanity check to catch most programming errors. + * This doesn't cost any extra system calls but can still miss + * the unlikely case where the symlink is to a file on a + * different filesystem with the same inode number as the + * symlink. + */ + if (found && found_inode != st.st_ino) { + ret = EINVAL; + 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); + } + return ret; +} diff --git a/ctdb/common/event_script.h b/ctdb/common/event_script.h new file mode 100644 index 0000000..bf5a8fd --- /dev/null +++ b/ctdb/common/event_script.h @@ -0,0 +1,72 @@ +/* + Low level event script handling + + Copyright (C) Amitay Isaacs 2017 + Copyright (C) Martin Schwenke 2018 + + 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/>. +*/ + +#ifndef __CTDB_SCRIPT_H__ +#define __CTDB_SCRIPT_H__ + +#include "replace.h" +#include "system/filesys.h" + +#include <talloc.h> + +/** + * @file script.h + * + * @brief Script listing and manipulation + */ + + +struct event_script { + char *name; + char *path; + bool enabled; +}; + +struct event_script_list { + unsigned int num_scripts; + struct event_script **script; +}; + + +/** + * @brief Retrieve a list of scripts + * + * @param[in] mem_ctx Talloc memory context + * @param[in] script_dir Directory containing scripts + * @param[out] out List of scripts + * @return 0 on success, errno on failure + */ +int event_script_get_list(TALLOC_CTX *mem_ctx, + const char *script_dir, + struct event_script_list **out); + +/** + * @brief Make a script executable or not executable + * + * @param[in] script_dir Directory containing script + * @param[in] script_name Name of the script to enable + * @param[in] executable True if script should be made executable + * @return 0 on success, errno on failure + */ +int event_script_chmod(const char *script_dir, + const char *script_name, + bool executable); + +#endif /* __CTDB_SCRIPT_H__ */ diff --git a/ctdb/common/run_event.c b/ctdb/common/run_event.c index a215550..91b3dd3 100644 --- a/ctdb/common/run_event.c +++ b/ctdb/common/run_event.c @@ -31,177 +31,70 @@ #include "common/logging.h" #include "common/run_proc.h" +#include "common/event_script.h" + #include "common/run_event.h" /* * Utility functions */ -static int script_filter(const struct dirent *de) -{ - int ret; - - /* Match a script pattern */ - ret = fnmatch("[0-9][0-9].*.script", de->d_name, 0); - if (ret == 0) { - return 1; - } - - return 0; -} - static int get_script_list(TALLOC_CTX *mem_ctx, const char *script_dir, struct run_event_script_list **out) { - struct dirent **namelist = NULL; + struct event_script_list *s_list; struct run_event_script_list *script_list; - size_t ls; - int count, ret; - int i; + unsigned int i; + int ret; - count = scandir(script_dir, &namelist, script_filter, alphasort); - if (count == -1) { - ret = errno; + ret = event_script_get_list(mem_ctx, script_dir, &s_list); + if (ret != 0) { if (ret == ENOENT) { D_WARNING("event script dir %s removed\n", script_dir); } else { - D_WARNING("scandir() failed on %s, ret=%d\n", + D_WARNING("failed to get script list for %s, ret=%d\n", script_dir, ret); } - *out = NULL; - goto done; + return ret; } - if (count == 0) { + if (s_list->num_scripts == 0) { *out = NULL; - ret = 0; - goto done; + talloc_free(s_list); + return 0; } script_list = talloc_zero(mem_ctx, struct run_event_script_list); if (script_list == NULL) { + talloc_free(s_list); return ENOMEM; } - script_list->num_scripts = count; + script_list->num_scripts = s_list->num_scripts; script_list->script = talloc_zero_array(script_list, struct run_event_script, - count); + script_list->num_scripts); if (script_list->script == NULL) { - ret = ENOMEM; + talloc_free(s_list); talloc_free(script_list); - goto done; - } - - ls = strlen(".script"); - for (i=0; i<count; i++) { - struct run_event_script *s = &script_list->script[i]; - - s->name = talloc_strndup(script_list, - namelist[i]->d_name, - strlen(namelist[i]->d_name) - ls); - 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; - char script_file[PATH_MAX]; - int ret, new_mode; - char *filename; - struct stat st; - bool found; - int fd = -1; - - ret = snprintf(script_file, - sizeof(script_file), - "%s.script", - script_name); - if (ret >= sizeof(script_file)) { - return ENAMETOOLONG; - } - - dirp = opendir(script_dir); - if (dirp == NULL) { - return errno; - } - - found = false; - while ((de = readdir(dirp)) != NULL) { - if (strcmp(de->d_name, script_file) == 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_file); - if (filename == NULL) { return ENOMEM; } - fd = open(filename, O_RDWR); - if (fd == -1) { - ret = errno; - goto done; - } -- Samba Shared Repository