2017-02-23 10:40:48 +03:00
/*
Run scripts in a directory with specific event arguments
Copyright ( C ) Amitay Isaacs 2017
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
# include "replace.h"
# include "system/filesys.h"
# include "system/dir.h"
2018-05-15 11:36:29 +03:00
# include "system/glob.h"
2017-02-23 10:40:48 +03:00
# include "system/wait.h"
# include <talloc.h>
# include <tevent.h>
# include "lib/util/tevent_unix.h"
# include "lib/util/debug.h"
# include "common/logging.h"
# include "common/run_proc.h"
2018-07-12 06:26:27 +03:00
# include "common/event_script.h"
2017-02-23 10:40:48 +03:00
# include "common/run_event.h"
/*
* Utility functions
*/
static int get_script_list ( TALLOC_CTX * mem_ctx ,
const char * script_dir ,
struct run_event_script_list * * out )
{
2018-07-12 06:26:27 +03:00
struct event_script_list * s_list ;
2017-02-23 10:40:48 +03:00
struct run_event_script_list * script_list ;
2018-07-12 06:26:27 +03:00
unsigned int i ;
int ret ;
2017-02-23 10:40:48 +03:00
2018-07-12 06:26:27 +03:00
ret = event_script_get_list ( mem_ctx , script_dir , & s_list ) ;
if ( ret ! = 0 ) {
2017-02-23 10:40:48 +03:00
if ( ret = = ENOENT ) {
D_WARNING ( " event script dir %s removed \n " , script_dir ) ;
} else {
2018-07-12 06:26:27 +03:00
D_WARNING ( " failed to get script list for %s, ret=%d \n " ,
2017-02-23 10:40:48 +03:00
script_dir , ret ) ;
}
2018-07-12 06:26:27 +03:00
return ret ;
2017-02-23 10:40:48 +03:00
}
2018-07-12 06:26:27 +03:00
if ( s_list - > num_scripts = = 0 ) {
2017-02-23 10:40:48 +03:00
* out = NULL ;
2018-07-12 06:26:27 +03:00
talloc_free ( s_list ) ;
return 0 ;
2017-02-23 10:40:48 +03:00
}
script_list = talloc_zero ( mem_ctx , struct run_event_script_list ) ;
if ( script_list = = NULL ) {
2018-07-12 06:26:27 +03:00
talloc_free ( s_list ) ;
2017-02-23 10:40:48 +03:00
return ENOMEM ;
}
2018-07-12 06:26:27 +03:00
script_list - > num_scripts = s_list - > num_scripts ;
2017-02-23 10:40:48 +03:00
script_list - > script = talloc_zero_array ( script_list ,
struct run_event_script ,
2018-07-12 06:26:27 +03:00
script_list - > num_scripts ) ;
2017-02-23 10:40:48 +03:00
if ( script_list - > script = = NULL ) {
2018-07-12 06:26:27 +03:00
talloc_free ( s_list ) ;
2017-02-23 10:40:48 +03:00
talloc_free ( script_list ) ;
return ENOMEM ;
}
2018-07-12 06:26:27 +03:00
for ( i = 0 ; i < s_list - > num_scripts ; i + + ) {
struct event_script * s = s_list - > script [ i ] ;
struct run_event_script * script = & script_list - > script [ i ] ;
2017-02-23 10:40:48 +03:00
2018-07-12 06:26:27 +03:00
script - > name = talloc_steal ( script_list - > script , s - > name ) ;
2017-02-23 10:40:48 +03:00
2018-07-12 06:26:27 +03:00
if ( ! s - > enabled ) {
script - > summary = - ENOEXEC ;
}
2017-02-23 10:40:48 +03:00
}
2018-07-12 06:26:27 +03:00
talloc_free ( s_list ) ;
* out = script_list ;
return 0 ;
2017-02-23 10:40:48 +03:00
}
static int script_args ( TALLOC_CTX * mem_ctx , const char * event_str ,
const char * arg_str , const char * * * out )
{
const char * * argv ;
2019-05-22 14:55:18 +03:00
size_t argc ;
2017-02-23 10:40:48 +03:00
size_t len ;
/* Preallocate argv array to avoid reallocation. */
len = 8 ;
argv = talloc_array ( mem_ctx , const char * , len ) ;
if ( argv = = NULL ) {
return ENOMEM ;
}
argv [ 0 ] = NULL ; /* script name */
argv [ 1 ] = event_str ;
argc = 2 ;
if ( arg_str ! = NULL ) {
char * str , * t , * tok ;
str = talloc_strdup ( argv , arg_str ) ;
if ( str = = NULL ) {
return ENOMEM ;
}
t = str ;
while ( ( tok = strtok ( t , " " ) ) ! = NULL ) {
argv [ argc ] = talloc_strdup ( argv , tok ) ;
if ( argv [ argc ] = = NULL ) {
talloc_free ( argv ) ;
return ENOMEM ;
}
argc + = 1 ;
if ( argc > = len ) {
argv = talloc_realloc ( mem_ctx , argv ,
const char * , len + 8 ) ;
if ( argv = = NULL ) {
return ENOMEM ;
}
len + = 8 ;
}
t = NULL ;
}
talloc_free ( str ) ;
}
argv [ argc ] = NULL ;
2019-05-23 10:53:19 +03:00
/* argc += 1 */
2017-02-23 10:40:48 +03:00
* out = argv ;
return 0 ;
}
struct run_event_context {
struct run_proc_context * run_proc_ctx ;
const char * script_dir ;
const char * debug_prog ;
bool debug_running ;
2017-11-08 11:31:05 +03:00
struct tevent_queue * queue ;
struct tevent_req * current_req ;
bool monitor_running ;
2017-02-23 10:40:48 +03:00
} ;
2018-05-09 09:42:40 +03:00
int run_event_init ( TALLOC_CTX * mem_ctx , struct run_proc_context * run_proc_ctx ,
2017-02-23 10:40:48 +03:00
const char * script_dir , const char * debug_prog ,
struct run_event_context * * out )
{
struct run_event_context * run_ctx ;
struct stat st ;
int ret ;
run_ctx = talloc_zero ( mem_ctx , struct run_event_context ) ;
if ( run_ctx = = NULL ) {
return ENOMEM ;
}
2018-05-09 09:42:40 +03:00
run_ctx - > run_proc_ctx = run_proc_ctx ;
2017-02-23 10:40:48 +03:00
ret = stat ( script_dir , & st ) ;
if ( ret ! = 0 ) {
ret = errno ;
talloc_free ( run_ctx ) ;
return ret ;
}
if ( ! S_ISDIR ( st . st_mode ) ) {
talloc_free ( run_ctx ) ;
2018-05-10 09:50:35 +03:00
return ENOTDIR ;
2017-02-23 10:40:48 +03:00
}
run_ctx - > script_dir = talloc_strdup ( run_ctx , script_dir ) ;
if ( run_ctx - > script_dir = = NULL ) {
talloc_free ( run_ctx ) ;
return ENOMEM ;
}
if ( debug_prog ! = NULL ) {
run_ctx - > debug_prog = talloc_strdup ( run_ctx , debug_prog ) ;
if ( run_ctx - > debug_prog = = NULL ) {
talloc_free ( run_ctx ) ;
return ENOMEM ;
}
}
run_ctx - > debug_running = false ;
2017-11-08 11:31:05 +03:00
run_ctx - > queue = tevent_queue_create ( run_ctx , " run event queue " ) ;
if ( run_ctx - > queue = = NULL ) {
talloc_free ( run_ctx ) ;
return ENOMEM ;
}
run_ctx - > monitor_running = false ;
2017-02-23 10:40:48 +03:00
* out = run_ctx ;
return 0 ;
}
static struct run_proc_context *
run_event_run_proc_context ( struct run_event_context * run_ctx )
{
return run_ctx - > run_proc_ctx ;
}
static const char * run_event_script_dir ( struct run_event_context * run_ctx )
{
return run_ctx - > script_dir ;
}
static const char * run_event_debug_prog ( struct run_event_context * run_ctx )
{
return run_ctx - > debug_prog ;
}
2017-11-08 11:31:05 +03:00
static struct tevent_queue * run_event_queue ( struct run_event_context * run_ctx )
{
return run_ctx - > queue ;
}
static void run_event_start_running ( struct run_event_context * run_ctx ,
struct tevent_req * req , bool is_monitor )
{
run_ctx - > current_req = req ;
run_ctx - > monitor_running = is_monitor ;
}
static void run_event_stop_running ( struct run_event_context * run_ctx )
{
run_ctx - > current_req = NULL ;
run_ctx - > monitor_running = false ;
}
static struct tevent_req * run_event_get_running (
struct run_event_context * run_ctx ,
bool * is_monitor )
{
* is_monitor = run_ctx - > monitor_running ;
return run_ctx - > current_req ;
}
2017-02-23 10:40:48 +03:00
static int run_event_script_status ( struct run_event_script * script )
{
int ret ;
if ( script - > result . sig > 0 ) {
ret = - EINTR ;
} else if ( script - > result . err > 0 ) {
if ( script - > result . err = = EACCES ) {
/* Map EACCESS to ENOEXEC */
ret = - ENOEXEC ;
} else {
ret = - script - > result . err ;
}
} else {
ret = script - > result . status ;
}
return ret ;
}
2018-05-10 06:50:01 +03:00
int run_event_list ( struct run_event_context * run_ctx ,
TALLOC_CTX * mem_ctx ,
struct run_event_script_list * * output )
2017-02-23 10:40:48 +03:00
{
2019-05-23 10:51:46 +03:00
struct event_script_list * s_list = NULL ;
struct run_event_script_list * script_list = NULL ;
2019-05-22 14:55:18 +03:00
unsigned int i ;
int ret ;
2017-02-23 10:40:48 +03:00
2018-07-12 06:26:27 +03:00
ret = event_script_get_list ( mem_ctx ,
run_event_script_dir ( run_ctx ) ,
& s_list ) ;
2017-02-23 10:40:48 +03:00
if ( ret ! = 0 ) {
return ret ;
}
2018-07-12 06:26:27 +03:00
if ( s_list - > num_scripts = = 0 ) {
2017-02-23 10:40:48 +03:00
* output = NULL ;
2018-07-12 06:26:27 +03:00
talloc_free ( s_list ) ;
2017-02-23 10:40:48 +03:00
return 0 ;
}
2018-07-12 06:26:27 +03:00
script_list = talloc_zero ( mem_ctx , struct run_event_script_list ) ;
if ( script_list = = NULL ) {
return ENOMEM ;
}
script_list - > num_scripts = s_list - > num_scripts ;
script_list - > script = talloc_zero_array ( script_list ,
struct run_event_script ,
script_list - > num_scripts ) ;
if ( script_list - > script = = NULL ) {
talloc_free ( s_list ) ;
talloc_free ( script_list ) ;
return ENOMEM ;
}
for ( i = 0 ; i < s_list - > num_scripts ; i + + ) {
struct event_script * s = s_list - > script [ i ] ;
2017-02-23 10:40:48 +03:00
struct run_event_script * script = & script_list - > script [ i ] ;
2018-07-12 06:26:27 +03:00
script - > name = talloc_steal ( script_list - > script , s - > name ) ;
2017-02-23 10:40:48 +03:00
2018-07-12 06:26:27 +03:00
if ( ! s - > enabled ) {
2017-02-23 10:40:48 +03:00
script - > summary = - ENOEXEC ;
}
}
2018-07-12 06:26:27 +03:00
talloc_free ( s_list ) ;
2017-02-23 10:40:48 +03:00
* output = script_list ;
return 0 ;
}
int run_event_script_enable ( struct run_event_context * run_ctx ,
const char * script_name )
{
2018-07-12 06:26:27 +03:00
return event_script_chmod ( run_event_script_dir ( run_ctx ) ,
script_name ,
true ) ;
2017-02-23 10:40:48 +03:00
}
int run_event_script_disable ( struct run_event_context * run_ctx ,
const char * script_name )
{
2018-07-12 06:26:27 +03:00
return event_script_chmod ( run_event_script_dir ( run_ctx ) ,
script_name ,
false ) ;
2017-02-23 10:40:48 +03:00
}
/*
* Run debug program to diagnose hung scripts
*/
static int debug_args ( TALLOC_CTX * mem_ctx , const char * path ,
const char * event_str , pid_t pid , const char * * * out )
{
const char * * argv ;
argv = talloc_array ( mem_ctx , const char * , 4 ) ;
if ( argv = = NULL ) {
return ENOMEM ;
}
argv [ 0 ] = path ;
argv [ 1 ] = talloc_asprintf ( argv , " %d " , pid ) ;
argv [ 2 ] = event_str ;
if ( argv [ 1 ] = = NULL ) {
talloc_free ( argv ) ;
return ENOMEM ;
}
argv [ 3 ] = NULL ;
* out = argv ;
return 0 ;
}
static void debug_log ( int loglevel , const char * output , const char * log_prefix )
{
char * line , * s ;
s = strdup ( output ) ;
if ( s = = NULL ) {
DEBUG ( loglevel , ( " %s: %s \n " , log_prefix , output ) ) ;
return ;
}
line = strtok ( s , " \n " ) ;
while ( line ! = NULL ) {
DEBUG ( loglevel , ( " %s: %s \n " , log_prefix , line ) ) ;
line = strtok ( NULL , " \n " ) ;
}
free ( s ) ;
}
struct run_debug_state {
struct run_event_context * run_ctx ;
pid_t pid ;
} ;
static void run_debug_done ( struct tevent_req * subreq ) ;
static struct tevent_req * run_debug_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct run_event_context * run_ctx ,
const char * event_str , pid_t pid )
{
struct tevent_req * req , * subreq ;
struct run_debug_state * state ;
const char * * argv ;
const char * debug_prog ;
int ret ;
req = tevent_req_create ( mem_ctx , & state , struct run_debug_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > run_ctx = run_ctx ;
state - > pid = pid ;
debug_prog = run_event_debug_prog ( run_ctx ) ;
if ( debug_prog = = NULL ) {
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
if ( run_ctx - > debug_running ) {
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
if ( pid = = - 1 ) {
D_DEBUG ( " Event script terminated, nothing to debug \n " ) ;
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
ret = debug_args ( state , debug_prog , event_str , pid , & argv ) ;
if ( ret ! = 0 ) {
D_ERR ( " debug_args() failed \n " ) ;
tevent_req_error ( req , ret ) ;
return tevent_req_post ( req , ev ) ;
}
D_DEBUG ( " Running debug %s with args \" %s %s \" \n " ,
debug_prog , argv [ 1 ] , argv [ 2 ] ) ;
subreq = run_proc_send ( state , ev , run_event_run_proc_context ( run_ctx ) ,
debug_prog , argv , - 1 , tevent_timeval_zero ( ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , run_debug_done , req ) ;
run_ctx - > debug_running = true ;
talloc_free ( argv ) ;
return req ;
}
static void run_debug_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct run_debug_state * state = tevent_req_data (
req , struct run_debug_state ) ;
char * output ;
int ret ;
bool status ;
state - > run_ctx - > debug_running = false ;
status = run_proc_recv ( subreq , & ret , NULL , NULL , state , & output ) ;
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
D_ERR ( " Running debug failed, ret=%d \n " , ret ) ;
}
/* Log output */
if ( output ! = NULL ) {
debug_log ( DEBUG_ERR , output , " event_debug " ) ;
talloc_free ( output ) ;
}
kill ( - state - > pid , SIGTERM ) ;
tevent_req_done ( req ) ;
}
static bool run_debug_recv ( struct tevent_req * req , int * perr )
{
int ret ;
if ( tevent_req_is_unix_error ( req , & ret ) ) {
if ( perr ! = NULL ) {
* perr = ret ;
}
return false ;
}
return true ;
}
/*
* Run a single event
*/
struct run_event_state {
struct tevent_context * ev ;
struct run_event_context * run_ctx ;
const char * event_str ;
2017-11-08 11:31:05 +03:00
const char * arg_str ;
2017-02-23 10:40:48 +03:00
struct timeval timeout ;
2018-05-17 06:32:37 +03:00
bool continue_on_failure ;
2017-02-23 10:40:48 +03:00
struct run_event_script_list * script_list ;
const char * * argv ;
2017-11-08 11:31:05 +03:00
struct tevent_req * script_subreq ;
2019-06-24 09:42:21 +03:00
unsigned int index ;
2017-11-08 11:31:05 +03:00
bool cancelled ;
2017-02-23 10:40:48 +03:00
} ;
2017-11-08 11:31:05 +03:00
static void run_event_cancel ( struct tevent_req * req ) ;
static void run_event_trigger ( struct tevent_req * req , void * private_data ) ;
2017-02-23 10:40:48 +03:00
static struct tevent_req * run_event_run_script ( struct tevent_req * req ) ;
static void run_event_next_script ( struct tevent_req * subreq ) ;
static void run_event_debug ( struct tevent_req * req , pid_t pid ) ;
static void run_event_debug_done ( struct tevent_req * subreq ) ;
struct tevent_req * run_event_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct run_event_context * run_ctx ,
const char * event_str ,
const char * arg_str ,
2018-05-17 06:32:37 +03:00
struct timeval timeout ,
bool continue_on_failure )
2017-02-23 10:40:48 +03:00
{
2017-11-08 11:31:05 +03:00
struct tevent_req * req , * current_req ;
2017-02-23 10:40:48 +03:00
struct run_event_state * state ;
2017-11-08 11:31:05 +03:00
bool monitor_running , status ;
2017-02-23 10:40:48 +03:00
req = tevent_req_create ( mem_ctx , & state , struct run_event_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > run_ctx = run_ctx ;
state - > event_str = talloc_strdup ( state , event_str ) ;
if ( tevent_req_nomem ( state - > event_str , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2017-11-08 11:31:05 +03:00
if ( arg_str ! = NULL ) {
state - > arg_str = talloc_strdup ( state , arg_str ) ;
if ( tevent_req_nomem ( state - > arg_str , req ) ) {
return tevent_req_post ( req , ev ) ;
}
}
2017-02-23 10:40:48 +03:00
state - > timeout = timeout ;
2018-05-17 06:32:37 +03:00
state - > continue_on_failure = continue_on_failure ;
2017-11-08 11:31:05 +03:00
state - > cancelled = false ;
2018-05-10 05:43:24 +03:00
state - > script_list = talloc_zero ( state , struct run_event_script_list ) ;
if ( tevent_req_nomem ( state - > script_list , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2017-11-08 11:31:05 +03:00
/*
* If monitor event is running ,
* cancel the running monitor event and run new event
*
* If any other event is running ,
* if new event is monitor , cancel that event
* else add new event to the queue
*/
current_req = run_event_get_running ( run_ctx , & monitor_running ) ;
if ( current_req ! = NULL ) {
if ( monitor_running ) {
run_event_cancel ( current_req ) ;
} else if ( strcmp ( event_str , " monitor " ) = = 0 ) {
state - > script_list - > summary = - ECANCELED ;
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
}
status = tevent_queue_add ( run_event_queue ( run_ctx ) , ev , req ,
run_event_trigger , NULL ) ;
if ( ! status ) {
tevent_req_error ( req , ENOMEM ) ;
return tevent_req_post ( req , ev ) ;
}
return req ;
}
2017-02-23 10:40:48 +03:00
2017-11-08 11:31:05 +03:00
static void run_event_cancel ( struct tevent_req * req )
{
struct run_event_state * state = tevent_req_data (
req , struct run_event_state ) ;
run_event_stop_running ( state - > run_ctx ) ;
state - > script_list - > summary = - ECANCELED ;
state - > cancelled = true ;
TALLOC_FREE ( state - > script_subreq ) ;
tevent_req_done ( req ) ;
}
static void run_event_trigger ( struct tevent_req * req , void * private_data )
{
struct tevent_req * subreq ;
struct run_event_state * state = tevent_req_data (
req , struct run_event_state ) ;
2018-05-10 05:43:24 +03:00
struct run_event_script_list * script_list ;
2017-11-08 11:31:05 +03:00
int ret ;
bool is_monitor = false ;
D_DEBUG ( " Running event %s with args \" %s \" \n " , state - > event_str ,
state - > arg_str = = NULL ? " (null) " : state - > arg_str ) ;
2018-05-10 05:43:24 +03:00
ret = get_script_list ( state ,
run_event_script_dir ( state - > run_ctx ) ,
& script_list ) ;
2017-02-23 10:40:48 +03:00
if ( ret ! = 0 ) {
D_ERR ( " get_script_list() failed, ret=%d \n " , ret ) ;
tevent_req_error ( req , ret ) ;
2017-11-08 11:31:05 +03:00
return ;
2017-02-23 10:40:48 +03:00
}
/* No scripts */
2018-05-10 05:43:24 +03:00
if ( script_list = = NULL | | script_list - > num_scripts = = 0 ) {
2017-02-23 10:40:48 +03:00
tevent_req_done ( req ) ;
2017-11-08 11:31:05 +03:00
return ;
2017-02-23 10:40:48 +03:00
}
2018-05-10 05:43:24 +03:00
talloc_free ( state - > script_list ) ;
state - > script_list = script_list ;
2017-11-08 11:31:05 +03:00
ret = script_args ( state , state - > event_str , state - > arg_str ,
& state - > argv ) ;
2017-02-23 10:40:48 +03:00
if ( ret ! = 0 ) {
D_ERR ( " script_args() failed, ret=%d \n " , ret ) ;
tevent_req_error ( req , ret ) ;
2017-11-08 11:31:05 +03:00
return ;
2017-02-23 10:40:48 +03:00
}
state - > index = 0 ;
subreq = run_event_run_script ( req ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
2017-11-08 11:31:05 +03:00
return ;
2017-02-23 10:40:48 +03:00
}
tevent_req_set_callback ( subreq , run_event_next_script , req ) ;
2017-11-08 11:31:05 +03:00
state - > script_subreq = subreq ;
if ( strcmp ( state - > event_str , " monitor " ) = = 0 ) {
is_monitor = true ;
}
run_event_start_running ( state - > run_ctx , req , is_monitor ) ;
2017-02-23 10:40:48 +03:00
}
static struct tevent_req * run_event_run_script ( struct tevent_req * req )
{
struct run_event_state * state = tevent_req_data (
req , struct run_event_state ) ;
struct run_event_script * script ;
struct tevent_req * subreq ;
char * path ;
script = & state - > script_list - > script [ state - > index ] ;
2018-05-15 11:36:29 +03:00
path = talloc_asprintf ( state , " %s/%s.script " ,
2017-02-23 10:40:48 +03:00
run_event_script_dir ( state - > run_ctx ) ,
script - > name ) ;
if ( path = = NULL ) {
return NULL ;
}
state - > argv [ 0 ] = script - > name ;
script - > begin = tevent_timeval_current ( ) ;
D_DEBUG ( " Running %s with args \" %s %s \" \n " ,
path , state - > argv [ 0 ] , state - > argv [ 1 ] ) ;
subreq = run_proc_send ( state , state - > ev ,
run_event_run_proc_context ( state - > run_ctx ) ,
path , state - > argv , - 1 , state - > timeout ) ;
talloc_free ( path ) ;
return subreq ;
}
static void run_event_next_script ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct run_event_state * state = tevent_req_data (
req , struct run_event_state ) ;
struct run_event_script * script ;
pid_t pid ;
int ret ;
bool status ;
script = & state - > script_list - > script [ state - > index ] ;
script - > end = tevent_timeval_current ( ) ;
status = run_proc_recv ( subreq , & ret , & script - > result , & pid ,
state - > script_list , & script - > output ) ;
TALLOC_FREE ( subreq ) ;
2017-11-08 11:31:05 +03:00
state - > script_subreq = NULL ;
2017-02-23 10:40:48 +03:00
if ( ! status ) {
D_ERR ( " run_proc failed for %s, ret=%d \n " , script - > name , ret ) ;
2018-05-10 11:49:06 +03:00
run_event_stop_running ( state - > run_ctx ) ;
2017-02-23 10:40:48 +03:00
tevent_req_error ( req , ret ) ;
return ;
}
2017-11-08 11:31:05 +03:00
if ( state - > cancelled ) {
return ;
}
2017-02-23 10:40:48 +03:00
/* Log output */
if ( script - > output ! = NULL ) {
debug_log ( DEBUG_ERR , script - > output , script - > name ) ;
}
D_DEBUG ( " Script %s finished sig=%d, err=%d, status=%d \n " ,
script - > name , script - > result . sig , script - > result . err ,
script - > result . status ) ;
/* If a script fails, stop running */
script - > summary = run_event_script_status ( script ) ;
if ( script - > summary ! = 0 & & script - > summary ! = - ENOEXEC ) {
state - > script_list - > summary = script - > summary ;
2018-05-17 06:32:37 +03:00
if ( ! state - > continue_on_failure ) {
state - > script_list - > num_scripts = state - > index + 1 ;
2018-07-10 11:19:09 +03:00
if ( script - > summary = = - ETIMEDOUT & & pid ! = - 1 ) {
2018-05-17 06:32:37 +03:00
run_event_debug ( req , pid ) ;
}
D_NOTICE ( " %s event %s \n " , state - > event_str ,
2018-07-10 11:19:09 +03:00
( script - > summary = = - ETIMEDOUT ) ?
2018-05-17 06:32:37 +03:00
" timed out " :
" failed " ) ;
run_event_stop_running ( state - > run_ctx ) ;
tevent_req_done ( req ) ;
return ;
}
2017-02-23 10:40:48 +03:00
}
state - > index + = 1 ;
/* All scripts executed */
if ( state - > index > = state - > script_list - > num_scripts ) {
2017-11-08 11:31:05 +03:00
run_event_stop_running ( state - > run_ctx ) ;
2017-02-23 10:40:48 +03:00
tevent_req_done ( req ) ;
return ;
}
subreq = run_event_run_script ( req ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , run_event_next_script , req ) ;
2017-11-08 11:31:05 +03:00
state - > script_subreq = subreq ;
2017-02-23 10:40:48 +03:00
}
static void run_event_debug ( struct tevent_req * req , pid_t pid )
{
struct run_event_state * state = tevent_req_data (
req , struct run_event_state ) ;
struct tevent_req * subreq ;
/* Debug script is run with ectx as the memory context */
subreq = run_debug_send ( state - > run_ctx , state - > ev , state - > run_ctx ,
state - > event_str , pid ) ;
if ( subreq = = NULL ) {
/* If run debug fails, it's not an error */
D_NOTICE ( " Failed to run event debug \n " ) ;
return ;
}
tevent_req_set_callback ( subreq , run_event_debug_done , NULL ) ;
}
static void run_event_debug_done ( struct tevent_req * subreq )
{
int ret = 0 ;
bool status ;
status = run_debug_recv ( subreq , & ret ) ;
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
D_NOTICE ( " run_debug() failed, ret=%d \n " , ret ) ;
}
}
bool run_event_recv ( struct tevent_req * req , int * perr ,
TALLOC_CTX * mem_ctx ,
struct run_event_script_list * * script_list )
{
struct run_event_state * state = tevent_req_data (
req , struct run_event_state ) ;
int ret ;
if ( tevent_req_is_unix_error ( req , & ret ) ) {
if ( perr ! = NULL ) {
* perr = ret ;
}
return false ;
}
if ( script_list ! = NULL ) {
* script_list = talloc_steal ( mem_ctx , state - > script_list ) ;
}
return true ;
}