ctdb-scripts: Update statd-callout to try several configuration files
[vlendec/samba-autobuild/.git] / ctdb / common / run_event.c
1 /*
2    Run scripts in a directory with specific event arguments
3
4    Copyright (C) Amitay Isaacs  2017
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/glob.h"
24 #include "system/wait.h"
25
26 #include <talloc.h>
27 #include <tevent.h>
28
29 #include "lib/util/tevent_unix.h"
30 #include "lib/util/debug.h"
31
32 #include "common/logging.h"
33 #include "common/run_proc.h"
34 #include "common/event_script.h"
35
36 #include "common/run_event.h"
37
38 /*
39  * Utility functions
40  */
41
42 static int get_script_list(TALLOC_CTX *mem_ctx,
43                            const char *script_dir,
44                            struct run_event_script_list **out)
45 {
46         struct event_script_list *s_list;
47         struct run_event_script_list *script_list;
48         unsigned int i;
49         int ret;
50
51         ret = event_script_get_list(mem_ctx, script_dir, &s_list);
52         if (ret != 0) {
53                 if (ret == ENOENT) {
54                         D_WARNING("event script dir %s removed\n", script_dir);
55                 } else {
56                         D_WARNING("failed to get script list for %s, ret=%d\n",
57                                   script_dir, ret);
58                 }
59                 return ret;
60         }
61
62         if (s_list->num_scripts == 0) {
63                 *out = NULL;
64                 talloc_free(s_list);
65                 return 0;
66         }
67
68         script_list = talloc_zero(mem_ctx, struct run_event_script_list);
69         if (script_list == NULL) {
70                 talloc_free(s_list);
71                 return ENOMEM;
72         }
73
74         script_list->num_scripts = s_list->num_scripts;
75         script_list->script = talloc_zero_array(script_list,
76                                                 struct run_event_script,
77                                                 script_list->num_scripts);
78         if (script_list->script == NULL) {
79                 talloc_free(s_list);
80                 talloc_free(script_list);
81                 return ENOMEM;
82         }
83
84         for (i = 0; i < s_list->num_scripts; i++) {
85                 struct event_script *s = s_list->script[i];
86                 struct run_event_script *script = &script_list->script[i];
87
88                 script->name = talloc_steal(script_list->script, s->name);
89
90                 if (! s->enabled) {
91                         script->summary = -ENOEXEC;
92                 }
93         }
94
95         talloc_free(s_list);
96         *out = script_list;
97         return 0;
98 }
99
100 static int script_args(TALLOC_CTX *mem_ctx, const char *event_str,
101                        const char *arg_str, const char ***out)
102 {
103         const char **argv;
104         int argc;
105         size_t len;
106
107         /* Preallocate argv array to avoid reallocation. */
108         len = 8;
109         argv = talloc_array(mem_ctx, const char *, len);
110         if (argv == NULL) {
111                 return ENOMEM;
112         }
113
114         argv[0] = NULL; /* script name */
115         argv[1] = event_str;
116         argc = 2;
117
118         if (arg_str != NULL) {
119                 char *str, *t, *tok;
120
121                 str = talloc_strdup(argv, arg_str);
122                 if (str == NULL) {
123                         return ENOMEM;
124                 }
125
126                 t = str;
127                 while ((tok = strtok(t, " ")) != NULL) {
128                         argv[argc] = talloc_strdup(argv, tok);
129                         if (argv[argc] == NULL) {
130                                 talloc_free(argv);
131                                 return ENOMEM;
132                         }
133                         argc += 1;
134                         if (argc >= len) {
135                                 argv = talloc_realloc(mem_ctx, argv,
136                                                       const char *, len + 8);
137                                 if (argv == NULL) {
138                                         return ENOMEM;
139                                 }
140                                 len += 8;
141                         }
142                         t = NULL;
143                 }
144
145                 talloc_free(str);
146         }
147
148         argv[argc] = NULL;
149         argc += 1;
150
151         *out = argv;
152         return 0;
153 }
154
155 struct run_event_context {
156         struct run_proc_context *run_proc_ctx;
157         const char *script_dir;
158         const char *debug_prog;
159         bool debug_running;
160
161         struct tevent_queue *queue;
162         struct tevent_req *current_req;
163         bool monitor_running;
164 };
165
166
167 int run_event_init(TALLOC_CTX *mem_ctx, struct run_proc_context *run_proc_ctx,
168                    const char *script_dir, const char *debug_prog,
169                    struct run_event_context **out)
170 {
171         struct run_event_context *run_ctx;
172         struct stat st;
173         int ret;
174
175         run_ctx = talloc_zero(mem_ctx, struct run_event_context);
176         if (run_ctx == NULL) {
177                 return ENOMEM;
178         }
179
180         run_ctx->run_proc_ctx = run_proc_ctx;
181
182         ret = stat(script_dir, &st);
183         if (ret != 0) {
184                 ret = errno;
185                 talloc_free(run_ctx);
186                 return ret;
187         }
188
189         if (! S_ISDIR(st.st_mode)) {
190                 talloc_free(run_ctx);
191                 return ENOTDIR;
192         }
193
194         run_ctx->script_dir = talloc_strdup(run_ctx, script_dir);
195         if (run_ctx->script_dir == NULL) {
196                 talloc_free(run_ctx);
197                 return ENOMEM;
198         }
199
200         if (debug_prog != NULL) {
201                 run_ctx->debug_prog = talloc_strdup(run_ctx, debug_prog);
202                 if (run_ctx->debug_prog == NULL) {
203                         talloc_free(run_ctx);
204                         return ENOMEM;
205                 }
206         }
207
208         run_ctx->debug_running = false;
209
210         run_ctx->queue = tevent_queue_create(run_ctx, "run event queue");
211         if (run_ctx->queue == NULL) {
212                 talloc_free(run_ctx);
213                 return ENOMEM;
214         }
215
216         run_ctx->monitor_running = false;
217
218         *out = run_ctx;
219         return 0;
220 }
221
222 static struct run_proc_context *
223 run_event_run_proc_context(struct run_event_context *run_ctx)
224 {
225         return run_ctx->run_proc_ctx;
226 }
227
228 static const char *run_event_script_dir(struct run_event_context *run_ctx)
229 {
230         return run_ctx->script_dir;
231 }
232
233 static const char *run_event_debug_prog(struct run_event_context *run_ctx)
234 {
235         return run_ctx->debug_prog;
236 }
237
238 static struct tevent_queue *run_event_queue(struct run_event_context *run_ctx)
239 {
240         return run_ctx->queue;
241 }
242
243 static void run_event_start_running(struct run_event_context *run_ctx,
244                                     struct tevent_req *req, bool is_monitor)
245 {
246         run_ctx->current_req = req;
247         run_ctx->monitor_running = is_monitor;
248 }
249
250 static void run_event_stop_running(struct run_event_context *run_ctx)
251 {
252         run_ctx->current_req = NULL;
253         run_ctx->monitor_running = false;
254 }
255
256 static struct tevent_req *run_event_get_running(
257                                 struct run_event_context *run_ctx,
258                                 bool *is_monitor)
259 {
260         *is_monitor = run_ctx->monitor_running;
261         return run_ctx->current_req;
262 }
263
264 static int run_event_script_status(struct run_event_script *script)
265 {
266         int ret;
267
268         if (script->result.sig > 0) {
269                 ret = -EINTR;
270         } else if (script->result.err > 0) {
271                 if (script->result.err == EACCES) {
272                         /* Map EACCESS to ENOEXEC */
273                         ret = -ENOEXEC;
274                 } else {
275                         ret = -script->result.err;
276                 }
277         } else {
278                 ret = script->result.status;
279         }
280
281         return ret;
282 }
283
284 int run_event_list(struct run_event_context *run_ctx,
285                    TALLOC_CTX *mem_ctx,
286                    struct run_event_script_list **output)
287 {
288         struct event_script_list *s_list;
289         struct run_event_script_list *script_list;
290         int ret, i;
291
292         ret = event_script_get_list(mem_ctx,
293                                     run_event_script_dir(run_ctx),
294                                     &s_list);
295         if (ret != 0) {
296                 return ret;
297         }
298
299         if (s_list->num_scripts == 0) {
300                 *output = NULL;
301                 talloc_free(s_list);
302                 return 0;
303         }
304
305         script_list = talloc_zero(mem_ctx, struct run_event_script_list);
306         if (script_list == NULL) {
307                 return ENOMEM;
308         }
309
310         script_list->num_scripts = s_list->num_scripts;
311         script_list->script = talloc_zero_array(script_list,
312                                                 struct run_event_script,
313                                                 script_list->num_scripts);
314         if (script_list->script == NULL) {
315                 talloc_free(s_list);
316                 talloc_free(script_list);
317                 return ENOMEM;
318         }
319
320         for (i=0; i < s_list->num_scripts; i++) {
321                 struct event_script *s = s_list->script[i];
322                 struct run_event_script *script = &script_list->script[i];
323
324                 script->name = talloc_steal(script_list->script, s->name);
325
326                 if (! s->enabled) {
327                         script->summary = -ENOEXEC;
328                 }
329         }
330
331
332         talloc_free(s_list);
333         *output = script_list;
334         return 0;
335 }
336
337 int run_event_script_enable(struct run_event_context *run_ctx,
338                             const char *script_name)
339 {
340         return event_script_chmod(run_event_script_dir(run_ctx),
341                                   script_name,
342                                   true);
343 }
344
345 int run_event_script_disable(struct run_event_context *run_ctx,
346                              const char *script_name)
347 {
348         return event_script_chmod(run_event_script_dir(run_ctx),
349                                   script_name,
350                                   false);
351 }
352
353 /*
354  * Run debug program to diagnose hung scripts
355  */
356
357 static int debug_args(TALLOC_CTX *mem_ctx, const char *path,
358                       const char *event_str, pid_t pid, const char ***out)
359 {
360         const char **argv;
361
362         argv = talloc_array(mem_ctx, const char *, 4);
363         if (argv == NULL) {
364                 return ENOMEM;
365         }
366
367         argv[0] = path;
368         argv[1] = talloc_asprintf(argv, "%d", pid);
369         argv[2] = event_str;
370         if (argv[1] == NULL) {
371                 talloc_free(argv);
372                 return ENOMEM;
373         }
374         argv[3] = NULL;
375
376         *out = argv;
377         return 0;
378 }
379
380 static void debug_log(int loglevel, const char *output, const char *log_prefix)
381 {
382         char *line, *s;
383
384         s = strdup(output);
385         if (s == NULL) {
386                 DEBUG(loglevel, ("%s: %s\n", log_prefix, output));
387                 return;
388         }
389
390         line = strtok(s, "\n");
391         while (line != NULL) {
392                 DEBUG(loglevel, ("%s: %s\n", log_prefix, line));
393                 line = strtok(NULL, "\n");
394         }
395         free(s);
396 }
397
398 struct run_debug_state {
399         struct run_event_context *run_ctx;
400         pid_t pid;
401 };
402
403 static void run_debug_done(struct tevent_req *subreq);
404
405 static struct tevent_req *run_debug_send(TALLOC_CTX *mem_ctx,
406                                          struct tevent_context *ev,
407                                          struct run_event_context *run_ctx,
408                                          const char *event_str, pid_t pid)
409 {
410         struct tevent_req *req, *subreq;
411         struct run_debug_state *state;
412         const char **argv;
413         const char *debug_prog;
414         int ret;
415
416         req = tevent_req_create(mem_ctx, &state, struct run_debug_state);
417         if (req == NULL) {
418                 return NULL;
419         }
420
421         state->run_ctx = run_ctx;
422         state->pid = pid;
423
424         debug_prog = run_event_debug_prog(run_ctx);
425         if (debug_prog == NULL) {
426                 tevent_req_done(req);
427                 return tevent_req_post(req, ev);
428         }
429
430         if (run_ctx->debug_running) {
431                 tevent_req_done(req);
432                 return tevent_req_post(req, ev);
433         }
434
435         if (pid == -1) {
436                 D_DEBUG("Event script terminated, nothing to debug\n");
437                 tevent_req_done(req);
438                 return tevent_req_post(req, ev);
439         }
440
441         ret = debug_args(state, debug_prog, event_str, pid, &argv);
442         if (ret != 0) {
443                 D_ERR("debug_args() failed\n");
444                 tevent_req_error(req, ret);
445                 return tevent_req_post(req, ev);
446         }
447
448         D_DEBUG("Running debug %s with args \"%s %s\"\n",
449                 debug_prog, argv[1], argv[2]);
450
451         subreq = run_proc_send(state, ev, run_event_run_proc_context(run_ctx),
452                                debug_prog, argv, -1, tevent_timeval_zero());
453         if (tevent_req_nomem(subreq, req)) {
454                 return tevent_req_post(req, ev);
455         }
456         tevent_req_set_callback(subreq, run_debug_done, req);
457
458         run_ctx->debug_running = true;
459
460         talloc_free(argv);
461         return req;
462 }
463
464 static void run_debug_done(struct tevent_req *subreq)
465 {
466         struct tevent_req *req = tevent_req_callback_data(
467                 subreq, struct tevent_req);
468         struct run_debug_state *state = tevent_req_data(
469                 req, struct run_debug_state);
470         char *output;
471         int ret;
472         bool status;
473
474         state->run_ctx->debug_running = false;
475
476         status = run_proc_recv(subreq, &ret, NULL, NULL, state, &output);
477         TALLOC_FREE(subreq);
478         if (! status) {
479                 D_ERR("Running debug failed, ret=%d\n", ret);
480         }
481
482         /* Log output */
483         if (output != NULL) {
484                 debug_log(DEBUG_ERR, output, "event_debug");
485                 talloc_free(output);
486         }
487
488         kill(-state->pid, SIGTERM);
489         tevent_req_done(req);
490 }
491
492 static bool run_debug_recv(struct tevent_req *req, int *perr)
493 {
494         int ret;
495
496         if (tevent_req_is_unix_error(req, &ret)) {
497                 if (perr != NULL) {
498                         *perr = ret;
499                 }
500                 return false;
501         }
502
503         return true;
504 }
505
506 /*
507  * Run a single event
508  */
509
510 struct run_event_state {
511         struct tevent_context *ev;
512         struct run_event_context *run_ctx;
513         const char *event_str;
514         const char *arg_str;
515         struct timeval timeout;
516         bool continue_on_failure;
517
518         struct run_event_script_list *script_list;
519         const char **argv;
520         struct tevent_req *script_subreq;
521         int index;
522         bool cancelled;
523 };
524
525 static void run_event_cancel(struct tevent_req *req);
526 static void run_event_trigger(struct tevent_req *req, void *private_data);
527 static struct tevent_req *run_event_run_script(struct tevent_req *req);
528 static void run_event_next_script(struct tevent_req *subreq);
529 static void run_event_debug(struct tevent_req *req, pid_t pid);
530 static void run_event_debug_done(struct tevent_req *subreq);
531
532 struct tevent_req *run_event_send(TALLOC_CTX *mem_ctx,
533                                   struct tevent_context *ev,
534                                   struct run_event_context *run_ctx,
535                                   const char *event_str,
536                                   const char *arg_str,
537                                   struct timeval timeout,
538                                   bool continue_on_failure)
539 {
540         struct tevent_req *req, *current_req;
541         struct run_event_state *state;
542         bool monitor_running, status;
543
544         req = tevent_req_create(mem_ctx, &state, struct run_event_state);
545         if (req == NULL) {
546                 return NULL;
547         }
548
549         state->ev = ev;
550         state->run_ctx = run_ctx;
551         state->event_str = talloc_strdup(state, event_str);
552         if (tevent_req_nomem(state->event_str, req)) {
553                 return tevent_req_post(req, ev);
554         }
555         if (arg_str != NULL) {
556                 state->arg_str = talloc_strdup(state, arg_str);
557                 if (tevent_req_nomem(state->arg_str, req)) {
558                         return tevent_req_post(req, ev);
559                 }
560         }
561         state->timeout = timeout;
562         state->continue_on_failure = continue_on_failure;
563         state->cancelled = false;
564
565         state->script_list = talloc_zero(state, struct run_event_script_list);
566         if (tevent_req_nomem(state->script_list, req)) {
567                 return tevent_req_post(req, ev);
568         }
569
570         /*
571          * If monitor event is running,
572          *   cancel the running monitor event and run new event
573          *
574          * If any other event is running,
575          *   if new event is monitor, cancel that event
576          *   else add new event to the queue
577          */
578
579         current_req = run_event_get_running(run_ctx, &monitor_running);
580         if (current_req != NULL) {
581                 if (monitor_running) {
582                         run_event_cancel(current_req);
583                 } else if (strcmp(event_str, "monitor") == 0) {
584                         state->script_list->summary = -ECANCELED;
585                         tevent_req_done(req);
586                         return tevent_req_post(req, ev);
587                 }
588         }
589
590         status = tevent_queue_add(run_event_queue(run_ctx), ev, req,
591                                   run_event_trigger, NULL);
592         if (! status) {
593                 tevent_req_error(req, ENOMEM);
594                 return tevent_req_post(req, ev);
595         }
596
597         return req;
598 }
599
600 static void run_event_cancel(struct tevent_req *req)
601 {
602         struct run_event_state *state = tevent_req_data(
603                 req, struct run_event_state);
604
605         run_event_stop_running(state->run_ctx);
606
607         state->script_list->summary = -ECANCELED;
608         state->cancelled = true;
609
610         TALLOC_FREE(state->script_subreq);
611
612         tevent_req_done(req);
613 }
614
615 static void run_event_trigger(struct tevent_req *req, void *private_data)
616 {
617         struct tevent_req *subreq;
618         struct run_event_state *state = tevent_req_data(
619                 req, struct run_event_state);
620         struct run_event_script_list *script_list;
621         int ret;
622         bool is_monitor = false;
623
624         D_DEBUG("Running event %s with args \"%s\"\n", state->event_str,
625                 state->arg_str == NULL ? "(null)" : state->arg_str);
626
627         ret = get_script_list(state,
628                               run_event_script_dir(state->run_ctx),
629                               &script_list);
630         if (ret != 0) {
631                 D_ERR("get_script_list() failed, ret=%d\n", ret);
632                 tevent_req_error(req, ret);
633                 return;
634         }
635
636         /* No scripts */
637         if (script_list == NULL || script_list->num_scripts == 0) {
638                 tevent_req_done(req);
639                 return;
640         }
641
642         talloc_free(state->script_list);
643         state->script_list = script_list;
644
645         ret = script_args(state, state->event_str, state->arg_str,
646                           &state->argv);
647         if (ret != 0) {
648                 D_ERR("script_args() failed, ret=%d\n", ret);
649                 tevent_req_error(req, ret);
650                 return;
651         }
652
653         state->index = 0;
654
655         subreq = run_event_run_script(req);
656         if (tevent_req_nomem(subreq, req)) {
657                 return;
658         }
659         tevent_req_set_callback(subreq, run_event_next_script, req);
660
661         state->script_subreq = subreq;
662
663         if (strcmp(state->event_str, "monitor") == 0) {
664                 is_monitor = true;
665         }
666         run_event_start_running(state->run_ctx, req, is_monitor);
667 }
668
669 static struct tevent_req *run_event_run_script(struct tevent_req *req)
670 {
671         struct run_event_state *state = tevent_req_data(
672                 req, struct run_event_state);
673         struct run_event_script *script;
674         struct tevent_req *subreq;
675         char *path;
676
677         script = &state->script_list->script[state->index];
678
679         path = talloc_asprintf(state, "%s/%s.script",
680                                run_event_script_dir(state->run_ctx),
681                                script->name);
682         if (path == NULL) {
683                 return NULL;
684         }
685
686         state->argv[0] = script->name;
687         script->begin = tevent_timeval_current();
688
689         D_DEBUG("Running %s with args \"%s %s\"\n",
690                 path, state->argv[0], state->argv[1]);
691
692         subreq = run_proc_send(state, state->ev,
693                                run_event_run_proc_context(state->run_ctx),
694                                path, state->argv, -1, state->timeout);
695
696         talloc_free(path);
697
698         return subreq;
699 }
700
701 static void run_event_next_script(struct tevent_req *subreq)
702 {
703         struct tevent_req *req = tevent_req_callback_data(
704                 subreq, struct tevent_req);
705         struct run_event_state *state = tevent_req_data(
706                 req, struct run_event_state);
707         struct run_event_script *script;
708         pid_t pid;
709         int ret;
710         bool status;
711
712         script = &state->script_list->script[state->index];
713         script->end = tevent_timeval_current();
714
715         status = run_proc_recv(subreq, &ret, &script->result, &pid,
716                                state->script_list, &script->output);
717         TALLOC_FREE(subreq);
718         state->script_subreq = NULL;
719         if (! status) {
720                 D_ERR("run_proc failed for %s, ret=%d\n", script->name, ret);
721                 run_event_stop_running(state->run_ctx);
722                 tevent_req_error(req, ret);
723                 return;
724         }
725
726         if (state->cancelled) {
727                 return;
728         }
729
730         /* Log output */
731         if (script->output != NULL) {
732                 debug_log(DEBUG_ERR, script->output, script->name);
733         }
734
735         D_DEBUG("Script %s finished sig=%d, err=%d, status=%d\n",
736                 script->name, script->result.sig, script->result.err,
737                 script->result.status);
738
739
740         /* If a script fails, stop running */
741         script->summary = run_event_script_status(script);
742         if (script->summary != 0 && script->summary != -ENOEXEC) {
743                 state->script_list->summary = script->summary;
744
745                 if (! state->continue_on_failure) {
746                         state->script_list->num_scripts = state->index + 1;
747
748                         if (script->summary == -ETIMEDOUT && pid != -1) {
749                                 run_event_debug(req, pid);
750                         }
751                         D_NOTICE("%s event %s\n", state->event_str,
752                                  (script->summary == -ETIMEDOUT) ?
753                                   "timed out" :
754                                   "failed");
755                         run_event_stop_running(state->run_ctx);
756                         tevent_req_done(req);
757                         return;
758                 }
759         }
760
761         state->index += 1;
762
763         /* All scripts executed */
764         if (state->index >= state->script_list->num_scripts) {
765                 run_event_stop_running(state->run_ctx);
766                 tevent_req_done(req);
767                 return;
768         }
769
770         subreq = run_event_run_script(req);
771         if (tevent_req_nomem(subreq, req)) {
772                 return;
773         }
774         tevent_req_set_callback(subreq, run_event_next_script, req);
775
776         state->script_subreq = subreq;
777 }
778
779 static void run_event_debug(struct tevent_req *req, pid_t pid)
780 {
781         struct run_event_state *state = tevent_req_data(
782                 req, struct run_event_state);
783         struct tevent_req *subreq;
784
785         /* Debug script is run with ectx as the memory context */
786         subreq = run_debug_send(state->run_ctx, state->ev, state->run_ctx,
787                                 state->event_str, pid);
788         if (subreq == NULL) {
789                 /* If run debug fails, it's not an error */
790                 D_NOTICE("Failed to run event debug\n");
791                 return;
792         }
793         tevent_req_set_callback(subreq, run_event_debug_done, NULL);
794 }
795
796 static void run_event_debug_done(struct tevent_req *subreq)
797 {
798         int ret = 0;
799         bool status;
800
801         status = run_debug_recv(subreq, &ret);
802         TALLOC_FREE(subreq);
803         if (! status) {
804                 D_NOTICE("run_debug() failed, ret=%d\n", ret);
805         }
806 }
807
808 bool run_event_recv(struct tevent_req *req, int *perr,
809                     TALLOC_CTX *mem_ctx,
810                     struct run_event_script_list **script_list)
811 {
812         struct run_event_state *state = tevent_req_data(
813                 req, struct run_event_state);
814         int ret;
815
816         if (tevent_req_is_unix_error(req, &ret)) {
817                 if (perr != NULL) {
818                         *perr = ret;
819                 }
820                 return false;
821         }
822
823         if (script_list != NULL) {
824                 *script_list = talloc_steal(mem_ctx, state->script_list);
825         }
826         return true;
827 }
828