s3: VFS: vfs_snapper: Make chflags return errno = EROFS on a shadow copy path.
[Samba.git] / ctdb / server / eventscript.c
blobe7a74468cc2ebe1e3b92942091ccd238b400814b
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/rb_tree.h"
40 #include "common/common.h"
41 #include "common/logging.h"
42 #include "common/reqid.h"
43 #include "common/sock_io.h"
44 #include "common/path.h"
46 #include "protocol/protocol_util.h"
47 #include "event/event_protocol_api.h"
50 * Setting up event daemon
53 struct eventd_context {
54 struct tevent_context *ev;
55 const char *path;
56 const char *socket;
58 /* server state */
59 pid_t eventd_pid;
60 struct tevent_fd *eventd_fde;
62 /* client state */
63 struct reqid_context *idr;
64 struct sock_queue *queue;
65 struct eventd_client_state *calls;
68 static bool eventd_context_init(TALLOC_CTX *mem_ctx,
69 struct ctdb_context *ctdb,
70 struct eventd_context **out)
72 struct eventd_context *ectx;
73 const char *eventd = CTDB_HELPER_BINDIR "/ctdb-eventd";
74 const char *value;
75 int ret;
77 ectx = talloc_zero(mem_ctx, struct eventd_context);
78 if (ectx == NULL) {
79 return false;
82 ectx->ev = ctdb->ev;
84 value = getenv("CTDB_EVENTD");
85 if (value != NULL) {
86 eventd = value;
89 ectx->path = talloc_strdup(ectx, eventd);
90 if (ectx->path == NULL) {
91 talloc_free(ectx);
92 return false;
95 ectx->socket = path_socket(ectx, "eventd");
96 if (ectx->socket == NULL) {
97 talloc_free(ectx);
98 return false;
101 ret = reqid_init(ectx, 1, &ectx->idr);
102 if (ret != 0) {
103 talloc_free(ectx);
104 return false;
107 ectx->eventd_pid = -1;
109 *out = ectx;
110 return true;
113 struct eventd_startup_state {
114 bool done;
115 int ret;
116 int fd;
119 static void eventd_startup_timeout_handler(struct tevent_context *ev,
120 struct tevent_timer *te,
121 struct timeval t,
122 void *private_data)
124 struct eventd_startup_state *state =
125 (struct eventd_startup_state *) private_data;
127 state->done = true;
128 state->ret = ETIMEDOUT;
131 static void eventd_startup_handler(struct tevent_context *ev,
132 struct tevent_fd *fde, uint16_t flags,
133 void *private_data)
135 struct eventd_startup_state *state =
136 (struct eventd_startup_state *)private_data;
137 unsigned int data;
138 ssize_t num_read;
140 num_read = sys_read(state->fd, &data, sizeof(data));
141 if (num_read == sizeof(data)) {
142 if (data == 0) {
143 state->ret = 0;
144 } else {
145 state->ret = EIO;
147 } else if (num_read == 0) {
148 state->ret = EPIPE;
149 } else if (num_read == -1) {
150 state->ret = errno;
151 } else {
152 state->ret = EINVAL;
155 state->done = true;
159 static int wait_for_daemon_startup(struct tevent_context *ev,
160 int fd)
162 TALLOC_CTX *mem_ctx;
163 struct tevent_timer *timer;
164 struct tevent_fd *fde;
165 struct eventd_startup_state state = {
166 .done = false,
167 .ret = 0,
168 .fd = fd,
171 mem_ctx = talloc_new(ev);
172 if (mem_ctx == NULL) {
173 return ENOMEM;
176 timer = tevent_add_timer(ev,
177 mem_ctx,
178 tevent_timeval_current_ofs(10, 0),
179 eventd_startup_timeout_handler,
180 &state);
181 if (timer == NULL) {
182 talloc_free(mem_ctx);
183 return ENOMEM;
186 fde = tevent_add_fd(ev,
187 mem_ctx,
189 TEVENT_FD_READ,
190 eventd_startup_handler,
191 &state);
192 if (fde == NULL) {
193 talloc_free(mem_ctx);
194 return ENOMEM;
197 while (! state.done) {
198 tevent_loop_once(ev);
201 talloc_free(mem_ctx);
203 return state.ret;
208 * Start and stop event daemon
211 static bool eventd_client_connect(struct eventd_context *ectx);
212 static void eventd_dead_handler(struct tevent_context *ev,
213 struct tevent_fd *fde, uint16_t flags,
214 void *private_data);
216 int ctdb_start_eventd(struct ctdb_context *ctdb)
218 struct eventd_context *ectx;
219 const char **argv;
220 int fd[2];
221 pid_t pid;
222 int ret;
223 bool status;
225 if (ctdb->ectx == NULL) {
226 status = eventd_context_init(ctdb, ctdb, &ctdb->ectx);
227 if (! status) {
228 DEBUG(DEBUG_ERR,
229 ("Failed to initialize eventd context\n"));
230 return -1;
234 ectx = ctdb->ectx;
236 if (! sock_clean(ectx->socket)) {
237 return -1;
240 ret = pipe(fd);
241 if (ret != 0) {
242 return -1;
245 argv = talloc_array(ectx, const char *, 6);
246 if (argv == NULL) {
247 close(fd[0]);
248 close(fd[1]);
249 return -1;
252 argv[0] = ectx->path;
253 argv[1] = "-P";
254 argv[2] = talloc_asprintf(argv, "%d", ctdb->ctdbd_pid);
255 argv[3] = "-S";
256 argv[4] = talloc_asprintf(argv, "%d", fd[1]);
257 argv[5] = NULL;
259 if (argv[2] == NULL || argv[4] == NULL) {
260 close(fd[0]);
261 close(fd[1]);
262 talloc_free(argv);
263 return -1;
266 D_NOTICE("Starting event daemon %s %s %s %s %s\n",
267 argv[0],
268 argv[1],
269 argv[2],
270 argv[3],
271 argv[4]);
273 pid = ctdb_fork(ctdb);
274 if (pid == -1) {
275 close(fd[0]);
276 close(fd[1]);
277 talloc_free(argv);
278 return -1;
281 if (pid == 0) {
282 close(fd[0]);
283 ret = execv(argv[0], discard_const(argv));
284 if (ret == -1) {
285 _exit(errno);
287 _exit(0);
290 talloc_free(argv);
291 close(fd[1]);
293 ret = wait_for_daemon_startup(ctdb->ev, fd[0]);
294 if (ret != 0) {
295 ctdb_kill(ctdb, pid, SIGKILL);
296 close(fd[0]);
297 D_ERR("Failed to initialize event daemon (%d)\n", ret);
298 return -1;
301 ectx->eventd_fde = tevent_add_fd(ctdb->ev, ectx, fd[0],
302 TEVENT_FD_READ,
303 eventd_dead_handler, ectx);
304 if (ectx->eventd_fde == NULL) {
305 ctdb_kill(ctdb, pid, SIGKILL);
306 close(fd[0]);
307 return -1;
310 tevent_fd_set_auto_close(ectx->eventd_fde);
311 ectx->eventd_pid = pid;
313 status = eventd_client_connect(ectx);
314 if (! status) {
315 DEBUG(DEBUG_ERR, ("Failed to connect to event daemon\n"));
316 ctdb_stop_eventd(ctdb);
317 return -1;
320 return 0;
323 static void eventd_dead_handler(struct tevent_context *ev,
324 struct tevent_fd *fde, uint16_t flags,
325 void *private_data)
327 D_ERR("Eventd went away - exiting\n");
328 exit(1);
331 void ctdb_stop_eventd(struct ctdb_context *ctdb)
333 struct eventd_context *ectx = ctdb->ectx;
335 if (ectx == NULL) {
336 return;
339 TALLOC_FREE(ectx->eventd_fde);
340 if (ectx->eventd_pid != -1) {
341 kill(ectx->eventd_pid, SIGTERM);
342 ectx->eventd_pid = -1;
344 TALLOC_FREE(ctdb->ectx);
348 * Connect to event daemon
351 struct eventd_client_state {
352 struct eventd_client_state *prev, *next;
354 struct eventd_context *ectx;
355 void (*callback)(struct ctdb_event_reply *reply, void *private_data);
356 void *private_data;
358 uint32_t reqid;
359 uint8_t *buf;
360 size_t buflen;
363 static void eventd_client_read(uint8_t *buf, size_t buflen,
364 void *private_data);
365 static int eventd_client_state_destructor(struct eventd_client_state *state);
367 static bool eventd_client_connect(struct eventd_context *ectx)
369 int fd;
371 if (ectx->queue != NULL) {
372 return true;
375 fd = sock_connect(ectx->socket);
376 if (fd == -1) {
377 return false;
380 ectx->queue = sock_queue_setup(ectx, ectx->ev, fd,
381 eventd_client_read, ectx);
382 if (ectx->queue == NULL) {
383 close(fd);
384 return false;
387 return true;
390 static int eventd_client_write(struct eventd_context *ectx,
391 TALLOC_CTX *mem_ctx,
392 struct ctdb_event_request *request,
393 void (*callback)(struct ctdb_event_reply *reply,
394 void *private_data),
395 void *private_data)
397 struct ctdb_event_header header = { 0 };
398 struct eventd_client_state *state;
399 int ret;
401 if (! eventd_client_connect(ectx)) {
402 return -1;
405 state = talloc_zero(mem_ctx, struct eventd_client_state);
406 if (state == NULL) {
407 return -1;
410 state->ectx = ectx;
411 state->callback = callback;
412 state->private_data = private_data;
414 state->reqid = reqid_new(ectx->idr, state);
415 if (state->reqid == REQID_INVALID) {
416 talloc_free(state);
417 return -1;
420 talloc_set_destructor(state, eventd_client_state_destructor);
422 header.reqid = state->reqid;
424 state->buflen = ctdb_event_request_len(&header, request);
425 state->buf = talloc_size(state, state->buflen);
426 if (state->buf == NULL) {
427 talloc_free(state);
428 return -1;
431 ret = ctdb_event_request_push(&header,
432 request,
433 state->buf,
434 &state->buflen);
435 if (ret != 0) {
436 talloc_free(state);
437 return -1;
440 ret = sock_queue_write(ectx->queue, state->buf, state->buflen);
441 if (ret != 0) {
442 talloc_free(state);
443 return -1;
446 DLIST_ADD(ectx->calls, state);
448 return 0;
451 static int eventd_client_state_destructor(struct eventd_client_state *state)
453 struct eventd_context *ectx = state->ectx;
455 reqid_remove(ectx->idr, state->reqid);
456 DLIST_REMOVE(ectx->calls, state);
457 return 0;
460 static void eventd_client_read(uint8_t *buf, size_t buflen,
461 void *private_data)
463 struct eventd_context *ectx = talloc_get_type_abort(
464 private_data, struct eventd_context);
465 struct eventd_client_state *state;
466 struct ctdb_event_header header;
467 struct ctdb_event_reply *reply;
468 int ret;
470 if (buf == NULL) {
471 /* connection lost */
472 TALLOC_FREE(ectx->queue);
473 return;
476 ret = ctdb_event_reply_pull(buf, buflen, &header, ectx, &reply);
477 if (ret != 0) {
478 D_ERR("Invalid packet received, ret=%d\n", ret);
479 return;
482 if (buflen != header.length) {
483 D_ERR("Packet size mismatch %zu != %"PRIu32"\n",
484 buflen, header.length);
485 talloc_free(reply);
486 return;
489 state = reqid_find(ectx->idr, header.reqid,
490 struct eventd_client_state);
491 if (state == NULL) {
492 talloc_free(reply);
493 return;
496 if (state->reqid != header.reqid) {
497 talloc_free(reply);
498 return;
501 state = talloc_steal(reply, state);
502 state->callback(reply, state->private_data);
503 talloc_free(reply);
507 * Run an event
510 struct eventd_client_run_state {
511 struct eventd_context *ectx;
512 void (*callback)(int result, void *private_data);
513 void *private_data;
516 static void eventd_client_run_done(struct ctdb_event_reply *reply,
517 void *private_data);
519 static int eventd_client_run(struct eventd_context *ectx,
520 TALLOC_CTX *mem_ctx,
521 void (*callback)(int result,
522 void *private_data),
523 void *private_data,
524 enum ctdb_event event,
525 const char *arg_str,
526 uint32_t timeout)
528 struct eventd_client_run_state *state;
529 struct ctdb_event_request request;
530 struct ctdb_event_request_run rdata;
531 int ret;
533 state = talloc_zero(mem_ctx, struct eventd_client_run_state);
534 if (state == NULL) {
535 return -1;
538 state->ectx = ectx;
539 state->callback = callback;
540 state->private_data = private_data;
542 rdata.component = "legacy";
543 rdata.event = ctdb_event_to_string(event);
544 rdata.args = arg_str;
545 rdata.timeout = timeout;
546 rdata.flags = 0;
548 request.cmd = CTDB_EVENT_CMD_RUN;
549 request.data.run = &rdata;
551 ret = eventd_client_write(ectx, state, &request,
552 eventd_client_run_done, state);
553 if (ret != 0) {
554 talloc_free(state);
555 return ret;
558 return 0;
561 static void eventd_client_run_done(struct ctdb_event_reply *reply,
562 void *private_data)
564 struct eventd_client_run_state *state = talloc_get_type_abort(
565 private_data, struct eventd_client_run_state);
567 state = talloc_steal(state->ectx, state);
568 state->callback(reply->result, state->private_data);
569 talloc_free(state);
573 * CTDB event script functions
576 int ctdb_event_script_run(struct ctdb_context *ctdb,
577 TALLOC_CTX *mem_ctx,
578 void (*callback)(struct ctdb_context *ctdb,
579 int result, void *private_data),
580 void *private_data,
581 enum ctdb_event event,
582 const char *fmt, va_list ap)
583 PRINTF_ATTRIBUTE(6,0);
585 struct ctdb_event_script_run_state {
586 struct ctdb_context *ctdb;
587 void (*callback)(struct ctdb_context *ctdb, int result,
588 void *private_data);
589 void *private_data;
590 enum ctdb_event event;
593 static bool event_allowed_during_recovery(enum ctdb_event event);
594 static void ctdb_event_script_run_done(int result, void *private_data);
595 static bool check_options(enum ctdb_event call, const char *options);
597 int ctdb_event_script_run(struct ctdb_context *ctdb,
598 TALLOC_CTX *mem_ctx,
599 void (*callback)(struct ctdb_context *ctdb,
600 int result, void *private_data),
601 void *private_data,
602 enum ctdb_event event,
603 const char *fmt, va_list ap)
605 struct ctdb_event_script_run_state *state;
606 char *arg_str;
607 int ret;
609 if ( (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) &&
610 (! event_allowed_during_recovery(event)) ) {
611 DEBUG(DEBUG_ERR,
612 ("Refusing to run event '%s' while in recovery\n",
613 ctdb_eventscript_call_names[event]));
614 return -1;
617 state = talloc_zero(mem_ctx, struct ctdb_event_script_run_state);
618 if (state == NULL) {
619 return -1;
622 state->ctdb = ctdb;
623 state->callback = callback;
624 state->private_data = private_data;
625 state->event = event;
627 if (fmt != NULL) {
628 arg_str = talloc_vasprintf(state, fmt, ap);
629 if (arg_str == NULL) {
630 talloc_free(state);
631 return -1;
633 } else {
634 arg_str = NULL;
637 if (! check_options(event, arg_str)) {
638 DEBUG(DEBUG_ERR,
639 ("Bad event script arguments '%s' for '%s'\n",
640 arg_str, ctdb_eventscript_call_names[event]));
641 talloc_free(arg_str);
642 return -1;
645 ret = eventd_client_run(ctdb->ectx, state,
646 ctdb_event_script_run_done, state,
647 event, arg_str, ctdb->tunable.script_timeout);
648 if (ret != 0) {
649 talloc_free(state);
650 return ret;
653 DEBUG(DEBUG_INFO,
654 (__location__ " Running event %s with arguments %s\n",
655 ctdb_eventscript_call_names[event], arg_str));
657 talloc_free(arg_str);
658 return 0;
661 static void ctdb_event_script_run_done(int result, void *private_data)
663 struct ctdb_event_script_run_state *state = talloc_get_type_abort(
664 private_data, struct ctdb_event_script_run_state);
666 if (result == ETIMEDOUT) {
667 switch (state->event) {
668 case CTDB_EVENT_START_RECOVERY:
669 case CTDB_EVENT_RECOVERED:
670 case CTDB_EVENT_TAKE_IP:
671 case CTDB_EVENT_RELEASE_IP:
672 DEBUG(DEBUG_ERR,
673 ("Ignoring hung script for %s event\n",
674 ctdb_eventscript_call_names[state->event]));
675 result = 0;
676 break;
678 default:
679 break;
683 state = talloc_steal(state->ctdb, state);
684 state->callback(state->ctdb, result, state->private_data);
685 talloc_free(state);
689 static unsigned int count_words(const char *options)
691 unsigned int words = 0;
693 if (options == NULL) {
694 return 0;
697 options += strspn(options, " \t");
698 while (*options) {
699 words++;
700 options += strcspn(options, " \t");
701 options += strspn(options, " \t");
703 return words;
706 static bool check_options(enum ctdb_event call, const char *options)
708 switch (call) {
709 /* These all take no arguments. */
710 case CTDB_EVENT_INIT:
711 case CTDB_EVENT_SETUP:
712 case CTDB_EVENT_STARTUP:
713 case CTDB_EVENT_START_RECOVERY:
714 case CTDB_EVENT_RECOVERED:
715 case CTDB_EVENT_MONITOR:
716 case CTDB_EVENT_SHUTDOWN:
717 case CTDB_EVENT_IPREALLOCATED:
718 return count_words(options) == 0;
720 case CTDB_EVENT_TAKE_IP: /* interface, IP address, netmask bits. */
721 case CTDB_EVENT_RELEASE_IP:
722 return count_words(options) == 3;
724 case CTDB_EVENT_UPDATE_IP: /* old interface, new interface, IP address, netmask bits. */
725 return count_words(options) == 4;
727 default:
728 DEBUG(DEBUG_ERR,(__location__ "Unknown ctdb_event %u\n", call));
729 return false;
733 /* only specific events are allowed while in recovery */
734 static bool event_allowed_during_recovery(enum ctdb_event event)
736 const enum ctdb_event allowed_events[] = {
737 CTDB_EVENT_INIT,
738 CTDB_EVENT_SETUP,
739 CTDB_EVENT_START_RECOVERY,
740 CTDB_EVENT_SHUTDOWN,
741 CTDB_EVENT_RELEASE_IP,
742 CTDB_EVENT_IPREALLOCATED,
744 size_t i;
746 for (i = 0; i < ARRAY_SIZE(allowed_events); i++) {
747 if (event == allowed_events[i]) {
748 return true;
752 return false;
756 run the event script in the background, calling the callback when
757 finished. If mem_ctx is freed, callback will never be called.
759 int ctdb_event_script_callback(struct ctdb_context *ctdb,
760 TALLOC_CTX *mem_ctx,
761 void (*callback)(struct ctdb_context *, int, void *),
762 void *private_data,
763 enum ctdb_event call,
764 const char *fmt, ...)
766 va_list ap;
767 int ret;
769 va_start(ap, fmt);
770 ret = ctdb_event_script_run(ctdb, mem_ctx, callback, private_data,
771 call, fmt, ap);
772 va_end(ap);
774 return ret;
778 struct ctdb_event_script_args_state {
779 bool done;
780 int status;
783 static void ctdb_event_script_args_done(struct ctdb_context *ctdb,
784 int status, void *private_data)
786 struct ctdb_event_script_args_state *s =
787 (struct ctdb_event_script_args_state *)private_data;
789 s->done = true;
790 s->status = status;
794 run the event script, waiting for it to complete. Used when the caller
795 doesn't want to continue till the event script has finished.
797 int ctdb_event_script_args(struct ctdb_context *ctdb, enum ctdb_event call,
798 const char *fmt, ...)
800 va_list ap;
801 int ret;
802 struct ctdb_event_script_args_state state = {
803 .status = -1,
804 .done = false,
807 va_start(ap, fmt);
808 ret = ctdb_event_script_run(ctdb, ctdb,
809 ctdb_event_script_args_done, &state,
810 call, fmt, ap);
811 va_end(ap);
812 if (ret != 0) {
813 return ret;
816 while (! state.done) {
817 tevent_loop_once(ctdb->ev);
820 if (state.status == ETIMEDOUT) {
821 /* Don't ban self if CTDB is starting up or shutting down */
822 if (call != CTDB_EVENT_INIT && call != CTDB_EVENT_SHUTDOWN) {
823 DEBUG(DEBUG_ERR,
824 (__location__ " eventscript for '%s' timed out."
825 " Immediately banning ourself for %d seconds\n",
826 ctdb_eventscript_call_names[call],
827 ctdb->tunable.recovery_ban_period));
828 ctdb_ban_self(ctdb);
832 return state.status;
835 int ctdb_event_script(struct ctdb_context *ctdb, enum ctdb_event call)
837 /* GCC complains about empty format string, so use %s and "". */
838 return ctdb_event_script_args(ctdb, call, NULL);