nsswitch:libwbclient - fix leak in wbcCtxPingDc2
[Samba.git] / ctdb / server / eventscript.c
blob3ea7d74e95538eb479c9e85d46253a3d7e8af066
1 /*
2 event script handling
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/>.
20 #include "replace.h"
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"
29 #include <talloc.h>
30 #include <tevent.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/common.h"
40 #include "common/logging.h"
41 #include "common/reqid.h"
42 #include "common/sock_io.h"
43 #include "common/path.h"
45 #include "protocol/protocol_util.h"
46 #include "event/event_protocol_api.h"
49 * Setting up event daemon
52 struct eventd_context {
53 struct tevent_context *ev;
54 const char *path;
55 const char *socket;
57 /* server state */
58 pid_t eventd_pid;
59 struct tevent_fd *eventd_fde;
61 /* client state */
62 struct reqid_context *idr;
63 struct sock_queue *queue;
64 struct eventd_client_state *calls;
67 static bool eventd_context_init(TALLOC_CTX *mem_ctx,
68 struct ctdb_context *ctdb,
69 struct eventd_context **out)
71 struct eventd_context *ectx;
72 const char *eventd = CTDB_HELPER_BINDIR "/ctdb-eventd";
73 const char *value;
74 int ret;
76 ectx = talloc_zero(mem_ctx, struct eventd_context);
77 if (ectx == NULL) {
78 return false;
81 ectx->ev = ctdb->ev;
83 value = getenv("CTDB_EVENTD");
84 if (value != NULL) {
85 eventd = value;
88 ectx->path = talloc_strdup(ectx, eventd);
89 if (ectx->path == NULL) {
90 talloc_free(ectx);
91 return false;
94 ectx->socket = path_socket(ectx, "eventd");
95 if (ectx->socket == NULL) {
96 talloc_free(ectx);
97 return false;
100 ret = reqid_init(ectx, 1, &ectx->idr);
101 if (ret != 0) {
102 talloc_free(ectx);
103 return false;
106 ectx->eventd_pid = -1;
108 *out = ectx;
109 return true;
112 struct eventd_startup_state {
113 bool done;
114 int ret;
115 int fd;
118 static void eventd_startup_timeout_handler(struct tevent_context *ev,
119 struct tevent_timer *te,
120 struct timeval t,
121 void *private_data)
123 struct eventd_startup_state *state =
124 (struct eventd_startup_state *) private_data;
126 state->done = true;
127 state->ret = ETIMEDOUT;
130 static void eventd_startup_handler(struct tevent_context *ev,
131 struct tevent_fd *fde, uint16_t flags,
132 void *private_data)
134 struct eventd_startup_state *state =
135 (struct eventd_startup_state *)private_data;
136 unsigned int data;
137 ssize_t num_read;
139 num_read = sys_read(state->fd, &data, sizeof(data));
140 if (num_read == sizeof(data)) {
141 if (data == 0) {
142 state->ret = 0;
143 } else {
144 state->ret = EIO;
146 } else if (num_read == 0) {
147 state->ret = EPIPE;
148 } else if (num_read == -1) {
149 state->ret = errno;
150 } else {
151 state->ret = EINVAL;
154 state->done = true;
158 static int wait_for_daemon_startup(struct tevent_context *ev,
159 int fd)
161 TALLOC_CTX *mem_ctx;
162 struct tevent_timer *timer;
163 struct tevent_fd *fde;
164 struct eventd_startup_state state = {
165 .done = false,
166 .ret = 0,
167 .fd = fd,
170 mem_ctx = talloc_new(ev);
171 if (mem_ctx == NULL) {
172 return ENOMEM;
175 timer = tevent_add_timer(ev,
176 mem_ctx,
177 tevent_timeval_current_ofs(10, 0),
178 eventd_startup_timeout_handler,
179 &state);
180 if (timer == NULL) {
181 talloc_free(mem_ctx);
182 return ENOMEM;
185 fde = tevent_add_fd(ev,
186 mem_ctx,
188 TEVENT_FD_READ,
189 eventd_startup_handler,
190 &state);
191 if (fde == NULL) {
192 talloc_free(mem_ctx);
193 return ENOMEM;
196 while (! state.done) {
197 tevent_loop_once(ev);
200 talloc_free(mem_ctx);
202 return state.ret;
207 * Start and stop event daemon
210 static bool eventd_client_connect(struct eventd_context *ectx);
211 static void eventd_dead_handler(struct tevent_context *ev,
212 struct tevent_fd *fde, uint16_t flags,
213 void *private_data);
215 int ctdb_start_eventd(struct ctdb_context *ctdb)
217 struct eventd_context *ectx;
218 const char **argv;
219 int fd[2];
220 pid_t pid;
221 int ret;
222 bool status;
224 if (ctdb->ectx == NULL) {
225 status = eventd_context_init(ctdb, ctdb, &ctdb->ectx);
226 if (! status) {
227 DEBUG(DEBUG_ERR,
228 ("Failed to initialize eventd context\n"));
229 return -1;
233 ectx = ctdb->ectx;
235 if (! sock_clean(ectx->socket)) {
236 return -1;
239 ret = pipe(fd);
240 if (ret != 0) {
241 return -1;
244 argv = talloc_array(ectx, const char *, 6);
245 if (argv == NULL) {
246 close(fd[0]);
247 close(fd[1]);
248 return -1;
251 argv[0] = ectx->path;
252 argv[1] = "-P";
253 argv[2] = talloc_asprintf(argv, "%d", ctdb->ctdbd_pid);
254 argv[3] = "-S";
255 argv[4] = talloc_asprintf(argv, "%d", fd[1]);
256 argv[5] = NULL;
258 if (argv[2] == NULL || argv[4] == NULL) {
259 close(fd[0]);
260 close(fd[1]);
261 talloc_free(argv);
262 return -1;
265 D_NOTICE("Starting event daemon %s %s %s %s %s\n",
266 argv[0],
267 argv[1],
268 argv[2],
269 argv[3],
270 argv[4]);
272 pid = ctdb_fork(ctdb);
273 if (pid == -1) {
274 close(fd[0]);
275 close(fd[1]);
276 talloc_free(argv);
277 return -1;
280 if (pid == 0) {
281 close(fd[0]);
282 ret = execv(argv[0], discard_const(argv));
283 if (ret == -1) {
284 _exit(errno);
286 _exit(0);
289 talloc_free(argv);
290 close(fd[1]);
292 ret = wait_for_daemon_startup(ctdb->ev, fd[0]);
293 if (ret != 0) {
294 ctdb_kill(ctdb, pid, SIGKILL);
295 close(fd[0]);
296 D_ERR("Failed to initialize event daemon (%d)\n", ret);
297 return -1;
300 ectx->eventd_fde = tevent_add_fd(ctdb->ev, ectx, fd[0],
301 TEVENT_FD_READ,
302 eventd_dead_handler, ectx);
303 if (ectx->eventd_fde == NULL) {
304 ctdb_kill(ctdb, pid, SIGKILL);
305 close(fd[0]);
306 return -1;
309 tevent_fd_set_auto_close(ectx->eventd_fde);
310 ectx->eventd_pid = pid;
312 status = eventd_client_connect(ectx);
313 if (! status) {
314 DEBUG(DEBUG_ERR, ("Failed to connect to event daemon\n"));
315 ctdb_stop_eventd(ctdb);
316 return -1;
319 return 0;
322 static void eventd_dead_handler(struct tevent_context *ev,
323 struct tevent_fd *fde, uint16_t flags,
324 void *private_data)
326 D_ERR("Eventd went away - exiting\n");
327 exit(1);
330 void ctdb_stop_eventd(struct ctdb_context *ctdb)
332 struct eventd_context *ectx = ctdb->ectx;
334 if (ectx == NULL) {
335 return;
338 TALLOC_FREE(ectx->eventd_fde);
339 if (ectx->eventd_pid != -1) {
340 kill(ectx->eventd_pid, SIGTERM);
341 ectx->eventd_pid = -1;
343 TALLOC_FREE(ctdb->ectx);
347 * Connect to event daemon
350 struct eventd_client_state {
351 struct eventd_client_state *prev, *next;
353 struct eventd_context *ectx;
354 void (*callback)(struct ctdb_event_reply *reply, void *private_data);
355 void *private_data;
357 uint32_t reqid;
358 uint8_t *buf;
359 size_t buflen;
362 static void eventd_client_read(uint8_t *buf, size_t buflen,
363 void *private_data);
364 static int eventd_client_state_destructor(struct eventd_client_state *state);
366 static bool eventd_client_connect(struct eventd_context *ectx)
368 int fd;
370 if (ectx->queue != NULL) {
371 return true;
374 fd = sock_connect(ectx->socket);
375 if (fd == -1) {
376 return false;
379 ectx->queue = sock_queue_setup(ectx, ectx->ev, fd,
380 eventd_client_read, ectx);
381 if (ectx->queue == NULL) {
382 close(fd);
383 return false;
386 return true;
389 static int eventd_client_write(struct eventd_context *ectx,
390 TALLOC_CTX *mem_ctx,
391 struct ctdb_event_request *request,
392 void (*callback)(struct ctdb_event_reply *reply,
393 void *private_data),
394 void *private_data)
396 struct ctdb_event_header header = { 0 };
397 struct eventd_client_state *state;
398 int ret;
400 if (! eventd_client_connect(ectx)) {
401 return -1;
404 state = talloc_zero(mem_ctx, struct eventd_client_state);
405 if (state == NULL) {
406 return -1;
409 state->ectx = ectx;
410 state->callback = callback;
411 state->private_data = private_data;
413 state->reqid = reqid_new(ectx->idr, state);
414 if (state->reqid == REQID_INVALID) {
415 talloc_free(state);
416 return -1;
419 talloc_set_destructor(state, eventd_client_state_destructor);
421 header.reqid = state->reqid;
423 state->buflen = ctdb_event_request_len(&header, request);
424 state->buf = talloc_size(state, state->buflen);
425 if (state->buf == NULL) {
426 talloc_free(state);
427 return -1;
430 ret = ctdb_event_request_push(&header,
431 request,
432 state->buf,
433 &state->buflen);
434 if (ret != 0) {
435 talloc_free(state);
436 return -1;
439 ret = sock_queue_write(ectx->queue, state->buf, state->buflen);
440 if (ret != 0) {
441 talloc_free(state);
442 return -1;
445 DLIST_ADD(ectx->calls, state);
447 return 0;
450 static int eventd_client_state_destructor(struct eventd_client_state *state)
452 struct eventd_context *ectx = state->ectx;
454 reqid_remove(ectx->idr, state->reqid);
455 DLIST_REMOVE(ectx->calls, state);
456 return 0;
459 static void eventd_client_read(uint8_t *buf, size_t buflen,
460 void *private_data)
462 struct eventd_context *ectx = talloc_get_type_abort(
463 private_data, struct eventd_context);
464 struct eventd_client_state *state;
465 struct ctdb_event_header header;
466 struct ctdb_event_reply *reply;
467 int ret;
469 if (buf == NULL) {
470 /* connection lost */
471 TALLOC_FREE(ectx->queue);
472 return;
475 ret = ctdb_event_reply_pull(buf, buflen, &header, ectx, &reply);
476 if (ret != 0) {
477 D_ERR("Invalid packet received, ret=%d\n", ret);
478 return;
481 if (buflen != header.length) {
482 D_ERR("Packet size mismatch %zu != %"PRIu32"\n",
483 buflen, header.length);
484 talloc_free(reply);
485 return;
488 state = reqid_find(ectx->idr, header.reqid,
489 struct eventd_client_state);
490 if (state == NULL) {
491 talloc_free(reply);
492 return;
495 if (state->reqid != header.reqid) {
496 talloc_free(reply);
497 return;
500 state = talloc_steal(reply, state);
501 state->callback(reply, state->private_data);
502 talloc_free(reply);
506 * Run an event
509 struct eventd_client_run_state {
510 struct eventd_context *ectx;
511 void (*callback)(int result, void *private_data);
512 void *private_data;
515 static void eventd_client_run_done(struct ctdb_event_reply *reply,
516 void *private_data);
518 static int eventd_client_run(struct eventd_context *ectx,
519 TALLOC_CTX *mem_ctx,
520 void (*callback)(int result,
521 void *private_data),
522 void *private_data,
523 enum ctdb_event event,
524 const char *arg_str,
525 uint32_t timeout)
527 struct eventd_client_run_state *state;
528 struct ctdb_event_request request;
529 struct ctdb_event_request_run rdata;
530 int ret;
532 state = talloc_zero(mem_ctx, struct eventd_client_run_state);
533 if (state == NULL) {
534 return -1;
537 state->ectx = ectx;
538 state->callback = callback;
539 state->private_data = private_data;
541 rdata.component = "legacy";
542 rdata.event = ctdb_event_to_string(event);
543 rdata.args = arg_str;
544 rdata.timeout = timeout;
545 rdata.flags = 0;
547 request.cmd = CTDB_EVENT_CMD_RUN;
548 request.data.run = &rdata;
550 ret = eventd_client_write(ectx, state, &request,
551 eventd_client_run_done, state);
552 if (ret != 0) {
553 talloc_free(state);
554 return ret;
557 return 0;
560 static void eventd_client_run_done(struct ctdb_event_reply *reply,
561 void *private_data)
563 struct eventd_client_run_state *state = talloc_get_type_abort(
564 private_data, struct eventd_client_run_state);
566 state = talloc_steal(state->ectx, state);
567 state->callback(reply->result, state->private_data);
568 talloc_free(state);
572 * CTDB event script functions
575 int ctdb_event_script_run(struct ctdb_context *ctdb,
576 TALLOC_CTX *mem_ctx,
577 void (*callback)(struct ctdb_context *ctdb,
578 int result, void *private_data),
579 void *private_data,
580 enum ctdb_event event,
581 const char *fmt, va_list ap)
582 PRINTF_ATTRIBUTE(6,0);
584 struct ctdb_event_script_run_state {
585 struct ctdb_context *ctdb;
586 void (*callback)(struct ctdb_context *ctdb, int result,
587 void *private_data);
588 void *private_data;
589 enum ctdb_event event;
592 static bool event_allowed_during_recovery(enum ctdb_event event);
593 static void ctdb_event_script_run_done(int result, void *private_data);
594 static bool check_options(enum ctdb_event call, const char *options);
596 int ctdb_event_script_run(struct ctdb_context *ctdb,
597 TALLOC_CTX *mem_ctx,
598 void (*callback)(struct ctdb_context *ctdb,
599 int result, void *private_data),
600 void *private_data,
601 enum ctdb_event event,
602 const char *fmt, va_list ap)
604 struct ctdb_event_script_run_state *state;
605 char *arg_str;
606 int ret;
608 if ( (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) &&
609 (! event_allowed_during_recovery(event)) ) {
610 DEBUG(DEBUG_ERR,
611 ("Refusing to run event '%s' while in recovery\n",
612 ctdb_eventscript_call_names[event]));
613 return -1;
616 state = talloc_zero(mem_ctx, struct ctdb_event_script_run_state);
617 if (state == NULL) {
618 return -1;
621 state->ctdb = ctdb;
622 state->callback = callback;
623 state->private_data = private_data;
624 state->event = event;
626 if (fmt != NULL) {
627 arg_str = talloc_vasprintf(state, fmt, ap);
628 if (arg_str == NULL) {
629 talloc_free(state);
630 return -1;
632 } else {
633 arg_str = NULL;
636 if (! check_options(event, arg_str)) {
637 DEBUG(DEBUG_ERR,
638 ("Bad event script arguments '%s' for '%s'\n",
639 arg_str, ctdb_eventscript_call_names[event]));
640 talloc_free(arg_str);
641 return -1;
644 ret = eventd_client_run(ctdb->ectx, state,
645 ctdb_event_script_run_done, state,
646 event, arg_str, ctdb->tunable.script_timeout);
647 if (ret != 0) {
648 talloc_free(state);
649 return ret;
652 DEBUG(DEBUG_INFO,
653 (__location__ " Running event %s with arguments %s\n",
654 ctdb_eventscript_call_names[event], arg_str));
656 talloc_free(arg_str);
657 return 0;
660 static void ctdb_event_script_run_done(int result, void *private_data)
662 struct ctdb_event_script_run_state *state = talloc_get_type_abort(
663 private_data, struct ctdb_event_script_run_state);
665 if (result == ETIMEDOUT) {
666 switch (state->event) {
667 case CTDB_EVENT_START_RECOVERY:
668 case CTDB_EVENT_RECOVERED:
669 case CTDB_EVENT_TAKE_IP:
670 case CTDB_EVENT_RELEASE_IP:
671 DEBUG(DEBUG_ERR,
672 ("Ignoring hung script for %s event\n",
673 ctdb_eventscript_call_names[state->event]));
674 result = 0;
675 break;
677 default:
678 break;
682 state = talloc_steal(state->ctdb, state);
683 state->callback(state->ctdb, result, state->private_data);
684 talloc_free(state);
688 static unsigned int count_words(const char *options)
690 unsigned int words = 0;
692 if (options == NULL) {
693 return 0;
696 options += strspn(options, " \t");
697 while (*options) {
698 words++;
699 options += strcspn(options, " \t");
700 options += strspn(options, " \t");
702 return words;
705 static bool check_options(enum ctdb_event call, const char *options)
707 switch (call) {
708 /* These all take no arguments. */
709 case CTDB_EVENT_INIT:
710 case CTDB_EVENT_SETUP:
711 case CTDB_EVENT_STARTUP:
712 case CTDB_EVENT_START_RECOVERY:
713 case CTDB_EVENT_RECOVERED:
714 case CTDB_EVENT_MONITOR:
715 case CTDB_EVENT_SHUTDOWN:
716 case CTDB_EVENT_IPREALLOCATED:
717 return count_words(options) == 0;
719 case CTDB_EVENT_TAKE_IP: /* interface, IP address, netmask bits. */
720 case CTDB_EVENT_RELEASE_IP:
721 return count_words(options) == 3;
723 case CTDB_EVENT_UPDATE_IP: /* old interface, new interface, IP address, netmask bits. */
724 return count_words(options) == 4;
726 default:
727 DEBUG(DEBUG_ERR,(__location__ "Unknown ctdb_event %u\n", call));
728 return false;
732 /* only specific events are allowed while in recovery */
733 static bool event_allowed_during_recovery(enum ctdb_event event)
735 const enum ctdb_event allowed_events[] = {
736 CTDB_EVENT_INIT,
737 CTDB_EVENT_SETUP,
738 CTDB_EVENT_START_RECOVERY,
739 CTDB_EVENT_SHUTDOWN,
740 CTDB_EVENT_RELEASE_IP,
741 CTDB_EVENT_IPREALLOCATED,
743 size_t i;
745 for (i = 0; i < ARRAY_SIZE(allowed_events); i++) {
746 if (event == allowed_events[i]) {
747 return true;
751 return false;
755 run the event script in the background, calling the callback when
756 finished. If mem_ctx is freed, callback will never be called.
758 int ctdb_event_script_callback(struct ctdb_context *ctdb,
759 TALLOC_CTX *mem_ctx,
760 void (*callback)(struct ctdb_context *, int, void *),
761 void *private_data,
762 enum ctdb_event call,
763 const char *fmt, ...)
765 va_list ap;
766 int ret;
768 va_start(ap, fmt);
769 ret = ctdb_event_script_run(ctdb, mem_ctx, callback, private_data,
770 call, fmt, ap);
771 va_end(ap);
773 return ret;
777 struct ctdb_event_script_args_state {
778 bool done;
779 int status;
782 static void ctdb_event_script_args_done(struct ctdb_context *ctdb,
783 int status, void *private_data)
785 struct ctdb_event_script_args_state *s =
786 (struct ctdb_event_script_args_state *)private_data;
788 s->done = true;
789 s->status = status;
793 run the event script, waiting for it to complete. Used when the caller
794 doesn't want to continue till the event script has finished.
796 int ctdb_event_script_args(struct ctdb_context *ctdb, enum ctdb_event call,
797 const char *fmt, ...)
799 va_list ap;
800 int ret;
801 struct ctdb_event_script_args_state state = {
802 .status = -1,
803 .done = false,
806 va_start(ap, fmt);
807 ret = ctdb_event_script_run(ctdb, ctdb,
808 ctdb_event_script_args_done, &state,
809 call, fmt, ap);
810 va_end(ap);
811 if (ret != 0) {
812 return ret;
815 while (! state.done) {
816 tevent_loop_once(ctdb->ev);
819 if (state.status == ETIMEDOUT) {
820 /* Don't ban self if CTDB is starting up or shutting down */
821 if (call != CTDB_EVENT_INIT && call != CTDB_EVENT_SHUTDOWN) {
822 DEBUG(DEBUG_ERR,
823 (__location__ " eventscript for '%s' timed out."
824 " Immediately banning ourself for %d seconds\n",
825 ctdb_eventscript_call_names[call],
826 ctdb->tunable.recovery_ban_period));
827 ctdb_ban_self(ctdb);
831 return state.status;
834 int ctdb_event_script(struct ctdb_context *ctdb, enum ctdb_event call)
836 /* GCC complains about empty format string, so use %s and "". */
837 return ctdb_event_script_args(ctdb, call, NULL);
840 void ctdb_event_reopen_logs(struct ctdb_context *ctdb)
842 if (ctdb->ectx->eventd_pid > 0) {
843 kill(ctdb->ectx->eventd_pid, SIGHUP);