ctdb-common: Add config file parsing code
[Samba.git] / ctdb / server / ctdb_eventd.c
blobfeeac074890837e47debf760ccd9260721399b8c
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"
38 #include "protocol/protocol_util.h"
40 #include "common/comm.h"
41 #include "common/logging.h"
42 #include "common/run_event.h"
43 #include "common/sock_daemon.h"
45 struct eventd_client {
46 struct eventd_client *prev, *next;
48 struct sock_client_context *client_ctx;
49 struct pending_event *pending_list;
52 struct eventd_context {
53 struct run_event_context *run_ctx;
55 /* result of last execution */
56 struct run_event_script_list *status_run[CTDB_EVENT_MAX];
57 struct run_event_script_list *status_pass[CTDB_EVENT_MAX];
58 struct run_event_script_list *status_fail[CTDB_EVENT_MAX];
60 struct eventd_client *client_list;
64 * Global state manipulation functions
67 static int eventd_context_init(TALLOC_CTX *mem_ctx,
68 struct tevent_context *ev,
69 const char *script_dir,
70 const char *debug_script,
71 struct eventd_context **result)
73 struct eventd_context *ectx;
74 int ret;
76 ectx = talloc_zero(mem_ctx, struct eventd_context);
77 if (ectx == NULL) {
78 return ENOMEM;
81 ret = run_event_init(ectx, ev, script_dir, debug_script,
82 &ectx->run_ctx);
83 if (ret != 0) {
84 talloc_free(ectx);
85 return ret;
88 *result = ectx;
89 return 0;
92 static struct run_event_context *eventd_run_context(struct eventd_context *ectx)
94 return ectx->run_ctx;
97 static struct run_event_script_list *script_list_copy(
98 TALLOC_CTX *mem_ctx,
99 struct run_event_script_list *s)
101 struct run_event_script_list *s2;
103 s2 = talloc_zero(mem_ctx, struct run_event_script_list);
104 if (s2 == NULL) {
105 return NULL;
108 s2->num_scripts = s->num_scripts;
109 s2->script = talloc_memdup(s2, s->script,
110 s->num_scripts *
111 sizeof(struct run_event_script));
112 if (s2->script == NULL) {
113 talloc_free(s2);
114 return NULL;
116 s2->summary = s->summary;
118 return s2;
121 static struct ctdb_script_list *script_list_to_ctdb_script_list(
122 TALLOC_CTX *mem_ctx,
123 struct run_event_script_list *s)
125 struct ctdb_script_list *sl;
126 int i;
128 sl = talloc_zero(mem_ctx, struct ctdb_script_list);
129 if (sl == NULL) {
130 return NULL;
133 sl->script = talloc_zero_array(sl, struct ctdb_script, s->num_scripts);
134 if (sl->script == NULL) {
135 talloc_free(sl);
136 return NULL;
139 sl->num_scripts = s->num_scripts;
141 for (i=0; i<s->num_scripts; i++) {
142 struct run_event_script *escript = &s->script[i];
143 struct ctdb_script *script = &sl->script[i];
145 strlcpy(script->name, escript->name, MAX_SCRIPT_NAME+1);
146 script->start = escript->begin;
147 script->finished = escript->end;
148 script->status = escript->summary;
149 if (escript->output != NULL) {
150 strlcpy(script->output, escript->output,
151 MAX_SCRIPT_OUTPUT+1);
155 return sl;
158 static void eventd_set_result(struct eventd_context *ectx,
159 enum ctdb_event event,
160 struct run_event_script_list *script_list)
162 struct run_event_script_list *s;
164 if (script_list == NULL) {
165 return;
168 /* Do not update status if event was cancelled */
169 if (script_list->summary == -ECANCELED) {
170 return;
173 TALLOC_FREE(ectx->status_run[event]);
174 ectx->status_run[event] = talloc_steal(ectx, script_list);
176 s = script_list_copy(ectx, script_list);
177 if (s == NULL) {
178 return;
181 if (s->summary == 0) {
182 TALLOC_FREE(ectx->status_pass[event]);
183 ectx->status_pass[event] = s;
184 } else {
185 TALLOC_FREE(ectx->status_fail[event]);
186 ectx->status_fail[event] = s;
190 static int eventd_get_result(struct eventd_context *ectx,
191 enum ctdb_event event,
192 enum ctdb_event_status_state state,
193 TALLOC_CTX *mem_ctx,
194 struct ctdb_script_list **out)
196 struct run_event_script_list *s = NULL;
198 switch (state) {
199 case CTDB_EVENT_LAST_RUN:
200 s = ectx->status_run[event];
201 break;
203 case CTDB_EVENT_LAST_PASS:
204 s = ectx->status_pass[event];
205 break;
207 case CTDB_EVENT_LAST_FAIL:
208 s = ectx->status_fail[event];
209 break;
212 if (s == NULL) {
213 *out = NULL;
214 return 0;
217 *out = script_list_to_ctdb_script_list(mem_ctx, s);
218 return s->summary;
222 * Process RUN command
225 struct command_run_state {
226 struct eventd_context *ectx;
228 enum ctdb_event event;
229 struct ctdb_event_reply *reply;
232 static void command_run_done(struct tevent_req *subreq);
234 static struct tevent_req *command_run_send(TALLOC_CTX *mem_ctx,
235 struct tevent_context *ev,
236 struct eventd_context *ectx,
237 struct eventd_client *client,
238 struct ctdb_event_request *request)
240 struct tevent_req *req, *subreq;
241 struct command_run_state *state;
242 uint32_t timeout;
244 req = tevent_req_create(mem_ctx, &state, struct command_run_state);
245 if (req == NULL) {
246 return NULL;
249 state->ectx = ectx;
250 state->event = request->rdata.data.run->event;
252 state->reply = talloc_zero(state, struct ctdb_event_reply);
253 if (tevent_req_nomem(state->reply, req)) {
254 return tevent_req_post(req, ev);
257 state->reply->rdata.command = request->rdata.command;
259 timeout = request->rdata.data.run->timeout;
260 subreq = run_event_send(state, ev,
261 eventd_run_context(state->ectx),
262 ctdb_event_to_string(state->event),
263 request->rdata.data.run->arg_str,
264 tevent_timeval_current_ofs(timeout, 0));
265 if (tevent_req_nomem(subreq, req)) {
266 return tevent_req_post(req, ev);
268 tevent_req_set_callback(subreq, command_run_done, req);
270 return req;
273 static void command_run_done(struct tevent_req *subreq)
275 struct tevent_req *req = tevent_req_callback_data(
276 subreq, struct tevent_req);
277 struct command_run_state *state = tevent_req_data(
278 req, struct command_run_state);
279 struct run_event_script_list *script_list;
280 int ret;
281 bool status;
283 status = run_event_recv(subreq, &ret, state, &script_list);
284 TALLOC_FREE(subreq);
285 if (! status) {
286 tevent_req_error(req, ret);
287 return;
290 if (script_list == NULL) {
291 eventd_set_result(state->ectx, state->event, NULL);
292 state->reply->rdata.result = 0;
293 } else {
294 eventd_set_result(state->ectx, state->event, script_list);
295 state->reply->rdata.result = script_list->summary;
298 tevent_req_done(req);
301 static bool command_run_recv(struct tevent_req *req, int *perr,
302 TALLOC_CTX *mem_ctx,
303 struct ctdb_event_reply **reply)
305 struct command_run_state *state = tevent_req_data(
306 req, struct command_run_state);
307 int ret;
309 if (tevent_req_is_unix_error(req, &ret)) {
310 if (perr != NULL) {
311 *perr = ret;
313 return false;
316 if (reply != NULL) {
317 *reply = talloc_steal(mem_ctx, state->reply);
319 return true;
323 * Process STATUS command
326 struct command_status_state {
327 struct ctdb_event_reply *reply;
330 static struct tevent_req *command_status_send(
331 TALLOC_CTX *mem_ctx,
332 struct tevent_context *ev,
333 struct eventd_context *ectx,
334 struct eventd_client *client,
335 struct ctdb_event_request *request)
337 struct tevent_req *req;
338 struct command_status_state *state;
339 enum ctdb_event event;
340 enum ctdb_event_status_state estate;
342 req = tevent_req_create(mem_ctx, &state, struct command_status_state);
343 if (req == NULL) {
344 return NULL;
347 event = request->rdata.data.status->event;
348 estate = request->rdata.data.status->state;
350 state->reply = talloc_zero(state, struct ctdb_event_reply);
351 if (tevent_req_nomem(state->reply, req)) {
352 return tevent_req_post(req, ev);
355 state->reply->rdata.data.status =
356 talloc(state->reply, struct ctdb_event_reply_status);
357 if (tevent_req_nomem(state->reply->rdata.data.status, req)) {
358 return tevent_req_post(req, ev);
361 state->reply->rdata.command = request->rdata.command;
362 state->reply->rdata.result = 0;
363 state->reply->rdata.data.status->status =
364 eventd_get_result(ectx, event, estate, state->reply,
365 &state->reply->rdata.data.status->script_list);
367 tevent_req_done(req);
368 return tevent_req_post(req, ev);
371 static bool command_status_recv(struct tevent_req *req, int *perr,
372 TALLOC_CTX *mem_ctx,
373 struct ctdb_event_reply **reply)
375 struct command_status_state *state = tevent_req_data(
376 req, struct command_status_state);
377 int ret;
379 if (tevent_req_is_unix_error(req, &ret)) {
380 if (perr != NULL) {
381 *perr = ret;
383 return false;
386 if (reply != NULL) {
387 *reply = talloc_steal(mem_ctx, state->reply);
389 return true;
393 * Process SCRIPT_LIST command
396 struct command_script_list_state {
397 struct ctdb_event_reply *reply;
400 static struct tevent_req *command_script_list_send(
401 TALLOC_CTX *mem_ctx,
402 struct tevent_context *ev,
403 struct eventd_context *ectx,
404 struct eventd_client *client,
405 struct ctdb_event_request *request)
407 struct tevent_req *req;
408 struct command_script_list_state *state;
409 struct run_event_script_list *s;
410 int ret;
412 req = tevent_req_create(mem_ctx, &state,
413 struct command_script_list_state);
414 if (req == NULL) {
415 return NULL;
418 state->reply = talloc_zero(state, struct ctdb_event_reply);
419 if (tevent_req_nomem(state->reply, req)) {
420 return tevent_req_post(req, ev);
423 state->reply->rdata.data.script_list =
424 talloc(state->reply, struct ctdb_event_reply_script_list);
425 if (tevent_req_nomem(state->reply->rdata.data.script_list, req)) {
426 return tevent_req_post(req, ev);
429 ret = run_event_script_list(eventd_run_context(ectx), state->reply,
430 &s);
431 if (ret != 0) {
432 tevent_req_error(req, ret);
433 return tevent_req_post(req, ev);
436 state->reply->rdata.command = request->rdata.command;
437 if (s == NULL) {
438 state->reply->rdata.result = 0;
439 state->reply->rdata.data.script_list->script_list = NULL;
440 } else {
441 state->reply->rdata.result = s->summary;
442 state->reply->rdata.data.script_list->script_list =
443 script_list_to_ctdb_script_list(state->reply, s);
446 tevent_req_done(req);
447 return tevent_req_post(req, ev);
450 static bool command_script_list_recv(struct tevent_req *req, int *perr,
451 TALLOC_CTX *mem_ctx,
452 struct ctdb_event_reply **reply)
454 struct command_script_list_state *state = tevent_req_data(
455 req, struct command_script_list_state);
456 int ret;
458 if (tevent_req_is_unix_error(req, &ret)) {
459 if (perr != NULL) {
460 *perr = ret;
462 return false;
465 if (reply != NULL) {
466 *reply = talloc_steal(mem_ctx, state->reply);
468 return true;
472 * Process SCRIPT_ENABLE command
475 struct command_script_enable_state {
476 struct ctdb_event_reply *reply;
479 static struct tevent_req *command_script_enable_send(
480 TALLOC_CTX *mem_ctx,
481 struct tevent_context *ev,
482 struct eventd_context *ectx,
483 struct eventd_client *client,
484 struct ctdb_event_request *request)
486 struct tevent_req *req;
487 struct command_script_enable_state *state;
488 const char *script_name;
489 int ret;
491 req = tevent_req_create(mem_ctx, &state,
492 struct command_script_enable_state);
493 if (req == NULL) {
494 return NULL;
497 script_name = request->rdata.data.script_enable->script_name;
499 state->reply = talloc_zero(state, struct ctdb_event_reply);
500 if (tevent_req_nomem(state->reply, req)) {
501 return tevent_req_post(req, ev);
504 state->reply->rdata.command = request->rdata.command;
506 ret = run_event_script_enable(eventd_run_context(ectx), script_name);
507 state->reply->rdata.result = -ret;
509 tevent_req_done(req);
510 return tevent_req_post(req, ev);
513 static bool command_script_enable_recv(struct tevent_req *req, int *perr,
514 TALLOC_CTX *mem_ctx,
515 struct ctdb_event_reply **reply)
517 struct command_script_enable_state *state = tevent_req_data(
518 req, struct command_script_enable_state);
519 int ret;
521 if (tevent_req_is_unix_error(req, &ret)) {
522 if (perr != NULL) {
523 *perr = ret;
525 return false;
528 if (reply != NULL) {
529 *reply = talloc_steal(mem_ctx, state->reply);
531 return true;
535 * Process SCRIPT_DISABLE command
538 struct command_script_disable_state {
539 struct ctdb_event_reply *reply;
542 static struct tevent_req *command_script_disable_send(
543 TALLOC_CTX *mem_ctx,
544 struct tevent_context *ev,
545 struct eventd_context *ectx,
546 struct eventd_client *client,
547 struct ctdb_event_request *request)
549 struct tevent_req *req;
550 struct command_script_disable_state *state;
551 const char *script_name;
552 int ret;
554 req = tevent_req_create(mem_ctx, &state,
555 struct command_script_disable_state);
556 if (req == NULL) {
557 return NULL;
560 script_name = request->rdata.data.script_disable->script_name;
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.command = request->rdata.command;
569 ret = run_event_script_disable(eventd_run_context(ectx), script_name);
570 state->reply->rdata.result = -ret;
572 tevent_req_done(req);
573 return tevent_req_post(req, ev);
576 static bool command_script_disable_recv(struct tevent_req *req, int *perr,
577 TALLOC_CTX *mem_ctx,
578 struct ctdb_event_reply **reply)
580 struct command_script_disable_state *state = tevent_req_data(
581 req, struct command_script_disable_state);
582 int ret;
584 if (tevent_req_is_unix_error(req, &ret)) {
585 if (perr != NULL) {
586 *perr = ret;
588 return false;
591 if (reply != NULL) {
592 *reply = talloc_steal(mem_ctx, state->reply);
594 return true;
598 * Process clients
601 static struct eventd_client *client_find(struct eventd_context *ectx,
602 struct sock_client_context *client_ctx)
604 struct eventd_client *client;
606 for (client = ectx->client_list;
607 client != NULL;
608 client = client->next) {
609 if (client->client_ctx == client_ctx) {
610 return client;
614 return NULL;
617 static bool client_connect(struct sock_client_context *client_ctx,
618 void *private_data)
620 struct eventd_context *ectx = talloc_get_type_abort(
621 private_data, struct eventd_context);
622 struct eventd_client *client;
624 client = talloc_zero(ectx, struct eventd_client);
625 if (client == NULL) {
626 return false;
629 client->client_ctx = client_ctx;
631 DLIST_ADD(ectx->client_list, client);
632 return true;
635 static void client_disconnect(struct sock_client_context *client_ctx,
636 void *private_data)
638 struct eventd_context *ectx = talloc_get_type_abort(
639 private_data, struct eventd_context);
640 struct eventd_client *client;
642 client = client_find(ectx, client_ctx);
643 if (client == NULL) {
644 return;
647 DLIST_REMOVE(ectx->client_list, client);
648 talloc_free(client);
651 struct client_process_state {
652 struct tevent_context *ev;
654 struct eventd_client *client;
655 struct ctdb_event_request request;
658 static void client_run_done(struct tevent_req *subreq);
659 static void client_status_done(struct tevent_req *subreq);
660 static void client_script_list_done(struct tevent_req *subreq);
661 static void client_script_enable_done(struct tevent_req *subreq);
662 static void client_script_disable_done(struct tevent_req *subreq);
663 static void client_process_reply(struct tevent_req *req,
664 struct ctdb_event_reply *reply);
665 static void client_process_reply_done(struct tevent_req *subreq);
667 static struct tevent_req *client_process_send(
668 TALLOC_CTX *mem_ctx,
669 struct tevent_context *ev,
670 struct sock_client_context *client_ctx,
671 uint8_t *buf, size_t buflen,
672 void *private_data)
674 struct eventd_context *ectx = talloc_get_type_abort(
675 private_data, struct eventd_context);
676 struct tevent_req *req, *subreq;
677 struct client_process_state *state;
678 int ret;
680 req = tevent_req_create(mem_ctx, &state, struct client_process_state);
681 if (req == NULL) {
682 return NULL;
685 state->ev = ev;
687 state->client = client_find(ectx, client_ctx);
688 if (state->client == NULL) {
689 tevent_req_error(req, EIO);
690 return tevent_req_post(req, ev);
693 ret = ctdb_event_request_pull(buf, buflen, state, &state->request);
694 if (ret != 0) {
695 tevent_req_error(req, EPROTO);
696 return tevent_req_post(req, ev);
699 switch (state->request.rdata.command) {
700 case CTDB_EVENT_COMMAND_RUN:
701 subreq = command_run_send(state, ev, ectx, state->client,
702 &state->request);
703 if (tevent_req_nomem(subreq, req)) {
704 return tevent_req_post(req, ev);
706 tevent_req_set_callback(subreq, client_run_done, req);
707 break;
709 case CTDB_EVENT_COMMAND_STATUS:
710 subreq = command_status_send(state, ev, ectx, state->client,
711 &state->request);
712 if (tevent_req_nomem(subreq, req)) {
713 return tevent_req_post(req, ev);
715 tevent_req_set_callback(subreq, client_status_done, req);
716 break;
718 case CTDB_EVENT_COMMAND_SCRIPT_LIST:
719 subreq = command_script_list_send(state, ev, ectx,
720 state->client,
721 &state->request);
722 if (tevent_req_nomem(subreq, req)) {
723 return tevent_req_post(req, ev);
725 tevent_req_set_callback(subreq, client_script_list_done, req);
726 break;
728 case CTDB_EVENT_COMMAND_SCRIPT_ENABLE:
729 subreq = command_script_enable_send(state, ev, ectx,
730 state->client,
731 &state->request);
732 if (tevent_req_nomem(subreq, req)) {
733 return tevent_req_post(req, ev);
735 tevent_req_set_callback(subreq, client_script_enable_done,
736 req);
737 break;
739 case CTDB_EVENT_COMMAND_SCRIPT_DISABLE:
740 subreq = command_script_disable_send(state, ev, ectx,
741 state->client,
742 &state->request);
743 if (tevent_req_nomem(subreq, req)) {
744 return tevent_req_post(req, ev);
746 tevent_req_set_callback(subreq, client_script_disable_done,
747 req);
748 break;
751 return req;
754 static void client_run_done(struct tevent_req *subreq)
756 struct tevent_req *req = tevent_req_callback_data(
757 subreq, struct tevent_req);
758 struct client_process_state *state = tevent_req_data(
759 req, struct client_process_state);
760 struct ctdb_event_reply *reply = NULL;
761 int ret = 0;
762 bool status;
764 status = command_run_recv(subreq, &ret, state, &reply);
765 TALLOC_FREE(subreq);
766 if (! status) {
767 D_ERR("COMMAND_RUN failed\n");
768 tevent_req_error(req, ret);
769 return;
772 client_process_reply(req, reply);
773 talloc_free(reply);
776 static void client_status_done(struct tevent_req *subreq)
778 struct tevent_req *req = tevent_req_callback_data(
779 subreq, struct tevent_req);
780 struct client_process_state *state = tevent_req_data(
781 req, struct client_process_state);
782 struct ctdb_event_reply *reply = NULL;
783 int ret = 0;
784 bool status;
786 status = command_status_recv(subreq, &ret, state, &reply);
787 TALLOC_FREE(subreq);
788 if (! status) {
789 D_ERR("COMMAND_STATUS failed\n");
790 tevent_req_error(req, ret);
791 return;
794 client_process_reply(req, reply);
795 talloc_free(reply);
798 static void client_script_list_done(struct tevent_req *subreq)
800 struct tevent_req *req = tevent_req_callback_data(
801 subreq, struct tevent_req);
802 struct client_process_state *state = tevent_req_data(
803 req, struct client_process_state);
804 struct ctdb_event_reply *reply = NULL;
805 int ret = 0;
806 bool status;
808 status = command_script_list_recv(subreq, &ret, state, &reply);
809 TALLOC_FREE(subreq);
810 if (! status) {
811 D_ERR("COMMAND_SCRIPT_LIST failed\n");
812 tevent_req_error(req, ret);
813 return;
816 client_process_reply(req, reply);
817 talloc_free(reply);
820 static void client_script_enable_done(struct tevent_req *subreq)
822 struct tevent_req *req = tevent_req_callback_data(
823 subreq, struct tevent_req);
824 struct client_process_state *state = tevent_req_data(
825 req, struct client_process_state);
826 struct ctdb_event_reply *reply = NULL;
827 int ret = 0;
828 bool status;
830 status = command_script_enable_recv(subreq, &ret, state, &reply);
831 TALLOC_FREE(subreq);
832 if (! status) {
833 D_ERR("COMMAND_SCRIPT_ENABLE failed\n");
834 tevent_req_error(req, ret);
835 return;
838 client_process_reply(req, reply);
839 talloc_free(reply);
842 static void client_script_disable_done(struct tevent_req *subreq)
844 struct tevent_req *req = tevent_req_callback_data(
845 subreq, struct tevent_req);
846 struct client_process_state *state = tevent_req_data(
847 req, struct client_process_state);
848 struct ctdb_event_reply *reply = NULL;
849 int ret = 0;
850 bool status;
852 status = command_script_disable_recv(subreq, &ret, state, &reply);
853 TALLOC_FREE(subreq);
854 if (! status) {
855 D_ERR("COMMAND_SCRIPT_DISABLE failed\n");
856 tevent_req_error(req, ret);
857 return;
860 client_process_reply(req, reply);
861 talloc_free(reply);
864 static void client_process_reply(struct tevent_req *req,
865 struct ctdb_event_reply *reply)
867 struct client_process_state *state = tevent_req_data(
868 req, struct client_process_state);
869 struct tevent_req *subreq;
870 uint8_t *buf;
871 size_t buflen;
872 int ret;
874 sock_packet_header_set_reqid(&reply->header,
875 state->request.header.reqid);
877 buflen = ctdb_event_reply_len(reply);
878 buf = talloc_zero_size(state, buflen);
879 if (tevent_req_nomem(buf, req)) {
880 return;
883 ret = ctdb_event_reply_push(reply, buf, &buflen);
884 if (ret != 0) {
885 talloc_free(buf);
886 tevent_req_error(req, ret);
887 return;
890 subreq = sock_socket_write_send(state, state->ev,
891 state->client->client_ctx,
892 buf, buflen);
893 if (tevent_req_nomem(subreq, req)) {
894 return;
896 tevent_req_set_callback(subreq, client_process_reply_done, req);
899 static void client_process_reply_done(struct tevent_req *subreq)
901 struct tevent_req *req = tevent_req_callback_data(
902 subreq, struct tevent_req);
903 int ret;
904 bool status;
906 status = sock_socket_write_recv(subreq, &ret);
907 TALLOC_FREE(subreq);
908 if (! status) {
909 D_ERR("Sending reply failed\n");
910 tevent_req_error(req, ret);
911 return;
914 tevent_req_done(req);
917 static bool client_process_recv(struct tevent_req *req, int *perr)
919 int ret;
921 if (tevent_req_is_unix_error(req, &ret)) {
922 if (perr != NULL) {
923 *perr = ret;
925 return false;
928 return true;
932 * Event daemon
935 static void eventd_shutdown(void *private_data)
937 struct eventd_context *ectx = talloc_get_type_abort(
938 private_data, struct eventd_context);
939 struct eventd_client *client;
941 while ((client = ectx->client_list) != NULL) {
942 DLIST_REMOVE(ectx->client_list, client);
943 talloc_free(client);
947 static struct {
948 const char *debug_script;
949 const char *script_dir;
950 const char *logging;
951 const char *debug_level;
952 const char *pidfile;
953 const char *socket;
954 int pid;
955 } options = {
956 .debug_level = "ERR",
959 struct poptOption cmdline_options[] = {
960 POPT_AUTOHELP
961 { "debug_script", 'D', POPT_ARG_STRING, &options.debug_script, 0,
962 "debug script", "FILE" },
963 { "pid", 'P', POPT_ARG_INT, &options.pid, 0,
964 "pid to wait for", "PID" },
965 { "event_script_dir", 'e', POPT_ARG_STRING, &options.script_dir, 0,
966 "event script dir", "DIRECTORY" },
967 { "logging", 'l', POPT_ARG_STRING, &options.logging, 0,
968 "logging specification" },
969 { "debug", 'd', POPT_ARG_STRING, &options.debug_level, 0,
970 "debug level" },
971 { "pidfile", 'p', POPT_ARG_STRING, &options.pidfile, 0,
972 "eventd pid file", "FILE" },
973 { "socket", 's', POPT_ARG_STRING, &options.socket, 0,
974 "eventd socket path", "FILE" },
975 POPT_TABLEEND
978 int main(int argc, const char **argv)
980 poptContext pc;
981 TALLOC_CTX *mem_ctx;
982 struct tevent_context *ev;
983 struct eventd_context *ectx;
984 struct sock_daemon_context *sockd;
985 struct sock_daemon_funcs daemon_funcs;
986 struct sock_socket_funcs socket_funcs;
987 struct stat statbuf;
988 int opt, ret;
990 /* Set default options */
991 options.pid = -1;
993 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
994 POPT_CONTEXT_KEEP_FIRST);
995 while ((opt = poptGetNextOpt(pc)) != -1) {
996 fprintf(stderr, "Invalid options %s: %s\n",
997 poptBadOption(pc, 0), poptStrerror(opt));
998 exit(1);
1001 if (options.socket == NULL) {
1002 fprintf(stderr, "Please specify eventd socket (--socket)\n");
1003 exit(1);
1006 if (options.script_dir == NULL) {
1007 fprintf(stderr,
1008 "Please specify script dir (--event_script_dir)\n");
1009 exit(1);
1012 if (options.logging == NULL) {
1013 fprintf(stderr,
1014 "Please specify logging (--logging)\n");
1015 exit(1);
1018 ret = stat(options.script_dir, &statbuf);
1019 if (ret != 0) {
1020 ret = errno;
1021 fprintf(stderr, "Error reading script_dir %s, ret=%d\n",
1022 options.script_dir, ret);
1023 exit(1);
1025 if (! S_ISDIR(statbuf.st_mode)) {
1026 fprintf(stderr, "script_dir %s is not a directory\n",
1027 options.script_dir);
1028 exit(1);
1031 mem_ctx = talloc_new(NULL);
1032 if (mem_ctx == NULL) {
1033 exit(1);
1036 ev = tevent_context_init(mem_ctx);
1037 if (ev == NULL) {
1038 ret = 1;
1039 goto fail;
1042 ret = eventd_context_init(mem_ctx, ev, options.script_dir,
1043 options.debug_script, &ectx);
1044 if (ret != 0) {
1045 goto fail;
1048 daemon_funcs = (struct sock_daemon_funcs) {
1049 .shutdown = eventd_shutdown,
1052 ret = sock_daemon_setup(mem_ctx, "ctdb-eventd", options.logging,
1053 options.debug_level,
1054 &daemon_funcs, ectx, &sockd);
1055 if (ret != 0) {
1056 goto fail;
1059 socket_funcs = (struct sock_socket_funcs) {
1060 .connect = client_connect,
1061 .disconnect = client_disconnect,
1062 .read_send = client_process_send,
1063 .read_recv = client_process_recv,
1066 ret = sock_daemon_add_unix(sockd, options.socket, &socket_funcs, ectx);
1067 if (ret != 0) {
1068 goto fail;
1071 ret = sock_daemon_run(ev, sockd,
1072 options.pidfile, false, false, options.pid);
1073 if (ret == EINTR) {
1074 ret = 0;
1077 fail:
1078 talloc_free(mem_ctx);
1079 (void)poptFreeContext(pc);
1080 exit(ret);