ctdb-daemon: Move ctdb_init() to the only place it is used
[vlendec/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_event_context *run_ctx;
54
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];
59
60         struct eventd_client *client_list;
61 };
62
63 /*
64  * Global state manipulation functions
65  */
66
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)
72 {
73         struct eventd_context *ectx;
74         int ret;
75
76         ectx = talloc_zero(mem_ctx, struct eventd_context);
77         if (ectx == NULL) {
78                 return ENOMEM;
79         }
80
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;
86         }
87
88         *result = ectx;
89         return 0;
90 }
91
92 static struct run_event_context *eventd_run_context(struct eventd_context *ectx)
93 {
94         return ectx->run_ctx;
95 }
96
97 static struct run_event_script_list *script_list_copy(
98                                         TALLOC_CTX *mem_ctx,
99                                         struct run_event_script_list *s)
100 {
101         struct run_event_script_list *s2;
102
103         s2 = talloc_zero(mem_ctx, struct run_event_script_list);
104         if (s2 == NULL) {
105                 return NULL;
106         }
107
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;
115         }
116         s2->summary = s->summary;
117
118         return s2;
119 }
120
121 static struct ctdb_script_list *script_list_to_ctdb_script_list(
122                                         TALLOC_CTX *mem_ctx,
123                                         struct run_event_script_list *s)
124 {
125         struct ctdb_script_list *sl;
126         int i;
127
128         sl = talloc_zero(mem_ctx, struct ctdb_script_list);
129         if (sl == NULL) {
130                 return NULL;
131         }
132
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;
137         }
138
139         sl->num_scripts = s->num_scripts;
140
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];
144
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);
152                 }
153         }
154
155         return sl;
156 }
157
158 static void eventd_set_result(struct eventd_context *ectx,
159                               enum ctdb_event event,
160                               struct run_event_script_list *script_list)
161 {
162         struct run_event_script_list *s;
163
164         if (script_list == NULL) {
165                 return;
166         }
167
168         /* Do not update status if event was cancelled */
169         if (script_list->summary == -ECANCELED) {
170                 return;
171         }
172
173         TALLOC_FREE(ectx->status_run[event]);
174         ectx->status_run[event] = talloc_steal(ectx, script_list);
175
176         s = script_list_copy(ectx, script_list);
177         if (s == NULL) {
178                 return;
179         }
180
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;
187         }
188 }
189
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)
195 {
196         struct run_event_script_list *s = NULL;
197
198         switch (state) {
199                 case CTDB_EVENT_LAST_RUN:
200                         s = ectx->status_run[event];
201                         break;
202
203                 case CTDB_EVENT_LAST_PASS:
204                         s = ectx->status_pass[event];
205                         break;
206
207                 case CTDB_EVENT_LAST_FAIL:
208                         s = ectx->status_fail[event];
209                         break;
210         }
211
212         if (s == NULL) {
213                 *out = NULL;
214                 return 0;
215         }
216
217         *out = script_list_to_ctdb_script_list(mem_ctx, s);
218         return s->summary;
219 }
220
221 /*
222  * Process RUN command
223  */
224
225 struct command_run_state {
226         struct eventd_context *ectx;
227
228         enum ctdb_event event;
229         struct ctdb_event_reply *reply;
230 };
231
232 static void command_run_done(struct tevent_req *subreq);
233
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)
239 {
240         struct tevent_req *req, *subreq;
241         struct command_run_state *state;
242         uint32_t timeout;
243
244         req = tevent_req_create(mem_ctx, &state, struct command_run_state);
245         if (req == NULL) {
246                 return NULL;
247         }
248
249         state->ectx = ectx;
250         state->event = request->rdata.data.run->event;
251
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);
255         }
256
257         state->reply->rdata.command = request->rdata.command;
258
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);
267         }
268         tevent_req_set_callback(subreq, command_run_done, req);
269
270         return req;
271 }
272
273 static void command_run_done(struct tevent_req *subreq)
274 {
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;
282
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;
288         }
289
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;
296         }
297
298         tevent_req_done(req);
299 }
300
301 static bool command_run_recv(struct tevent_req *req, int *perr,
302                              TALLOC_CTX *mem_ctx,
303                              struct ctdb_event_reply **reply)
304 {
305         struct command_run_state *state = tevent_req_data(
306                 req, struct command_run_state);
307         int ret;
308
309         if (tevent_req_is_unix_error(req, &ret)) {
310                 if (perr != NULL) {
311                         *perr = ret;
312                 }
313                 return false;
314         }
315
316         if (reply != NULL) {
317                 *reply = talloc_steal(mem_ctx, state->reply);
318         }
319         return true;
320 }
321
322 /*
323  * Process STATUS command
324  */
325
326 struct command_status_state {
327         struct ctdb_event_reply *reply;
328 };
329
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)
336 {
337         struct tevent_req *req;
338         struct command_status_state *state;
339         enum ctdb_event event;
340         enum ctdb_event_status_state estate;
341
342         req = tevent_req_create(mem_ctx, &state, struct command_status_state);
343         if (req == NULL) {
344                 return NULL;
345         }
346
347         event = request->rdata.data.status->event;
348         estate = request->rdata.data.status->state;
349
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);
353         }
354
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);
359         }
360
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);
366
367         tevent_req_done(req);
368         return tevent_req_post(req, ev);
369 }
370
371 static bool command_status_recv(struct tevent_req *req, int *perr,
372                                 TALLOC_CTX *mem_ctx,
373                                 struct ctdb_event_reply **reply)
374 {
375         struct command_status_state *state = tevent_req_data(
376                 req, struct command_status_state);
377         int ret;
378
379         if (tevent_req_is_unix_error(req, &ret)) {
380                 if (perr != NULL) {
381                         *perr = ret;
382                 }
383                 return false;
384         }
385
386         if (reply != NULL) {
387                 *reply = talloc_steal(mem_ctx, state->reply);
388         }
389         return true;
390 }
391
392 /*
393  * Process SCRIPT_LIST command
394  */
395
396 struct command_script_list_state {
397         struct ctdb_event_reply *reply;
398 };
399
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)
406 {
407         struct tevent_req *req;
408         struct command_script_list_state *state;
409         struct run_event_script_list *s;
410         int ret;
411
412         req = tevent_req_create(mem_ctx, &state,
413                                 struct command_script_list_state);
414         if (req == NULL) {
415                 return NULL;
416         }
417
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);
421         }
422
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);
427         }
428
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);
434         }
435
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);
444         }
445
446         tevent_req_done(req);
447         return tevent_req_post(req, ev);
448 }
449
450 static bool command_script_list_recv(struct tevent_req *req, int *perr,
451                                      TALLOC_CTX *mem_ctx,
452                                      struct ctdb_event_reply **reply)
453 {
454         struct command_script_list_state *state = tevent_req_data(
455                 req, struct command_script_list_state);
456         int ret;
457
458         if (tevent_req_is_unix_error(req, &ret)) {
459                 if (perr != NULL) {
460                         *perr = ret;
461                 }
462                 return false;
463         }
464
465         if (reply != NULL) {
466                 *reply = talloc_steal(mem_ctx, state->reply);
467         }
468         return true;
469 }
470
471 /*
472  * Process SCRIPT_ENABLE command
473  */
474
475 struct command_script_enable_state {
476         struct ctdb_event_reply *reply;
477 };
478
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)
485 {
486         struct tevent_req *req;
487         struct command_script_enable_state *state;
488         const char *script_name;
489         int ret;
490
491         req = tevent_req_create(mem_ctx, &state,
492                                 struct command_script_enable_state);
493         if (req == NULL) {
494                 return NULL;
495         }
496
497         script_name = request->rdata.data.script_enable->script_name;
498
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);
502         }
503
504         state->reply->rdata.command = request->rdata.command;
505
506         ret = run_event_script_enable(eventd_run_context(ectx), script_name);
507         state->reply->rdata.result = -ret;
508
509         tevent_req_done(req);
510         return tevent_req_post(req, ev);
511 }
512
513 static bool command_script_enable_recv(struct tevent_req *req, int *perr,
514                                        TALLOC_CTX *mem_ctx,
515                                        struct ctdb_event_reply **reply)
516 {
517         struct command_script_enable_state *state = tevent_req_data(
518                 req, struct command_script_enable_state);
519         int ret;
520
521         if (tevent_req_is_unix_error(req, &ret)) {
522                 if (perr != NULL) {
523                         *perr = ret;
524                 }
525                 return false;
526         }
527
528         if (reply != NULL) {
529                 *reply = talloc_steal(mem_ctx, state->reply);
530         }
531         return true;
532 }
533
534 /*
535  * Process SCRIPT_DISABLE command
536  */
537
538 struct command_script_disable_state {
539         struct ctdb_event_reply *reply;
540 };
541
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)
548 {
549         struct tevent_req *req;
550         struct command_script_disable_state *state;
551         const char *script_name;
552         int ret;
553
554         req = tevent_req_create(mem_ctx, &state,
555                                 struct command_script_disable_state);
556         if (req == NULL) {
557                 return NULL;
558         }
559
560         script_name = request->rdata.data.script_disable->script_name;
561
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);
565         }
566
567         state->reply->rdata.command = request->rdata.command;
568
569         ret = run_event_script_disable(eventd_run_context(ectx), script_name);
570         state->reply->rdata.result = -ret;
571
572         tevent_req_done(req);
573         return tevent_req_post(req, ev);
574 }
575
576 static bool command_script_disable_recv(struct tevent_req *req, int *perr,
577                                         TALLOC_CTX *mem_ctx,
578                                         struct ctdb_event_reply **reply)
579 {
580         struct command_script_disable_state *state = tevent_req_data(
581                 req, struct command_script_disable_state);
582         int ret;
583
584         if (tevent_req_is_unix_error(req, &ret)) {
585                 if (perr != NULL) {
586                         *perr = ret;
587                 }
588                 return false;
589         }
590
591         if (reply != NULL) {
592                 *reply = talloc_steal(mem_ctx, state->reply);
593         }
594         return true;
595 }
596
597 /*
598  * Process clients
599  */
600
601 static struct eventd_client *client_find(struct eventd_context *ectx,
602                                          struct sock_client_context *client_ctx)
603 {
604         struct eventd_client *client;
605
606         for (client = ectx->client_list;
607              client != NULL;
608              client = client->next) {
609                 if (client->client_ctx == client_ctx) {
610                         return client;
611                 }
612         }
613
614         return NULL;
615 }
616
617 static bool client_connect(struct sock_client_context *client_ctx,
618                            void *private_data)
619 {
620         struct eventd_context *ectx = talloc_get_type_abort(
621                 private_data, struct eventd_context);
622         struct eventd_client *client;
623
624         client = talloc_zero(ectx, struct eventd_client);
625         if (client == NULL) {
626                 return false;
627         }
628
629         client->client_ctx = client_ctx;
630
631         DLIST_ADD(ectx->client_list, client);
632         return true;
633 }
634
635 static void client_disconnect(struct sock_client_context *client_ctx,
636                               void *private_data)
637 {
638         struct eventd_context *ectx = talloc_get_type_abort(
639                 private_data, struct eventd_context);
640         struct eventd_client *client;
641
642         client = client_find(ectx, client_ctx);
643         if (client == NULL) {
644                 return;
645         }
646
647         DLIST_REMOVE(ectx->client_list, client);
648         talloc_free(client);
649 }
650
651 struct client_process_state {
652         struct tevent_context *ev;
653
654         struct eventd_client *client;
655         struct ctdb_event_request request;
656 };
657
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);
666
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)
673 {
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;
679
680         req = tevent_req_create(mem_ctx, &state, struct client_process_state);
681         if (req == NULL) {
682                 return NULL;
683         }
684
685         state->ev = ev;
686
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);
691         }
692
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);
697         }
698
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);
705                 }
706                 tevent_req_set_callback(subreq, client_run_done, req);
707                 break;
708
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);
714                 }
715                 tevent_req_set_callback(subreq, client_status_done, req);
716                 break;
717
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);
724                 }
725                 tevent_req_set_callback(subreq, client_script_list_done, req);
726                 break;
727
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);
734                 }
735                 tevent_req_set_callback(subreq, client_script_enable_done,
736                                         req);
737                 break;
738
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);
745                 }
746                 tevent_req_set_callback(subreq, client_script_disable_done,
747                                         req);
748                 break;
749         }
750
751         return req;
752 }
753
754 static void client_run_done(struct tevent_req *subreq)
755 {
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;
763
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;
770         }
771
772         client_process_reply(req, reply);
773         talloc_free(reply);
774 }
775
776 static void client_status_done(struct tevent_req *subreq)
777 {
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;
785
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;
792         }
793
794         client_process_reply(req, reply);
795         talloc_free(reply);
796 }
797
798 static void client_script_list_done(struct tevent_req *subreq)
799 {
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;
807
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;
814         }
815
816         client_process_reply(req, reply);
817         talloc_free(reply);
818 }
819
820 static void client_script_enable_done(struct tevent_req *subreq)
821 {
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;
829
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;
836         }
837
838         client_process_reply(req, reply);
839         talloc_free(reply);
840 }
841
842 static void client_script_disable_done(struct tevent_req *subreq)
843 {
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;
851
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;
858         }
859
860         client_process_reply(req, reply);
861         talloc_free(reply);
862 }
863
864 static void client_process_reply(struct tevent_req *req,
865                                  struct ctdb_event_reply *reply)
866 {
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;
873
874         sock_packet_header_set_reqid(&reply->header,
875                                      state->request.header.reqid);
876
877         buflen = ctdb_event_reply_len(reply);
878         buf = talloc_zero_size(state, buflen);
879         if (tevent_req_nomem(buf, req)) {
880                 return;
881         }
882
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;
888         }
889
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;
895         }
896         tevent_req_set_callback(subreq, client_process_reply_done, req);
897 }
898
899 static void client_process_reply_done(struct tevent_req *subreq)
900 {
901         struct tevent_req *req = tevent_req_callback_data(
902                 subreq, struct tevent_req);
903         int ret;
904         bool status;
905
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;
912         }
913
914         tevent_req_done(req);
915 }
916
917 static bool client_process_recv(struct tevent_req *req, int *perr)
918 {
919         int ret;
920
921         if (tevent_req_is_unix_error(req, &ret)) {
922                 if (perr != NULL) {
923                         *perr = ret;
924                 }
925                 return false;
926         }
927
928         return true;
929 }
930
931 /*
932  * Event daemon
933  */
934
935 static void eventd_shutdown(void *private_data)
936 {
937         struct eventd_context *ectx = talloc_get_type_abort(
938                 private_data, struct eventd_context);
939         struct eventd_client *client;
940
941         while ((client = ectx->client_list) != NULL) {
942                 DLIST_REMOVE(ectx->client_list, client);
943                 talloc_free(client);
944         }
945 }
946
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",
957 };
958
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
976 };
977
978 int main(int argc, const char **argv)
979 {
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;
989
990         /* Set default options */
991         options.pid = -1;
992
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);
999         }
1000
1001         if (options.socket == NULL) {
1002                 fprintf(stderr, "Please specify eventd socket (--socket)\n");
1003                 exit(1);
1004         }
1005
1006         if (options.script_dir == NULL) {
1007                 fprintf(stderr,
1008                         "Please specify script dir (--event_script_dir)\n");
1009                 exit(1);
1010         }
1011
1012         if (options.logging == NULL) {
1013                 fprintf(stderr,
1014                         "Please specify logging (--logging)\n");
1015                 exit(1);
1016         }
1017
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);
1024         }
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);
1029         }
1030
1031         mem_ctx = talloc_new(NULL);
1032         if (mem_ctx == NULL) {
1033                 exit(1);
1034         }
1035
1036         ev = tevent_context_init(mem_ctx);
1037         if (ev == NULL) {
1038                 ret = 1;
1039                 goto fail;
1040         }
1041
1042         ret = eventd_context_init(mem_ctx, ev, options.script_dir,
1043                                   options.debug_script, &ectx);
1044         if (ret != 0) {
1045                 goto fail;
1046         }
1047
1048         daemon_funcs = (struct sock_daemon_funcs) {
1049                 .shutdown = eventd_shutdown,
1050         };
1051
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;
1057         }
1058
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,
1064         };
1065
1066         ret = sock_daemon_add_unix(sockd, options.socket, &socket_funcs, ectx);
1067         if (ret != 0) {
1068                 goto fail;
1069         }
1070
1071         ret = sock_daemon_run(ev, sockd,
1072                               options.pidfile, false, false, options.pid);
1073         if (ret == EINTR) {
1074                 ret = 0;
1075         }
1076
1077 fail:
1078         talloc_free(mem_ctx);
1079         (void)poptFreeContext(pc);
1080         exit(ret);
1081 }