ctdb-common: Add support to run events through failure
[kai/samba-autobuild/.git] / ctdb / server / ctdb_eventd.c
1 /*
2    Event script running daemon
3
4    Copyright (C) Amitay Isaacs  2016
5
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.
10
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.
15
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/>.
18 */
19
20 #include "replace.h"
21 #include "system/filesys.h"
22 #include "system/dir.h"
23 #include "system/wait.h"
24 #include "system/locale.h"
25
26 #include <popt.h>
27 #include <talloc.h>
28 #include <tevent.h>
29
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"
36
37 #include "protocol/protocol_api.h"
38 #include "protocol/protocol_util.h"
39
40 #include "common/comm.h"
41 #include "common/logging.h"
42 #include "common/run_event.h"
43 #include "common/sock_daemon.h"
44
45 struct eventd_client {
46         struct eventd_client *prev, *next;
47
48         struct sock_client_context *client_ctx;
49         struct pending_event *pending_list;
50 };
51
52 struct eventd_context {
53         struct run_proc_context *run_proc_ctx;
54         struct run_event_context *run_ctx;
55
56         /* result of last execution */
57         struct run_event_script_list *status_run[CTDB_EVENT_MAX];
58         struct run_event_script_list *status_pass[CTDB_EVENT_MAX];
59         struct run_event_script_list *status_fail[CTDB_EVENT_MAX];
60
61         struct eventd_client *client_list;
62 };
63
64 /*
65  * Global state manipulation functions
66  */
67
68 static int eventd_context_init(TALLOC_CTX *mem_ctx,
69                                struct tevent_context *ev,
70                                const char *script_dir,
71                                const char *debug_script,
72                                struct eventd_context **result)
73 {
74         struct eventd_context *ectx;
75         int ret;
76
77         ectx = talloc_zero(mem_ctx, struct eventd_context);
78         if (ectx == NULL) {
79                 return ENOMEM;
80         }
81
82         ret = run_proc_init(ectx, ev, &ectx->run_proc_ctx);
83         if (ret != 0) {
84                 talloc_free(ectx);
85                 return ret;
86         }
87
88         ret = run_event_init(ectx,
89                              ectx->run_proc_ctx,
90                              script_dir,
91                              debug_script,
92                              &ectx->run_ctx);
93         if (ret != 0) {
94                 talloc_free(ectx);
95                 return ret;
96         }
97
98         *result = ectx;
99         return 0;
100 }
101
102 static struct run_event_context *eventd_run_context(struct eventd_context *ectx)
103 {
104         return ectx->run_ctx;
105 }
106
107 static struct run_event_script_list *script_list_copy(
108                                         TALLOC_CTX *mem_ctx,
109                                         struct run_event_script_list *s)
110 {
111         struct run_event_script_list *s2;
112
113         s2 = talloc_zero(mem_ctx, struct run_event_script_list);
114         if (s2 == NULL) {
115                 return NULL;
116         }
117
118         s2->num_scripts = s->num_scripts;
119         s2->script = talloc_memdup(s2, s->script,
120                                    s->num_scripts *
121                                    sizeof(struct run_event_script));
122         if (s2->script == NULL) {
123                 talloc_free(s2);
124                 return NULL;
125         }
126         s2->summary = s->summary;
127
128         return s2;
129 }
130
131 static struct ctdb_script_list *script_list_to_ctdb_script_list(
132                                         TALLOC_CTX *mem_ctx,
133                                         struct run_event_script_list *s)
134 {
135         struct ctdb_script_list *sl;
136         int i;
137
138         sl = talloc_zero(mem_ctx, struct ctdb_script_list);
139         if (sl == NULL) {
140                 return NULL;
141         }
142
143         sl->script = talloc_zero_array(sl, struct ctdb_script, s->num_scripts);
144         if (sl->script == NULL) {
145                 talloc_free(sl);
146                 return NULL;
147         }
148
149         sl->num_scripts = s->num_scripts;
150
151         for (i=0; i<s->num_scripts; i++) {
152                 struct run_event_script *escript = &s->script[i];
153                 struct ctdb_script *script = &sl->script[i];
154
155                 strlcpy(script->name, escript->name, MAX_SCRIPT_NAME+1);
156                 script->start = escript->begin;
157                 script->finished = escript->end;
158                 script->status = escript->summary;
159                 if (escript->output != NULL) {
160                         strlcpy(script->output, escript->output,
161                                 MAX_SCRIPT_OUTPUT+1);
162                 }
163         }
164
165         return sl;
166 }
167
168 static void eventd_set_result(struct eventd_context *ectx,
169                               enum ctdb_event event,
170                               struct run_event_script_list *script_list)
171 {
172         struct run_event_script_list *s;
173
174         if (script_list == NULL) {
175                 return;
176         }
177
178         /* Do not update status if event was cancelled */
179         if (script_list->summary == -ECANCELED) {
180                 return;
181         }
182
183         TALLOC_FREE(ectx->status_run[event]);
184         ectx->status_run[event] = talloc_steal(ectx, script_list);
185
186         s = script_list_copy(ectx, script_list);
187         if (s == NULL) {
188                 return;
189         }
190
191         if (s->summary == 0) {
192                 TALLOC_FREE(ectx->status_pass[event]);
193                 ectx->status_pass[event] = s;
194         } else {
195                 TALLOC_FREE(ectx->status_fail[event]);
196                 ectx->status_fail[event] = s;
197         }
198 }
199
200 static int eventd_get_result(struct eventd_context *ectx,
201                              enum ctdb_event event,
202                              enum ctdb_event_status_state state,
203                              TALLOC_CTX *mem_ctx,
204                              struct ctdb_script_list **out)
205 {
206         struct run_event_script_list *s = NULL;
207
208         switch (state) {
209                 case CTDB_EVENT_LAST_RUN:
210                         s = ectx->status_run[event];
211                         break;
212
213                 case CTDB_EVENT_LAST_PASS:
214                         s = ectx->status_pass[event];
215                         break;
216
217                 case CTDB_EVENT_LAST_FAIL:
218                         s = ectx->status_fail[event];
219                         break;
220         }
221
222         if (s == NULL) {
223                 *out = NULL;
224                 return 0;
225         }
226
227         *out = script_list_to_ctdb_script_list(mem_ctx, s);
228         return s->summary;
229 }
230
231 /*
232  * Process RUN command
233  */
234
235 struct command_run_state {
236         struct eventd_context *ectx;
237
238         enum ctdb_event event;
239         struct ctdb_event_reply *reply;
240 };
241
242 static void command_run_done(struct tevent_req *subreq);
243
244 static struct tevent_req *command_run_send(TALLOC_CTX *mem_ctx,
245                                            struct tevent_context *ev,
246                                            struct eventd_context *ectx,
247                                            struct eventd_client *client,
248                                            struct ctdb_event_request *request)
249 {
250         struct tevent_req *req, *subreq;
251         struct command_run_state *state;
252         uint32_t timeout;
253
254         req = tevent_req_create(mem_ctx, &state, struct command_run_state);
255         if (req == NULL) {
256                 return NULL;
257         }
258
259         state->ectx = ectx;
260         state->event = request->rdata.data.run->event;
261
262         state->reply = talloc_zero(state, struct ctdb_event_reply);
263         if (tevent_req_nomem(state->reply, req)) {
264                 return tevent_req_post(req, ev);
265         }
266
267         state->reply->rdata.command = request->rdata.command;
268
269         timeout = request->rdata.data.run->timeout;
270         subreq = run_event_send(state, ev,
271                                 eventd_run_context(state->ectx),
272                                 ctdb_event_to_string(state->event),
273                                 request->rdata.data.run->arg_str,
274                                 tevent_timeval_current_ofs(timeout, 0),
275                                 false);
276         if (tevent_req_nomem(subreq, req)) {
277                 return tevent_req_post(req, ev);
278         }
279         tevent_req_set_callback(subreq, command_run_done, req);
280
281         return req;
282 }
283
284 static void command_run_done(struct tevent_req *subreq)
285 {
286         struct tevent_req *req = tevent_req_callback_data(
287                 subreq, struct tevent_req);
288         struct command_run_state *state = tevent_req_data(
289                 req, struct command_run_state);
290         struct run_event_script_list *script_list;
291         int ret;
292         bool status;
293
294         status = run_event_recv(subreq, &ret, state, &script_list);
295         TALLOC_FREE(subreq);
296         if (! status) {
297                 tevent_req_error(req, ret);
298                 return;
299         }
300
301         if (script_list == NULL) {
302                 eventd_set_result(state->ectx, state->event, NULL);
303                 state->reply->rdata.result = 0;
304         } else {
305                 eventd_set_result(state->ectx, state->event, script_list);
306                 state->reply->rdata.result = script_list->summary;
307         }
308
309         tevent_req_done(req);
310 }
311
312 static bool command_run_recv(struct tevent_req *req, int *perr,
313                              TALLOC_CTX *mem_ctx,
314                              struct ctdb_event_reply **reply)
315 {
316         struct command_run_state *state = tevent_req_data(
317                 req, struct command_run_state);
318         int ret;
319
320         if (tevent_req_is_unix_error(req, &ret)) {
321                 if (perr != NULL) {
322                         *perr = ret;
323                 }
324                 return false;
325         }
326
327         if (reply != NULL) {
328                 *reply = talloc_steal(mem_ctx, state->reply);
329         }
330         return true;
331 }
332
333 /*
334  * Process STATUS command
335  */
336
337 struct command_status_state {
338         struct ctdb_event_reply *reply;
339 };
340
341 static struct tevent_req *command_status_send(
342                                         TALLOC_CTX *mem_ctx,
343                                         struct tevent_context *ev,
344                                         struct eventd_context *ectx,
345                                         struct eventd_client *client,
346                                         struct ctdb_event_request *request)
347 {
348         struct tevent_req *req;
349         struct command_status_state *state;
350         enum ctdb_event event;
351         enum ctdb_event_status_state estate;
352
353         req = tevent_req_create(mem_ctx, &state, struct command_status_state);
354         if (req == NULL) {
355                 return NULL;
356         }
357
358         event = request->rdata.data.status->event;
359         estate = request->rdata.data.status->state;
360
361         state->reply = talloc_zero(state, struct ctdb_event_reply);
362         if (tevent_req_nomem(state->reply, req)) {
363                 return tevent_req_post(req, ev);
364         }
365
366         state->reply->rdata.data.status =
367                 talloc(state->reply, struct ctdb_event_reply_status);
368         if (tevent_req_nomem(state->reply->rdata.data.status, req)) {
369                 return tevent_req_post(req, ev);
370         }
371
372         state->reply->rdata.command = request->rdata.command;
373         state->reply->rdata.result = 0;
374         state->reply->rdata.data.status->status =
375                 eventd_get_result(ectx, event, estate, state->reply,
376                                 &state->reply->rdata.data.status->script_list);
377
378         tevent_req_done(req);
379         return tevent_req_post(req, ev);
380 }
381
382 static bool command_status_recv(struct tevent_req *req, int *perr,
383                                 TALLOC_CTX *mem_ctx,
384                                 struct ctdb_event_reply **reply)
385 {
386         struct command_status_state *state = tevent_req_data(
387                 req, struct command_status_state);
388         int ret;
389
390         if (tevent_req_is_unix_error(req, &ret)) {
391                 if (perr != NULL) {
392                         *perr = ret;
393                 }
394                 return false;
395         }
396
397         if (reply != NULL) {
398                 *reply = talloc_steal(mem_ctx, state->reply);
399         }
400         return true;
401 }
402
403 /*
404  * Process SCRIPT_LIST command
405  */
406
407 struct command_script_list_state {
408         struct ctdb_event_reply *reply;
409 };
410
411 static struct tevent_req *command_script_list_send(
412                                         TALLOC_CTX *mem_ctx,
413                                         struct tevent_context *ev,
414                                         struct eventd_context *ectx,
415                                         struct eventd_client *client,
416                                         struct ctdb_event_request *request)
417 {
418         struct tevent_req *req;
419         struct command_script_list_state *state;
420         struct run_event_script_list *s;
421         int ret;
422
423         req = tevent_req_create(mem_ctx, &state,
424                                 struct command_script_list_state);
425         if (req == NULL) {
426                 return NULL;
427         }
428
429         state->reply = talloc_zero(state, struct ctdb_event_reply);
430         if (tevent_req_nomem(state->reply, req)) {
431                 return tevent_req_post(req, ev);
432         }
433
434         state->reply->rdata.data.script_list =
435                 talloc(state->reply, struct ctdb_event_reply_script_list);
436         if (tevent_req_nomem(state->reply->rdata.data.script_list, req)) {
437                 return tevent_req_post(req, ev);
438         }
439
440         ret = run_event_list(eventd_run_context(ectx), state->reply, &s);
441         if (ret != 0) {
442                 tevent_req_error(req, ret);
443                 return tevent_req_post(req, ev);
444         }
445
446         state->reply->rdata.command = request->rdata.command;
447         if (s == NULL) {
448                 state->reply->rdata.result = 0;
449                 state->reply->rdata.data.script_list->script_list = NULL;
450         } else {
451                 state->reply->rdata.result = s->summary;
452                 state->reply->rdata.data.script_list->script_list =
453                         script_list_to_ctdb_script_list(state->reply, s);
454         }
455
456         tevent_req_done(req);
457         return tevent_req_post(req, ev);
458 }
459
460 static bool command_script_list_recv(struct tevent_req *req, int *perr,
461                                      TALLOC_CTX *mem_ctx,
462                                      struct ctdb_event_reply **reply)
463 {
464         struct command_script_list_state *state = tevent_req_data(
465                 req, struct command_script_list_state);
466         int ret;
467
468         if (tevent_req_is_unix_error(req, &ret)) {
469                 if (perr != NULL) {
470                         *perr = ret;
471                 }
472                 return false;
473         }
474
475         if (reply != NULL) {
476                 *reply = talloc_steal(mem_ctx, state->reply);
477         }
478         return true;
479 }
480
481 /*
482  * Process SCRIPT_ENABLE command
483  */
484
485 struct command_script_enable_state {
486         struct ctdb_event_reply *reply;
487 };
488
489 static struct tevent_req *command_script_enable_send(
490                                         TALLOC_CTX *mem_ctx,
491                                         struct tevent_context *ev,
492                                         struct eventd_context *ectx,
493                                         struct eventd_client *client,
494                                         struct ctdb_event_request *request)
495 {
496         struct tevent_req *req;
497         struct command_script_enable_state *state;
498         const char *script_name;
499         int ret;
500
501         req = tevent_req_create(mem_ctx, &state,
502                                 struct command_script_enable_state);
503         if (req == NULL) {
504                 return NULL;
505         }
506
507         script_name = request->rdata.data.script_enable->script_name;
508
509         state->reply = talloc_zero(state, struct ctdb_event_reply);
510         if (tevent_req_nomem(state->reply, req)) {
511                 return tevent_req_post(req, ev);
512         }
513
514         state->reply->rdata.command = request->rdata.command;
515
516         ret = run_event_script_enable(eventd_run_context(ectx), script_name);
517         state->reply->rdata.result = -ret;
518
519         tevent_req_done(req);
520         return tevent_req_post(req, ev);
521 }
522
523 static bool command_script_enable_recv(struct tevent_req *req, int *perr,
524                                        TALLOC_CTX *mem_ctx,
525                                        struct ctdb_event_reply **reply)
526 {
527         struct command_script_enable_state *state = tevent_req_data(
528                 req, struct command_script_enable_state);
529         int ret;
530
531         if (tevent_req_is_unix_error(req, &ret)) {
532                 if (perr != NULL) {
533                         *perr = ret;
534                 }
535                 return false;
536         }
537
538         if (reply != NULL) {
539                 *reply = talloc_steal(mem_ctx, state->reply);
540         }
541         return true;
542 }
543
544 /*
545  * Process SCRIPT_DISABLE command
546  */
547
548 struct command_script_disable_state {
549         struct ctdb_event_reply *reply;
550 };
551
552 static struct tevent_req *command_script_disable_send(
553                                         TALLOC_CTX *mem_ctx,
554                                         struct tevent_context *ev,
555                                         struct eventd_context *ectx,
556                                         struct eventd_client *client,
557                                         struct ctdb_event_request *request)
558 {
559         struct tevent_req *req;
560         struct command_script_disable_state *state;
561         const char *script_name;
562         int ret;
563
564         req = tevent_req_create(mem_ctx, &state,
565                                 struct command_script_disable_state);
566         if (req == NULL) {
567                 return NULL;
568         }
569
570         script_name = request->rdata.data.script_disable->script_name;
571
572         state->reply = talloc_zero(state, struct ctdb_event_reply);
573         if (tevent_req_nomem(state->reply, req)) {
574                 return tevent_req_post(req, ev);
575         }
576
577         state->reply->rdata.command = request->rdata.command;
578
579         ret = run_event_script_disable(eventd_run_context(ectx), script_name);
580         state->reply->rdata.result = -ret;
581
582         tevent_req_done(req);
583         return tevent_req_post(req, ev);
584 }
585
586 static bool command_script_disable_recv(struct tevent_req *req, int *perr,
587                                         TALLOC_CTX *mem_ctx,
588                                         struct ctdb_event_reply **reply)
589 {
590         struct command_script_disable_state *state = tevent_req_data(
591                 req, struct command_script_disable_state);
592         int ret;
593
594         if (tevent_req_is_unix_error(req, &ret)) {
595                 if (perr != NULL) {
596                         *perr = ret;
597                 }
598                 return false;
599         }
600
601         if (reply != NULL) {
602                 *reply = talloc_steal(mem_ctx, state->reply);
603         }
604         return true;
605 }
606
607 /*
608  * Process clients
609  */
610
611 static struct eventd_client *client_find(struct eventd_context *ectx,
612                                          struct sock_client_context *client_ctx)
613 {
614         struct eventd_client *client;
615
616         for (client = ectx->client_list;
617              client != NULL;
618              client = client->next) {
619                 if (client->client_ctx == client_ctx) {
620                         return client;
621                 }
622         }
623
624         return NULL;
625 }
626
627 static bool client_connect(struct sock_client_context *client_ctx,
628                            void *private_data)
629 {
630         struct eventd_context *ectx = talloc_get_type_abort(
631                 private_data, struct eventd_context);
632         struct eventd_client *client;
633
634         client = talloc_zero(ectx, struct eventd_client);
635         if (client == NULL) {
636                 return false;
637         }
638
639         client->client_ctx = client_ctx;
640
641         DLIST_ADD(ectx->client_list, client);
642         return true;
643 }
644
645 static void client_disconnect(struct sock_client_context *client_ctx,
646                               void *private_data)
647 {
648         struct eventd_context *ectx = talloc_get_type_abort(
649                 private_data, struct eventd_context);
650         struct eventd_client *client;
651
652         client = client_find(ectx, client_ctx);
653         if (client == NULL) {
654                 return;
655         }
656
657         DLIST_REMOVE(ectx->client_list, client);
658         talloc_free(client);
659 }
660
661 struct client_process_state {
662         struct tevent_context *ev;
663
664         struct eventd_client *client;
665         struct ctdb_event_request request;
666 };
667
668 static void client_run_done(struct tevent_req *subreq);
669 static void client_status_done(struct tevent_req *subreq);
670 static void client_script_list_done(struct tevent_req *subreq);
671 static void client_script_enable_done(struct tevent_req *subreq);
672 static void client_script_disable_done(struct tevent_req *subreq);
673 static void client_process_reply(struct tevent_req *req,
674                                  struct ctdb_event_reply *reply);
675 static void client_process_reply_done(struct tevent_req *subreq);
676
677 static struct tevent_req *client_process_send(
678                                 TALLOC_CTX *mem_ctx,
679                                 struct tevent_context *ev,
680                                 struct sock_client_context *client_ctx,
681                                 uint8_t *buf, size_t buflen,
682                                 void *private_data)
683 {
684         struct eventd_context *ectx = talloc_get_type_abort(
685                 private_data, struct eventd_context);
686         struct tevent_req *req, *subreq;
687         struct client_process_state *state;
688         int ret;
689
690         req = tevent_req_create(mem_ctx, &state, struct client_process_state);
691         if (req == NULL) {
692                 return NULL;
693         }
694
695         state->ev = ev;
696
697         state->client = client_find(ectx, client_ctx);
698         if (state->client == NULL) {
699                 tevent_req_error(req, EIO);
700                 return tevent_req_post(req, ev);
701         }
702
703         ret = ctdb_event_request_pull(buf, buflen, state, &state->request);
704         if (ret != 0) {
705                 tevent_req_error(req, EPROTO);
706                 return tevent_req_post(req, ev);
707         }
708
709         switch (state->request.rdata.command) {
710         case CTDB_EVENT_COMMAND_RUN:
711                 subreq = command_run_send(state, ev, ectx, state->client,
712                                           &state->request);
713                 if (tevent_req_nomem(subreq, req)) {
714                         return tevent_req_post(req, ev);
715                 }
716                 tevent_req_set_callback(subreq, client_run_done, req);
717                 break;
718
719         case CTDB_EVENT_COMMAND_STATUS:
720                 subreq = command_status_send(state, ev, ectx, state->client,
721                                              &state->request);
722                 if (tevent_req_nomem(subreq, req)) {
723                         return tevent_req_post(req, ev);
724                 }
725                 tevent_req_set_callback(subreq, client_status_done, req);
726                 break;
727
728         case CTDB_EVENT_COMMAND_SCRIPT_LIST:
729                 subreq = command_script_list_send(state, ev, ectx,
730                                                   state->client,
731                                                   &state->request);
732                 if (tevent_req_nomem(subreq, req)) {
733                         return tevent_req_post(req, ev);
734                 }
735                 tevent_req_set_callback(subreq, client_script_list_done, req);
736                 break;
737
738         case CTDB_EVENT_COMMAND_SCRIPT_ENABLE:
739                 subreq = command_script_enable_send(state, ev, ectx,
740                                                     state->client,
741                                                     &state->request);
742                 if (tevent_req_nomem(subreq, req)) {
743                         return tevent_req_post(req, ev);
744                 }
745                 tevent_req_set_callback(subreq, client_script_enable_done,
746                                         req);
747                 break;
748
749         case CTDB_EVENT_COMMAND_SCRIPT_DISABLE:
750                 subreq = command_script_disable_send(state, ev, ectx,
751                                                      state->client,
752                                                      &state->request);
753                 if (tevent_req_nomem(subreq, req)) {
754                         return tevent_req_post(req, ev);
755                 }
756                 tevent_req_set_callback(subreq, client_script_disable_done,
757                                         req);
758                 break;
759         }
760
761         return req;
762 }
763
764 static void client_run_done(struct tevent_req *subreq)
765 {
766         struct tevent_req *req = tevent_req_callback_data(
767                 subreq, struct tevent_req);
768         struct client_process_state *state = tevent_req_data(
769                 req, struct client_process_state);
770         struct ctdb_event_reply *reply = NULL;
771         int ret = 0;
772         bool status;
773
774         status = command_run_recv(subreq, &ret, state, &reply);
775         TALLOC_FREE(subreq);
776         if (! status) {
777                 D_ERR("COMMAND_RUN failed\n");
778                 tevent_req_error(req, ret);
779                 return;
780         }
781
782         client_process_reply(req, reply);
783         talloc_free(reply);
784 }
785
786 static void client_status_done(struct tevent_req *subreq)
787 {
788         struct tevent_req *req = tevent_req_callback_data(
789                 subreq, struct tevent_req);
790         struct client_process_state *state = tevent_req_data(
791                 req, struct client_process_state);
792         struct ctdb_event_reply *reply = NULL;
793         int ret = 0;
794         bool status;
795
796         status = command_status_recv(subreq, &ret, state, &reply);
797         TALLOC_FREE(subreq);
798         if (! status) {
799                 D_ERR("COMMAND_STATUS failed\n");
800                 tevent_req_error(req, ret);
801                 return;
802         }
803
804         client_process_reply(req, reply);
805         talloc_free(reply);
806 }
807
808 static void client_script_list_done(struct tevent_req *subreq)
809 {
810         struct tevent_req *req = tevent_req_callback_data(
811                 subreq, struct tevent_req);
812         struct client_process_state *state = tevent_req_data(
813                 req, struct client_process_state);
814         struct ctdb_event_reply *reply = NULL;
815         int ret = 0;
816         bool status;
817
818         status = command_script_list_recv(subreq, &ret, state, &reply);
819         TALLOC_FREE(subreq);
820         if (! status) {
821                 D_ERR("COMMAND_SCRIPT_LIST failed\n");
822                 tevent_req_error(req, ret);
823                 return;
824         }
825
826         client_process_reply(req, reply);
827         talloc_free(reply);
828 }
829
830 static void client_script_enable_done(struct tevent_req *subreq)
831 {
832         struct tevent_req *req = tevent_req_callback_data(
833                 subreq, struct tevent_req);
834         struct client_process_state *state = tevent_req_data(
835                 req, struct client_process_state);
836         struct ctdb_event_reply *reply = NULL;
837         int ret = 0;
838         bool status;
839
840         status = command_script_enable_recv(subreq, &ret, state, &reply);
841         TALLOC_FREE(subreq);
842         if (! status) {
843                 D_ERR("COMMAND_SCRIPT_ENABLE failed\n");
844                 tevent_req_error(req, ret);
845                 return;
846         }
847
848         client_process_reply(req, reply);
849         talloc_free(reply);
850 }
851
852 static void client_script_disable_done(struct tevent_req *subreq)
853 {
854         struct tevent_req *req = tevent_req_callback_data(
855                 subreq, struct tevent_req);
856         struct client_process_state *state = tevent_req_data(
857                 req, struct client_process_state);
858         struct ctdb_event_reply *reply = NULL;
859         int ret = 0;
860         bool status;
861
862         status = command_script_disable_recv(subreq, &ret, state, &reply);
863         TALLOC_FREE(subreq);
864         if (! status) {
865                 D_ERR("COMMAND_SCRIPT_DISABLE failed\n");
866                 tevent_req_error(req, ret);
867                 return;
868         }
869
870         client_process_reply(req, reply);
871         talloc_free(reply);
872 }
873
874 static void client_process_reply(struct tevent_req *req,
875                                  struct ctdb_event_reply *reply)
876 {
877         struct client_process_state *state = tevent_req_data(
878                 req, struct client_process_state);
879         struct tevent_req *subreq;
880         uint8_t *buf;
881         size_t buflen;
882         int ret;
883
884         sock_packet_header_set_reqid(&reply->header,
885                                      state->request.header.reqid);
886
887         buflen = ctdb_event_reply_len(reply);
888         buf = talloc_zero_size(state, buflen);
889         if (tevent_req_nomem(buf, req)) {
890                 return;
891         }
892
893         ret = ctdb_event_reply_push(reply, buf, &buflen);
894         if (ret != 0) {
895                 talloc_free(buf);
896                 tevent_req_error(req, ret);
897                 return;
898         }
899
900         subreq = sock_socket_write_send(state, state->ev,
901                                         state->client->client_ctx,
902                                         buf, buflen);
903         if (tevent_req_nomem(subreq, req)) {
904                 return;
905         }
906         tevent_req_set_callback(subreq, client_process_reply_done, req);
907 }
908
909 static void client_process_reply_done(struct tevent_req *subreq)
910 {
911         struct tevent_req *req = tevent_req_callback_data(
912                 subreq, struct tevent_req);
913         int ret;
914         bool status;
915
916         status = sock_socket_write_recv(subreq, &ret);
917         TALLOC_FREE(subreq);
918         if (! status) {
919                 D_ERR("Sending reply failed\n");
920                 tevent_req_error(req, ret);
921                 return;
922         }
923
924         tevent_req_done(req);
925 }
926
927 static bool client_process_recv(struct tevent_req *req, int *perr)
928 {
929         int ret;
930
931         if (tevent_req_is_unix_error(req, &ret)) {
932                 if (perr != NULL) {
933                         *perr = ret;
934                 }
935                 return false;
936         }
937
938         return true;
939 }
940
941 /*
942  * Event daemon
943  */
944
945 static void eventd_shutdown(void *private_data)
946 {
947         struct eventd_context *ectx = talloc_get_type_abort(
948                 private_data, struct eventd_context);
949         struct eventd_client *client;
950
951         while ((client = ectx->client_list) != NULL) {
952                 DLIST_REMOVE(ectx->client_list, client);
953                 talloc_free(client);
954         }
955 }
956
957 static struct {
958         const char *debug_script;
959         const char *script_dir;
960         const char *logging;
961         const char *debug_level;
962         const char *pidfile;
963         const char *socket;
964         int pid;
965 } options = {
966         .debug_level = "ERR",
967 };
968
969 struct poptOption cmdline_options[] = {
970         POPT_AUTOHELP
971         { "debug_script", 'D', POPT_ARG_STRING, &options.debug_script, 0,
972                 "debug script", "FILE" },
973         { "pid", 'P', POPT_ARG_INT, &options.pid, 0,
974                 "pid to wait for", "PID" },
975         { "event_script_dir", 'e', POPT_ARG_STRING, &options.script_dir, 0,
976                 "event script dir", "DIRECTORY" },
977         { "logging", 'l', POPT_ARG_STRING, &options.logging, 0,
978                 "logging specification" },
979         { "debug", 'd', POPT_ARG_STRING, &options.debug_level, 0,
980                 "debug level" },
981         { "pidfile", 'p', POPT_ARG_STRING, &options.pidfile, 0,
982                 "eventd pid file", "FILE" },
983         { "socket", 's', POPT_ARG_STRING, &options.socket, 0,
984                 "eventd socket path", "FILE" },
985         POPT_TABLEEND
986 };
987
988 int main(int argc, const char **argv)
989 {
990         poptContext pc;
991         TALLOC_CTX *mem_ctx;
992         struct tevent_context *ev;
993         struct eventd_context *ectx;
994         struct sock_daemon_context *sockd;
995         struct sock_daemon_funcs daemon_funcs;
996         struct sock_socket_funcs socket_funcs;
997         struct stat statbuf;
998         int opt, ret;
999
1000         /* Set default options */
1001         options.pid = -1;
1002
1003         pc = poptGetContext(argv[0], argc, argv, cmdline_options,
1004                             POPT_CONTEXT_KEEP_FIRST);
1005         while ((opt = poptGetNextOpt(pc)) != -1) {
1006                 fprintf(stderr, "Invalid options %s: %s\n",
1007                         poptBadOption(pc, 0), poptStrerror(opt));
1008                 exit(1);
1009         }
1010
1011         if (options.socket == NULL) {
1012                 fprintf(stderr, "Please specify eventd socket (--socket)\n");
1013                 exit(1);
1014         }
1015
1016         if (options.script_dir == NULL) {
1017                 fprintf(stderr,
1018                         "Please specify script dir (--event_script_dir)\n");
1019                 exit(1);
1020         }
1021
1022         if (options.logging == NULL) {
1023                 fprintf(stderr,
1024                         "Please specify logging (--logging)\n");
1025                 exit(1);
1026         }
1027
1028         ret = stat(options.script_dir, &statbuf);
1029         if (ret != 0) {
1030                 ret = errno;
1031                 fprintf(stderr, "Error reading script_dir %s, ret=%d\n",
1032                         options.script_dir, ret);
1033                 exit(1);
1034         }
1035         if (! S_ISDIR(statbuf.st_mode)) {
1036                 fprintf(stderr, "script_dir %s is not a directory\n",
1037                         options.script_dir);
1038                 exit(1);
1039         }
1040
1041         mem_ctx = talloc_new(NULL);
1042         if (mem_ctx == NULL) {
1043                 exit(1);
1044         }
1045
1046         ev = tevent_context_init(mem_ctx);
1047         if (ev == NULL) {
1048                 ret = 1;
1049                 goto fail;
1050         }
1051
1052         ret = eventd_context_init(mem_ctx, ev, options.script_dir,
1053                                   options.debug_script, &ectx);
1054         if (ret != 0) {
1055                 goto fail;
1056         }
1057
1058         daemon_funcs = (struct sock_daemon_funcs) {
1059                 .shutdown = eventd_shutdown,
1060         };
1061
1062         ret = sock_daemon_setup(mem_ctx, "ctdb-eventd", options.logging,
1063                                 options.debug_level,
1064                                 &daemon_funcs, ectx, &sockd);
1065         if (ret != 0) {
1066                 goto fail;
1067         }
1068
1069         socket_funcs = (struct sock_socket_funcs) {
1070                 .connect = client_connect,
1071                 .disconnect = client_disconnect,
1072                 .read_send = client_process_send,
1073                 .read_recv = client_process_recv,
1074         };
1075
1076         ret = sock_daemon_add_unix(sockd, options.socket, &socket_funcs, ectx);
1077         if (ret != 0) {
1078                 goto fail;
1079         }
1080
1081         ret = sock_daemon_run(ev, sockd,
1082                               options.pidfile, false, false, options.pid);
1083         if (ret == EINTR) {
1084                 ret = 0;
1085         }
1086
1087 fail:
1088         talloc_free(mem_ctx);
1089         (void)poptFreeContext(pc);
1090         exit(ret);
1091 }