wscript: separate embedded_heimdal from system_heimdal
[Samba.git] / ctdb / common / run_event.c
blob91b3dd3241aa4dd941b3cc7cbc8a03e3c253ef59
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/glob.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/event_script.h"
36 #include "common/run_event.h"
39 * Utility functions
42 static int get_script_list(TALLOC_CTX *mem_ctx,
43 const char *script_dir,
44 struct run_event_script_list **out)
46 struct event_script_list *s_list;
47 struct run_event_script_list *script_list;
48 unsigned int i;
49 int ret;
51 ret = event_script_get_list(mem_ctx, script_dir, &s_list);
52 if (ret != 0) {
53 if (ret == ENOENT) {
54 D_WARNING("event script dir %s removed\n", script_dir);
55 } else {
56 D_WARNING("failed to get script list for %s, ret=%d\n",
57 script_dir, ret);
59 return ret;
62 if (s_list->num_scripts == 0) {
63 *out = NULL;
64 talloc_free(s_list);
65 return 0;
68 script_list = talloc_zero(mem_ctx, struct run_event_script_list);
69 if (script_list == NULL) {
70 talloc_free(s_list);
71 return ENOMEM;
74 script_list->num_scripts = s_list->num_scripts;
75 script_list->script = talloc_zero_array(script_list,
76 struct run_event_script,
77 script_list->num_scripts);
78 if (script_list->script == NULL) {
79 talloc_free(s_list);
80 talloc_free(script_list);
81 return ENOMEM;
84 for (i = 0; i < s_list->num_scripts; i++) {
85 struct event_script *s = s_list->script[i];
86 struct run_event_script *script = &script_list->script[i];
88 script->name = talloc_steal(script_list->script, s->name);
90 if (! s->enabled) {
91 script->summary = -ENOEXEC;
95 talloc_free(s_list);
96 *out = script_list;
97 return 0;
100 static int script_args(TALLOC_CTX *mem_ctx, const char *event_str,
101 const char *arg_str, const char ***out)
103 const char **argv;
104 int argc;
105 size_t len;
107 /* Preallocate argv array to avoid reallocation. */
108 len = 8;
109 argv = talloc_array(mem_ctx, const char *, len);
110 if (argv == NULL) {
111 return ENOMEM;
114 argv[0] = NULL; /* script name */
115 argv[1] = event_str;
116 argc = 2;
118 if (arg_str != NULL) {
119 char *str, *t, *tok;
121 str = talloc_strdup(argv, arg_str);
122 if (str == NULL) {
123 return ENOMEM;
126 t = str;
127 while ((tok = strtok(t, " ")) != NULL) {
128 argv[argc] = talloc_strdup(argv, tok);
129 if (argv[argc] == NULL) {
130 talloc_free(argv);
131 return ENOMEM;
133 argc += 1;
134 if (argc >= len) {
135 argv = talloc_realloc(mem_ctx, argv,
136 const char *, len + 8);
137 if (argv == NULL) {
138 return ENOMEM;
140 len += 8;
142 t = NULL;
145 talloc_free(str);
148 argv[argc] = NULL;
149 argc += 1;
151 *out = argv;
152 return 0;
155 struct run_event_context {
156 struct run_proc_context *run_proc_ctx;
157 const char *script_dir;
158 const char *debug_prog;
159 bool debug_running;
161 struct tevent_queue *queue;
162 struct tevent_req *current_req;
163 bool monitor_running;
167 int run_event_init(TALLOC_CTX *mem_ctx, struct run_proc_context *run_proc_ctx,
168 const char *script_dir, const char *debug_prog,
169 struct run_event_context **out)
171 struct run_event_context *run_ctx;
172 struct stat st;
173 int ret;
175 run_ctx = talloc_zero(mem_ctx, struct run_event_context);
176 if (run_ctx == NULL) {
177 return ENOMEM;
180 run_ctx->run_proc_ctx = run_proc_ctx;
182 ret = stat(script_dir, &st);
183 if (ret != 0) {
184 ret = errno;
185 talloc_free(run_ctx);
186 return ret;
189 if (! S_ISDIR(st.st_mode)) {
190 talloc_free(run_ctx);
191 return ENOTDIR;
194 run_ctx->script_dir = talloc_strdup(run_ctx, script_dir);
195 if (run_ctx->script_dir == NULL) {
196 talloc_free(run_ctx);
197 return ENOMEM;
200 if (debug_prog != NULL) {
201 run_ctx->debug_prog = talloc_strdup(run_ctx, debug_prog);
202 if (run_ctx->debug_prog == NULL) {
203 talloc_free(run_ctx);
204 return ENOMEM;
208 run_ctx->debug_running = false;
210 run_ctx->queue = tevent_queue_create(run_ctx, "run event queue");
211 if (run_ctx->queue == NULL) {
212 talloc_free(run_ctx);
213 return ENOMEM;
216 run_ctx->monitor_running = false;
218 *out = run_ctx;
219 return 0;
222 static struct run_proc_context *
223 run_event_run_proc_context(struct run_event_context *run_ctx)
225 return run_ctx->run_proc_ctx;
228 static const char *run_event_script_dir(struct run_event_context *run_ctx)
230 return run_ctx->script_dir;
233 static const char *run_event_debug_prog(struct run_event_context *run_ctx)
235 return run_ctx->debug_prog;
238 static struct tevent_queue *run_event_queue(struct run_event_context *run_ctx)
240 return run_ctx->queue;
243 static void run_event_start_running(struct run_event_context *run_ctx,
244 struct tevent_req *req, bool is_monitor)
246 run_ctx->current_req = req;
247 run_ctx->monitor_running = is_monitor;
250 static void run_event_stop_running(struct run_event_context *run_ctx)
252 run_ctx->current_req = NULL;
253 run_ctx->monitor_running = false;
256 static struct tevent_req *run_event_get_running(
257 struct run_event_context *run_ctx,
258 bool *is_monitor)
260 *is_monitor = run_ctx->monitor_running;
261 return run_ctx->current_req;
264 static int run_event_script_status(struct run_event_script *script)
266 int ret;
268 if (script->result.sig > 0) {
269 ret = -EINTR;
270 } else if (script->result.err > 0) {
271 if (script->result.err == EACCES) {
272 /* Map EACCESS to ENOEXEC */
273 ret = -ENOEXEC;
274 } else {
275 ret = -script->result.err;
277 } else {
278 ret = script->result.status;
281 return ret;
284 int run_event_list(struct run_event_context *run_ctx,
285 TALLOC_CTX *mem_ctx,
286 struct run_event_script_list **output)
288 struct event_script_list *s_list;
289 struct run_event_script_list *script_list;
290 int ret, i;
292 ret = event_script_get_list(mem_ctx,
293 run_event_script_dir(run_ctx),
294 &s_list);
295 if (ret != 0) {
296 return ret;
299 if (s_list->num_scripts == 0) {
300 *output = NULL;
301 talloc_free(s_list);
302 return 0;
305 script_list = talloc_zero(mem_ctx, struct run_event_script_list);
306 if (script_list == NULL) {
307 return ENOMEM;
310 script_list->num_scripts = s_list->num_scripts;
311 script_list->script = talloc_zero_array(script_list,
312 struct run_event_script,
313 script_list->num_scripts);
314 if (script_list->script == NULL) {
315 talloc_free(s_list);
316 talloc_free(script_list);
317 return ENOMEM;
320 for (i=0; i < s_list->num_scripts; i++) {
321 struct event_script *s = s_list->script[i];
322 struct run_event_script *script = &script_list->script[i];
324 script->name = talloc_steal(script_list->script, s->name);
326 if (! s->enabled) {
327 script->summary = -ENOEXEC;
332 talloc_free(s_list);
333 *output = script_list;
334 return 0;
337 int run_event_script_enable(struct run_event_context *run_ctx,
338 const char *script_name)
340 return event_script_chmod(run_event_script_dir(run_ctx),
341 script_name,
342 true);
345 int run_event_script_disable(struct run_event_context *run_ctx,
346 const char *script_name)
348 return event_script_chmod(run_event_script_dir(run_ctx),
349 script_name,
350 false);
354 * Run debug program to diagnose hung scripts
357 static int debug_args(TALLOC_CTX *mem_ctx, const char *path,
358 const char *event_str, pid_t pid, const char ***out)
360 const char **argv;
362 argv = talloc_array(mem_ctx, const char *, 4);
363 if (argv == NULL) {
364 return ENOMEM;
367 argv[0] = path;
368 argv[1] = talloc_asprintf(argv, "%d", pid);
369 argv[2] = event_str;
370 if (argv[1] == NULL) {
371 talloc_free(argv);
372 return ENOMEM;
374 argv[3] = NULL;
376 *out = argv;
377 return 0;
380 static void debug_log(int loglevel, const char *output, const char *log_prefix)
382 char *line, *s;
384 s = strdup(output);
385 if (s == NULL) {
386 DEBUG(loglevel, ("%s: %s\n", log_prefix, output));
387 return;
390 line = strtok(s, "\n");
391 while (line != NULL) {
392 DEBUG(loglevel, ("%s: %s\n", log_prefix, line));
393 line = strtok(NULL, "\n");
395 free(s);
398 struct run_debug_state {
399 struct run_event_context *run_ctx;
400 pid_t pid;
403 static void run_debug_done(struct tevent_req *subreq);
405 static struct tevent_req *run_debug_send(TALLOC_CTX *mem_ctx,
406 struct tevent_context *ev,
407 struct run_event_context *run_ctx,
408 const char *event_str, pid_t pid)
410 struct tevent_req *req, *subreq;
411 struct run_debug_state *state;
412 const char **argv;
413 const char *debug_prog;
414 int ret;
416 req = tevent_req_create(mem_ctx, &state, struct run_debug_state);
417 if (req == NULL) {
418 return NULL;
421 state->run_ctx = run_ctx;
422 state->pid = pid;
424 debug_prog = run_event_debug_prog(run_ctx);
425 if (debug_prog == NULL) {
426 tevent_req_done(req);
427 return tevent_req_post(req, ev);
430 if (run_ctx->debug_running) {
431 tevent_req_done(req);
432 return tevent_req_post(req, ev);
435 if (pid == -1) {
436 D_DEBUG("Event script terminated, nothing to debug\n");
437 tevent_req_done(req);
438 return tevent_req_post(req, ev);
441 ret = debug_args(state, debug_prog, event_str, pid, &argv);
442 if (ret != 0) {
443 D_ERR("debug_args() failed\n");
444 tevent_req_error(req, ret);
445 return tevent_req_post(req, ev);
448 D_DEBUG("Running debug %s with args \"%s %s\"\n",
449 debug_prog, argv[1], argv[2]);
451 subreq = run_proc_send(state, ev, run_event_run_proc_context(run_ctx),
452 debug_prog, argv, -1, tevent_timeval_zero());
453 if (tevent_req_nomem(subreq, req)) {
454 return tevent_req_post(req, ev);
456 tevent_req_set_callback(subreq, run_debug_done, req);
458 run_ctx->debug_running = true;
460 talloc_free(argv);
461 return req;
464 static void run_debug_done(struct tevent_req *subreq)
466 struct tevent_req *req = tevent_req_callback_data(
467 subreq, struct tevent_req);
468 struct run_debug_state *state = tevent_req_data(
469 req, struct run_debug_state);
470 char *output;
471 int ret;
472 bool status;
474 state->run_ctx->debug_running = false;
476 status = run_proc_recv(subreq, &ret, NULL, NULL, state, &output);
477 TALLOC_FREE(subreq);
478 if (! status) {
479 D_ERR("Running debug failed, ret=%d\n", ret);
482 /* Log output */
483 if (output != NULL) {
484 debug_log(DEBUG_ERR, output, "event_debug");
485 talloc_free(output);
488 kill(-state->pid, SIGTERM);
489 tevent_req_done(req);
492 static bool run_debug_recv(struct tevent_req *req, int *perr)
494 int ret;
496 if (tevent_req_is_unix_error(req, &ret)) {
497 if (perr != NULL) {
498 *perr = ret;
500 return false;
503 return true;
507 * Run a single event
510 struct run_event_state {
511 struct tevent_context *ev;
512 struct run_event_context *run_ctx;
513 const char *event_str;
514 const char *arg_str;
515 struct timeval timeout;
516 bool continue_on_failure;
518 struct run_event_script_list *script_list;
519 const char **argv;
520 struct tevent_req *script_subreq;
521 int index;
522 bool cancelled;
525 static void run_event_cancel(struct tevent_req *req);
526 static void run_event_trigger(struct tevent_req *req, void *private_data);
527 static struct tevent_req *run_event_run_script(struct tevent_req *req);
528 static void run_event_next_script(struct tevent_req *subreq);
529 static void run_event_debug(struct tevent_req *req, pid_t pid);
530 static void run_event_debug_done(struct tevent_req *subreq);
532 struct tevent_req *run_event_send(TALLOC_CTX *mem_ctx,
533 struct tevent_context *ev,
534 struct run_event_context *run_ctx,
535 const char *event_str,
536 const char *arg_str,
537 struct timeval timeout,
538 bool continue_on_failure)
540 struct tevent_req *req, *current_req;
541 struct run_event_state *state;
542 bool monitor_running, status;
544 req = tevent_req_create(mem_ctx, &state, struct run_event_state);
545 if (req == NULL) {
546 return NULL;
549 state->ev = ev;
550 state->run_ctx = run_ctx;
551 state->event_str = talloc_strdup(state, event_str);
552 if (tevent_req_nomem(state->event_str, req)) {
553 return tevent_req_post(req, ev);
555 if (arg_str != NULL) {
556 state->arg_str = talloc_strdup(state, arg_str);
557 if (tevent_req_nomem(state->arg_str, req)) {
558 return tevent_req_post(req, ev);
561 state->timeout = timeout;
562 state->continue_on_failure = continue_on_failure;
563 state->cancelled = false;
565 state->script_list = talloc_zero(state, struct run_event_script_list);
566 if (tevent_req_nomem(state->script_list, req)) {
567 return tevent_req_post(req, ev);
571 * If monitor event is running,
572 * cancel the running monitor event and run new event
574 * If any other event is running,
575 * if new event is monitor, cancel that event
576 * else add new event to the queue
579 current_req = run_event_get_running(run_ctx, &monitor_running);
580 if (current_req != NULL) {
581 if (monitor_running) {
582 run_event_cancel(current_req);
583 } else if (strcmp(event_str, "monitor") == 0) {
584 state->script_list->summary = -ECANCELED;
585 tevent_req_done(req);
586 return tevent_req_post(req, ev);
590 status = tevent_queue_add(run_event_queue(run_ctx), ev, req,
591 run_event_trigger, NULL);
592 if (! status) {
593 tevent_req_error(req, ENOMEM);
594 return tevent_req_post(req, ev);
597 return req;
600 static void run_event_cancel(struct tevent_req *req)
602 struct run_event_state *state = tevent_req_data(
603 req, struct run_event_state);
605 run_event_stop_running(state->run_ctx);
607 state->script_list->summary = -ECANCELED;
608 state->cancelled = true;
610 TALLOC_FREE(state->script_subreq);
612 tevent_req_done(req);
615 static void run_event_trigger(struct tevent_req *req, void *private_data)
617 struct tevent_req *subreq;
618 struct run_event_state *state = tevent_req_data(
619 req, struct run_event_state);
620 struct run_event_script_list *script_list;
621 int ret;
622 bool is_monitor = false;
624 D_DEBUG("Running event %s with args \"%s\"\n", state->event_str,
625 state->arg_str == NULL ? "(null)" : state->arg_str);
627 ret = get_script_list(state,
628 run_event_script_dir(state->run_ctx),
629 &script_list);
630 if (ret != 0) {
631 D_ERR("get_script_list() failed, ret=%d\n", ret);
632 tevent_req_error(req, ret);
633 return;
636 /* No scripts */
637 if (script_list == NULL || script_list->num_scripts == 0) {
638 tevent_req_done(req);
639 return;
642 talloc_free(state->script_list);
643 state->script_list = script_list;
645 ret = script_args(state, state->event_str, state->arg_str,
646 &state->argv);
647 if (ret != 0) {
648 D_ERR("script_args() failed, ret=%d\n", ret);
649 tevent_req_error(req, ret);
650 return;
653 state->index = 0;
655 subreq = run_event_run_script(req);
656 if (tevent_req_nomem(subreq, req)) {
657 return;
659 tevent_req_set_callback(subreq, run_event_next_script, req);
661 state->script_subreq = subreq;
663 if (strcmp(state->event_str, "monitor") == 0) {
664 is_monitor = true;
666 run_event_start_running(state->run_ctx, req, is_monitor);
669 static struct tevent_req *run_event_run_script(struct tevent_req *req)
671 struct run_event_state *state = tevent_req_data(
672 req, struct run_event_state);
673 struct run_event_script *script;
674 struct tevent_req *subreq;
675 char *path;
677 script = &state->script_list->script[state->index];
679 path = talloc_asprintf(state, "%s/%s.script",
680 run_event_script_dir(state->run_ctx),
681 script->name);
682 if (path == NULL) {
683 return NULL;
686 state->argv[0] = script->name;
687 script->begin = tevent_timeval_current();
689 D_DEBUG("Running %s with args \"%s %s\"\n",
690 path, state->argv[0], state->argv[1]);
692 subreq = run_proc_send(state, state->ev,
693 run_event_run_proc_context(state->run_ctx),
694 path, state->argv, -1, state->timeout);
696 talloc_free(path);
698 return subreq;
701 static void run_event_next_script(struct tevent_req *subreq)
703 struct tevent_req *req = tevent_req_callback_data(
704 subreq, struct tevent_req);
705 struct run_event_state *state = tevent_req_data(
706 req, struct run_event_state);
707 struct run_event_script *script;
708 pid_t pid;
709 int ret;
710 bool status;
712 script = &state->script_list->script[state->index];
713 script->end = tevent_timeval_current();
715 status = run_proc_recv(subreq, &ret, &script->result, &pid,
716 state->script_list, &script->output);
717 TALLOC_FREE(subreq);
718 state->script_subreq = NULL;
719 if (! status) {
720 D_ERR("run_proc failed for %s, ret=%d\n", script->name, ret);
721 run_event_stop_running(state->run_ctx);
722 tevent_req_error(req, ret);
723 return;
726 if (state->cancelled) {
727 return;
730 /* Log output */
731 if (script->output != NULL) {
732 debug_log(DEBUG_ERR, script->output, script->name);
735 D_DEBUG("Script %s finished sig=%d, err=%d, status=%d\n",
736 script->name, script->result.sig, script->result.err,
737 script->result.status);
740 /* If a script fails, stop running */
741 script->summary = run_event_script_status(script);
742 if (script->summary != 0 && script->summary != -ENOEXEC) {
743 state->script_list->summary = script->summary;
745 if (! state->continue_on_failure) {
746 state->script_list->num_scripts = state->index + 1;
748 if (script->summary == -ETIMEDOUT && pid != -1) {
749 run_event_debug(req, pid);
751 D_NOTICE("%s event %s\n", state->event_str,
752 (script->summary == -ETIMEDOUT) ?
753 "timed out" :
754 "failed");
755 run_event_stop_running(state->run_ctx);
756 tevent_req_done(req);
757 return;
761 state->index += 1;
763 /* All scripts executed */
764 if (state->index >= state->script_list->num_scripts) {
765 run_event_stop_running(state->run_ctx);
766 tevent_req_done(req);
767 return;
770 subreq = run_event_run_script(req);
771 if (tevent_req_nomem(subreq, req)) {
772 return;
774 tevent_req_set_callback(subreq, run_event_next_script, req);
776 state->script_subreq = subreq;
779 static void run_event_debug(struct tevent_req *req, pid_t pid)
781 struct run_event_state *state = tevent_req_data(
782 req, struct run_event_state);
783 struct tevent_req *subreq;
785 /* Debug script is run with ectx as the memory context */
786 subreq = run_debug_send(state->run_ctx, state->ev, state->run_ctx,
787 state->event_str, pid);
788 if (subreq == NULL) {
789 /* If run debug fails, it's not an error */
790 D_NOTICE("Failed to run event debug\n");
791 return;
793 tevent_req_set_callback(subreq, run_event_debug_done, NULL);
796 static void run_event_debug_done(struct tevent_req *subreq)
798 int ret = 0;
799 bool status;
801 status = run_debug_recv(subreq, &ret);
802 TALLOC_FREE(subreq);
803 if (! status) {
804 D_NOTICE("run_debug() failed, ret=%d\n", ret);
808 bool run_event_recv(struct tevent_req *req, int *perr,
809 TALLOC_CTX *mem_ctx,
810 struct run_event_script_list **script_list)
812 struct run_event_state *state = tevent_req_data(
813 req, struct run_event_state);
814 int ret;
816 if (tevent_req_is_unix_error(req, &ret)) {
817 if (perr != NULL) {
818 *perr = ret;
820 return false;
823 if (script_list != NULL) {
824 *script_list = talloc_steal(mem_ctx, state->script_list);
826 return true;