ldap_server: Move a variable into a smaller scope
[Samba.git] / ctdb / server / ctdb_eventd.c
blob232711ce4e24586bd463f8e478196239a64dfdc4
1 /*
2 Event script running daemon
4 Copyright (C) Amitay Isaacs 2016
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/wait.h"
24 #include "system/locale.h"
26 #include <popt.h>
27 #include <talloc.h>
28 #include <tevent.h>
30 #include "lib/util/debug.h"
31 #include "lib/util/tevent_unix.h"
32 #include "lib/util/blocking.h"
33 #include "lib/util/sys_rw.h"
34 #include "lib/util/dlinklist.h"
35 #include "lib/async_req/async_sock.h"
37 #include "protocol/protocol_api.h"
39 #include "common/comm.h"
40 #include "common/logging.h"
41 #include "common/run_proc.h"
42 #include "common/sock_daemon.h"
44 struct pending_event {
45 struct pending_event *prev, *next;
47 struct tevent_req *req;
50 struct eventd_client {
51 struct eventd_client *prev, *next;
53 struct sock_client_context *client_ctx;
54 struct pending_event *pending_list;
57 struct eventd_context {
58 const char *script_dir;
59 const char *debug_script;
60 struct run_proc_context *run_ctx;
61 struct tevent_queue *queue;
63 /* current state */
64 bool running;
65 enum ctdb_event event;
66 struct tevent_req *req;
68 /* result of last execution */
69 int result_run;
70 int result_fail;
71 struct ctdb_script_list *status_run[CTDB_EVENT_MAX];
72 struct ctdb_script_list *status_pass[CTDB_EVENT_MAX];
73 struct ctdb_script_list *status_fail[CTDB_EVENT_MAX];
75 struct eventd_client *client_list;
79 * Global state manipulation functions
82 static int eventd_context_init(TALLOC_CTX *mem_ctx,
83 struct tevent_context *ev,
84 const char *script_dir,
85 const char *debug_script,
86 struct eventd_context **result)
88 struct eventd_context *ectx;
89 int ret;
91 ectx = talloc_zero(mem_ctx, struct eventd_context);
92 if (ectx == NULL) {
93 return ENOMEM;
96 ectx->script_dir = talloc_strdup(ectx, script_dir);
97 if (ectx->script_dir == NULL) {
98 talloc_free(ectx);
99 return ENOMEM;
102 if (debug_script != NULL) {
103 ectx->debug_script = talloc_strdup(ectx, debug_script);
104 if (ectx->debug_script == NULL) {
105 talloc_free(ectx);
106 return ENOMEM;
110 ret = run_proc_init(ectx, ev, &ectx->run_ctx);
111 if (ret != 0) {
112 talloc_free(ectx);
113 return ret;
116 ectx->queue = tevent_queue_create(ectx, "run event queue");
117 if (ectx->queue == NULL) {
118 talloc_free(ectx);
119 return ENOMEM;
122 ectx->running = false;
123 ectx->event = CTDB_EVENT_INIT;
125 *result = ectx;
126 return 0;
129 static const char *eventd_script_dir(struct eventd_context *ectx)
131 return ectx->script_dir;
134 static const char *eventd_debug_script(struct eventd_context *ectx)
136 return ectx->debug_script;
139 static struct tevent_queue *eventd_queue(struct eventd_context *ectx)
141 return ectx->queue;
144 static void eventd_start_running(struct eventd_context *ectx,
145 enum ctdb_event event,
146 struct tevent_req *req)
148 ectx->running = true;
149 ectx->event = event;
150 ectx->req = req;
153 static void eventd_stop_running(struct eventd_context *ectx)
155 ectx->running = false;
156 ectx->req = NULL;
159 static void eventd_cancel_running(struct eventd_context *ectx)
161 if (ectx->req != NULL) {
162 tevent_req_error(ectx->req, ECANCELED);
165 eventd_stop_running(ectx);
168 static bool eventd_is_running(struct eventd_context *ectx,
169 enum ctdb_event *event)
171 if (event != NULL && ectx->running) {
172 *event = ectx->event;
175 return ectx->running;
178 static struct ctdb_script_list *script_list_copy(TALLOC_CTX *mem_ctx,
179 struct ctdb_script_list *s)
181 struct ctdb_script_list *s2;
183 s2 = talloc_zero(mem_ctx, struct ctdb_script_list);
184 if (s2 == NULL) {
185 return NULL;
188 s2->num_scripts = s->num_scripts;
189 s2->script = talloc_memdup(s2, s->script,
190 s->num_scripts * sizeof(struct ctdb_script));
191 if (s2->script == NULL) {
192 talloc_free(s2);
193 return NULL;
196 return s2;
199 static void eventd_set_result(struct eventd_context *ectx,
200 enum ctdb_event event,
201 struct ctdb_script_list *script_list,
202 int result)
204 struct ctdb_script_list *s;
206 /* Avoid negative values, they represent -errno */
207 result = (result < 0) ? -result : result;
209 ectx->result_run = result;
210 if (script_list == NULL) {
211 return;
214 TALLOC_FREE(ectx->status_run[event]);
215 ectx->status_run[event] = talloc_steal(ectx, script_list);
217 s = script_list_copy(ectx, script_list);
218 if (s == NULL) {
219 return;
222 if (result == 0) {
223 TALLOC_FREE(ectx->status_pass[event]);
224 ectx->status_pass[event] = s;
225 } else {
226 TALLOC_FREE(ectx->status_fail[event]);
227 ectx->status_fail[event] = s;
228 ectx->result_fail = result;
232 static int eventd_get_result(struct eventd_context *ectx,
233 enum ctdb_event event,
234 enum ctdb_event_status_state state,
235 struct ctdb_script_list **out)
237 struct ctdb_script_list *s = NULL;
238 int result = 0;
240 switch (state) {
241 case CTDB_EVENT_LAST_RUN:
242 s = ectx->status_run[event];
243 result = ectx->result_run;
244 break;
246 case CTDB_EVENT_LAST_PASS:
247 s = ectx->status_pass[event];
248 result = 0;
249 break;
251 case CTDB_EVENT_LAST_FAIL:
252 s = ectx->status_fail[event];
253 result = ectx->result_fail;
254 break;
257 *out = s;
258 return result;
262 * Run debug script to dianose hung scripts
265 static int debug_args(TALLOC_CTX *mem_ctx, const char *path,
266 enum ctdb_event event, pid_t pid, const char ***out)
268 const char **argv;
270 argv = talloc_array(mem_ctx, const char *, 4);
271 if (argv == NULL) {
272 return ENOMEM;
275 argv[0] = path;
276 argv[1] = talloc_asprintf(argv, "%d", pid);
277 argv[2] = ctdb_event_to_string(event);
278 if (argv[1] == NULL) {
279 talloc_free(argv);
280 return ENOMEM;
282 argv[3] = NULL;
284 *out = argv;
285 return 0;
288 static void debug_log(int loglevel, char *output, const char *log_prefix)
290 char *line;
292 line = strtok(output, "\n");
293 while (line != NULL) {
294 DEBUG(loglevel, ("%s: %s\n", log_prefix, line));
295 line = strtok(NULL, "\n");
299 struct run_debug_state {
300 pid_t pid;
303 static void run_debug_done(struct tevent_req *subreq);
305 static struct tevent_req *run_debug_send(TALLOC_CTX *mem_ctx,
306 struct tevent_context *ev,
307 struct eventd_context *ectx,
308 enum ctdb_event event, pid_t pid)
310 struct tevent_req *req, *subreq;
311 struct run_debug_state *state;
312 const char **argv;
313 const char *debug_script;
314 int ret;
316 req = tevent_req_create(mem_ctx, &state, struct run_debug_state);
317 if (req == NULL) {
318 return NULL;
321 state->pid = pid;
323 debug_script = eventd_debug_script(ectx);
324 if (debug_script == NULL) {
325 tevent_req_done(req);
326 return tevent_req_post(req, ev);
329 if (pid == -1) {
330 D_DEBUG("Script terminated, nothing to debug\n");
331 tevent_req_done(req);
332 return tevent_req_post(req, ev);
335 ret = debug_args(state, debug_script, event, pid, &argv);
336 if (ret != 0) {
337 D_ERR("debug_args() failed\n");
338 tevent_req_error(req, ret);
339 return tevent_req_post(req, ev);
342 D_DEBUG("Running debug %s with args \"%s %s\"\n",
343 debug_script, argv[1], argv[2]);
345 subreq = run_proc_send(state, ev, ectx->run_ctx, debug_script, argv,
346 tevent_timeval_zero());
347 if (tevent_req_nomem(subreq, req)) {
348 return tevent_req_post(req, ev);
350 tevent_req_set_callback(subreq, run_debug_done, req);
352 talloc_free(argv);
353 return req;
356 static void run_debug_done(struct tevent_req *subreq)
358 struct tevent_req *req = tevent_req_callback_data(
359 subreq, struct tevent_req);
360 struct run_debug_state *state = tevent_req_data(
361 req, struct run_debug_state);
362 char *output;
363 int ret;
364 bool status;
366 status = run_proc_recv(subreq, &ret, NULL, NULL, state, &output);
367 TALLOC_FREE(subreq);
368 if (! status) {
369 D_ERR("Running debug failed, ret=%d\n", ret);
372 /* Log output */
373 if (output != NULL) {
374 debug_log(DEBUG_ERR, output, "event_debug");
375 talloc_free(output);
378 kill(-state->pid, SIGTERM);
379 tevent_req_done(req);
382 static bool run_debug_recv(struct tevent_req *req, int *perr)
384 int ret;
386 if (tevent_req_is_unix_error(req, &ret)) {
387 if (perr != NULL) {
388 *perr = ret;
390 return false;
393 return true;
397 * Utility functions for running a single event
400 static int script_filter(const struct dirent *de)
402 size_t namelen = strlen(de->d_name);
403 char *ptr;
405 /* Ignore . and .. */
406 if (namelen < 3) {
407 return 0;
410 /* Skip filenames with ~ */
411 ptr = strchr(de->d_name, '~');
412 if (ptr != NULL) {
413 return 0;
416 /* Filename should start with [0-9][0-9]. */
417 if ((! isdigit(de->d_name[0])) ||
418 (! isdigit(de->d_name[1])) ||
419 (de->d_name[2] != '.')) {
420 return 0;
423 /* Ignore file names longer than MAX_SCRIPT_NAME */
424 if (namelen > MAX_SCRIPT_NAME) {
425 return 0;
428 return 1;
431 static int get_script_list(TALLOC_CTX *mem_ctx,
432 const char *script_dir,
433 struct ctdb_script_list **out)
435 struct dirent **namelist = NULL;
436 struct ctdb_script_list *script_list;
437 int count, ret;
438 int i;
440 script_list = talloc_zero(mem_ctx, struct ctdb_script_list);
441 if (script_list == NULL) {
442 return ENOMEM;
445 count = scandir(script_dir, &namelist, script_filter, alphasort);
446 if (count == -1) {
447 ret = errno;
448 if (ret == ENOENT) {
449 D_WARNING("event script dir %s removed\n", script_dir);
450 } else {
451 D_WARNING("scandir() failed on %s, ret=%d\n",
452 script_dir, ret);
454 *out = script_list;
455 ret = 0;
456 goto done;
459 if (count == 0) {
460 *out = script_list;
461 ret = 0;
462 goto done;
465 script_list->num_scripts = count;
466 script_list->script = talloc_zero_array(script_list,
467 struct ctdb_script,
468 count);
469 if (script_list->script == NULL) {
470 ret = ENOMEM;
471 talloc_free(script_list);
472 goto done;
475 for (i=0; i<count; i++) {
476 struct ctdb_script *s = &script_list->script[i];
477 size_t len;
479 len = strlcpy(s->name, namelist[i]->d_name, sizeof(s->name));
480 if (len >= sizeof(s->name)) {
481 ret = EIO;
482 talloc_free(script_list);
483 goto done;
487 *out = script_list;
488 ret = 0;
490 done:
491 if (namelist != NULL && count != -1) {
492 for (i=0; i<count; i++) {
493 free(namelist[i]);
495 free(namelist);
497 return ret;
500 static int script_chmod(TALLOC_CTX *mem_ctx, const char *script_dir,
501 const char *script_name, bool enable)
503 DIR *dirp;
504 struct dirent *de;
505 int ret, new_mode;
506 char *filename;
507 struct stat st;
508 bool found;
510 dirp = opendir(script_dir);
511 if (dirp == NULL) {
512 return errno;
515 found = false;
516 while ((de = readdir(dirp)) != NULL) {
517 if (strcmp(de->d_name, script_name) == 0) {
519 /* check for valid script names */
520 ret = script_filter(de);
521 if (ret == 0) {
522 closedir(dirp);
523 return EINVAL;
526 found = true;
527 break;
530 closedir(dirp);
532 if (! found) {
533 return ENOENT;
536 filename = talloc_asprintf(mem_ctx, "%s/%s", script_dir, script_name);
537 if (filename == NULL) {
538 return ENOMEM;
541 ret = stat(filename, &st);
542 if (ret != 0) {
543 ret = errno;
544 goto done;
547 if (enable) {
548 new_mode = st.st_mode | S_IXUSR;
549 } else {
550 new_mode = st.st_mode & ~(S_IXUSR | S_IXGRP | S_IXOTH);
553 ret = chmod(filename, new_mode);
554 if (ret != 0) {
555 ret = errno;
556 goto done;
559 done:
560 talloc_free(filename);
561 return ret;
564 static int script_args(TALLOC_CTX *mem_ctx, enum ctdb_event event,
565 const char *arg_str, const char ***out)
567 const char **argv;
568 int argc;
570 argv = talloc_array(mem_ctx, const char *, 7);
571 if (argv == NULL) {
572 return ENOMEM;
575 argv[0] = NULL; /* script name */
576 argv[1] = ctdb_event_to_string(event);
577 argc = 2;
579 if (arg_str != NULL) {
580 char *str, *t, *tok;
582 str = talloc_strdup(argv, arg_str);
583 if (str == NULL) {
584 return ENOMEM;
587 t = str;
588 while ((tok = strtok(t, " ")) != NULL) {
589 argv[argc] = talloc_strdup(argv, tok);
590 if (argv[argc] == NULL) {
591 talloc_free(argv);
592 return ENOMEM;
594 argc += 1;
595 if (argc >= 7) {
596 talloc_free(argv);
597 return EINVAL;
599 t = NULL;
602 talloc_free(str);
605 argv[argc] = NULL;
606 argc += 1;
608 *out = argv;
609 return 0;
613 * Run a single event
616 struct run_event_state {
617 struct tevent_context *ev;
618 struct eventd_context *ectx;
619 struct timeval timeout;
620 enum ctdb_event event;
622 struct ctdb_script_list *script_list;
623 const char **argv;
624 int index;
625 int status;
628 static struct tevent_req *run_event_run_script(struct tevent_req *req);
629 static void run_event_next_script(struct tevent_req *subreq);
630 static void run_event_debug(struct tevent_req *req, pid_t pid);
631 static void run_event_debug_done(struct tevent_req *subreq);
633 static struct tevent_req *run_event_send(TALLOC_CTX *mem_ctx,
634 struct tevent_context *ev,
635 struct eventd_context *ectx,
636 enum ctdb_event event,
637 const char *arg_str,
638 uint32_t timeout)
640 struct tevent_req *req, *subreq;
641 struct run_event_state *state;
642 int ret;
644 req = tevent_req_create(mem_ctx, &state, struct run_event_state);
645 if (req == NULL) {
646 return NULL;
649 state->ev = ev;
650 state->ectx = ectx;
651 state->event = event;
653 ret = get_script_list(state, eventd_script_dir(ectx),
654 &state->script_list);
655 if (ret != 0) {
656 D_ERR("get_script_list() failed, ret=%d\n", ret);
657 tevent_req_error(req, ret);
658 return tevent_req_post(req, ev);
661 /* No scripts */
662 if (state->script_list->num_scripts == 0) {
663 tevent_req_done(req);
664 return tevent_req_post(req, ev);
667 ret = script_args(state, event, arg_str, &state->argv);
668 if (ret != 0) {
669 D_ERR("script_args() failed, ret=%d\n", ret);
670 tevent_req_error(req, ret);
671 return tevent_req_post(req, ev);
674 if (timeout > 0) {
675 state->timeout = tevent_timeval_current_ofs(timeout, 0);
677 state->index = 0;
678 eventd_start_running(ectx, event, req);
680 subreq = run_event_run_script(req);
681 if (tevent_req_nomem(subreq, req)) {
682 return tevent_req_post(req, ev);
684 tevent_req_set_callback(subreq, run_event_next_script, req);
686 return req;
689 static struct tevent_req *run_event_run_script(struct tevent_req *req)
691 struct run_event_state *state = tevent_req_data(
692 req, struct run_event_state);
693 struct ctdb_script *script;
694 struct tevent_req *subreq;
695 char *path;
697 script = &state->script_list->script[state->index];
699 path = talloc_asprintf(state, "%s/%s",
700 eventd_script_dir(state->ectx), script->name);
701 if (path == NULL) {
702 return NULL;
705 state->argv[0] = script->name;
706 script->start = tevent_timeval_current();
708 D_DEBUG("Running %s with args \"%s %s\"\n",
709 path, state->argv[0], state->argv[1]);
711 subreq = run_proc_send(state, state->ev, state->ectx->run_ctx,
712 path, state->argv, state->timeout);
714 talloc_free(path);
716 return subreq;
719 static void run_event_next_script(struct tevent_req *subreq)
721 struct tevent_req *req = tevent_req_callback_data(
722 subreq, struct tevent_req);
723 struct run_event_state *state = tevent_req_data(
724 req, struct run_event_state);
725 struct ctdb_script *script;
726 char *output;
727 struct run_proc_result result;
728 pid_t pid;
729 int ret;
730 bool status;
732 script = &state->script_list->script[state->index];
733 script->finished = tevent_timeval_current();
735 status = run_proc_recv(subreq, &ret, &result, &pid, state, &output);
736 TALLOC_FREE(subreq);
737 if (! status) {
738 D_ERR("run_proc failed for %s, ret=%d\n", script->name, ret);
739 tevent_req_error(req, ret);
740 return;
743 D_DEBUG("Script %s finished sig=%d, err=%d, status=%d\n",
744 script->name, result.sig, result.err, result.status);
746 if (output != NULL) {
747 debug_log(DEBUG_ERR, output, script->name);
750 if (result.sig > 0) {
751 script->status = -EINTR;
752 } else if (result.err > 0) {
753 if (result.err == EACCES) {
754 /* Map EACCESS to ENOEXEC */
755 script->status = -ENOEXEC;
756 } else {
757 script->status = -result.err;
759 } else {
760 script->status = result.status;
763 if (script->status != 0 && output != NULL) {
764 size_t n;
766 n = strlcpy(script->output, output, MAX_SCRIPT_OUTPUT);
767 if (n >= MAX_SCRIPT_OUTPUT) {
768 script->output[MAX_SCRIPT_OUTPUT] = '\0';
772 /* If a script fails, stop running */
773 if (script->status != 0 && script->status != -ENOEXEC) {
774 state->status = script->status;
775 eventd_stop_running(state->ectx);
776 state->script_list->num_scripts = state->index + 1;
777 eventd_set_result(state->ectx, state->event,
778 state->script_list, state->status);
780 if (state->status == -ETIME && pid != -1) {
781 run_event_debug(req, pid);
784 D_ERR("%s event %s\n", ctdb_event_to_string(state->event),
785 (state->status == -ETIME) ? "timed out" : "failed");
787 tevent_req_done(req);
788 return;
791 state->index += 1;
793 /* All scripts executed */
794 if (state->index >= state->script_list->num_scripts) {
795 eventd_stop_running(state->ectx);
796 eventd_set_result(state->ectx, state->event,
797 state->script_list, state->status);
798 tevent_req_done(req);
799 return;
802 subreq = run_event_run_script(req);
803 if (tevent_req_nomem(subreq, req)) {
804 return;
806 tevent_req_set_callback(subreq, run_event_next_script, req);
809 static void run_event_debug(struct tevent_req *req, pid_t pid)
811 struct run_event_state *state = tevent_req_data(
812 req, struct run_event_state);
813 struct tevent_req *subreq;
815 /* Debug script is run with ectx as the memory context */
816 subreq = run_debug_send(state->ectx, state->ev, state->ectx,
817 state->event, pid);
818 if (subreq == NULL) {
819 /* If run debug fails, it's not an error */
820 D_NOTICE("Failed to run event debug\n");
821 return;
823 tevent_req_set_callback(subreq, run_event_debug_done, NULL);
826 static void run_event_debug_done(struct tevent_req *subreq)
828 int ret = 0;
829 bool status;
831 status = run_debug_recv(subreq, &ret);
832 TALLOC_FREE(subreq);
833 if (! status) {
834 D_NOTICE("run_debug() failed, ret=%d\n", ret);
838 static bool run_event_recv(struct tevent_req *req, int *perr, int *status)
840 struct run_event_state *state = tevent_req_data(
841 req, struct run_event_state);
842 int ret;
844 if (tevent_req_is_unix_error(req, &ret)) {
845 if (ret == ECANCELED) {
846 if (status != NULL) {
847 *status = -ECANCELED;
849 return true;
852 if (perr != NULL) {
853 *perr = ret;
855 return false;
858 if (status != NULL) {
859 *status = state->status;
861 return true;
865 * Process RUN command
868 struct command_run_state {
869 struct tevent_context *ev;
870 struct eventd_context *ectx;
871 struct eventd_client *client;
873 enum ctdb_event event;
874 uint32_t timeout;
875 const char *arg_str;
876 struct ctdb_event_reply *reply;
879 static void command_run_trigger(struct tevent_req *req, void *private_data);
880 static void command_run_done(struct tevent_req *subreq);
882 static struct tevent_req *command_run_send(TALLOC_CTX *mem_ctx,
883 struct tevent_context *ev,
884 struct eventd_context *ectx,
885 struct eventd_client *client,
886 struct ctdb_event_request *request)
888 struct tevent_req *req;
889 struct command_run_state *state;
890 struct pending_event *pending;
891 enum ctdb_event running_event;
892 bool running, status;
894 req = tevent_req_create(mem_ctx, &state, struct command_run_state);
895 if (req == NULL) {
896 return NULL;
899 state->ev = ev;
900 state->ectx = ectx;
901 state->client = client;
903 state->event = request->rdata.data.run->event;
904 state->timeout = request->rdata.data.run->timeout;
905 state->arg_str = talloc_steal(state, request->rdata.data.run->arg_str);
907 state->reply = talloc_zero(state, struct ctdb_event_reply);
908 if (tevent_req_nomem(state->reply, req)) {
909 return tevent_req_post(req, ev);
912 state->reply->rdata.command = request->rdata.command;
915 * If monitor event is running,
916 * Cancel the running monitor event and run new event
918 * If any other event is running,
919 * If new event is monitor, cancel that event
920 * Else add new event to the queue
923 running = eventd_is_running(ectx, &running_event);
924 if (running) {
925 if (running_event == CTDB_EVENT_MONITOR) {
926 eventd_cancel_running(ectx);
927 } else if (state->event == CTDB_EVENT_MONITOR) {
928 state->reply->rdata.result = -ECANCELED;
929 tevent_req_done(req);
930 return tevent_req_post(req, ev);
934 pending = talloc_zero(state, struct pending_event);
935 if (tevent_req_nomem(pending, req)) {
936 return tevent_req_post(req, ev);
939 pending->req = req;
940 DLIST_ADD(client->pending_list, pending);
942 status = tevent_queue_add(eventd_queue(ectx), ev, req,
943 command_run_trigger, pending);
944 if (! status) {
945 tevent_req_error(req, ENOMEM);
946 return tevent_req_post(req, ev);
949 return req;
952 static void command_run_trigger(struct tevent_req *req, void *private_data)
954 struct pending_event *pending = talloc_get_type_abort(
955 private_data, struct pending_event);
956 struct command_run_state *state = tevent_req_data(
957 req, struct command_run_state);
958 struct tevent_req *subreq;
960 DLIST_REMOVE(state->client->pending_list, pending);
962 if (pending->req != req) {
963 tevent_req_error(req, EIO);
964 return;
967 talloc_free(pending);
969 D_DEBUG("Running event %s with args \"%s\"\n",
970 ctdb_event_to_string(state->event), state->arg_str);
972 subreq = run_event_send(state, state->ev, state->ectx,
973 state->event, state->arg_str, state->timeout);
974 if (tevent_req_nomem(subreq, req)) {
975 return;
977 tevent_req_set_callback(subreq, command_run_done, req);
980 static void command_run_done(struct tevent_req *subreq)
982 struct tevent_req *req = tevent_req_callback_data(
983 subreq, struct tevent_req);
984 struct command_run_state *state = tevent_req_data(
985 req, struct command_run_state);
986 int ret, result;
987 bool status;
989 status = run_event_recv(subreq, &ret, &result);
990 if (! status) {
991 tevent_req_error(req, ret);
992 return;
995 state->reply->rdata.result = result;
996 tevent_req_done(req);
999 static bool command_run_recv(struct tevent_req *req, int *perr,
1000 TALLOC_CTX *mem_ctx,
1001 struct ctdb_event_reply **reply)
1003 struct command_run_state *state = tevent_req_data(
1004 req, struct command_run_state);
1005 int ret;
1007 if (tevent_req_is_unix_error(req, &ret)) {
1008 if (perr != NULL) {
1009 *perr = ret;
1011 return false;
1014 if (reply != NULL) {
1015 *reply = talloc_steal(mem_ctx, state->reply);
1017 return true;
1021 * Process STATUS command
1024 struct command_status_state {
1025 struct ctdb_event_reply *reply;
1028 static struct tevent_req *command_status_send(
1029 TALLOC_CTX *mem_ctx,
1030 struct tevent_context *ev,
1031 struct eventd_context *ectx,
1032 struct eventd_client *client,
1033 struct ctdb_event_request *request)
1035 struct tevent_req *req;
1036 struct command_status_state *state;
1037 enum ctdb_event event;
1038 enum ctdb_event_status_state estate;
1040 req = tevent_req_create(mem_ctx, &state, struct command_status_state);
1041 if (req == NULL) {
1042 return NULL;
1045 event = request->rdata.data.status->event;
1046 estate = request->rdata.data.status->state;
1048 state->reply = talloc_zero(state, struct ctdb_event_reply);
1049 if (tevent_req_nomem(state->reply, req)) {
1050 return tevent_req_post(req, ev);
1053 state->reply->rdata.data.status =
1054 talloc(state->reply, struct ctdb_event_reply_status);
1055 if (tevent_req_nomem(state->reply->rdata.data.status, req)) {
1056 return tevent_req_post(req, ev);
1059 state->reply->rdata.command = request->rdata.command;
1060 state->reply->rdata.result = 0;
1061 state->reply->rdata.data.status->status =
1062 eventd_get_result(ectx, event, estate,
1063 &state->reply->rdata.data.status->script_list);
1065 tevent_req_done(req);
1066 return tevent_req_post(req, ev);
1069 static bool command_status_recv(struct tevent_req *req, int *perr,
1070 TALLOC_CTX *mem_ctx,
1071 struct ctdb_event_reply **reply)
1073 struct command_status_state *state = tevent_req_data(
1074 req, struct command_status_state);
1075 int ret;
1077 if (tevent_req_is_unix_error(req, &ret)) {
1078 if (perr != NULL) {
1079 *perr = ret;
1081 return false;
1084 if (reply != NULL) {
1085 *reply = talloc_steal(mem_ctx, state->reply);
1087 return true;
1091 * Process SCRIPT_LIST command
1094 struct command_script_list_state {
1095 struct ctdb_event_reply *reply;
1098 static struct tevent_req *command_script_list_send(
1099 TALLOC_CTX *mem_ctx,
1100 struct tevent_context *ev,
1101 struct eventd_context *ectx,
1102 struct eventd_client *client,
1103 struct ctdb_event_request *request)
1105 struct tevent_req *req;
1106 struct command_script_list_state *state;
1107 struct ctdb_script_list *script_list;
1108 int ret, i;
1110 req = tevent_req_create(mem_ctx, &state,
1111 struct command_script_list_state);
1112 if (req == NULL) {
1113 return NULL;
1116 state->reply = talloc_zero(state, struct ctdb_event_reply);
1117 if (tevent_req_nomem(state->reply, req)) {
1118 return tevent_req_post(req, ev);
1121 state->reply->rdata.data.script_list =
1122 talloc(state->reply, struct ctdb_event_reply_script_list);
1123 if (tevent_req_nomem(state->reply->rdata.data.script_list, req)) {
1124 return tevent_req_post(req, ev);
1127 state->reply->rdata.command = request->rdata.command;
1129 ret = get_script_list(state, eventd_script_dir(ectx), &script_list);
1130 if (ret != 0) {
1131 state->reply->rdata.result = -ret;
1132 state->reply->rdata.data.script_list->script_list = NULL;
1134 tevent_req_done(req);
1135 return tevent_req_post(req, ev);
1138 for (i=0; i<script_list->num_scripts; i++) {
1139 struct ctdb_script *script = &script_list->script[i];
1140 struct stat st;
1141 char *path = NULL;
1143 path = talloc_asprintf(state, "%s/%s",
1144 eventd_script_dir(ectx), script->name);
1145 if (tevent_req_nomem(path, req)) {
1146 continue;
1149 ret = stat(path, &st);
1150 if (ret != 0) {
1151 TALLOC_FREE(path);
1152 continue;
1155 if (! (st.st_mode & S_IXUSR)) {
1156 script->status = -ENOEXEC;
1159 TALLOC_FREE(path);
1162 state->reply->rdata.data.script_list->script_list =
1163 talloc_steal(state->reply, script_list);
1165 tevent_req_done(req);
1166 return tevent_req_post(req, ev);
1169 static bool command_script_list_recv(struct tevent_req *req, int *perr,
1170 TALLOC_CTX *mem_ctx,
1171 struct ctdb_event_reply **reply)
1173 struct command_script_list_state *state = tevent_req_data(
1174 req, struct command_script_list_state);
1175 int ret;
1177 if (tevent_req_is_unix_error(req, &ret)) {
1178 if (perr != NULL) {
1179 *perr = ret;
1181 return false;
1184 if (reply != NULL) {
1185 *reply = talloc_steal(mem_ctx, state->reply);
1187 return true;
1191 * Process SCRIPT_ENABLE command
1194 struct command_script_enable_state {
1195 struct ctdb_event_reply *reply;
1198 static struct tevent_req *command_script_enable_send(
1199 TALLOC_CTX *mem_ctx,
1200 struct tevent_context *ev,
1201 struct eventd_context *ectx,
1202 struct eventd_client *client,
1203 struct ctdb_event_request *request)
1205 struct tevent_req *req;
1206 struct command_script_enable_state *state;
1207 const char *script_name;
1208 int ret;
1210 req = tevent_req_create(mem_ctx, &state,
1211 struct command_script_enable_state);
1212 if (req == NULL) {
1213 return NULL;
1216 script_name = request->rdata.data.script_enable->script_name;
1218 state->reply = talloc_zero(state, struct ctdb_event_reply);
1219 if (tevent_req_nomem(state->reply, req)) {
1220 return tevent_req_post(req, ev);
1223 state->reply->rdata.command = request->rdata.command;
1225 ret = script_chmod(state, eventd_script_dir(ectx), script_name, true);
1226 state->reply->rdata.result = -ret;
1228 tevent_req_done(req);
1229 return tevent_req_post(req, ev);
1232 static bool command_script_enable_recv(struct tevent_req *req, int *perr,
1233 TALLOC_CTX *mem_ctx,
1234 struct ctdb_event_reply **reply)
1236 struct command_script_enable_state *state = tevent_req_data(
1237 req, struct command_script_enable_state);
1238 int ret;
1240 if (tevent_req_is_unix_error(req, &ret)) {
1241 if (perr != NULL) {
1242 *perr = ret;
1244 return false;
1247 if (reply != NULL) {
1248 *reply = talloc_steal(mem_ctx, state->reply);
1250 return true;
1254 * Process SCRIPT_DISABLE command
1257 struct command_script_disable_state {
1258 struct ctdb_event_reply *reply;
1261 static struct tevent_req *command_script_disable_send(
1262 TALLOC_CTX *mem_ctx,
1263 struct tevent_context *ev,
1264 struct eventd_context *ectx,
1265 struct eventd_client *client,
1266 struct ctdb_event_request *request)
1268 struct tevent_req *req;
1269 struct command_script_disable_state *state;
1270 const char *script_name;
1271 int ret;
1273 req = tevent_req_create(mem_ctx, &state,
1274 struct command_script_disable_state);
1275 if (req == NULL) {
1276 return NULL;
1279 script_name = request->rdata.data.script_disable->script_name;
1281 state->reply = talloc_zero(state, struct ctdb_event_reply);
1282 if (tevent_req_nomem(state->reply, req)) {
1283 return tevent_req_post(req, ev);
1286 state->reply->rdata.command = request->rdata.command;
1288 ret = script_chmod(state, eventd_script_dir(ectx), script_name, false);
1289 state->reply->rdata.result = -ret;
1291 tevent_req_done(req);
1292 return tevent_req_post(req, ev);
1295 static bool command_script_disable_recv(struct tevent_req *req, int *perr,
1296 TALLOC_CTX *mem_ctx,
1297 struct ctdb_event_reply **reply)
1299 struct command_script_disable_state *state = tevent_req_data(
1300 req, struct command_script_disable_state);
1301 int ret;
1303 if (tevent_req_is_unix_error(req, &ret)) {
1304 if (perr != NULL) {
1305 *perr = ret;
1307 return false;
1310 if (reply != NULL) {
1311 *reply = talloc_steal(mem_ctx, state->reply);
1313 return true;
1317 * Process clients
1320 static struct eventd_client *client_find(struct eventd_context *ectx,
1321 struct sock_client_context *client_ctx)
1323 struct eventd_client *client;
1325 for (client = ectx->client_list;
1326 client != NULL;
1327 client = client->next) {
1328 if (client->client_ctx == client_ctx) {
1329 return client;
1333 return NULL;
1336 static bool client_connect(struct sock_client_context *client_ctx,
1337 void *private_data)
1339 struct eventd_context *ectx = talloc_get_type_abort(
1340 private_data, struct eventd_context);
1341 struct eventd_client *client;
1343 client = talloc_zero(ectx, struct eventd_client);
1344 if (client == NULL) {
1345 return false;
1348 client->client_ctx = client_ctx;
1350 DLIST_ADD(ectx->client_list, client);
1351 return true;
1354 static void client_disconnect(struct sock_client_context *client_ctx,
1355 void *private_data)
1357 struct eventd_context *ectx = talloc_get_type_abort(
1358 private_data, struct eventd_context);
1359 struct eventd_client *client;
1360 struct pending_event *pe;
1362 client = client_find(ectx, client_ctx);
1363 if (client == NULL) {
1364 return;
1367 /* Get rid of pending events */
1368 while ((pe = client->pending_list) != NULL) {
1369 DLIST_REMOVE(client->pending_list, pe);
1370 talloc_free(pe->req);
1374 struct client_process_state {
1375 struct tevent_context *ev;
1377 struct eventd_client *client;
1378 struct ctdb_event_request request;
1381 static void client_run_done(struct tevent_req *subreq);
1382 static void client_status_done(struct tevent_req *subreq);
1383 static void client_script_list_done(struct tevent_req *subreq);
1384 static void client_script_enable_done(struct tevent_req *subreq);
1385 static void client_script_disable_done(struct tevent_req *subreq);
1386 static void client_process_reply(struct tevent_req *req,
1387 struct ctdb_event_reply *reply);
1388 static void client_process_reply_done(struct tevent_req *subreq);
1390 static struct tevent_req *client_process_send(
1391 TALLOC_CTX *mem_ctx,
1392 struct tevent_context *ev,
1393 struct sock_client_context *client_ctx,
1394 uint8_t *buf, size_t buflen,
1395 void *private_data)
1397 struct eventd_context *ectx = talloc_get_type_abort(
1398 private_data, struct eventd_context);
1399 struct tevent_req *req, *subreq;
1400 struct client_process_state *state;
1401 int ret;
1403 req = tevent_req_create(mem_ctx, &state, struct client_process_state);
1404 if (req == NULL) {
1405 return NULL;
1408 state->ev = ev;
1410 state->client = client_find(ectx, client_ctx);
1411 if (state->client == NULL) {
1412 tevent_req_error(req, EIO);
1413 return tevent_req_post(req, ev);
1416 ret = ctdb_event_request_pull(buf, buflen, state, &state->request);
1417 if (ret != 0) {
1418 tevent_req_error(req, EPROTO);
1419 return tevent_req_post(req, ev);
1422 switch (state->request.rdata.command) {
1423 case CTDB_EVENT_COMMAND_RUN:
1424 subreq = command_run_send(state, ev, ectx, state->client,
1425 &state->request);
1426 if (tevent_req_nomem(subreq, req)) {
1427 return tevent_req_post(req, ev);
1429 tevent_req_set_callback(subreq, client_run_done, req);
1430 break;
1432 case CTDB_EVENT_COMMAND_STATUS:
1433 subreq = command_status_send(state, ev, ectx, state->client,
1434 &state->request);
1435 if (tevent_req_nomem(subreq, req)) {
1436 return tevent_req_post(req, ev);
1438 tevent_req_set_callback(subreq, client_status_done, req);
1439 break;
1441 case CTDB_EVENT_COMMAND_SCRIPT_LIST:
1442 subreq = command_script_list_send(state, ev, ectx,
1443 state->client,
1444 &state->request);
1445 if (tevent_req_nomem(subreq, req)) {
1446 return tevent_req_post(req, ev);
1448 tevent_req_set_callback(subreq, client_script_list_done, req);
1449 break;
1451 case CTDB_EVENT_COMMAND_SCRIPT_ENABLE:
1452 subreq = command_script_enable_send(state, ev, ectx,
1453 state->client,
1454 &state->request);
1455 if (tevent_req_nomem(subreq, req)) {
1456 return tevent_req_post(req, ev);
1458 tevent_req_set_callback(subreq, client_script_enable_done,
1459 req);
1460 break;
1462 case CTDB_EVENT_COMMAND_SCRIPT_DISABLE:
1463 subreq = command_script_disable_send(state, ev, ectx,
1464 state->client,
1465 &state->request);
1466 if (tevent_req_nomem(subreq, req)) {
1467 return tevent_req_post(req, ev);
1469 tevent_req_set_callback(subreq, client_script_disable_done,
1470 req);
1471 break;
1474 return req;
1477 static void client_run_done(struct tevent_req *subreq)
1479 struct tevent_req *req = tevent_req_callback_data(
1480 subreq, struct tevent_req);
1481 struct client_process_state *state = tevent_req_data(
1482 req, struct client_process_state);
1483 struct ctdb_event_reply *reply = NULL;
1484 int ret = 0;
1485 bool status;
1487 status = command_run_recv(subreq, &ret, state, &reply);
1488 TALLOC_FREE(subreq);
1489 if (! status) {
1490 D_ERR("COMMAND_RUN failed\n");
1491 tevent_req_error(req, ret);
1492 return;
1495 client_process_reply(req, reply);
1496 talloc_free(reply);
1499 static void client_status_done(struct tevent_req *subreq)
1501 struct tevent_req *req = tevent_req_callback_data(
1502 subreq, struct tevent_req);
1503 struct client_process_state *state = tevent_req_data(
1504 req, struct client_process_state);
1505 struct ctdb_event_reply *reply = NULL;
1506 int ret = 0;
1507 bool status;
1509 status = command_status_recv(subreq, &ret, state, &reply);
1510 TALLOC_FREE(subreq);
1511 if (! status) {
1512 D_ERR("COMMAND_STATUS failed\n");
1513 tevent_req_error(req, ret);
1514 return;
1517 client_process_reply(req, reply);
1518 talloc_free(reply);
1521 static void client_script_list_done(struct tevent_req *subreq)
1523 struct tevent_req *req = tevent_req_callback_data(
1524 subreq, struct tevent_req);
1525 struct client_process_state *state = tevent_req_data(
1526 req, struct client_process_state);
1527 struct ctdb_event_reply *reply = NULL;
1528 int ret = 0;
1529 bool status;
1531 status = command_script_list_recv(subreq, &ret, state, &reply);
1532 TALLOC_FREE(subreq);
1533 if (! status) {
1534 D_ERR("COMMAND_SCRIPT_LIST failed\n");
1535 tevent_req_error(req, ret);
1536 return;
1539 client_process_reply(req, reply);
1540 talloc_free(reply);
1543 static void client_script_enable_done(struct tevent_req *subreq)
1545 struct tevent_req *req = tevent_req_callback_data(
1546 subreq, struct tevent_req);
1547 struct client_process_state *state = tevent_req_data(
1548 req, struct client_process_state);
1549 struct ctdb_event_reply *reply = NULL;
1550 int ret = 0;
1551 bool status;
1553 status = command_script_enable_recv(subreq, &ret, state, &reply);
1554 TALLOC_FREE(subreq);
1555 if (! status) {
1556 D_ERR("COMMAND_SCRIPT_ENABLE failed\n");
1557 tevent_req_error(req, ret);
1558 return;
1561 client_process_reply(req, reply);
1562 talloc_free(reply);
1565 static void client_script_disable_done(struct tevent_req *subreq)
1567 struct tevent_req *req = tevent_req_callback_data(
1568 subreq, struct tevent_req);
1569 struct client_process_state *state = tevent_req_data(
1570 req, struct client_process_state);
1571 struct ctdb_event_reply *reply = NULL;
1572 int ret = 0;
1573 bool status;
1575 status = command_script_disable_recv(subreq, &ret, state, &reply);
1576 TALLOC_FREE(subreq);
1577 if (! status) {
1578 D_ERR("COMMAND_SCRIPT_DISABLE failed\n");
1579 tevent_req_error(req, ret);
1580 return;
1583 client_process_reply(req, reply);
1584 talloc_free(reply);
1587 static void client_process_reply(struct tevent_req *req,
1588 struct ctdb_event_reply *reply)
1590 struct client_process_state *state = tevent_req_data(
1591 req, struct client_process_state);
1592 struct tevent_req *subreq;
1593 uint8_t *buf;
1594 size_t buflen;
1595 int ret;
1597 ctdb_event_header_fill(&reply->header, state->request.header.reqid);
1599 buflen = ctdb_event_reply_len(reply);
1600 buf = talloc_zero_size(state, buflen);
1601 if (tevent_req_nomem(buf, req)) {
1602 return;
1605 ret = ctdb_event_reply_push(reply, buf, &buflen);
1606 if (ret != 0) {
1607 talloc_free(buf);
1608 tevent_req_error(req, ret);
1609 return;
1612 subreq = sock_socket_write_send(state, state->ev,
1613 state->client->client_ctx,
1614 buf, buflen);
1615 if (tevent_req_nomem(subreq, req)) {
1616 return;
1618 tevent_req_set_callback(subreq, client_process_reply_done, req);
1621 static void client_process_reply_done(struct tevent_req *subreq)
1623 struct tevent_req *req = tevent_req_callback_data(
1624 subreq, struct tevent_req);
1625 int ret;
1626 bool status;
1628 status = sock_socket_write_recv(subreq, &ret);
1629 TALLOC_FREE(subreq);
1630 if (! status) {
1631 D_ERR("Sending reply failed\n");
1632 tevent_req_error(req, ret);
1633 return;
1636 tevent_req_done(req);
1639 static bool client_process_recv(struct tevent_req *req, int *perr)
1641 int ret;
1643 if (tevent_req_is_unix_error(req, &ret)) {
1644 if (perr != NULL) {
1645 *perr = ret;
1647 return false;
1650 return true;
1654 * Event daemon
1657 static void eventd_shutdown(void *private_data)
1659 struct eventd_context *ectx = talloc_get_type_abort(
1660 private_data, struct eventd_context);
1661 struct eventd_client *client;
1663 while ((client = ectx->client_list) != NULL) {
1664 DLIST_REMOVE(ectx->client_list, client);
1665 talloc_free(client);
1669 static struct {
1670 const char *debug_script;
1671 const char *script_dir;
1672 const char *logging;
1673 const char *debug_level;
1674 const char *pidfile;
1675 const char *socket;
1676 int pid;
1677 } options = {
1678 .debug_level = "ERR",
1681 struct poptOption cmdline_options[] = {
1682 POPT_AUTOHELP
1683 { "debug_script", 'D', POPT_ARG_STRING, &options.debug_script, 0,
1684 "debug script", "FILE" },
1685 { "pid", 'P', POPT_ARG_INT, &options.pid, 0,
1686 "pid to wait for", "PID" },
1687 { "event_script_dir", 'e', POPT_ARG_STRING, &options.script_dir, 0,
1688 "event script dir", "DIRECTORY" },
1689 { "logging", 'l', POPT_ARG_STRING, &options.logging, 0,
1690 "logging specification" },
1691 { "debug", 'd', POPT_ARG_STRING, &options.debug_level, 0,
1692 "debug level" },
1693 { "pidfile", 'p', POPT_ARG_STRING, &options.pidfile, 0,
1694 "eventd pid file", "FILE" },
1695 { "socket", 's', POPT_ARG_STRING, &options.socket, 0,
1696 "eventd socket path", "FILE" },
1697 POPT_TABLEEND
1700 int main(int argc, const char **argv)
1702 poptContext pc;
1703 TALLOC_CTX *mem_ctx;
1704 struct tevent_context *ev;
1705 struct eventd_context *ectx;
1706 struct sock_daemon_context *sockd;
1707 struct sock_daemon_funcs daemon_funcs;
1708 struct sock_socket_funcs socket_funcs;
1709 struct stat statbuf;
1710 int opt, ret;
1712 /* Set default options */
1713 options.pid = -1;
1715 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
1716 POPT_CONTEXT_KEEP_FIRST);
1717 while ((opt = poptGetNextOpt(pc)) != -1) {
1718 fprintf(stderr, "Invalid options %s: %s\n",
1719 poptBadOption(pc, 0), poptStrerror(opt));
1720 exit(1);
1723 if (options.socket == NULL) {
1724 fprintf(stderr, "Please specify eventd socket (--socket)\n");
1725 exit(1);
1728 if (options.script_dir == NULL) {
1729 fprintf(stderr,
1730 "Please specify script dir (--event_script_dir)\n");
1731 exit(1);
1734 if (options.logging == NULL) {
1735 fprintf(stderr,
1736 "Please specify logging (--logging)\n");
1737 exit(1);
1740 ret = stat(options.script_dir, &statbuf);
1741 if (ret != 0) {
1742 ret = errno;
1743 fprintf(stderr, "Error reading script_dir %s, ret=%d\n",
1744 options.script_dir, ret);
1745 exit(1);
1747 if (! S_ISDIR(statbuf.st_mode)) {
1748 fprintf(stderr, "script_dir %s is not a directory\n",
1749 options.script_dir);
1750 exit(1);
1753 mem_ctx = talloc_new(NULL);
1754 if (mem_ctx == NULL) {
1755 exit(1);
1758 ev = tevent_context_init(mem_ctx);
1759 if (ev == NULL) {
1760 ret = 1;
1761 goto fail;
1764 ret = eventd_context_init(mem_ctx, ev, options.script_dir,
1765 options.debug_script, &ectx);
1766 if (ret != 0) {
1767 goto fail;
1770 daemon_funcs = (struct sock_daemon_funcs) {
1771 .shutdown = eventd_shutdown,
1774 ret = sock_daemon_setup(mem_ctx, "ctdb-eventd", options.logging,
1775 options.debug_level, options.pidfile,
1776 &daemon_funcs, ectx, &sockd);
1777 if (ret != 0) {
1778 goto fail;
1781 socket_funcs = (struct sock_socket_funcs) {
1782 .connect = client_connect,
1783 .disconnect = client_disconnect,
1784 .read_send = client_process_send,
1785 .read_recv = client_process_recv,
1788 ret = sock_daemon_add_unix(sockd, options.socket, &socket_funcs, ectx);
1789 if (ret != 0) {
1790 goto fail;
1793 ret = sock_daemon_run(ev, sockd, options.pid);
1794 if (ret == EINTR) {
1795 ret = 0;
1798 fail:
1799 talloc_free(mem_ctx);
1800 (void)poptFreeContext(pc);
1801 exit(ret);