auth/common: add support for auth4_ctx->check_ntlm_password_send/recv()
[Samba.git] / ctdb / server / ctdb_eventd.c
bloba6ab2197e74c932eda38c48fe6b127db513769a3
1 /*
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/>.
20 #include "replace.h"
21 #include "system/filesys.h"
22 #include "system/dir.h"
23 #include "system/wait.h"
24 #include "system/locale.h"
26 #include <popt.h>
27 #include <talloc.h>
28 #include <tevent.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;
61 /* current state */
62 bool running;
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;
85 int ret;
87 ectx = talloc_zero(mem_ctx, struct eventd_context);
88 if (ectx == NULL) {
89 return ENOMEM;
92 ret = run_event_init(ectx, ev, script_dir, debug_script,
93 &ectx->run_ctx);
94 if (ret != 0) {
95 talloc_free(ectx);
96 return ret;
99 ectx->queue = tevent_queue_create(ectx, "run event queue");
100 if (ectx->queue == NULL) {
101 talloc_free(ectx);
102 return ENOMEM;
105 ectx->running = false;
106 ectx->event = CTDB_EVENT_INIT;
108 *result = ectx;
109 return 0;
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)
119 return ectx->queue;
122 static void eventd_start_running(struct eventd_context *ectx,
123 enum ctdb_event event,
124 struct tevent_req *req)
126 ectx->running = true;
127 ectx->event = event;
128 ectx->req = req;
131 static void eventd_stop_running(struct eventd_context *ectx)
133 ectx->running = false;
134 ectx->req = NULL;
137 static struct tevent_req *eventd_cancel_running(struct eventd_context *ectx)
139 struct tevent_req *req = ectx->req;
141 ectx->req = NULL;
142 eventd_stop_running(ectx);
144 return req;
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(
158 TALLOC_CTX *mem_ctx,
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);
164 if (s2 == NULL) {
165 return NULL;
168 s2->num_scripts = s->num_scripts;
169 s2->script = talloc_memdup(s2, s->script,
170 s->num_scripts *
171 sizeof(struct run_event_script));
172 if (s2->script == NULL) {
173 talloc_free(s2);
174 return NULL;
176 s2->summary = s->summary;
178 return s2;
181 static struct ctdb_script_list *script_list_to_ctdb_script_list(
182 TALLOC_CTX *mem_ctx,
183 struct run_event_script_list *s)
185 struct ctdb_script_list *sl;
186 int i;
188 sl = talloc_zero(mem_ctx, struct ctdb_script_list);
189 if (sl == NULL) {
190 return NULL;
193 sl->script = talloc_zero_array(sl, struct ctdb_script, s->num_scripts);
194 if (sl->script == NULL) {
195 talloc_free(sl);
196 return 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);
215 return sl;
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) {
225 return;
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);
232 if (s == NULL) {
233 return;
236 if (s->summary == 0) {
237 TALLOC_FREE(ectx->status_pass[event]);
238 ectx->status_pass[event] = s;
239 } else {
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,
248 TALLOC_CTX *mem_ctx,
249 struct ctdb_script_list **out)
251 struct run_event_script_list *s = NULL;
253 switch (state) {
254 case CTDB_EVENT_LAST_RUN:
255 s = ectx->status_run[event];
256 break;
258 case CTDB_EVENT_LAST_PASS:
259 s = ectx->status_pass[event];
260 break;
262 case CTDB_EVENT_LAST_FAIL:
263 s = ectx->status_fail[event];
264 break;
267 if (s == NULL) {
268 *out = NULL;
269 return 0;
272 *out = script_list_to_ctdb_script_list(mem_ctx, s);
273 return s->summary;
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;
286 uint32_t timeout;
287 const char *arg_str;
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);
309 if (req == NULL) {
310 return NULL;
313 state->ev = ev;
314 state->ectx = ectx;
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);
338 if (running) {
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);
354 pending->req = req;
355 DLIST_ADD(client->pending_list, pending);
357 status = tevent_queue_add(eventd_queue(ectx), ev, req,
358 command_run_trigger, pending);
359 if (! status) {
360 tevent_req_error(req, ENOMEM);
361 return tevent_req_post(req, ev);
364 return req;
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);
378 return;
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),
390 state->arg_str,
391 tevent_timeval_current_ofs(
392 state->timeout, 0));
393 if (tevent_req_nomem(state->subreq, req)) {
394 return;
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;
408 int ret;
409 bool status;
411 eventd_stop_running(state->ectx);
413 status = run_event_recv(subreq, &ret, state, &script_list);
414 TALLOC_FREE(subreq);
415 if (! status) {
416 tevent_req_error(req, ret);
417 return;
420 if (script_list == NULL) {
421 eventd_set_result(state->ectx, state->event, NULL);
422 state->reply->rdata.result = 0;
423 } else {
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,
446 TALLOC_CTX *mem_ctx,
447 struct ctdb_event_reply **reply)
449 struct command_run_state *state = tevent_req_data(
450 req, struct command_run_state);
451 int ret;
453 if (tevent_req_is_unix_error(req, &ret)) {
454 if (perr != NULL) {
455 *perr = ret;
457 return false;
460 if (reply != NULL) {
461 *reply = talloc_steal(mem_ctx, state->reply);
463 return true;
467 * Process STATUS command
470 struct command_status_state {
471 struct ctdb_event_reply *reply;
474 static struct tevent_req *command_status_send(
475 TALLOC_CTX *mem_ctx,
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);
487 if (req == NULL) {
488 return NULL;
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,
516 TALLOC_CTX *mem_ctx,
517 struct ctdb_event_reply **reply)
519 struct command_status_state *state = tevent_req_data(
520 req, struct command_status_state);
521 int ret;
523 if (tevent_req_is_unix_error(req, &ret)) {
524 if (perr != NULL) {
525 *perr = ret;
527 return false;
530 if (reply != NULL) {
531 *reply = talloc_steal(mem_ctx, state->reply);
533 return true;
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(
545 TALLOC_CTX *mem_ctx,
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;
554 int ret;
556 req = tevent_req_create(mem_ctx, &state,
557 struct command_script_list_state);
558 if (req == NULL) {
559 return NULL;
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,
574 &s);
575 if (ret != 0) {
576 tevent_req_error(req, ret);
577 return tevent_req_post(req, ev);
580 state->reply->rdata.command = request->rdata.command;
581 if (s == NULL) {
582 state->reply->rdata.result = 0;
583 state->reply->rdata.data.script_list->script_list = NULL;
584 } else {
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,
595 TALLOC_CTX *mem_ctx,
596 struct ctdb_event_reply **reply)
598 struct command_script_list_state *state = tevent_req_data(
599 req, struct command_script_list_state);
600 int ret;
602 if (tevent_req_is_unix_error(req, &ret)) {
603 if (perr != NULL) {
604 *perr = ret;
606 return false;
609 if (reply != NULL) {
610 *reply = talloc_steal(mem_ctx, state->reply);
612 return true;
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(
624 TALLOC_CTX *mem_ctx,
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;
633 int ret;
635 req = tevent_req_create(mem_ctx, &state,
636 struct command_script_enable_state);
637 if (req == NULL) {
638 return NULL;
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,
658 TALLOC_CTX *mem_ctx,
659 struct ctdb_event_reply **reply)
661 struct command_script_enable_state *state = tevent_req_data(
662 req, struct command_script_enable_state);
663 int ret;
665 if (tevent_req_is_unix_error(req, &ret)) {
666 if (perr != NULL) {
667 *perr = ret;
669 return false;
672 if (reply != NULL) {
673 *reply = talloc_steal(mem_ctx, state->reply);
675 return true;
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(
687 TALLOC_CTX *mem_ctx,
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;
696 int ret;
698 req = tevent_req_create(mem_ctx, &state,
699 struct command_script_disable_state);
700 if (req == NULL) {
701 return NULL;
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,
721 TALLOC_CTX *mem_ctx,
722 struct ctdb_event_reply **reply)
724 struct command_script_disable_state *state = tevent_req_data(
725 req, struct command_script_disable_state);
726 int ret;
728 if (tevent_req_is_unix_error(req, &ret)) {
729 if (perr != NULL) {
730 *perr = ret;
732 return false;
735 if (reply != NULL) {
736 *reply = talloc_steal(mem_ctx, state->reply);
738 return true;
742 * Process clients
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;
751 client != NULL;
752 client = client->next) {
753 if (client->client_ctx == client_ctx) {
754 return client;
758 return NULL;
761 static bool client_connect(struct sock_client_context *client_ctx,
762 void *private_data)
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) {
770 return false;
773 client->client_ctx = client_ctx;
775 DLIST_ADD(ectx->client_list, client);
776 return true;
779 static void client_disconnect(struct sock_client_context *client_ctx,
780 void *private_data)
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) {
789 return;
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(
816 TALLOC_CTX *mem_ctx,
817 struct tevent_context *ev,
818 struct sock_client_context *client_ctx,
819 uint8_t *buf, size_t buflen,
820 void *private_data)
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;
826 int ret;
828 req = tevent_req_create(mem_ctx, &state, struct client_process_state);
829 if (req == NULL) {
830 return NULL;
833 state->ev = ev;
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);
842 if (ret != 0) {
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,
850 &state->request);
851 if (tevent_req_nomem(subreq, req)) {
852 return tevent_req_post(req, ev);
854 tevent_req_set_callback(subreq, client_run_done, req);
855 break;
857 case CTDB_EVENT_COMMAND_STATUS:
858 subreq = command_status_send(state, ev, ectx, state->client,
859 &state->request);
860 if (tevent_req_nomem(subreq, req)) {
861 return tevent_req_post(req, ev);
863 tevent_req_set_callback(subreq, client_status_done, req);
864 break;
866 case CTDB_EVENT_COMMAND_SCRIPT_LIST:
867 subreq = command_script_list_send(state, ev, ectx,
868 state->client,
869 &state->request);
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);
874 break;
876 case CTDB_EVENT_COMMAND_SCRIPT_ENABLE:
877 subreq = command_script_enable_send(state, ev, ectx,
878 state->client,
879 &state->request);
880 if (tevent_req_nomem(subreq, req)) {
881 return tevent_req_post(req, ev);
883 tevent_req_set_callback(subreq, client_script_enable_done,
884 req);
885 break;
887 case CTDB_EVENT_COMMAND_SCRIPT_DISABLE:
888 subreq = command_script_disable_send(state, ev, ectx,
889 state->client,
890 &state->request);
891 if (tevent_req_nomem(subreq, req)) {
892 return tevent_req_post(req, ev);
894 tevent_req_set_callback(subreq, client_script_disable_done,
895 req);
896 break;
899 return req;
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;
909 int ret = 0;
910 bool status;
912 status = command_run_recv(subreq, &ret, state, &reply);
913 TALLOC_FREE(subreq);
914 if (! status) {
915 D_ERR("COMMAND_RUN failed\n");
916 tevent_req_error(req, ret);
917 return;
920 client_process_reply(req, reply);
921 talloc_free(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;
931 int ret = 0;
932 bool status;
934 status = command_status_recv(subreq, &ret, state, &reply);
935 TALLOC_FREE(subreq);
936 if (! status) {
937 D_ERR("COMMAND_STATUS failed\n");
938 tevent_req_error(req, ret);
939 return;
942 client_process_reply(req, reply);
943 talloc_free(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;
953 int ret = 0;
954 bool status;
956 status = command_script_list_recv(subreq, &ret, state, &reply);
957 TALLOC_FREE(subreq);
958 if (! status) {
959 D_ERR("COMMAND_SCRIPT_LIST failed\n");
960 tevent_req_error(req, ret);
961 return;
964 client_process_reply(req, reply);
965 talloc_free(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;
975 int ret = 0;
976 bool status;
978 status = command_script_enable_recv(subreq, &ret, state, &reply);
979 TALLOC_FREE(subreq);
980 if (! status) {
981 D_ERR("COMMAND_SCRIPT_ENABLE failed\n");
982 tevent_req_error(req, ret);
983 return;
986 client_process_reply(req, reply);
987 talloc_free(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;
997 int ret = 0;
998 bool status;
1000 status = command_script_disable_recv(subreq, &ret, state, &reply);
1001 TALLOC_FREE(subreq);
1002 if (! status) {
1003 D_ERR("COMMAND_SCRIPT_DISABLE failed\n");
1004 tevent_req_error(req, ret);
1005 return;
1008 client_process_reply(req, reply);
1009 talloc_free(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;
1018 uint8_t *buf;
1019 size_t buflen;
1020 int ret;
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)) {
1027 return;
1030 ret = ctdb_event_reply_push(reply, buf, &buflen);
1031 if (ret != 0) {
1032 talloc_free(buf);
1033 tevent_req_error(req, ret);
1034 return;
1037 subreq = sock_socket_write_send(state, state->ev,
1038 state->client->client_ctx,
1039 buf, buflen);
1040 if (tevent_req_nomem(subreq, req)) {
1041 return;
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);
1050 int ret;
1051 bool status;
1053 status = sock_socket_write_recv(subreq, &ret);
1054 TALLOC_FREE(subreq);
1055 if (! status) {
1056 D_ERR("Sending reply failed\n");
1057 tevent_req_error(req, ret);
1058 return;
1061 tevent_req_done(req);
1064 static bool client_process_recv(struct tevent_req *req, int *perr)
1066 int ret;
1068 if (tevent_req_is_unix_error(req, &ret)) {
1069 if (perr != NULL) {
1070 *perr = ret;
1072 return false;
1075 return true;
1079 * Event daemon
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);
1094 static struct {
1095 const char *debug_script;
1096 const char *script_dir;
1097 const char *logging;
1098 const char *debug_level;
1099 const char *pidfile;
1100 const char *socket;
1101 int pid;
1102 } options = {
1103 .debug_level = "ERR",
1106 struct poptOption cmdline_options[] = {
1107 POPT_AUTOHELP
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,
1117 "debug level" },
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" },
1122 POPT_TABLEEND
1125 int main(int argc, const char **argv)
1127 poptContext pc;
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;
1135 int opt, ret;
1137 /* Set default options */
1138 options.pid = -1;
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));
1145 exit(1);
1148 if (options.socket == NULL) {
1149 fprintf(stderr, "Please specify eventd socket (--socket)\n");
1150 exit(1);
1153 if (options.script_dir == NULL) {
1154 fprintf(stderr,
1155 "Please specify script dir (--event_script_dir)\n");
1156 exit(1);
1159 if (options.logging == NULL) {
1160 fprintf(stderr,
1161 "Please specify logging (--logging)\n");
1162 exit(1);
1165 ret = stat(options.script_dir, &statbuf);
1166 if (ret != 0) {
1167 ret = errno;
1168 fprintf(stderr, "Error reading script_dir %s, ret=%d\n",
1169 options.script_dir, ret);
1170 exit(1);
1172 if (! S_ISDIR(statbuf.st_mode)) {
1173 fprintf(stderr, "script_dir %s is not a directory\n",
1174 options.script_dir);
1175 exit(1);
1178 mem_ctx = talloc_new(NULL);
1179 if (mem_ctx == NULL) {
1180 exit(1);
1183 ev = tevent_context_init(mem_ctx);
1184 if (ev == NULL) {
1185 ret = 1;
1186 goto fail;
1189 ret = eventd_context_init(mem_ctx, ev, options.script_dir,
1190 options.debug_script, &ectx);
1191 if (ret != 0) {
1192 goto fail;
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);
1202 if (ret != 0) {
1203 goto fail;
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);
1214 if (ret != 0) {
1215 goto fail;
1218 ret = sock_daemon_run(ev, sockd, options.pid);
1219 if (ret == EINTR) {
1220 ret = 0;
1223 fail:
1224 talloc_free(mem_ctx);
1225 (void)poptFreeContext(pc);
1226 exit(ret);