s3: ldap: Ensure the ADS_STRUCT pointer doesn't get freed on error, we don't own...
[Samba.git] / ctdb / common / run_event.c
blobe230b12f151ab0b16a3b0792d9ffa1aab23e4b6a
1 /*
2 Run scripts in a directory with specific event arguments
4 Copyright (C) Amitay Isaacs 2017
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "replace.h"
21 #include "system/filesys.h"
22 #include "system/dir.h"
23 #include "system/locale.h"
24 #include "system/wait.h"
26 #include <talloc.h>
27 #include <tevent.h>
29 #include "lib/util/tevent_unix.h"
30 #include "lib/util/debug.h"
32 #include "common/logging.h"
33 #include "common/run_proc.h"
34 #include "common/run_event.h"
37 * Utility functions
40 static int script_filter(const struct dirent *de)
42 size_t namelen = strlen(de->d_name);
43 char *ptr;
45 /* Ignore . and .. */
46 if (namelen < 3) {
47 return 0;
50 /* Skip filenames with ~ */
51 ptr = strchr(de->d_name, '~');
52 if (ptr != NULL) {
53 return 0;
56 /* Filename should start with [0-9][0-9]. */
57 if ((! isdigit(de->d_name[0])) ||
58 (! isdigit(de->d_name[1])) ||
59 (de->d_name[2] != '.')) {
60 return 0;
63 /* Ignore filenames with multiple '.'s */
64 ptr = index(&de->d_name[3], '.');
65 if (ptr != NULL) {
66 return 0;
69 return 1;
72 static int get_script_list(TALLOC_CTX *mem_ctx,
73 const char *script_dir,
74 struct run_event_script_list **out)
76 struct dirent **namelist = NULL;
77 struct run_event_script_list *script_list;
78 int count, ret;
79 int i;
81 count = scandir(script_dir, &namelist, script_filter, alphasort);
82 if (count == -1) {
83 ret = errno;
84 if (ret == ENOENT) {
85 D_WARNING("event script dir %s removed\n", script_dir);
86 } else {
87 D_WARNING("scandir() failed on %s, ret=%d\n",
88 script_dir, ret);
90 *out = NULL;
91 ret = 0;
92 goto done;
95 if (count == 0) {
96 *out = NULL;
97 ret = 0;
98 goto done;
101 script_list = talloc_zero(mem_ctx, struct run_event_script_list);
102 if (script_list == NULL) {
103 return ENOMEM;
106 script_list->num_scripts = count;
107 script_list->script = talloc_zero_array(script_list,
108 struct run_event_script,
109 count);
110 if (script_list->script == NULL) {
111 ret = ENOMEM;
112 talloc_free(script_list);
113 goto done;
116 for (i=0; i<count; i++) {
117 struct run_event_script *s = &script_list->script[i];
119 s->name = talloc_strdup(script_list, namelist[i]->d_name);
120 if (s->name == NULL) {
121 ret = ENOMEM;
122 talloc_free(script_list);
123 goto done;
127 *out = script_list;
128 ret = 0;
130 done:
131 if (namelist != NULL && count != -1) {
132 for (i=0; i<count; i++) {
133 free(namelist[i]);
135 free(namelist);
137 return ret;
140 static int script_chmod(TALLOC_CTX *mem_ctx, const char *script_dir,
141 const char *script_name, bool enable)
143 DIR *dirp;
144 struct dirent *de;
145 int ret, new_mode;
146 char *filename;
147 struct stat st;
148 bool found;
149 int fd = -1;
151 dirp = opendir(script_dir);
152 if (dirp == NULL) {
153 return errno;
156 found = false;
157 while ((de = readdir(dirp)) != NULL) {
158 if (strcmp(de->d_name, script_name) == 0) {
160 /* check for valid script names */
161 ret = script_filter(de);
162 if (ret == 0) {
163 closedir(dirp);
164 return EINVAL;
167 found = true;
168 break;
171 closedir(dirp);
173 if (! found) {
174 return ENOENT;
177 filename = talloc_asprintf(mem_ctx, "%s/%s", script_dir, script_name);
178 if (filename == NULL) {
179 return ENOMEM;
182 fd = open(filename, O_RDWR);
183 if (fd == -1) {
184 ret = errno;
185 goto done;
188 ret = fstat(fd, &st);
189 if (ret != 0) {
190 ret = errno;
191 goto done;
194 if (enable) {
195 new_mode = st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH);
196 } else {
197 new_mode = st.st_mode & ~(S_IXUSR | S_IXGRP | S_IXOTH);
200 ret = fchmod(fd, new_mode);
201 if (ret != 0) {
202 ret = errno;
203 goto done;
206 done:
207 if (fd != -1) {
208 close(fd);
210 talloc_free(filename);
211 return ret;
214 static int script_args(TALLOC_CTX *mem_ctx, const char *event_str,
215 const char *arg_str, const char ***out)
217 const char **argv;
218 int argc;
219 size_t len;
221 /* Preallocate argv array to avoid reallocation. */
222 len = 8;
223 argv = talloc_array(mem_ctx, const char *, len);
224 if (argv == NULL) {
225 return ENOMEM;
228 argv[0] = NULL; /* script name */
229 argv[1] = event_str;
230 argc = 2;
232 if (arg_str != NULL) {
233 char *str, *t, *tok;
235 str = talloc_strdup(argv, arg_str);
236 if (str == NULL) {
237 return ENOMEM;
240 t = str;
241 while ((tok = strtok(t, " ")) != NULL) {
242 argv[argc] = talloc_strdup(argv, tok);
243 if (argv[argc] == NULL) {
244 talloc_free(argv);
245 return ENOMEM;
247 argc += 1;
248 if (argc >= len) {
249 argv = talloc_realloc(mem_ctx, argv,
250 const char *, len + 8);
251 if (argv == NULL) {
252 return ENOMEM;
254 len += 8;
256 t = NULL;
259 talloc_free(str);
262 argv[argc] = NULL;
263 argc += 1;
265 *out = argv;
266 return 0;
269 struct run_event_context {
270 struct run_proc_context *run_proc_ctx;
271 const char *script_dir;
272 const char *debug_prog;
273 bool debug_running;
275 struct tevent_queue *queue;
276 struct tevent_req *current_req;
277 bool monitor_running;
281 int run_event_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
282 const char *script_dir, const char *debug_prog,
283 struct run_event_context **out)
285 struct run_event_context *run_ctx;
286 struct stat st;
287 int ret;
289 run_ctx = talloc_zero(mem_ctx, struct run_event_context);
290 if (run_ctx == NULL) {
291 return ENOMEM;
294 ret = run_proc_init(run_ctx, ev, &run_ctx->run_proc_ctx);
295 if (ret != 0) {
296 talloc_free(run_ctx);
297 return ret;
300 ret = stat(script_dir, &st);
301 if (ret != 0) {
302 ret = errno;
303 talloc_free(run_ctx);
304 return ret;
307 if (! S_ISDIR(st.st_mode)) {
308 talloc_free(run_ctx);
309 return EINVAL;
312 run_ctx->script_dir = talloc_strdup(run_ctx, script_dir);
313 if (run_ctx->script_dir == NULL) {
314 talloc_free(run_ctx);
315 return ENOMEM;
318 if (debug_prog != NULL) {
319 run_ctx->debug_prog = talloc_strdup(run_ctx, debug_prog);
320 if (run_ctx->debug_prog == NULL) {
321 talloc_free(run_ctx);
322 return ENOMEM;
326 run_ctx->debug_running = false;
328 run_ctx->queue = tevent_queue_create(run_ctx, "run event queue");
329 if (run_ctx->queue == NULL) {
330 talloc_free(run_ctx);
331 return ENOMEM;
334 run_ctx->monitor_running = false;
336 *out = run_ctx;
337 return 0;
340 static struct run_proc_context *
341 run_event_run_proc_context(struct run_event_context *run_ctx)
343 return run_ctx->run_proc_ctx;
346 static const char *run_event_script_dir(struct run_event_context *run_ctx)
348 return run_ctx->script_dir;
351 static const char *run_event_debug_prog(struct run_event_context *run_ctx)
353 return run_ctx->debug_prog;
356 static struct tevent_queue *run_event_queue(struct run_event_context *run_ctx)
358 return run_ctx->queue;
361 static void run_event_start_running(struct run_event_context *run_ctx,
362 struct tevent_req *req, bool is_monitor)
364 run_ctx->current_req = req;
365 run_ctx->monitor_running = is_monitor;
368 static void run_event_stop_running(struct run_event_context *run_ctx)
370 run_ctx->current_req = NULL;
371 run_ctx->monitor_running = false;
374 static struct tevent_req *run_event_get_running(
375 struct run_event_context *run_ctx,
376 bool *is_monitor)
378 *is_monitor = run_ctx->monitor_running;
379 return run_ctx->current_req;
382 static int run_event_script_status(struct run_event_script *script)
384 int ret;
386 if (script->result.sig > 0) {
387 ret = -EINTR;
388 } else if (script->result.err > 0) {
389 if (script->result.err == EACCES) {
390 /* Map EACCESS to ENOEXEC */
391 ret = -ENOEXEC;
392 } else {
393 ret = -script->result.err;
395 } else {
396 ret = script->result.status;
399 return ret;
402 int run_event_script_list(struct run_event_context *run_ctx,
403 TALLOC_CTX *mem_ctx,
404 struct run_event_script_list **output)
406 struct run_event_script_list *script_list;
407 int ret, i;
409 ret = get_script_list(mem_ctx, run_event_script_dir(run_ctx),
410 &script_list);
411 if (ret != 0) {
412 return ret;
415 if (script_list == NULL) {
416 *output = NULL;
417 return 0;
420 for (i=0; i<script_list->num_scripts; i++) {
421 struct run_event_script *script = &script_list->script[i];
422 struct stat st;
423 char *path = NULL;
425 path = talloc_asprintf(mem_ctx, "%s/%s",
426 run_event_script_dir(run_ctx),
427 script->name);
428 if (path == NULL) {
429 continue;
432 ret = stat(path, &st);
433 if (ret != 0) {
434 TALLOC_FREE(path);
435 continue;
438 if (! (st.st_mode & S_IXUSR)) {
439 script->summary = -ENOEXEC;
442 TALLOC_FREE(path);
445 *output = script_list;
446 return 0;
449 int run_event_script_enable(struct run_event_context *run_ctx,
450 const char *script_name)
452 return script_chmod(run_ctx, run_event_script_dir(run_ctx),
453 script_name, true);
456 int run_event_script_disable(struct run_event_context *run_ctx,
457 const char *script_name)
459 return script_chmod(run_ctx, run_event_script_dir(run_ctx),
460 script_name, false);
464 * Run debug program to diagnose hung scripts
467 static int debug_args(TALLOC_CTX *mem_ctx, const char *path,
468 const char *event_str, pid_t pid, const char ***out)
470 const char **argv;
472 argv = talloc_array(mem_ctx, const char *, 4);
473 if (argv == NULL) {
474 return ENOMEM;
477 argv[0] = path;
478 argv[1] = talloc_asprintf(argv, "%d", pid);
479 argv[2] = event_str;
480 if (argv[1] == NULL) {
481 talloc_free(argv);
482 return ENOMEM;
484 argv[3] = NULL;
486 *out = argv;
487 return 0;
490 static void debug_log(int loglevel, const char *output, const char *log_prefix)
492 char *line, *s;
494 s = strdup(output);
495 if (s == NULL) {
496 DEBUG(loglevel, ("%s: %s\n", log_prefix, output));
497 return;
500 line = strtok(s, "\n");
501 while (line != NULL) {
502 DEBUG(loglevel, ("%s: %s\n", log_prefix, line));
503 line = strtok(NULL, "\n");
505 free(s);
508 struct run_debug_state {
509 struct run_event_context *run_ctx;
510 pid_t pid;
513 static void run_debug_done(struct tevent_req *subreq);
515 static struct tevent_req *run_debug_send(TALLOC_CTX *mem_ctx,
516 struct tevent_context *ev,
517 struct run_event_context *run_ctx,
518 const char *event_str, pid_t pid)
520 struct tevent_req *req, *subreq;
521 struct run_debug_state *state;
522 const char **argv;
523 const char *debug_prog;
524 int ret;
526 req = tevent_req_create(mem_ctx, &state, struct run_debug_state);
527 if (req == NULL) {
528 return NULL;
531 state->run_ctx = run_ctx;
532 state->pid = pid;
534 debug_prog = run_event_debug_prog(run_ctx);
535 if (debug_prog == NULL) {
536 tevent_req_done(req);
537 return tevent_req_post(req, ev);
540 if (run_ctx->debug_running) {
541 tevent_req_done(req);
542 return tevent_req_post(req, ev);
545 if (pid == -1) {
546 D_DEBUG("Event script terminated, nothing to debug\n");
547 tevent_req_done(req);
548 return tevent_req_post(req, ev);
551 ret = debug_args(state, debug_prog, event_str, pid, &argv);
552 if (ret != 0) {
553 D_ERR("debug_args() failed\n");
554 tevent_req_error(req, ret);
555 return tevent_req_post(req, ev);
558 D_DEBUG("Running debug %s with args \"%s %s\"\n",
559 debug_prog, argv[1], argv[2]);
561 subreq = run_proc_send(state, ev, run_event_run_proc_context(run_ctx),
562 debug_prog, argv, -1, tevent_timeval_zero());
563 if (tevent_req_nomem(subreq, req)) {
564 return tevent_req_post(req, ev);
566 tevent_req_set_callback(subreq, run_debug_done, req);
568 run_ctx->debug_running = true;
570 talloc_free(argv);
571 return req;
574 static void run_debug_done(struct tevent_req *subreq)
576 struct tevent_req *req = tevent_req_callback_data(
577 subreq, struct tevent_req);
578 struct run_debug_state *state = tevent_req_data(
579 req, struct run_debug_state);
580 char *output;
581 int ret;
582 bool status;
584 state->run_ctx->debug_running = false;
586 status = run_proc_recv(subreq, &ret, NULL, NULL, state, &output);
587 TALLOC_FREE(subreq);
588 if (! status) {
589 D_ERR("Running debug failed, ret=%d\n", ret);
592 /* Log output */
593 if (output != NULL) {
594 debug_log(DEBUG_ERR, output, "event_debug");
595 talloc_free(output);
598 kill(-state->pid, SIGTERM);
599 tevent_req_done(req);
602 static bool run_debug_recv(struct tevent_req *req, int *perr)
604 int ret;
606 if (tevent_req_is_unix_error(req, &ret)) {
607 if (perr != NULL) {
608 *perr = ret;
610 return false;
613 return true;
617 * Run a single event
620 struct run_event_state {
621 struct tevent_context *ev;
622 struct run_event_context *run_ctx;
623 const char *event_str;
624 const char *arg_str;
625 struct timeval timeout;
627 struct run_event_script_list *script_list;
628 const char **argv;
629 struct tevent_req *script_subreq;
630 int index;
631 bool cancelled;
634 static void run_event_cancel(struct tevent_req *req);
635 static void run_event_trigger(struct tevent_req *req, void *private_data);
636 static struct tevent_req *run_event_run_script(struct tevent_req *req);
637 static void run_event_next_script(struct tevent_req *subreq);
638 static void run_event_debug(struct tevent_req *req, pid_t pid);
639 static void run_event_debug_done(struct tevent_req *subreq);
641 struct tevent_req *run_event_send(TALLOC_CTX *mem_ctx,
642 struct tevent_context *ev,
643 struct run_event_context *run_ctx,
644 const char *event_str,
645 const char *arg_str,
646 struct timeval timeout)
648 struct tevent_req *req, *current_req;
649 struct run_event_state *state;
650 bool monitor_running, status;
652 req = tevent_req_create(mem_ctx, &state, struct run_event_state);
653 if (req == NULL) {
654 return NULL;
657 state->ev = ev;
658 state->run_ctx = run_ctx;
659 state->event_str = talloc_strdup(state, event_str);
660 if (tevent_req_nomem(state->event_str, req)) {
661 return tevent_req_post(req, ev);
663 if (arg_str != NULL) {
664 state->arg_str = talloc_strdup(state, arg_str);
665 if (tevent_req_nomem(state->arg_str, req)) {
666 return tevent_req_post(req, ev);
669 state->timeout = timeout;
670 state->cancelled = false;
673 * If monitor event is running,
674 * cancel the running monitor event and run new event
676 * If any other event is running,
677 * if new event is monitor, cancel that event
678 * else add new event to the queue
681 current_req = run_event_get_running(run_ctx, &monitor_running);
682 if (current_req != NULL) {
683 if (monitor_running) {
684 run_event_cancel(current_req);
685 } else if (strcmp(event_str, "monitor") == 0) {
686 state->script_list = talloc_zero(
687 state, struct run_event_script_list);
688 if (tevent_req_nomem(state->script_list, req)) {
689 return tevent_req_post(req, ev);
691 state->script_list->summary = -ECANCELED;
692 tevent_req_done(req);
693 return tevent_req_post(req, ev);
697 status = tevent_queue_add(run_event_queue(run_ctx), ev, req,
698 run_event_trigger, NULL);
699 if (! status) {
700 tevent_req_error(req, ENOMEM);
701 return tevent_req_post(req, ev);
704 return req;
707 static void run_event_cancel(struct tevent_req *req)
709 struct run_event_state *state = tevent_req_data(
710 req, struct run_event_state);
712 run_event_stop_running(state->run_ctx);
714 state->script_list->summary = -ECANCELED;
715 state->cancelled = true;
717 TALLOC_FREE(state->script_subreq);
719 tevent_req_done(req);
722 static void run_event_trigger(struct tevent_req *req, void *private_data)
724 struct tevent_req *subreq;
725 struct run_event_state *state = tevent_req_data(
726 req, struct run_event_state);
727 int ret;
728 bool is_monitor = false;
730 D_DEBUG("Running event %s with args \"%s\"\n", state->event_str,
731 state->arg_str == NULL ? "(null)" : state->arg_str);
733 ret = get_script_list(state, run_event_script_dir(state->run_ctx),
734 &state->script_list);
735 if (ret != 0) {
736 D_ERR("get_script_list() failed, ret=%d\n", ret);
737 tevent_req_error(req, ret);
738 return;
741 /* No scripts */
742 if (state->script_list == NULL ||
743 state->script_list->num_scripts == 0) {
744 tevent_req_done(req);
745 return;
748 ret = script_args(state, state->event_str, state->arg_str,
749 &state->argv);
750 if (ret != 0) {
751 D_ERR("script_args() failed, ret=%d\n", ret);
752 tevent_req_error(req, ret);
753 return;
756 state->index = 0;
758 subreq = run_event_run_script(req);
759 if (tevent_req_nomem(subreq, req)) {
760 return;
762 tevent_req_set_callback(subreq, run_event_next_script, req);
764 state->script_subreq = subreq;
766 if (strcmp(state->event_str, "monitor") == 0) {
767 is_monitor = true;
769 run_event_start_running(state->run_ctx, req, is_monitor);
772 static struct tevent_req *run_event_run_script(struct tevent_req *req)
774 struct run_event_state *state = tevent_req_data(
775 req, struct run_event_state);
776 struct run_event_script *script;
777 struct tevent_req *subreq;
778 char *path;
780 script = &state->script_list->script[state->index];
782 path = talloc_asprintf(state, "%s/%s",
783 run_event_script_dir(state->run_ctx),
784 script->name);
785 if (path == NULL) {
786 return NULL;
789 state->argv[0] = script->name;
790 script->begin = tevent_timeval_current();
792 D_DEBUG("Running %s with args \"%s %s\"\n",
793 path, state->argv[0], state->argv[1]);
795 subreq = run_proc_send(state, state->ev,
796 run_event_run_proc_context(state->run_ctx),
797 path, state->argv, -1, state->timeout);
799 talloc_free(path);
801 return subreq;
804 static void run_event_next_script(struct tevent_req *subreq)
806 struct tevent_req *req = tevent_req_callback_data(
807 subreq, struct tevent_req);
808 struct run_event_state *state = tevent_req_data(
809 req, struct run_event_state);
810 struct run_event_script *script;
811 pid_t pid;
812 int ret;
813 bool status;
815 script = &state->script_list->script[state->index];
816 script->end = tevent_timeval_current();
818 status = run_proc_recv(subreq, &ret, &script->result, &pid,
819 state->script_list, &script->output);
820 TALLOC_FREE(subreq);
821 state->script_subreq = NULL;
822 if (! status) {
823 D_ERR("run_proc failed for %s, ret=%d\n", script->name, ret);
824 tevent_req_error(req, ret);
825 return;
828 if (state->cancelled) {
829 return;
832 /* Log output */
833 if (script->output != NULL) {
834 debug_log(DEBUG_ERR, script->output, script->name);
837 D_DEBUG("Script %s finished sig=%d, err=%d, status=%d\n",
838 script->name, script->result.sig, script->result.err,
839 script->result.status);
842 /* If a script fails, stop running */
843 script->summary = run_event_script_status(script);
844 if (script->summary != 0 && script->summary != -ENOEXEC) {
845 state->script_list->num_scripts = state->index + 1;
847 if (script->summary == -ETIME && pid != -1) {
848 run_event_debug(req, pid);
851 state->script_list->summary = script->summary;
852 D_NOTICE("%s event %s\n", state->event_str,
853 (script->summary == -ETIME) ? "timed out" : "failed");
855 run_event_stop_running(state->run_ctx);
856 tevent_req_done(req);
857 return;
860 state->index += 1;
862 /* All scripts executed */
863 if (state->index >= state->script_list->num_scripts) {
864 run_event_stop_running(state->run_ctx);
865 tevent_req_done(req);
866 return;
869 subreq = run_event_run_script(req);
870 if (tevent_req_nomem(subreq, req)) {
871 return;
873 tevent_req_set_callback(subreq, run_event_next_script, req);
875 state->script_subreq = subreq;
878 static void run_event_debug(struct tevent_req *req, pid_t pid)
880 struct run_event_state *state = tevent_req_data(
881 req, struct run_event_state);
882 struct tevent_req *subreq;
884 /* Debug script is run with ectx as the memory context */
885 subreq = run_debug_send(state->run_ctx, state->ev, state->run_ctx,
886 state->event_str, pid);
887 if (subreq == NULL) {
888 /* If run debug fails, it's not an error */
889 D_NOTICE("Failed to run event debug\n");
890 return;
892 tevent_req_set_callback(subreq, run_event_debug_done, NULL);
895 static void run_event_debug_done(struct tevent_req *subreq)
897 int ret = 0;
898 bool status;
900 status = run_debug_recv(subreq, &ret);
901 TALLOC_FREE(subreq);
902 if (! status) {
903 D_NOTICE("run_debug() failed, ret=%d\n", ret);
907 bool run_event_recv(struct tevent_req *req, int *perr,
908 TALLOC_CTX *mem_ctx,
909 struct run_event_script_list **script_list)
911 struct run_event_state *state = tevent_req_data(
912 req, struct run_event_state);
913 int ret;
915 if (tevent_req_is_unix_error(req, &ret)) {
916 if (perr != NULL) {
917 *perr = ret;
919 return false;
922 if (script_list != NULL) {
923 *script_list = talloc_steal(mem_ctx, state->script_list);
925 return true;