2 Run scripts in a directory with specific event arguments
4 Copyright (C) Amitay Isaacs 2017
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "system/filesys.h"
22 #include "system/dir.h"
23 #include "system/locale.h"
24 #include "system/wait.h"
29 #include "lib/util/tevent_unix.h"
30 #include "lib/util/debug.h"
32 #include "common/logging.h"
33 #include "common/run_proc.h"
34 #include "common/run_event.h"
40 static int script_filter(const struct dirent
*de
)
42 size_t namelen
= strlen(de
->d_name
);
50 /* Skip filenames with ~ */
51 ptr
= strchr(de
->d_name
, '~');
56 /* Filename should start with [0-9][0-9]. */
57 if ((! isdigit(de
->d_name
[0])) ||
58 (! isdigit(de
->d_name
[1])) ||
59 (de
->d_name
[2] != '.')) {
63 /* Ignore filenames with multiple '.'s */
64 ptr
= index(&de
->d_name
[3], '.');
72 static int get_script_list(TALLOC_CTX
*mem_ctx
,
73 const char *script_dir
,
74 struct run_event_script_list
**out
)
76 struct dirent
**namelist
= NULL
;
77 struct run_event_script_list
*script_list
;
81 count
= scandir(script_dir
, &namelist
, script_filter
, alphasort
);
85 D_WARNING("event script dir %s removed\n", script_dir
);
87 D_WARNING("scandir() failed on %s, ret=%d\n",
101 script_list
= talloc_zero(mem_ctx
, struct run_event_script_list
);
102 if (script_list
== NULL
) {
106 script_list
->num_scripts
= count
;
107 script_list
->script
= talloc_zero_array(script_list
,
108 struct run_event_script
,
110 if (script_list
->script
== NULL
) {
112 talloc_free(script_list
);
116 for (i
=0; i
<count
; i
++) {
117 struct run_event_script
*s
= &script_list
->script
[i
];
119 s
->name
= talloc_strdup(script_list
, namelist
[i
]->d_name
);
120 if (s
->name
== NULL
) {
122 talloc_free(script_list
);
131 if (namelist
!= NULL
&& count
!= -1) {
132 for (i
=0; i
<count
; i
++) {
140 static int script_chmod(TALLOC_CTX
*mem_ctx
, const char *script_dir
,
141 const char *script_name
, bool enable
)
151 dirp
= opendir(script_dir
);
157 while ((de
= readdir(dirp
)) != NULL
) {
158 if (strcmp(de
->d_name
, script_name
) == 0) {
160 /* check for valid script names */
161 ret
= script_filter(de
);
177 filename
= talloc_asprintf(mem_ctx
, "%s/%s", script_dir
, script_name
);
178 if (filename
== NULL
) {
182 fd
= open(filename
, O_RDWR
);
188 ret
= fstat(fd
, &st
);
195 new_mode
= st
.st_mode
| (S_IXUSR
| S_IXGRP
| S_IXOTH
);
197 new_mode
= st
.st_mode
& ~(S_IXUSR
| S_IXGRP
| S_IXOTH
);
200 ret
= fchmod(fd
, new_mode
);
210 talloc_free(filename
);
214 static int script_args(TALLOC_CTX
*mem_ctx
, const char *event_str
,
215 const char *arg_str
, const char ***out
)
221 /* Preallocate argv array to avoid reallocation. */
223 argv
= talloc_array(mem_ctx
, const char *, len
);
228 argv
[0] = NULL
; /* script name */
232 if (arg_str
!= NULL
) {
235 str
= talloc_strdup(argv
, arg_str
);
241 while ((tok
= strtok(t
, " ")) != NULL
) {
242 argv
[argc
] = talloc_strdup(argv
, tok
);
243 if (argv
[argc
] == NULL
) {
249 argv
= talloc_realloc(mem_ctx
, argv
,
250 const char *, len
+ 8);
269 struct run_event_context
{
270 struct run_proc_context
*run_proc_ctx
;
271 const char *script_dir
;
272 const char *debug_prog
;
275 struct tevent_queue
*queue
;
276 struct tevent_req
*current_req
;
277 bool monitor_running
;
281 int run_event_init(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
282 const char *script_dir
, const char *debug_prog
,
283 struct run_event_context
**out
)
285 struct run_event_context
*run_ctx
;
289 run_ctx
= talloc_zero(mem_ctx
, struct run_event_context
);
290 if (run_ctx
== NULL
) {
294 ret
= run_proc_init(run_ctx
, ev
, &run_ctx
->run_proc_ctx
);
296 talloc_free(run_ctx
);
300 ret
= stat(script_dir
, &st
);
303 talloc_free(run_ctx
);
307 if (! S_ISDIR(st
.st_mode
)) {
308 talloc_free(run_ctx
);
312 run_ctx
->script_dir
= talloc_strdup(run_ctx
, script_dir
);
313 if (run_ctx
->script_dir
== NULL
) {
314 talloc_free(run_ctx
);
318 if (debug_prog
!= NULL
) {
319 run_ctx
->debug_prog
= talloc_strdup(run_ctx
, debug_prog
);
320 if (run_ctx
->debug_prog
== NULL
) {
321 talloc_free(run_ctx
);
326 run_ctx
->debug_running
= false;
328 run_ctx
->queue
= tevent_queue_create(run_ctx
, "run event queue");
329 if (run_ctx
->queue
== NULL
) {
330 talloc_free(run_ctx
);
334 run_ctx
->monitor_running
= false;
340 static struct run_proc_context
*
341 run_event_run_proc_context(struct run_event_context
*run_ctx
)
343 return run_ctx
->run_proc_ctx
;
346 static const char *run_event_script_dir(struct run_event_context
*run_ctx
)
348 return run_ctx
->script_dir
;
351 static const char *run_event_debug_prog(struct run_event_context
*run_ctx
)
353 return run_ctx
->debug_prog
;
356 static struct tevent_queue
*run_event_queue(struct run_event_context
*run_ctx
)
358 return run_ctx
->queue
;
361 static void run_event_start_running(struct run_event_context
*run_ctx
,
362 struct tevent_req
*req
, bool is_monitor
)
364 run_ctx
->current_req
= req
;
365 run_ctx
->monitor_running
= is_monitor
;
368 static void run_event_stop_running(struct run_event_context
*run_ctx
)
370 run_ctx
->current_req
= NULL
;
371 run_ctx
->monitor_running
= false;
374 static struct tevent_req
*run_event_get_running(
375 struct run_event_context
*run_ctx
,
378 *is_monitor
= run_ctx
->monitor_running
;
379 return run_ctx
->current_req
;
382 static int run_event_script_status(struct run_event_script
*script
)
386 if (script
->result
.sig
> 0) {
388 } else if (script
->result
.err
> 0) {
389 if (script
->result
.err
== EACCES
) {
390 /* Map EACCESS to ENOEXEC */
393 ret
= -script
->result
.err
;
396 ret
= script
->result
.status
;
402 int run_event_script_list(struct run_event_context
*run_ctx
,
404 struct run_event_script_list
**output
)
406 struct run_event_script_list
*script_list
;
409 ret
= get_script_list(mem_ctx
, run_event_script_dir(run_ctx
),
415 if (script_list
== NULL
) {
420 for (i
=0; i
<script_list
->num_scripts
; i
++) {
421 struct run_event_script
*script
= &script_list
->script
[i
];
425 path
= talloc_asprintf(mem_ctx
, "%s/%s",
426 run_event_script_dir(run_ctx
),
432 ret
= stat(path
, &st
);
438 if (! (st
.st_mode
& S_IXUSR
)) {
439 script
->summary
= -ENOEXEC
;
445 *output
= script_list
;
449 int run_event_script_enable(struct run_event_context
*run_ctx
,
450 const char *script_name
)
452 return script_chmod(run_ctx
, run_event_script_dir(run_ctx
),
456 int run_event_script_disable(struct run_event_context
*run_ctx
,
457 const char *script_name
)
459 return script_chmod(run_ctx
, run_event_script_dir(run_ctx
),
464 * Run debug program to diagnose hung scripts
467 static int debug_args(TALLOC_CTX
*mem_ctx
, const char *path
,
468 const char *event_str
, pid_t pid
, const char ***out
)
472 argv
= talloc_array(mem_ctx
, const char *, 4);
478 argv
[1] = talloc_asprintf(argv
, "%d", pid
);
480 if (argv
[1] == NULL
) {
490 static void debug_log(int loglevel
, const char *output
, const char *log_prefix
)
496 DEBUG(loglevel
, ("%s: %s\n", log_prefix
, output
));
500 line
= strtok(s
, "\n");
501 while (line
!= NULL
) {
502 DEBUG(loglevel
, ("%s: %s\n", log_prefix
, line
));
503 line
= strtok(NULL
, "\n");
508 struct run_debug_state
{
509 struct run_event_context
*run_ctx
;
513 static void run_debug_done(struct tevent_req
*subreq
);
515 static struct tevent_req
*run_debug_send(TALLOC_CTX
*mem_ctx
,
516 struct tevent_context
*ev
,
517 struct run_event_context
*run_ctx
,
518 const char *event_str
, pid_t pid
)
520 struct tevent_req
*req
, *subreq
;
521 struct run_debug_state
*state
;
523 const char *debug_prog
;
526 req
= tevent_req_create(mem_ctx
, &state
, struct run_debug_state
);
531 state
->run_ctx
= run_ctx
;
534 debug_prog
= run_event_debug_prog(run_ctx
);
535 if (debug_prog
== NULL
) {
536 tevent_req_done(req
);
537 return tevent_req_post(req
, ev
);
540 if (run_ctx
->debug_running
) {
541 tevent_req_done(req
);
542 return tevent_req_post(req
, ev
);
546 D_DEBUG("Event script terminated, nothing to debug\n");
547 tevent_req_done(req
);
548 return tevent_req_post(req
, ev
);
551 ret
= debug_args(state
, debug_prog
, event_str
, pid
, &argv
);
553 D_ERR("debug_args() failed\n");
554 tevent_req_error(req
, ret
);
555 return tevent_req_post(req
, ev
);
558 D_DEBUG("Running debug %s with args \"%s %s\"\n",
559 debug_prog
, argv
[1], argv
[2]);
561 subreq
= run_proc_send(state
, ev
, run_event_run_proc_context(run_ctx
),
562 debug_prog
, argv
, -1, tevent_timeval_zero());
563 if (tevent_req_nomem(subreq
, req
)) {
564 return tevent_req_post(req
, ev
);
566 tevent_req_set_callback(subreq
, run_debug_done
, req
);
568 run_ctx
->debug_running
= true;
574 static void run_debug_done(struct tevent_req
*subreq
)
576 struct tevent_req
*req
= tevent_req_callback_data(
577 subreq
, struct tevent_req
);
578 struct run_debug_state
*state
= tevent_req_data(
579 req
, struct run_debug_state
);
584 state
->run_ctx
->debug_running
= false;
586 status
= run_proc_recv(subreq
, &ret
, NULL
, NULL
, state
, &output
);
589 D_ERR("Running debug failed, ret=%d\n", ret
);
593 if (output
!= NULL
) {
594 debug_log(DEBUG_ERR
, output
, "event_debug");
598 kill(-state
->pid
, SIGTERM
);
599 tevent_req_done(req
);
602 static bool run_debug_recv(struct tevent_req
*req
, int *perr
)
606 if (tevent_req_is_unix_error(req
, &ret
)) {
620 struct run_event_state
{
621 struct tevent_context
*ev
;
622 struct run_event_context
*run_ctx
;
623 const char *event_str
;
625 struct timeval timeout
;
627 struct run_event_script_list
*script_list
;
629 struct tevent_req
*script_subreq
;
634 static void run_event_cancel(struct tevent_req
*req
);
635 static void run_event_trigger(struct tevent_req
*req
, void *private_data
);
636 static struct tevent_req
*run_event_run_script(struct tevent_req
*req
);
637 static void run_event_next_script(struct tevent_req
*subreq
);
638 static void run_event_debug(struct tevent_req
*req
, pid_t pid
);
639 static void run_event_debug_done(struct tevent_req
*subreq
);
641 struct tevent_req
*run_event_send(TALLOC_CTX
*mem_ctx
,
642 struct tevent_context
*ev
,
643 struct run_event_context
*run_ctx
,
644 const char *event_str
,
646 struct timeval timeout
)
648 struct tevent_req
*req
, *current_req
;
649 struct run_event_state
*state
;
650 bool monitor_running
, status
;
652 req
= tevent_req_create(mem_ctx
, &state
, struct run_event_state
);
658 state
->run_ctx
= run_ctx
;
659 state
->event_str
= talloc_strdup(state
, event_str
);
660 if (tevent_req_nomem(state
->event_str
, req
)) {
661 return tevent_req_post(req
, ev
);
663 if (arg_str
!= NULL
) {
664 state
->arg_str
= talloc_strdup(state
, arg_str
);
665 if (tevent_req_nomem(state
->arg_str
, req
)) {
666 return tevent_req_post(req
, ev
);
669 state
->timeout
= timeout
;
670 state
->cancelled
= false;
673 * If monitor event is running,
674 * cancel the running monitor event and run new event
676 * If any other event is running,
677 * if new event is monitor, cancel that event
678 * else add new event to the queue
681 current_req
= run_event_get_running(run_ctx
, &monitor_running
);
682 if (current_req
!= NULL
) {
683 if (monitor_running
) {
684 run_event_cancel(current_req
);
685 } else if (strcmp(event_str
, "monitor") == 0) {
686 state
->script_list
= talloc_zero(
687 state
, struct run_event_script_list
);
688 if (tevent_req_nomem(state
->script_list
, req
)) {
689 return tevent_req_post(req
, ev
);
691 state
->script_list
->summary
= -ECANCELED
;
692 tevent_req_done(req
);
693 return tevent_req_post(req
, ev
);
697 status
= tevent_queue_add(run_event_queue(run_ctx
), ev
, req
,
698 run_event_trigger
, NULL
);
700 tevent_req_error(req
, ENOMEM
);
701 return tevent_req_post(req
, ev
);
707 static void run_event_cancel(struct tevent_req
*req
)
709 struct run_event_state
*state
= tevent_req_data(
710 req
, struct run_event_state
);
712 run_event_stop_running(state
->run_ctx
);
714 state
->script_list
->summary
= -ECANCELED
;
715 state
->cancelled
= true;
717 TALLOC_FREE(state
->script_subreq
);
719 tevent_req_done(req
);
722 static void run_event_trigger(struct tevent_req
*req
, void *private_data
)
724 struct tevent_req
*subreq
;
725 struct run_event_state
*state
= tevent_req_data(
726 req
, struct run_event_state
);
728 bool is_monitor
= false;
730 D_DEBUG("Running event %s with args \"%s\"\n", state
->event_str
,
731 state
->arg_str
== NULL
? "(null)" : state
->arg_str
);
733 ret
= get_script_list(state
, run_event_script_dir(state
->run_ctx
),
734 &state
->script_list
);
736 D_ERR("get_script_list() failed, ret=%d\n", ret
);
737 tevent_req_error(req
, ret
);
742 if (state
->script_list
== NULL
||
743 state
->script_list
->num_scripts
== 0) {
744 tevent_req_done(req
);
748 ret
= script_args(state
, state
->event_str
, state
->arg_str
,
751 D_ERR("script_args() failed, ret=%d\n", ret
);
752 tevent_req_error(req
, ret
);
758 subreq
= run_event_run_script(req
);
759 if (tevent_req_nomem(subreq
, req
)) {
762 tevent_req_set_callback(subreq
, run_event_next_script
, req
);
764 state
->script_subreq
= subreq
;
766 if (strcmp(state
->event_str
, "monitor") == 0) {
769 run_event_start_running(state
->run_ctx
, req
, is_monitor
);
772 static struct tevent_req
*run_event_run_script(struct tevent_req
*req
)
774 struct run_event_state
*state
= tevent_req_data(
775 req
, struct run_event_state
);
776 struct run_event_script
*script
;
777 struct tevent_req
*subreq
;
780 script
= &state
->script_list
->script
[state
->index
];
782 path
= talloc_asprintf(state
, "%s/%s",
783 run_event_script_dir(state
->run_ctx
),
789 state
->argv
[0] = script
->name
;
790 script
->begin
= tevent_timeval_current();
792 D_DEBUG("Running %s with args \"%s %s\"\n",
793 path
, state
->argv
[0], state
->argv
[1]);
795 subreq
= run_proc_send(state
, state
->ev
,
796 run_event_run_proc_context(state
->run_ctx
),
797 path
, state
->argv
, -1, state
->timeout
);
804 static void run_event_next_script(struct tevent_req
*subreq
)
806 struct tevent_req
*req
= tevent_req_callback_data(
807 subreq
, struct tevent_req
);
808 struct run_event_state
*state
= tevent_req_data(
809 req
, struct run_event_state
);
810 struct run_event_script
*script
;
815 script
= &state
->script_list
->script
[state
->index
];
816 script
->end
= tevent_timeval_current();
818 status
= run_proc_recv(subreq
, &ret
, &script
->result
, &pid
,
819 state
->script_list
, &script
->output
);
821 state
->script_subreq
= NULL
;
823 D_ERR("run_proc failed for %s, ret=%d\n", script
->name
, ret
);
824 tevent_req_error(req
, ret
);
828 if (state
->cancelled
) {
833 if (script
->output
!= NULL
) {
834 debug_log(DEBUG_ERR
, script
->output
, script
->name
);
837 D_DEBUG("Script %s finished sig=%d, err=%d, status=%d\n",
838 script
->name
, script
->result
.sig
, script
->result
.err
,
839 script
->result
.status
);
842 /* If a script fails, stop running */
843 script
->summary
= run_event_script_status(script
);
844 if (script
->summary
!= 0 && script
->summary
!= -ENOEXEC
) {
845 state
->script_list
->num_scripts
= state
->index
+ 1;
847 if (script
->summary
== -ETIME
&& pid
!= -1) {
848 run_event_debug(req
, pid
);
851 state
->script_list
->summary
= script
->summary
;
852 D_NOTICE("%s event %s\n", state
->event_str
,
853 (script
->summary
== -ETIME
) ? "timed out" : "failed");
855 run_event_stop_running(state
->run_ctx
);
856 tevent_req_done(req
);
862 /* All scripts executed */
863 if (state
->index
>= state
->script_list
->num_scripts
) {
864 run_event_stop_running(state
->run_ctx
);
865 tevent_req_done(req
);
869 subreq
= run_event_run_script(req
);
870 if (tevent_req_nomem(subreq
, req
)) {
873 tevent_req_set_callback(subreq
, run_event_next_script
, req
);
875 state
->script_subreq
= subreq
;
878 static void run_event_debug(struct tevent_req
*req
, pid_t pid
)
880 struct run_event_state
*state
= tevent_req_data(
881 req
, struct run_event_state
);
882 struct tevent_req
*subreq
;
884 /* Debug script is run with ectx as the memory context */
885 subreq
= run_debug_send(state
->run_ctx
, state
->ev
, state
->run_ctx
,
886 state
->event_str
, pid
);
887 if (subreq
== NULL
) {
888 /* If run debug fails, it's not an error */
889 D_NOTICE("Failed to run event debug\n");
892 tevent_req_set_callback(subreq
, run_event_debug_done
, NULL
);
895 static void run_event_debug_done(struct tevent_req
*subreq
)
900 status
= run_debug_recv(subreq
, &ret
);
903 D_NOTICE("run_debug() failed, ret=%d\n", ret
);
907 bool run_event_recv(struct tevent_req
*req
, int *perr
,
909 struct run_event_script_list
**script_list
)
911 struct run_event_state
*state
= tevent_req_data(
912 req
, struct run_event_state
);
915 if (tevent_req_is_unix_error(req
, &ret
)) {
922 if (script_list
!= NULL
) {
923 *script_list
= talloc_steal(mem_ctx
, state
->script_list
);