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/>.
21 #include "system/filesys.h"
22 #include "system/dir.h"
23 #include "system/wait.h"
24 #include "system/locale.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
;
65 enum ctdb_event event
;
66 struct tevent_req
*req
;
68 /* result of last execution */
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
;
91 ectx
= talloc_zero(mem_ctx
, struct eventd_context
);
96 ectx
->script_dir
= talloc_strdup(ectx
, script_dir
);
97 if (ectx
->script_dir
== NULL
) {
102 if (debug_script
!= NULL
) {
103 ectx
->debug_script
= talloc_strdup(ectx
, debug_script
);
104 if (ectx
->debug_script
== NULL
) {
110 ret
= run_proc_init(ectx
, ev
, &ectx
->run_ctx
);
116 ectx
->queue
= tevent_queue_create(ectx
, "run event queue");
117 if (ectx
->queue
== NULL
) {
122 ectx
->running
= false;
123 ectx
->event
= CTDB_EVENT_INIT
;
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
)
144 static void eventd_start_running(struct eventd_context
*ectx
,
145 enum ctdb_event event
,
146 struct tevent_req
*req
)
148 ectx
->running
= true;
153 static void eventd_stop_running(struct eventd_context
*ectx
)
155 ectx
->running
= false;
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
);
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
) {
199 static void eventd_set_result(struct eventd_context
*ectx
,
200 enum ctdb_event event
,
201 struct ctdb_script_list
*script_list
,
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
) {
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
);
223 TALLOC_FREE(ectx
->status_pass
[event
]);
224 ectx
->status_pass
[event
] = s
;
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
;
241 case CTDB_EVENT_LAST_RUN
:
242 s
= ectx
->status_run
[event
];
243 result
= ectx
->result_run
;
246 case CTDB_EVENT_LAST_PASS
:
247 s
= ectx
->status_pass
[event
];
251 case CTDB_EVENT_LAST_FAIL
:
252 s
= ectx
->status_fail
[event
];
253 result
= ectx
->result_fail
;
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
)
270 argv
= talloc_array(mem_ctx
, const char *, 4);
276 argv
[1] = talloc_asprintf(argv
, "%d", pid
);
277 argv
[2] = ctdb_event_to_string(event
);
278 if (argv
[1] == NULL
) {
288 static void debug_log(int loglevel
, char *output
, const char *log_prefix
)
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
{
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
;
313 const char *debug_script
;
316 req
= tevent_req_create(mem_ctx
, &state
, struct run_debug_state
);
323 debug_script
= eventd_debug_script(ectx
);
324 if (debug_script
== NULL
) {
325 tevent_req_done(req
);
326 return tevent_req_post(req
, ev
);
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
);
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
);
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
);
366 status
= run_proc_recv(subreq
, &ret
, NULL
, NULL
, state
, &output
);
369 D_ERR("Running debug failed, ret=%d\n", ret
);
373 if (output
!= NULL
) {
374 debug_log(DEBUG_ERR
, output
, "event_debug");
378 kill(-state
->pid
, SIGTERM
);
379 tevent_req_done(req
);
382 static bool run_debug_recv(struct tevent_req
*req
, int *perr
)
386 if (tevent_req_is_unix_error(req
, &ret
)) {
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
);
405 /* Ignore . and .. */
410 /* Skip filenames with ~ */
411 ptr
= strchr(de
->d_name
, '~');
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] != '.')) {
423 /* Ignore file names longer than MAX_SCRIPT_NAME */
424 if (namelen
> MAX_SCRIPT_NAME
) {
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
;
440 script_list
= talloc_zero(mem_ctx
, struct ctdb_script_list
);
441 if (script_list
== NULL
) {
445 count
= scandir(script_dir
, &namelist
, script_filter
, alphasort
);
449 D_WARNING("event script dir %s removed\n", script_dir
);
451 D_WARNING("scandir() failed on %s, ret=%d\n",
465 script_list
->num_scripts
= count
;
466 script_list
->script
= talloc_zero_array(script_list
,
469 if (script_list
->script
== NULL
) {
471 talloc_free(script_list
);
475 for (i
=0; i
<count
; i
++) {
476 struct ctdb_script
*s
= &script_list
->script
[i
];
479 len
= strlcpy(s
->name
, namelist
[i
]->d_name
, sizeof(s
->name
));
480 if (len
>= sizeof(s
->name
)) {
482 talloc_free(script_list
);
491 if (namelist
!= NULL
&& count
!= -1) {
492 for (i
=0; i
<count
; i
++) {
500 static int script_chmod(TALLOC_CTX
*mem_ctx
, const char *script_dir
,
501 const char *script_name
, bool enable
)
510 dirp
= opendir(script_dir
);
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
);
536 filename
= talloc_asprintf(mem_ctx
, "%s/%s", script_dir
, script_name
);
537 if (filename
== NULL
) {
541 ret
= stat(filename
, &st
);
548 new_mode
= st
.st_mode
| S_IXUSR
;
550 new_mode
= st
.st_mode
& ~(S_IXUSR
| S_IXGRP
| S_IXOTH
);
553 ret
= chmod(filename
, new_mode
);
560 talloc_free(filename
);
564 static int script_args(TALLOC_CTX
*mem_ctx
, enum ctdb_event event
,
565 const char *arg_str
, const char ***out
)
570 argv
= talloc_array(mem_ctx
, const char *, 7);
575 argv
[0] = NULL
; /* script name */
576 argv
[1] = ctdb_event_to_string(event
);
579 if (arg_str
!= NULL
) {
582 str
= talloc_strdup(argv
, arg_str
);
588 while ((tok
= strtok(t
, " ")) != NULL
) {
589 argv
[argc
] = talloc_strdup(argv
, tok
);
590 if (argv
[argc
] == NULL
) {
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
;
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
,
640 struct tevent_req
*req
, *subreq
;
641 struct run_event_state
*state
;
644 req
= tevent_req_create(mem_ctx
, &state
, struct run_event_state
);
651 state
->event
= event
;
653 ret
= get_script_list(state
, eventd_script_dir(ectx
),
654 &state
->script_list
);
656 D_ERR("get_script_list() failed, ret=%d\n", ret
);
657 tevent_req_error(req
, ret
);
658 return tevent_req_post(req
, ev
);
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
);
669 D_ERR("script_args() failed, ret=%d\n", ret
);
670 tevent_req_error(req
, ret
);
671 return tevent_req_post(req
, ev
);
675 state
->timeout
= tevent_timeval_current_ofs(timeout
, 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
);
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
;
697 script
= &state
->script_list
->script
[state
->index
];
699 path
= talloc_asprintf(state
, "%s/%s",
700 eventd_script_dir(state
->ectx
), script
->name
);
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
);
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
;
727 struct run_proc_result result
;
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
);
738 D_ERR("run_proc failed for %s, ret=%d\n", script
->name
, ret
);
739 tevent_req_error(req
, ret
);
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
;
757 script
->status
= -result
.err
;
760 script
->status
= result
.status
;
763 if (script
->status
!= 0 && output
!= NULL
) {
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
);
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
);
802 subreq
= run_event_run_script(req
);
803 if (tevent_req_nomem(subreq
, req
)) {
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
,
818 if (subreq
== NULL
) {
819 /* If run debug fails, it's not an error */
820 D_NOTICE("Failed to run event debug\n");
823 tevent_req_set_callback(subreq
, run_event_debug_done
, NULL
);
826 static void run_event_debug_done(struct tevent_req
*subreq
)
831 status
= run_debug_recv(subreq
, &ret
);
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
);
844 if (tevent_req_is_unix_error(req
, &ret
)) {
845 if (ret
== ECANCELED
) {
846 if (status
!= NULL
) {
847 *status
= -ECANCELED
;
858 if (status
!= NULL
) {
859 *status
= state
->status
;
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
;
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
);
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
);
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
);
940 DLIST_ADD(client
->pending_list
, pending
);
942 status
= tevent_queue_add(eventd_queue(ectx
), ev
, req
,
943 command_run_trigger
, pending
);
945 tevent_req_error(req
, ENOMEM
);
946 return tevent_req_post(req
, ev
);
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
);
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
)) {
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
);
989 status
= run_event_recv(subreq
, &ret
, &result
);
991 tevent_req_error(req
, ret
);
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
);
1007 if (tevent_req_is_unix_error(req
, &ret
)) {
1014 if (reply
!= NULL
) {
1015 *reply
= talloc_steal(mem_ctx
, state
->reply
);
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
);
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
);
1077 if (tevent_req_is_unix_error(req
, &ret
)) {
1084 if (reply
!= NULL
) {
1085 *reply
= talloc_steal(mem_ctx
, state
->reply
);
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
;
1110 req
= tevent_req_create(mem_ctx
, &state
,
1111 struct command_script_list_state
);
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
);
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
];
1143 path
= talloc_asprintf(state
, "%s/%s",
1144 eventd_script_dir(ectx
), script
->name
);
1145 if (tevent_req_nomem(path
, req
)) {
1149 ret
= stat(path
, &st
);
1155 if (! (st
.st_mode
& S_IXUSR
)) {
1156 script
->status
= -ENOEXEC
;
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
);
1177 if (tevent_req_is_unix_error(req
, &ret
)) {
1184 if (reply
!= NULL
) {
1185 *reply
= talloc_steal(mem_ctx
, state
->reply
);
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
;
1210 req
= tevent_req_create(mem_ctx
, &state
,
1211 struct command_script_enable_state
);
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
);
1240 if (tevent_req_is_unix_error(req
, &ret
)) {
1247 if (reply
!= NULL
) {
1248 *reply
= talloc_steal(mem_ctx
, state
->reply
);
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
;
1273 req
= tevent_req_create(mem_ctx
, &state
,
1274 struct command_script_disable_state
);
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
);
1303 if (tevent_req_is_unix_error(req
, &ret
)) {
1310 if (reply
!= NULL
) {
1311 *reply
= talloc_steal(mem_ctx
, state
->reply
);
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
;
1327 client
= client
->next
) {
1328 if (client
->client_ctx
== client_ctx
) {
1336 static bool client_connect(struct sock_client_context
*client_ctx
,
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
) {
1348 client
->client_ctx
= client_ctx
;
1350 DLIST_ADD(ectx
->client_list
, client
);
1354 static void client_disconnect(struct sock_client_context
*client_ctx
,
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
) {
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
,
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
;
1403 req
= tevent_req_create(mem_ctx
, &state
, struct client_process_state
);
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
);
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
,
1426 if (tevent_req_nomem(subreq
, req
)) {
1427 return tevent_req_post(req
, ev
);
1429 tevent_req_set_callback(subreq
, client_run_done
, req
);
1432 case CTDB_EVENT_COMMAND_STATUS
:
1433 subreq
= command_status_send(state
, ev
, ectx
, state
->client
,
1435 if (tevent_req_nomem(subreq
, req
)) {
1436 return tevent_req_post(req
, ev
);
1438 tevent_req_set_callback(subreq
, client_status_done
, req
);
1441 case CTDB_EVENT_COMMAND_SCRIPT_LIST
:
1442 subreq
= command_script_list_send(state
, ev
, ectx
,
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
);
1451 case CTDB_EVENT_COMMAND_SCRIPT_ENABLE
:
1452 subreq
= command_script_enable_send(state
, ev
, ectx
,
1455 if (tevent_req_nomem(subreq
, req
)) {
1456 return tevent_req_post(req
, ev
);
1458 tevent_req_set_callback(subreq
, client_script_enable_done
,
1462 case CTDB_EVENT_COMMAND_SCRIPT_DISABLE
:
1463 subreq
= command_script_disable_send(state
, ev
, ectx
,
1466 if (tevent_req_nomem(subreq
, req
)) {
1467 return tevent_req_post(req
, ev
);
1469 tevent_req_set_callback(subreq
, client_script_disable_done
,
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
;
1487 status
= command_run_recv(subreq
, &ret
, state
, &reply
);
1488 TALLOC_FREE(subreq
);
1490 D_ERR("COMMAND_RUN failed\n");
1491 tevent_req_error(req
, ret
);
1495 client_process_reply(req
, 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
;
1509 status
= command_status_recv(subreq
, &ret
, state
, &reply
);
1510 TALLOC_FREE(subreq
);
1512 D_ERR("COMMAND_STATUS failed\n");
1513 tevent_req_error(req
, ret
);
1517 client_process_reply(req
, 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
;
1531 status
= command_script_list_recv(subreq
, &ret
, state
, &reply
);
1532 TALLOC_FREE(subreq
);
1534 D_ERR("COMMAND_SCRIPT_LIST failed\n");
1535 tevent_req_error(req
, ret
);
1539 client_process_reply(req
, 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
;
1553 status
= command_script_enable_recv(subreq
, &ret
, state
, &reply
);
1554 TALLOC_FREE(subreq
);
1556 D_ERR("COMMAND_SCRIPT_ENABLE failed\n");
1557 tevent_req_error(req
, ret
);
1561 client_process_reply(req
, 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
;
1575 status
= command_script_disable_recv(subreq
, &ret
, state
, &reply
);
1576 TALLOC_FREE(subreq
);
1578 D_ERR("COMMAND_SCRIPT_DISABLE failed\n");
1579 tevent_req_error(req
, ret
);
1583 client_process_reply(req
, 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
;
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
)) {
1605 ret
= ctdb_event_reply_push(reply
, buf
, &buflen
);
1608 tevent_req_error(req
, ret
);
1612 subreq
= sock_socket_write_send(state
, state
->ev
,
1613 state
->client
->client_ctx
,
1615 if (tevent_req_nomem(subreq
, req
)) {
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
);
1628 status
= sock_socket_write_recv(subreq
, &ret
);
1629 TALLOC_FREE(subreq
);
1631 D_ERR("Sending reply failed\n");
1632 tevent_req_error(req
, ret
);
1636 tevent_req_done(req
);
1639 static bool client_process_recv(struct tevent_req
*req
, int *perr
)
1643 if (tevent_req_is_unix_error(req
, &ret
)) {
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
);
1670 const char *debug_script
;
1671 const char *script_dir
;
1672 const char *logging
;
1673 const char *debug_level
;
1674 const char *pidfile
;
1678 .debug_level
= "ERR",
1681 struct poptOption cmdline_options
[] = {
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,
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" },
1700 int main(int argc
, const char **argv
)
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
;
1712 /* Set default options */
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
));
1723 if (options
.socket
== NULL
) {
1724 fprintf(stderr
, "Please specify eventd socket (--socket)\n");
1728 if (options
.script_dir
== NULL
) {
1730 "Please specify script dir (--event_script_dir)\n");
1734 if (options
.logging
== NULL
) {
1736 "Please specify logging (--logging)\n");
1740 ret
= stat(options
.script_dir
, &statbuf
);
1743 fprintf(stderr
, "Error reading script_dir %s, ret=%d\n",
1744 options
.script_dir
, ret
);
1747 if (! S_ISDIR(statbuf
.st_mode
)) {
1748 fprintf(stderr
, "script_dir %s is not a directory\n",
1749 options
.script_dir
);
1753 mem_ctx
= talloc_new(NULL
);
1754 if (mem_ctx
== NULL
) {
1758 ev
= tevent_context_init(mem_ctx
);
1764 ret
= eventd_context_init(mem_ctx
, ev
, options
.script_dir
,
1765 options
.debug_script
, &ectx
);
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
);
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
);
1793 ret
= sock_daemon_run(ev
, sockd
, options
.pid
);
1799 talloc_free(mem_ctx
);
1800 (void)poptFreeContext(pc
);