4 Copyright (C) Andrew Tridgell 2007
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/network.h"
23 #include "system/wait.h"
24 #include "system/dir.h"
25 #include "system/locale.h"
26 #include "system/time.h"
27 #include "system/dir.h"
32 #include "lib/util/dlinklist.h"
33 #include "lib/util/debug.h"
34 #include "lib/util/samba_util.h"
35 #include "lib/util/sys_rw.h"
37 #include "ctdb_private.h"
39 #include "common/rb_tree.h"
40 #include "common/common.h"
41 #include "common/logging.h"
42 #include "common/reqid.h"
43 #include "common/sock_io.h"
45 #include "protocol/protocol_api.h"
48 * Setting up event daemon
51 struct eventd_context
{
52 struct tevent_context
*ev
;
54 const char *script_dir
;
57 const char *debug_hung_script
;
61 struct tevent_fd
*eventd_fde
;
64 struct reqid_context
*idr
;
65 struct sock_queue
*queue
;
66 struct eventd_client_state
*calls
;
69 static bool eventd_context_init(TALLOC_CTX
*mem_ctx
,
70 struct ctdb_context
*ctdb
,
71 struct eventd_context
**out
)
73 struct eventd_context
*ectx
;
74 const char *eventd
= CTDB_HELPER_BINDIR
"/ctdb_eventd";
75 const char *debug_hung_script
= CTDB_ETCDIR
"/debug-hung-script.sh";
80 ectx
= talloc_zero(mem_ctx
, struct eventd_context
);
87 value
= getenv("CTDB_EVENTD");
92 ectx
->path
= talloc_strdup(ectx
, eventd
);
93 if (ectx
->path
== NULL
) {
98 ectx
->script_dir
= ctdb
->event_script_dir
;
100 socket
= talloc_strdup(ectx
, ctdb_get_socketname(ctdb
));
101 if (socket
== NULL
) {
106 ectx
->socket
= talloc_asprintf(ectx
, "%s/eventd.sock",
108 if (ectx
->socket
== NULL
) {
115 value
= getenv("CTDB_DEBUG_HUNG_SCRIPT");
117 if (value
[0] == '\0') {
118 debug_hung_script
= NULL
;
120 debug_hung_script
= value
;
124 if (debug_hung_script
!= NULL
) {
125 ectx
->debug_hung_script
= talloc_strdup(ectx
,
127 if (ectx
->debug_hung_script
== NULL
) {
133 ret
= reqid_init(ectx
, 1, &ectx
->idr
);
139 ectx
->eventd_pid
= -1;
145 struct eventd_startup_state
{
151 static void eventd_startup_timeout_handler(struct tevent_context
*ev
,
152 struct tevent_timer
*te
,
156 struct eventd_startup_state
*state
=
157 (struct eventd_startup_state
*) private_data
;
160 state
->ret
= ETIMEDOUT
;
163 static void eventd_startup_handler(struct tevent_context
*ev
,
164 struct tevent_fd
*fde
, uint16_t flags
,
167 struct eventd_startup_state
*state
=
168 (struct eventd_startup_state
*)private_data
;
172 num_read
= sys_read(state
->fd
, &data
, sizeof(data
));
173 if (num_read
== sizeof(data
)) {
179 } else if (num_read
== 0) {
181 } else if (num_read
== -1) {
191 static int wait_for_daemon_startup(struct tevent_context
*ev
,
195 struct tevent_timer
*timer
;
196 struct tevent_fd
*fde
;
197 struct eventd_startup_state state
= {
203 mem_ctx
= talloc_new(ev
);
204 if (mem_ctx
== NULL
) {
208 timer
= tevent_add_timer(ev
,
210 tevent_timeval_current_ofs(10, 0),
211 eventd_startup_timeout_handler
,
214 talloc_free(mem_ctx
);
218 fde
= tevent_add_fd(ev
,
222 eventd_startup_handler
,
225 talloc_free(mem_ctx
);
229 while (! state
.done
) {
230 tevent_loop_once(ev
);
233 talloc_free(mem_ctx
);
240 * Start and stop event daemon
243 static bool eventd_client_connect(struct eventd_context
*ectx
);
244 static void eventd_dead_handler(struct tevent_context
*ev
,
245 struct tevent_fd
*fde
, uint16_t flags
,
248 int ctdb_start_eventd(struct ctdb_context
*ctdb
)
250 struct eventd_context
*ectx
;
257 if (ctdb
->ectx
== NULL
) {
258 status
= eventd_context_init(ctdb
, ctdb
, &ctdb
->ectx
);
261 ("Failed to initialize eventd context\n"));
268 if (! sock_clean(ectx
->socket
)) {
277 argv
= talloc_array(ectx
, const char *, 16);
284 argv
[0] = ectx
->path
;
286 argv
[2] = ectx
->script_dir
;
288 argv
[4] = ectx
->socket
;
290 argv
[6] = talloc_asprintf(argv
, "%d", ctdb
->ctdbd_pid
);
292 argv
[8] = getenv("CTDB_LOGGING");
294 argv
[10] = debug_level_to_string(DEBUGLEVEL
);
296 argv
[12] = talloc_asprintf(argv
, "%d", fd
[1]);
297 if (ectx
->debug_hung_script
== NULL
) {
302 argv
[14] = ectx
->debug_hung_script
;
306 if (argv
[6] == NULL
|| argv
[12] == NULL
) {
313 D_NOTICE("Starting event daemon "
314 "%s %s %s %s %s %s %s %s %s %s %s %s %s\n",
315 argv
[0], argv
[1], argv
[2], argv
[3], argv
[4], argv
[5],
316 argv
[6], argv
[7], argv
[8], argv
[9], argv
[10],
319 pid
= ctdb_fork(ctdb
);
329 ret
= execv(argv
[0], discard_const(argv
));
339 ret
= wait_for_daemon_startup(ctdb
->ev
, fd
[0]);
341 ctdb_kill(ctdb
, pid
, SIGKILL
);
343 D_ERR("Failed to initialize event daemon (%d)\n", ret
);
347 ectx
->eventd_fde
= tevent_add_fd(ctdb
->ev
, ectx
, fd
[0],
349 eventd_dead_handler
, ectx
);
350 if (ectx
->eventd_fde
== NULL
) {
351 ctdb_kill(ctdb
, pid
, SIGKILL
);
356 tevent_fd_set_auto_close(ectx
->eventd_fde
);
357 ectx
->eventd_pid
= pid
;
359 status
= eventd_client_connect(ectx
);
361 DEBUG(DEBUG_ERR
, ("Failed to connect to event daemon\n"));
362 ctdb_stop_eventd(ctdb
);
369 static void eventd_dead_handler(struct tevent_context
*ev
,
370 struct tevent_fd
*fde
, uint16_t flags
,
373 D_ERR("Eventd went away - exiting\n");
377 void ctdb_stop_eventd(struct ctdb_context
*ctdb
)
379 struct eventd_context
*ectx
= ctdb
->ectx
;
385 TALLOC_FREE(ectx
->eventd_fde
);
386 if (ectx
->eventd_pid
!= -1) {
387 kill(ectx
->eventd_pid
, SIGTERM
);
388 ectx
->eventd_pid
= -1;
390 TALLOC_FREE(ctdb
->ectx
);
394 * Connect to event daemon
397 struct eventd_client_state
{
398 struct eventd_client_state
*prev
, *next
;
400 struct eventd_context
*ectx
;
401 void (*callback
)(struct ctdb_event_reply
*reply
, void *private_data
);
409 static void eventd_client_read(uint8_t *buf
, size_t buflen
,
411 static int eventd_client_state_destructor(struct eventd_client_state
*state
);
413 static bool eventd_client_connect(struct eventd_context
*ectx
)
417 if (ectx
->queue
!= NULL
) {
421 fd
= sock_connect(ectx
->socket
);
426 ectx
->queue
= sock_queue_setup(ectx
, ectx
->ev
, fd
,
427 eventd_client_read
, ectx
);
428 if (ectx
->queue
== NULL
) {
436 static int eventd_client_write(struct eventd_context
*ectx
,
438 struct ctdb_event_request
*request
,
439 void (*callback
)(struct ctdb_event_reply
*reply
,
443 struct eventd_client_state
*state
;
446 if (! eventd_client_connect(ectx
)) {
450 state
= talloc_zero(mem_ctx
, struct eventd_client_state
);
456 state
->callback
= callback
;
457 state
->private_data
= private_data
;
459 state
->reqid
= reqid_new(ectx
->idr
, state
);
460 if (state
->reqid
== REQID_INVALID
) {
465 talloc_set_destructor(state
, eventd_client_state_destructor
);
467 sock_packet_header_set_reqid(&request
->header
, state
->reqid
);
469 state
->buflen
= ctdb_event_request_len(request
);
470 state
->buf
= talloc_size(state
, state
->buflen
);
471 if (state
->buf
== NULL
) {
476 ret
= ctdb_event_request_push(request
, state
->buf
, &state
->buflen
);
482 ret
= sock_queue_write(ectx
->queue
, state
->buf
, state
->buflen
);
488 DLIST_ADD(ectx
->calls
, state
);
493 static int eventd_client_state_destructor(struct eventd_client_state
*state
)
495 struct eventd_context
*ectx
= state
->ectx
;
497 reqid_remove(ectx
->idr
, state
->reqid
);
498 DLIST_REMOVE(ectx
->calls
, state
);
502 static void eventd_client_read(uint8_t *buf
, size_t buflen
,
505 struct eventd_context
*ectx
= talloc_get_type_abort(
506 private_data
, struct eventd_context
);
507 struct eventd_client_state
*state
;
508 struct ctdb_event_reply
*reply
;
512 /* connection lost */
513 TALLOC_FREE(ectx
->queue
);
517 reply
= talloc_zero(ectx
, struct ctdb_event_reply
);
522 ret
= ctdb_event_reply_pull(buf
, buflen
, reply
, reply
);
524 D_ERR("Invalid packet received, ret=%d\n", ret
);
529 if (buflen
!= reply
->header
.length
) {
530 D_ERR("Packet size mismatch %zu != %"PRIu32
"\n",
531 buflen
, reply
->header
.length
);
536 state
= reqid_find(ectx
->idr
, reply
->header
.reqid
,
537 struct eventd_client_state
);
543 if (state
->reqid
!= reply
->header
.reqid
) {
548 state
= talloc_steal(reply
, state
);
549 state
->callback(reply
, state
->private_data
);
557 struct eventd_client_run_state
{
558 struct eventd_context
*ectx
;
559 void (*callback
)(int result
, void *private_data
);
563 static void eventd_client_run_done(struct ctdb_event_reply
*reply
,
566 static int eventd_client_run(struct eventd_context
*ectx
,
568 void (*callback
)(int result
,
571 enum ctdb_event event
,
575 struct eventd_client_run_state
*state
;
576 struct ctdb_event_request request
;
577 struct ctdb_event_request_run rdata
;
580 state
= talloc_zero(mem_ctx
, struct eventd_client_run_state
);
586 state
->callback
= callback
;
587 state
->private_data
= private_data
;
590 rdata
.timeout
= timeout
;
591 rdata
.arg_str
= arg_str
;
593 request
.rdata
.command
= CTDB_EVENT_COMMAND_RUN
;
594 request
.rdata
.data
.run
= &rdata
;
596 ret
= eventd_client_write(ectx
, state
, &request
,
597 eventd_client_run_done
, state
);
606 static void eventd_client_run_done(struct ctdb_event_reply
*reply
,
609 struct eventd_client_run_state
*state
= talloc_get_type_abort(
610 private_data
, struct eventd_client_run_state
);
612 state
= talloc_steal(state
->ectx
, state
);
613 state
->callback(reply
->rdata
.result
, state
->private_data
);
618 * CTDB event script functions
621 int ctdb_event_script_run(struct ctdb_context
*ctdb
,
623 void (*callback
)(struct ctdb_context
*ctdb
,
624 int result
, void *private_data
),
626 enum ctdb_event event
,
627 const char *fmt
, va_list ap
)
628 PRINTF_ATTRIBUTE(6,0);
630 struct ctdb_event_script_run_state
{
631 struct ctdb_context
*ctdb
;
632 void (*callback
)(struct ctdb_context
*ctdb
, int result
,
635 enum ctdb_event event
;
638 static bool event_allowed_during_recovery(enum ctdb_event event
);
639 static void ctdb_event_script_run_done(int result
, void *private_data
);
640 static bool check_options(enum ctdb_event call
, const char *options
);
642 int ctdb_event_script_run(struct ctdb_context
*ctdb
,
644 void (*callback
)(struct ctdb_context
*ctdb
,
645 int result
, void *private_data
),
647 enum ctdb_event event
,
648 const char *fmt
, va_list ap
)
650 struct ctdb_event_script_run_state
*state
;
654 if ( (ctdb
->recovery_mode
!= CTDB_RECOVERY_NORMAL
) &&
655 (! event_allowed_during_recovery(event
)) ) {
657 ("Refusing to run event '%s' while in recovery\n",
658 ctdb_eventscript_call_names
[event
]));
662 state
= talloc_zero(mem_ctx
, struct ctdb_event_script_run_state
);
668 state
->callback
= callback
;
669 state
->private_data
= private_data
;
670 state
->event
= event
;
673 arg_str
= talloc_vasprintf(state
, fmt
, ap
);
674 if (arg_str
== NULL
) {
682 if (! check_options(event
, arg_str
)) {
684 ("Bad event script arguments '%s' for '%s'\n",
685 arg_str
, ctdb_eventscript_call_names
[event
]));
686 talloc_free(arg_str
);
690 ret
= eventd_client_run(ctdb
->ectx
, state
,
691 ctdb_event_script_run_done
, state
,
692 event
, arg_str
, ctdb
->tunable
.script_timeout
);
699 (__location__
" Running event %s with arguments %s\n",
700 ctdb_eventscript_call_names
[event
], arg_str
));
702 talloc_free(arg_str
);
706 static void ctdb_event_script_run_done(int result
, void *private_data
)
708 struct ctdb_event_script_run_state
*state
= talloc_get_type_abort(
709 private_data
, struct ctdb_event_script_run_state
);
711 if (result
== -ETIME
) {
712 switch (state
->event
) {
713 case CTDB_EVENT_START_RECOVERY
:
714 case CTDB_EVENT_RECOVERED
:
715 case CTDB_EVENT_TAKE_IP
:
716 case CTDB_EVENT_RELEASE_IP
:
718 ("Ignoring hung script for %s event\n",
719 ctdb_eventscript_call_names
[state
->event
]));
728 state
= talloc_steal(state
->ctdb
, state
);
729 state
->callback(state
->ctdb
, result
, state
->private_data
);
734 static unsigned int count_words(const char *options
)
736 unsigned int words
= 0;
738 if (options
== NULL
) {
742 options
+= strspn(options
, " \t");
745 options
+= strcspn(options
, " \t");
746 options
+= strspn(options
, " \t");
751 static bool check_options(enum ctdb_event call
, const char *options
)
754 /* These all take no arguments. */
755 case CTDB_EVENT_INIT
:
756 case CTDB_EVENT_SETUP
:
757 case CTDB_EVENT_STARTUP
:
758 case CTDB_EVENT_START_RECOVERY
:
759 case CTDB_EVENT_RECOVERED
:
760 case CTDB_EVENT_MONITOR
:
761 case CTDB_EVENT_SHUTDOWN
:
762 case CTDB_EVENT_IPREALLOCATED
:
763 return count_words(options
) == 0;
765 case CTDB_EVENT_TAKE_IP
: /* interface, IP address, netmask bits. */
766 case CTDB_EVENT_RELEASE_IP
:
767 return count_words(options
) == 3;
769 case CTDB_EVENT_UPDATE_IP
: /* old interface, new interface, IP address, netmask bits. */
770 return count_words(options
) == 4;
773 DEBUG(DEBUG_ERR
,(__location__
"Unknown ctdb_event %u\n", call
));
778 /* only specific events are allowed while in recovery */
779 static bool event_allowed_during_recovery(enum ctdb_event event
)
781 const enum ctdb_event allowed_events
[] = {
784 CTDB_EVENT_START_RECOVERY
,
786 CTDB_EVENT_RELEASE_IP
,
787 CTDB_EVENT_IPREALLOCATED
,
791 for (i
= 0; i
< ARRAY_SIZE(allowed_events
); i
++) {
792 if (event
== allowed_events
[i
]) {
801 run the event script in the background, calling the callback when
802 finished. If mem_ctx is freed, callback will never be called.
804 int ctdb_event_script_callback(struct ctdb_context
*ctdb
,
806 void (*callback
)(struct ctdb_context
*, int, void *),
808 enum ctdb_event call
,
809 const char *fmt
, ...)
815 ret
= ctdb_event_script_run(ctdb
, mem_ctx
, callback
, private_data
,
823 struct ctdb_event_script_args_state
{
828 static void ctdb_event_script_args_done(struct ctdb_context
*ctdb
,
829 int status
, void *private_data
)
831 struct ctdb_event_script_args_state
*s
=
832 (struct ctdb_event_script_args_state
*)private_data
;
839 run the event script, waiting for it to complete. Used when the caller
840 doesn't want to continue till the event script has finished.
842 int ctdb_event_script_args(struct ctdb_context
*ctdb
, enum ctdb_event call
,
843 const char *fmt
, ...)
847 struct ctdb_event_script_args_state state
= {
853 ret
= ctdb_event_script_run(ctdb
, ctdb
,
854 ctdb_event_script_args_done
, &state
,
861 while (! state
.done
) {
862 tevent_loop_once(ctdb
->ev
);
865 if (state
.status
== -ETIME
) {
866 /* Don't ban self if CTDB is starting up or shutting down */
867 if (call
!= CTDB_EVENT_INIT
&& call
!= CTDB_EVENT_SHUTDOWN
) {
869 (__location__
" eventscript for '%s' timed out."
870 " Immediately banning ourself for %d seconds\n",
871 ctdb_eventscript_call_names
[call
],
872 ctdb
->tunable
.recovery_ban_period
));
880 int ctdb_event_script(struct ctdb_context
*ctdb
, enum ctdb_event call
)
882 /* GCC complains about empty format string, so use %s and "". */
883 return ctdb_event_script_args(ctdb
, call
, NULL
);