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_event.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 struct run_event_context
*run_ctx
;
59 struct tevent_queue
*queue
;
63 enum ctdb_event event
;
64 struct tevent_req
*req
;
66 /* result of last execution */
67 struct run_event_script_list
*status_run
[CTDB_EVENT_MAX
];
68 struct run_event_script_list
*status_pass
[CTDB_EVENT_MAX
];
69 struct run_event_script_list
*status_fail
[CTDB_EVENT_MAX
];
71 struct eventd_client
*client_list
;
75 * Global state manipulation functions
78 static int eventd_context_init(TALLOC_CTX
*mem_ctx
,
79 struct tevent_context
*ev
,
80 const char *script_dir
,
81 const char *debug_script
,
82 struct eventd_context
**result
)
84 struct eventd_context
*ectx
;
87 ectx
= talloc_zero(mem_ctx
, struct eventd_context
);
92 ret
= run_event_init(ectx
, ev
, script_dir
, debug_script
,
99 ectx
->queue
= tevent_queue_create(ectx
, "run event queue");
100 if (ectx
->queue
== NULL
) {
105 ectx
->running
= false;
106 ectx
->event
= CTDB_EVENT_INIT
;
112 static struct run_event_context
*eventd_run_context(struct eventd_context
*ectx
)
114 return ectx
->run_ctx
;
117 static struct tevent_queue
*eventd_queue(struct eventd_context
*ectx
)
122 static void eventd_start_running(struct eventd_context
*ectx
,
123 enum ctdb_event event
,
124 struct tevent_req
*req
)
126 ectx
->running
= true;
131 static void eventd_stop_running(struct eventd_context
*ectx
)
133 ectx
->running
= false;
137 static struct tevent_req
*eventd_cancel_running(struct eventd_context
*ectx
)
139 struct tevent_req
*req
= ectx
->req
;
142 eventd_stop_running(ectx
);
147 static bool eventd_is_running(struct eventd_context
*ectx
,
148 enum ctdb_event
*event
)
150 if (event
!= NULL
&& ectx
->running
) {
151 *event
= ectx
->event
;
154 return ectx
->running
;
157 static struct run_event_script_list
*script_list_copy(
159 struct run_event_script_list
*s
)
161 struct run_event_script_list
*s2
;
163 s2
= talloc_zero(mem_ctx
, struct run_event_script_list
);
168 s2
->num_scripts
= s
->num_scripts
;
169 s2
->script
= talloc_memdup(s2
, s
->script
,
171 sizeof(struct run_event_script
));
172 if (s2
->script
== NULL
) {
176 s2
->summary
= s
->summary
;
181 static struct ctdb_script_list
*script_list_to_ctdb_script_list(
183 struct run_event_script_list
*s
)
185 struct ctdb_script_list
*sl
;
188 sl
= talloc_zero(mem_ctx
, struct ctdb_script_list
);
193 sl
->script
= talloc_zero_array(sl
, struct ctdb_script
, s
->num_scripts
);
194 if (sl
->script
== NULL
) {
199 sl
->num_scripts
= s
->num_scripts
;
201 for (i
=0; i
<s
->num_scripts
; i
++) {
202 struct run_event_script
*escript
= &s
->script
[i
];
203 struct ctdb_script
*script
= &sl
->script
[i
];
205 strlcpy(script
->name
, escript
->name
, MAX_SCRIPT_NAME
+1);
206 script
->start
= escript
->begin
;
207 script
->finished
= escript
->end
;
208 script
->status
= escript
->summary
;
209 if (escript
->output
!= NULL
) {
210 strlcpy(script
->output
, escript
->output
,
211 MAX_SCRIPT_OUTPUT
+1);
218 static void eventd_set_result(struct eventd_context
*ectx
,
219 enum ctdb_event event
,
220 struct run_event_script_list
*script_list
)
222 struct run_event_script_list
*s
;
224 if (script_list
== NULL
) {
228 TALLOC_FREE(ectx
->status_run
[event
]);
229 ectx
->status_run
[event
] = talloc_steal(ectx
, script_list
);
231 s
= script_list_copy(ectx
, script_list
);
236 if (s
->summary
== 0) {
237 TALLOC_FREE(ectx
->status_pass
[event
]);
238 ectx
->status_pass
[event
] = s
;
240 TALLOC_FREE(ectx
->status_fail
[event
]);
241 ectx
->status_fail
[event
] = s
;
245 static int eventd_get_result(struct eventd_context
*ectx
,
246 enum ctdb_event event
,
247 enum ctdb_event_status_state state
,
249 struct ctdb_script_list
**out
)
251 struct run_event_script_list
*s
= NULL
;
254 case CTDB_EVENT_LAST_RUN
:
255 s
= ectx
->status_run
[event
];
258 case CTDB_EVENT_LAST_PASS
:
259 s
= ectx
->status_pass
[event
];
262 case CTDB_EVENT_LAST_FAIL
:
263 s
= ectx
->status_fail
[event
];
272 *out
= script_list_to_ctdb_script_list(mem_ctx
, s
);
277 * Process RUN command
280 struct command_run_state
{
281 struct tevent_context
*ev
;
282 struct eventd_context
*ectx
;
283 struct eventd_client
*client
;
285 enum ctdb_event event
;
288 struct ctdb_event_reply
*reply
;
289 struct tevent_req
*subreq
;
292 static void command_run_trigger(struct tevent_req
*req
, void *private_data
);
293 static void command_run_done(struct tevent_req
*subreq
);
294 static void command_run_cancel(struct tevent_req
*req
);
296 static struct tevent_req
*command_run_send(TALLOC_CTX
*mem_ctx
,
297 struct tevent_context
*ev
,
298 struct eventd_context
*ectx
,
299 struct eventd_client
*client
,
300 struct ctdb_event_request
*request
)
302 struct tevent_req
*req
, *mon_req
;
303 struct command_run_state
*state
;
304 struct pending_event
*pending
;
305 enum ctdb_event running_event
;
306 bool running
, status
;
308 req
= tevent_req_create(mem_ctx
, &state
, struct command_run_state
);
315 state
->client
= client
;
317 state
->event
= request
->rdata
.data
.run
->event
;
318 state
->timeout
= request
->rdata
.data
.run
->timeout
;
319 state
->arg_str
= talloc_steal(state
, request
->rdata
.data
.run
->arg_str
);
321 state
->reply
= talloc_zero(state
, struct ctdb_event_reply
);
322 if (tevent_req_nomem(state
->reply
, req
)) {
323 return tevent_req_post(req
, ev
);
326 state
->reply
->rdata
.command
= request
->rdata
.command
;
329 * If monitor event is running,
330 * Cancel the running monitor event and run new event
332 * If any other event is running,
333 * If new event is monitor, cancel that event
334 * Else add new event to the queue
337 running
= eventd_is_running(ectx
, &running_event
);
339 if (running_event
== CTDB_EVENT_MONITOR
) {
340 mon_req
= eventd_cancel_running(ectx
);
341 command_run_cancel(mon_req
);
342 } else if (state
->event
== CTDB_EVENT_MONITOR
) {
343 state
->reply
->rdata
.result
= -ECANCELED
;
344 tevent_req_done(req
);
345 return tevent_req_post(req
, ev
);
349 pending
= talloc_zero(state
, struct pending_event
);
350 if (tevent_req_nomem(pending
, req
)) {
351 return tevent_req_post(req
, ev
);
355 DLIST_ADD(client
->pending_list
, pending
);
357 status
= tevent_queue_add(eventd_queue(ectx
), ev
, req
,
358 command_run_trigger
, pending
);
360 tevent_req_error(req
, ENOMEM
);
361 return tevent_req_post(req
, ev
);
367 static void command_run_trigger(struct tevent_req
*req
, void *private_data
)
369 struct pending_event
*pending
= talloc_get_type_abort(
370 private_data
, struct pending_event
);
371 struct command_run_state
*state
= tevent_req_data(
372 req
, struct command_run_state
);
374 DLIST_REMOVE(state
->client
->pending_list
, pending
);
376 if (pending
->req
!= req
) {
377 tevent_req_error(req
, EIO
);
381 talloc_free(pending
);
383 D_DEBUG("Running event %s with args \"%s\"\n",
384 ctdb_event_to_string(state
->event
),
385 state
->arg_str
== NULL
? "(null)" : state
->arg_str
);
387 state
->subreq
= run_event_send(state
, state
->ev
,
388 eventd_run_context(state
->ectx
),
389 ctdb_event_to_string(state
->event
),
391 tevent_timeval_current_ofs(
393 if (tevent_req_nomem(state
->subreq
, req
)) {
396 tevent_req_set_callback(state
->subreq
, command_run_done
, req
);
398 eventd_start_running(state
->ectx
, state
->event
, req
);
401 static void command_run_done(struct tevent_req
*subreq
)
403 struct tevent_req
*req
= tevent_req_callback_data(
404 subreq
, struct tevent_req
);
405 struct command_run_state
*state
= tevent_req_data(
406 req
, struct command_run_state
);
407 struct run_event_script_list
*script_list
;
411 eventd_stop_running(state
->ectx
);
413 status
= run_event_recv(subreq
, &ret
, state
, &script_list
);
416 tevent_req_error(req
, ret
);
420 if (script_list
== NULL
) {
421 eventd_set_result(state
->ectx
, state
->event
, NULL
);
422 state
->reply
->rdata
.result
= 0;
424 eventd_set_result(state
->ectx
, state
->event
, script_list
);
425 state
->reply
->rdata
.result
= script_list
->summary
;
428 tevent_req_done(req
);
431 static void command_run_cancel(struct tevent_req
*req
)
433 struct command_run_state
*state
= tevent_req_data(
434 req
, struct command_run_state
);
436 eventd_stop_running(state
->ectx
);
438 TALLOC_FREE(state
->subreq
);
440 state
->reply
->rdata
.result
= -ECANCELED
;
442 tevent_req_done(req
);
445 static bool command_run_recv(struct tevent_req
*req
, int *perr
,
447 struct ctdb_event_reply
**reply
)
449 struct command_run_state
*state
= tevent_req_data(
450 req
, struct command_run_state
);
453 if (tevent_req_is_unix_error(req
, &ret
)) {
461 *reply
= talloc_steal(mem_ctx
, state
->reply
);
467 * Process STATUS command
470 struct command_status_state
{
471 struct ctdb_event_reply
*reply
;
474 static struct tevent_req
*command_status_send(
476 struct tevent_context
*ev
,
477 struct eventd_context
*ectx
,
478 struct eventd_client
*client
,
479 struct ctdb_event_request
*request
)
481 struct tevent_req
*req
;
482 struct command_status_state
*state
;
483 enum ctdb_event event
;
484 enum ctdb_event_status_state estate
;
486 req
= tevent_req_create(mem_ctx
, &state
, struct command_status_state
);
491 event
= request
->rdata
.data
.status
->event
;
492 estate
= request
->rdata
.data
.status
->state
;
494 state
->reply
= talloc_zero(state
, struct ctdb_event_reply
);
495 if (tevent_req_nomem(state
->reply
, req
)) {
496 return tevent_req_post(req
, ev
);
499 state
->reply
->rdata
.data
.status
=
500 talloc(state
->reply
, struct ctdb_event_reply_status
);
501 if (tevent_req_nomem(state
->reply
->rdata
.data
.status
, req
)) {
502 return tevent_req_post(req
, ev
);
505 state
->reply
->rdata
.command
= request
->rdata
.command
;
506 state
->reply
->rdata
.result
= 0;
507 state
->reply
->rdata
.data
.status
->status
=
508 eventd_get_result(ectx
, event
, estate
, state
->reply
,
509 &state
->reply
->rdata
.data
.status
->script_list
);
511 tevent_req_done(req
);
512 return tevent_req_post(req
, ev
);
515 static bool command_status_recv(struct tevent_req
*req
, int *perr
,
517 struct ctdb_event_reply
**reply
)
519 struct command_status_state
*state
= tevent_req_data(
520 req
, struct command_status_state
);
523 if (tevent_req_is_unix_error(req
, &ret
)) {
531 *reply
= talloc_steal(mem_ctx
, state
->reply
);
537 * Process SCRIPT_LIST command
540 struct command_script_list_state
{
541 struct ctdb_event_reply
*reply
;
544 static struct tevent_req
*command_script_list_send(
546 struct tevent_context
*ev
,
547 struct eventd_context
*ectx
,
548 struct eventd_client
*client
,
549 struct ctdb_event_request
*request
)
551 struct tevent_req
*req
;
552 struct command_script_list_state
*state
;
553 struct run_event_script_list
*s
;
556 req
= tevent_req_create(mem_ctx
, &state
,
557 struct command_script_list_state
);
562 state
->reply
= talloc_zero(state
, struct ctdb_event_reply
);
563 if (tevent_req_nomem(state
->reply
, req
)) {
564 return tevent_req_post(req
, ev
);
567 state
->reply
->rdata
.data
.script_list
=
568 talloc(state
->reply
, struct ctdb_event_reply_script_list
);
569 if (tevent_req_nomem(state
->reply
->rdata
.data
.script_list
, req
)) {
570 return tevent_req_post(req
, ev
);
573 ret
= run_event_script_list(eventd_run_context(ectx
), state
->reply
,
576 tevent_req_error(req
, ret
);
577 return tevent_req_post(req
, ev
);
580 state
->reply
->rdata
.command
= request
->rdata
.command
;
582 state
->reply
->rdata
.result
= 0;
583 state
->reply
->rdata
.data
.script_list
->script_list
= NULL
;
585 state
->reply
->rdata
.result
= s
->summary
;
586 state
->reply
->rdata
.data
.script_list
->script_list
=
587 script_list_to_ctdb_script_list(state
->reply
, s
);
590 tevent_req_done(req
);
591 return tevent_req_post(req
, ev
);
594 static bool command_script_list_recv(struct tevent_req
*req
, int *perr
,
596 struct ctdb_event_reply
**reply
)
598 struct command_script_list_state
*state
= tevent_req_data(
599 req
, struct command_script_list_state
);
602 if (tevent_req_is_unix_error(req
, &ret
)) {
610 *reply
= talloc_steal(mem_ctx
, state
->reply
);
616 * Process SCRIPT_ENABLE command
619 struct command_script_enable_state
{
620 struct ctdb_event_reply
*reply
;
623 static struct tevent_req
*command_script_enable_send(
625 struct tevent_context
*ev
,
626 struct eventd_context
*ectx
,
627 struct eventd_client
*client
,
628 struct ctdb_event_request
*request
)
630 struct tevent_req
*req
;
631 struct command_script_enable_state
*state
;
632 const char *script_name
;
635 req
= tevent_req_create(mem_ctx
, &state
,
636 struct command_script_enable_state
);
641 script_name
= request
->rdata
.data
.script_enable
->script_name
;
643 state
->reply
= talloc_zero(state
, struct ctdb_event_reply
);
644 if (tevent_req_nomem(state
->reply
, req
)) {
645 return tevent_req_post(req
, ev
);
648 state
->reply
->rdata
.command
= request
->rdata
.command
;
650 ret
= run_event_script_enable(eventd_run_context(ectx
), script_name
);
651 state
->reply
->rdata
.result
= -ret
;
653 tevent_req_done(req
);
654 return tevent_req_post(req
, ev
);
657 static bool command_script_enable_recv(struct tevent_req
*req
, int *perr
,
659 struct ctdb_event_reply
**reply
)
661 struct command_script_enable_state
*state
= tevent_req_data(
662 req
, struct command_script_enable_state
);
665 if (tevent_req_is_unix_error(req
, &ret
)) {
673 *reply
= talloc_steal(mem_ctx
, state
->reply
);
679 * Process SCRIPT_DISABLE command
682 struct command_script_disable_state
{
683 struct ctdb_event_reply
*reply
;
686 static struct tevent_req
*command_script_disable_send(
688 struct tevent_context
*ev
,
689 struct eventd_context
*ectx
,
690 struct eventd_client
*client
,
691 struct ctdb_event_request
*request
)
693 struct tevent_req
*req
;
694 struct command_script_disable_state
*state
;
695 const char *script_name
;
698 req
= tevent_req_create(mem_ctx
, &state
,
699 struct command_script_disable_state
);
704 script_name
= request
->rdata
.data
.script_disable
->script_name
;
706 state
->reply
= talloc_zero(state
, struct ctdb_event_reply
);
707 if (tevent_req_nomem(state
->reply
, req
)) {
708 return tevent_req_post(req
, ev
);
711 state
->reply
->rdata
.command
= request
->rdata
.command
;
713 ret
= run_event_script_disable(eventd_run_context(ectx
), script_name
);
714 state
->reply
->rdata
.result
= -ret
;
716 tevent_req_done(req
);
717 return tevent_req_post(req
, ev
);
720 static bool command_script_disable_recv(struct tevent_req
*req
, int *perr
,
722 struct ctdb_event_reply
**reply
)
724 struct command_script_disable_state
*state
= tevent_req_data(
725 req
, struct command_script_disable_state
);
728 if (tevent_req_is_unix_error(req
, &ret
)) {
736 *reply
= talloc_steal(mem_ctx
, state
->reply
);
745 static struct eventd_client
*client_find(struct eventd_context
*ectx
,
746 struct sock_client_context
*client_ctx
)
748 struct eventd_client
*client
;
750 for (client
= ectx
->client_list
;
752 client
= client
->next
) {
753 if (client
->client_ctx
== client_ctx
) {
761 static bool client_connect(struct sock_client_context
*client_ctx
,
764 struct eventd_context
*ectx
= talloc_get_type_abort(
765 private_data
, struct eventd_context
);
766 struct eventd_client
*client
;
768 client
= talloc_zero(ectx
, struct eventd_client
);
769 if (client
== NULL
) {
773 client
->client_ctx
= client_ctx
;
775 DLIST_ADD(ectx
->client_list
, client
);
779 static void client_disconnect(struct sock_client_context
*client_ctx
,
782 struct eventd_context
*ectx
= talloc_get_type_abort(
783 private_data
, struct eventd_context
);
784 struct eventd_client
*client
;
785 struct pending_event
*pe
;
787 client
= client_find(ectx
, client_ctx
);
788 if (client
== NULL
) {
792 /* Get rid of pending events */
793 while ((pe
= client
->pending_list
) != NULL
) {
794 DLIST_REMOVE(client
->pending_list
, pe
);
795 talloc_free(pe
->req
);
799 struct client_process_state
{
800 struct tevent_context
*ev
;
802 struct eventd_client
*client
;
803 struct ctdb_event_request request
;
806 static void client_run_done(struct tevent_req
*subreq
);
807 static void client_status_done(struct tevent_req
*subreq
);
808 static void client_script_list_done(struct tevent_req
*subreq
);
809 static void client_script_enable_done(struct tevent_req
*subreq
);
810 static void client_script_disable_done(struct tevent_req
*subreq
);
811 static void client_process_reply(struct tevent_req
*req
,
812 struct ctdb_event_reply
*reply
);
813 static void client_process_reply_done(struct tevent_req
*subreq
);
815 static struct tevent_req
*client_process_send(
817 struct tevent_context
*ev
,
818 struct sock_client_context
*client_ctx
,
819 uint8_t *buf
, size_t buflen
,
822 struct eventd_context
*ectx
= talloc_get_type_abort(
823 private_data
, struct eventd_context
);
824 struct tevent_req
*req
, *subreq
;
825 struct client_process_state
*state
;
828 req
= tevent_req_create(mem_ctx
, &state
, struct client_process_state
);
835 state
->client
= client_find(ectx
, client_ctx
);
836 if (state
->client
== NULL
) {
837 tevent_req_error(req
, EIO
);
838 return tevent_req_post(req
, ev
);
841 ret
= ctdb_event_request_pull(buf
, buflen
, state
, &state
->request
);
843 tevent_req_error(req
, EPROTO
);
844 return tevent_req_post(req
, ev
);
847 switch (state
->request
.rdata
.command
) {
848 case CTDB_EVENT_COMMAND_RUN
:
849 subreq
= command_run_send(state
, ev
, ectx
, state
->client
,
851 if (tevent_req_nomem(subreq
, req
)) {
852 return tevent_req_post(req
, ev
);
854 tevent_req_set_callback(subreq
, client_run_done
, req
);
857 case CTDB_EVENT_COMMAND_STATUS
:
858 subreq
= command_status_send(state
, ev
, ectx
, state
->client
,
860 if (tevent_req_nomem(subreq
, req
)) {
861 return tevent_req_post(req
, ev
);
863 tevent_req_set_callback(subreq
, client_status_done
, req
);
866 case CTDB_EVENT_COMMAND_SCRIPT_LIST
:
867 subreq
= command_script_list_send(state
, ev
, ectx
,
870 if (tevent_req_nomem(subreq
, req
)) {
871 return tevent_req_post(req
, ev
);
873 tevent_req_set_callback(subreq
, client_script_list_done
, req
);
876 case CTDB_EVENT_COMMAND_SCRIPT_ENABLE
:
877 subreq
= command_script_enable_send(state
, ev
, ectx
,
880 if (tevent_req_nomem(subreq
, req
)) {
881 return tevent_req_post(req
, ev
);
883 tevent_req_set_callback(subreq
, client_script_enable_done
,
887 case CTDB_EVENT_COMMAND_SCRIPT_DISABLE
:
888 subreq
= command_script_disable_send(state
, ev
, ectx
,
891 if (tevent_req_nomem(subreq
, req
)) {
892 return tevent_req_post(req
, ev
);
894 tevent_req_set_callback(subreq
, client_script_disable_done
,
902 static void client_run_done(struct tevent_req
*subreq
)
904 struct tevent_req
*req
= tevent_req_callback_data(
905 subreq
, struct tevent_req
);
906 struct client_process_state
*state
= tevent_req_data(
907 req
, struct client_process_state
);
908 struct ctdb_event_reply
*reply
= NULL
;
912 status
= command_run_recv(subreq
, &ret
, state
, &reply
);
915 D_ERR("COMMAND_RUN failed\n");
916 tevent_req_error(req
, ret
);
920 client_process_reply(req
, reply
);
924 static void client_status_done(struct tevent_req
*subreq
)
926 struct tevent_req
*req
= tevent_req_callback_data(
927 subreq
, struct tevent_req
);
928 struct client_process_state
*state
= tevent_req_data(
929 req
, struct client_process_state
);
930 struct ctdb_event_reply
*reply
= NULL
;
934 status
= command_status_recv(subreq
, &ret
, state
, &reply
);
937 D_ERR("COMMAND_STATUS failed\n");
938 tevent_req_error(req
, ret
);
942 client_process_reply(req
, reply
);
946 static void client_script_list_done(struct tevent_req
*subreq
)
948 struct tevent_req
*req
= tevent_req_callback_data(
949 subreq
, struct tevent_req
);
950 struct client_process_state
*state
= tevent_req_data(
951 req
, struct client_process_state
);
952 struct ctdb_event_reply
*reply
= NULL
;
956 status
= command_script_list_recv(subreq
, &ret
, state
, &reply
);
959 D_ERR("COMMAND_SCRIPT_LIST failed\n");
960 tevent_req_error(req
, ret
);
964 client_process_reply(req
, reply
);
968 static void client_script_enable_done(struct tevent_req
*subreq
)
970 struct tevent_req
*req
= tevent_req_callback_data(
971 subreq
, struct tevent_req
);
972 struct client_process_state
*state
= tevent_req_data(
973 req
, struct client_process_state
);
974 struct ctdb_event_reply
*reply
= NULL
;
978 status
= command_script_enable_recv(subreq
, &ret
, state
, &reply
);
981 D_ERR("COMMAND_SCRIPT_ENABLE failed\n");
982 tevent_req_error(req
, ret
);
986 client_process_reply(req
, reply
);
990 static void client_script_disable_done(struct tevent_req
*subreq
)
992 struct tevent_req
*req
= tevent_req_callback_data(
993 subreq
, struct tevent_req
);
994 struct client_process_state
*state
= tevent_req_data(
995 req
, struct client_process_state
);
996 struct ctdb_event_reply
*reply
= NULL
;
1000 status
= command_script_disable_recv(subreq
, &ret
, state
, &reply
);
1001 TALLOC_FREE(subreq
);
1003 D_ERR("COMMAND_SCRIPT_DISABLE failed\n");
1004 tevent_req_error(req
, ret
);
1008 client_process_reply(req
, reply
);
1012 static void client_process_reply(struct tevent_req
*req
,
1013 struct ctdb_event_reply
*reply
)
1015 struct client_process_state
*state
= tevent_req_data(
1016 req
, struct client_process_state
);
1017 struct tevent_req
*subreq
;
1022 ctdb_event_header_fill(&reply
->header
, state
->request
.header
.reqid
);
1024 buflen
= ctdb_event_reply_len(reply
);
1025 buf
= talloc_zero_size(state
, buflen
);
1026 if (tevent_req_nomem(buf
, req
)) {
1030 ret
= ctdb_event_reply_push(reply
, buf
, &buflen
);
1033 tevent_req_error(req
, ret
);
1037 subreq
= sock_socket_write_send(state
, state
->ev
,
1038 state
->client
->client_ctx
,
1040 if (tevent_req_nomem(subreq
, req
)) {
1043 tevent_req_set_callback(subreq
, client_process_reply_done
, req
);
1046 static void client_process_reply_done(struct tevent_req
*subreq
)
1048 struct tevent_req
*req
= tevent_req_callback_data(
1049 subreq
, struct tevent_req
);
1053 status
= sock_socket_write_recv(subreq
, &ret
);
1054 TALLOC_FREE(subreq
);
1056 D_ERR("Sending reply failed\n");
1057 tevent_req_error(req
, ret
);
1061 tevent_req_done(req
);
1064 static bool client_process_recv(struct tevent_req
*req
, int *perr
)
1068 if (tevent_req_is_unix_error(req
, &ret
)) {
1082 static void eventd_shutdown(void *private_data
)
1084 struct eventd_context
*ectx
= talloc_get_type_abort(
1085 private_data
, struct eventd_context
);
1086 struct eventd_client
*client
;
1088 while ((client
= ectx
->client_list
) != NULL
) {
1089 DLIST_REMOVE(ectx
->client_list
, client
);
1090 talloc_free(client
);
1095 const char *debug_script
;
1096 const char *script_dir
;
1097 const char *logging
;
1098 const char *debug_level
;
1099 const char *pidfile
;
1103 .debug_level
= "ERR",
1106 struct poptOption cmdline_options
[] = {
1108 { "debug_script", 'D', POPT_ARG_STRING
, &options
.debug_script
, 0,
1109 "debug script", "FILE" },
1110 { "pid", 'P', POPT_ARG_INT
, &options
.pid
, 0,
1111 "pid to wait for", "PID" },
1112 { "event_script_dir", 'e', POPT_ARG_STRING
, &options
.script_dir
, 0,
1113 "event script dir", "DIRECTORY" },
1114 { "logging", 'l', POPT_ARG_STRING
, &options
.logging
, 0,
1115 "logging specification" },
1116 { "debug", 'd', POPT_ARG_STRING
, &options
.debug_level
, 0,
1118 { "pidfile", 'p', POPT_ARG_STRING
, &options
.pidfile
, 0,
1119 "eventd pid file", "FILE" },
1120 { "socket", 's', POPT_ARG_STRING
, &options
.socket
, 0,
1121 "eventd socket path", "FILE" },
1125 int main(int argc
, const char **argv
)
1128 TALLOC_CTX
*mem_ctx
;
1129 struct tevent_context
*ev
;
1130 struct eventd_context
*ectx
;
1131 struct sock_daemon_context
*sockd
;
1132 struct sock_daemon_funcs daemon_funcs
;
1133 struct sock_socket_funcs socket_funcs
;
1134 struct stat statbuf
;
1137 /* Set default options */
1140 pc
= poptGetContext(argv
[0], argc
, argv
, cmdline_options
,
1141 POPT_CONTEXT_KEEP_FIRST
);
1142 while ((opt
= poptGetNextOpt(pc
)) != -1) {
1143 fprintf(stderr
, "Invalid options %s: %s\n",
1144 poptBadOption(pc
, 0), poptStrerror(opt
));
1148 if (options
.socket
== NULL
) {
1149 fprintf(stderr
, "Please specify eventd socket (--socket)\n");
1153 if (options
.script_dir
== NULL
) {
1155 "Please specify script dir (--event_script_dir)\n");
1159 if (options
.logging
== NULL
) {
1161 "Please specify logging (--logging)\n");
1165 ret
= stat(options
.script_dir
, &statbuf
);
1168 fprintf(stderr
, "Error reading script_dir %s, ret=%d\n",
1169 options
.script_dir
, ret
);
1172 if (! S_ISDIR(statbuf
.st_mode
)) {
1173 fprintf(stderr
, "script_dir %s is not a directory\n",
1174 options
.script_dir
);
1178 mem_ctx
= talloc_new(NULL
);
1179 if (mem_ctx
== NULL
) {
1183 ev
= tevent_context_init(mem_ctx
);
1189 ret
= eventd_context_init(mem_ctx
, ev
, options
.script_dir
,
1190 options
.debug_script
, &ectx
);
1195 daemon_funcs
= (struct sock_daemon_funcs
) {
1196 .shutdown
= eventd_shutdown
,
1199 ret
= sock_daemon_setup(mem_ctx
, "ctdb-eventd", options
.logging
,
1200 options
.debug_level
, options
.pidfile
,
1201 &daemon_funcs
, ectx
, &sockd
);
1206 socket_funcs
= (struct sock_socket_funcs
) {
1207 .connect
= client_connect
,
1208 .disconnect
= client_disconnect
,
1209 .read_send
= client_process_send
,
1210 .read_recv
= client_process_recv
,
1213 ret
= sock_daemon_add_unix(sockd
, options
.socket
, &socket_funcs
, ectx
);
1218 ret
= sock_daemon_run(ev
, sockd
, options
.pid
);
1224 talloc_free(mem_ctx
);
1225 (void)poptFreeContext(pc
);