LCOV - code coverage report
Current view: top level - app/shared_dev/commands/configure - kill.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 247 0.0 %
Date: 2026-08-12 04:54:43 Functions: 0 13 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "../../../shared/commands/configure/configure.h"
       3             : 
       4             : #include <errno.h>
       5             : #include <stdlib.h> /* strtoul */
       6             : #include <unistd.h>
       7             : #include <stdio.h>
       8             : #include <dirent.h>
       9             : #include <signal.h>
      10             : #include <fcntl.h>
      11             : #include <pthread.h>
      12             : #include <sys/stat.h>
      13             : #include <sys/types.h>
      14             : 
      15           0 : #define NAME "kill"
      16             : 
      17             : static void
      18             : init_perm( fd_cap_chk_t *   chk,
      19           0 :            config_t const * config FD_PARAM_UNUSED ) {
      20           0 :   fd_cap_chk_root( chk, NAME, "check all open file descriptors in `/proc/`" );
      21           0 : }
      22             : 
      23             : static void
      24             : cmdline( char * buf,
      25             :          size_t len,
      26           0 :          ulong  pid ) {
      27           0 :   char path[ PATH_MAX ];
      28           0 :   FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/proc/%lu/cmdline", pid ) );
      29             : 
      30           0 :   FILE * fp = fopen( path, "r" );
      31           0 :   if( FD_UNLIKELY( !fp && errno==ENOENT ) ) {
      32           0 :     buf[ 0 ] = '\0';
      33           0 :     return;
      34           0 :   }
      35           0 :   if( FD_UNLIKELY( !fp ) ) FD_LOG_ERR(( "error opening `/proc/%lu/cmdline` (%i-%s)", pid, errno, fd_io_strerror( errno ) ));
      36             : 
      37           0 :   ulong read = fread( buf, 1, len - 1, fp );
      38           0 :   if( FD_UNLIKELY( ferror( fp ) ) ) FD_LOG_ERR(( "error reading `/proc/%lu/cmdline` (%i-%s)", pid, errno, fd_io_strerror( errno ) ));
      39           0 :   if( FD_UNLIKELY( fclose( fp ) ) ) FD_LOG_ERR(( "error closing `/proc/%lu/cmdline` (%i-%s)", pid, errno, fd_io_strerror( errno ) ));
      40             : 
      41           0 :   buf[ read ] = '\0';
      42           0 : }
      43             : 
      44             : /* hugetlb_kib returns the process's HugetlbPages: usage from
      45             :    /proc/<pid>/status (cheap counter read, no page table walk), or
      46             :    ULONG_MAX if the field is missing.  Both hugetlbfs file mappings
      47             :    (workspaces) and anonymous MAP_HUGETLB pages count toward it, so a
      48             :    zero here proves the expensive maps/numa_maps scans can be
      49             :    skipped. */
      50             : 
      51             : static ulong
      52           0 : hugetlb_kib( ulong pid ) {
      53           0 :   char path[ PATH_MAX ];
      54           0 :   FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/proc/%lu/status", pid ) );
      55             : 
      56           0 :   int fd = open( path, O_RDONLY|O_CLOEXEC );
      57           0 :   if( FD_UNLIKELY( -1==fd && errno==ENOENT ) ) return 0UL;
      58           0 :   if( FD_UNLIKELY( -1==fd ) ) FD_LOG_ERR(( "error opening `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      59             : 
      60             :   /* status is small (~1.5 KiB); one read gets it all */
      61           0 :   char buf[ 4096 ];
      62           0 :   long sz;
      63           0 :   do {
      64           0 :     sz = read( fd, buf, sizeof(buf)-1UL );
      65           0 :   }while( FD_UNLIKELY( -1L==sz && errno==EINTR ) );
      66           0 :   if( FD_UNLIKELY( sz<0L ) ) FD_LOG_ERR(( "error reading `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      67           0 :   if( FD_UNLIKELY( -1==close( fd ) ) ) FD_LOG_ERR(( "error closing `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      68           0 :   buf[ sz ] = '\0';
      69             : 
      70           0 :   char const * line = strstr( buf, "\nHugetlbPages:" );
      71           0 :   if( FD_UNLIKELY( !line ) ) return ULONG_MAX;
      72           0 :   return strtoul( line+14UL, NULL, 10 );
      73           0 : }
      74             : 
      75             : /* proc_start_time reads /proc/<pid>/stat field 22 (starttime, clock
      76             :    ticks since boot), 0 if the process is gone.  (pid, starttime)
      77             :    uniquely identifies a process; pids alone recycle.  stat is world
      78             :    readable except under hidepid, where a 0 would silently skip the
      79             :    process; fail loudly instead (like every other /proc error here).
      80             :    The comm field can contain spaces and parens, so parse from the
      81             :    last ')'. */
      82             : 
      83             : static ulong
      84           0 : proc_start_time( ulong pid ) {
      85           0 :   char path[ PATH_MAX ];
      86           0 :   FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/proc/%lu/stat", pid ) );
      87             : 
      88           0 :   char buf[ 4096 ];
      89           0 :   int fd = open( path, O_RDONLY|O_CLOEXEC );
      90           0 :   if( FD_UNLIKELY( -1==fd && (errno==EACCES || errno==EPERM) ) )
      91           0 :     FD_LOG_ERR(( "error opening `%s` (%i-%s); /proc is restricted (hidepid?), run as root", path, errno, fd_io_strerror( errno ) ));
      92           0 :   if( FD_UNLIKELY( -1==fd ) ) return 0UL;
      93           0 :   long sz;
      94           0 :   do sz = read( fd, buf, sizeof(buf)-1UL ); while( FD_UNLIKELY( -1L==sz && errno==EINTR ) );
      95           0 :   if( FD_UNLIKELY( -1==close( fd ) ) ) FD_LOG_ERR(( "error closing `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      96           0 :   if( FD_UNLIKELY( sz<=0L ) ) return 0UL;
      97           0 :   buf[ sz ] = '\0';
      98             : 
      99           0 :   char * p = strrchr( buf, ')' );
     100           0 :   if( FD_UNLIKELY( !p ) ) return 0UL;
     101             : 
     102           0 :   ulong start_time = 0UL;
     103           0 :   if( FD_UNLIKELY( 1!=sscanf( p+1UL, " %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %lu", &start_time ) ) ) return 0UL;
     104           0 :   return start_time;
     105           0 : }
     106             : 
     107           0 : #define KILL_NO                ( 0)
     108           0 : #define KILL_IS_FDDEV          (-1)
     109           0 : #define KILL_IS_FDCTL          (-2)
     110           0 : #define KILL_IS_FIREDANCER     (-3)
     111           0 : #define KILL_IS_FIREDANCER_DEV (-4)
     112           0 : #define KILL_HAS_WORKSPACE_FD  (-5)
     113           0 : #define KILL_HAS_HUGEPAGES     (-6)
     114           0 : #define KILL_CANT_INSPECT      (-7) /* check ran unprivileged; init (as root) decides */
     115             : 
     116             : static char const *
     117           0 : kill_reason( int err ) {
     118           0 :   switch( err ) {
     119           0 :     case KILL_IS_FDDEV:          return "is fddev";
     120           0 :     case KILL_IS_FDCTL:          return "is fdctl";
     121           0 :     case KILL_IS_FIREDANCER:     return "is firedancer";
     122           0 :     case KILL_IS_FIREDANCER_DEV: return "is firedancer-dev";
     123           0 :     case KILL_HAS_WORKSPACE_FD:  return "has a workspace file descriptor open";
     124           0 :     case KILL_HAS_HUGEPAGES:     return "has anonymous hugepages mapped";
     125           0 :     case KILL_CANT_INSPECT:      return "cannot be inspected without root";
     126           0 :     default: FD_LOG_ERR(( "unexpected error code" ));
     127           0 :   }
     128           0 : }
     129             : 
     130             : static int
     131           0 : check_binary( ulong pid ) {
     132             :   /* Match the executable name via one readlink rather than reading
     133             :      /proc/<pid>/cmdline for every process. */
     134           0 :   char exe_path[ PATH_MAX ];
     135           0 :   FD_TEST( fd_cstr_printf_check( exe_path, PATH_MAX, NULL, "/proc/%lu/exe", pid ) );
     136           0 :   char exe[ PATH_MAX ];
     137           0 :   long exe_len = readlink( exe_path, exe, PATH_MAX-1UL );
     138           0 :   if( FD_UNLIKELY( exe_len<0L && errno==EACCES ) ) {
     139             :     /* Unprivileged check of another user's process: exe is protected
     140             :        but cmdline is world-readable; match its suffix like the
     141             :        historical scan. */
     142           0 :     char proc_cmdline[ PATH_MAX ];
     143           0 :     cmdline( proc_cmdline, PATH_MAX, pid );
     144           0 :     ulong cmdline_len = strlen( proc_cmdline );
     145           0 :     exe_len = (long)fd_ulong_min( cmdline_len, PATH_MAX-1UL );
     146           0 :     fd_memcpy( exe, proc_cmdline, (ulong)exe_len );
     147           0 :   } else if( FD_UNLIKELY( exe_len<0L ) ) {
     148           0 :     return KILL_NO; /* kernel thread or gone */
     149           0 :   }
     150           0 :   exe[ exe_len ] = '\0';
     151             :   /* An overwritten binary reads "/path/binary (deleted)" */
     152           0 :   if( FD_UNLIKELY( exe_len>=10L && !strcmp( exe+exe_len-10L, " (deleted)" ) ) ) exe[ exe_len-10L ] = '\0';
     153           0 :   char const * base = strrchr( exe, '/' );
     154           0 :   base = base ? base+1UL : exe;
     155             : 
     156           0 :   static char const * binaries[] = { "fddev",       "fdctl",       "firedancer",       "firedancer-dev"       };
     157           0 :   static int const    errors[]   = { KILL_IS_FDDEV, KILL_IS_FDCTL, KILL_IS_FIREDANCER, KILL_IS_FIREDANCER_DEV };
     158           0 :   for( ulong i=0UL; i<sizeof(binaries)/sizeof(binaries[0]); i++ ) {
     159           0 :     if( FD_UNLIKELY( !strcmp( base, binaries[ i ] ) ) ) return errors[ i ];
     160           0 :   }
     161           0 :   return KILL_NO;
     162           0 : }
     163             : 
     164             : static int
     165             : check_hugepages( config_t const * config,
     166           0 :                  ulong            pid ) {
     167             :   /* No hugetlb usage -> cannot hold a workspace mapping or anonymous
     168             :      hugepages, skip the expensive maps scan. */
     169           0 :   if( FD_LIKELY( !hugetlb_kib( pid ) ) ) return KILL_NO;
     170             : 
     171           0 :   int result = KILL_NO;
     172             : 
     173           0 :   char path[ PATH_MAX ];
     174           0 :   FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/proc/%lu/maps", pid ) );
     175           0 :   FILE * fp = fopen( path, "r" );
     176           0 :   if( FD_UNLIKELY( !fp && errno==ENOENT ) ) return KILL_NO;
     177           0 :   else if( FD_UNLIKELY( !fp && errno==EACCES ) ) return KILL_CANT_INSPECT; /* unprivileged check; hugetlb user needs root inspection */
     178           0 :   else if( FD_UNLIKELY( !fp ) ) FD_LOG_ERR(( "error opening `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
     179             : 
     180           0 :   int maybe_huge = 0;
     181           0 :   char line[ 4096 ];
     182           0 :   while( FD_LIKELY( fgets( line, 4096, fp ) ) ) {
     183           0 :     if( FD_UNLIKELY( strlen( line ) == 4095 ) ) FD_LOG_ERR(( "line too long in `%s`", path ));
     184           0 :     if( FD_UNLIKELY( strstr( line, config->hugetlbfs.gigantic_page_mount_path ) ||
     185           0 :                       strstr( line, config->hugetlbfs.huge_page_mount_path ) ) ) {
     186           0 :       result = KILL_HAS_WORKSPACE_FD;
     187           0 :       break;
     188           0 :     }
     189             : 
     190           0 :     if( FD_UNLIKELY( strstr( line, "anon_hugepage" ) || strstr( line, "memfd:" ) ) ) maybe_huge = 1;
     191           0 :   }
     192           0 :   if( FD_UNLIKELY( ferror( fp ) ) )
     193           0 :     FD_LOG_ERR(( "error reading `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
     194           0 :   if( FD_LIKELY( fclose( fp ) ) )
     195           0 :     FD_LOG_ERR(( "error closing `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
     196             : 
     197           0 :   if( FD_UNLIKELY( result ) ) return result;
     198             : 
     199             :   /* No hugepage mappings in maps -> cannot have anonymous hugepages, so
     200             :      skip the expensive numa_maps read entirely. */
     201           0 :   if( FD_LIKELY( !maybe_huge ) ) return KILL_NO;
     202             : 
     203           0 :   FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/proc/%lu/numa_maps", pid ) );
     204           0 :   fp = fopen( path, "r" );
     205           0 :   if( FD_UNLIKELY( !fp && errno==ENOENT ) ) return KILL_NO;
     206           0 :   else if( FD_UNLIKELY( !fp ) ) FD_LOG_ERR(( "error opening `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
     207             : 
     208           0 :   while( FD_LIKELY( fgets( line, 4096, fp ) ) ) {
     209           0 :     if( FD_UNLIKELY( strlen( line ) == 4095 ) ) FD_LOG_ERR(( "line too long in `%s`", path ));
     210           0 :     if( FD_UNLIKELY( strstr( line, "huge" ) && strstr( line, "anon" ) ) ) {
     211           0 :       result = KILL_HAS_HUGEPAGES;
     212           0 :       break;
     213           0 :     }
     214           0 :   }
     215           0 :   if( FD_UNLIKELY( ferror( fp ) ) )
     216           0 :     FD_LOG_ERR(( "error reading `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
     217           0 :   if( FD_LIKELY( fclose( fp ) ) )
     218           0 :     FD_LOG_ERR(( "error closing `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
     219             : 
     220           0 :   return result;
     221           0 : }
     222             : 
     223             : static int
     224             : check_kill( config_t const * config,
     225           0 :             ulong            pid ) {
     226           0 :   int err = check_binary( pid );
     227           0 :   if( FD_UNLIKELY( err ) ) return err;
     228           0 :   return check_hugepages( config, pid );
     229           0 : }
     230             : 
     231             : static void
     232             : wait_dead( long  started,
     233             :            ulong pid,
     234           0 :            ulong start_time ) {
     235             :   /* We need to do this to prevent a race condition, since kill(SIGKILL) returns
     236             :      before the kernel actually terminates and reclaims the resources from the
     237             :      process.  A task blocked in an uninterruptible syscall (e.g. an
     238             :      fsync queued behind heavy writeback) does not die until the
     239             :      syscall completes, which can take seconds. */
     240           0 :   int notified = 0;
     241           0 :   while( 1 ) {
     242             :     /* starttime mismatch means the pid was recycled: ours is dead */
     243           0 :     if( FD_LIKELY( proc_start_time( pid )!=start_time ) ) return;
     244             : 
     245           0 :     long waited = fd_log_wallclock() - started;
     246           0 :     if( FD_UNLIKELY( waited>=(long)1e9 && !notified ) ) {
     247           0 :       FD_LOG_WARNING(( "waiting for killed process to exit %s(blocked in uninterruptible disk I/O)%s", fd_log_style_dim(), fd_log_style_normal() ));
     248           0 :       notified = 1;
     249           0 :     }
     250           0 :     if( FD_UNLIKELY( waited >= (long)5e9 ) ) FD_LOG_ERR(( "waited too long for process to exit" ));
     251           0 :   }
     252           0 : }
     253             : 
     254           0 : #define SCAN_THREADS  (16UL)
     255             : #define SCAN_PIDS_MAX (65536UL)
     256             : #define MATCHED_MAX   (1024UL)
     257             : 
     258             : struct kill_scan {
     259             :   config_t const * config;
     260             :   ulong const *    pids;
     261             :   ulong            pid_cnt;
     262             :   ulong            idx;      /* this worker's stride offset */
     263             :   ulong            matched      [ MATCHED_MAX ];
     264             :   ulong            matched_start[ MATCHED_MAX ];
     265             :   int              match_err    [ MATCHED_MAX ];
     266             :   ulong            matched_cnt;
     267             : };
     268             : 
     269             : static void *
     270           0 : kill_scan_thread( void * arg ) {
     271           0 :   struct kill_scan * scan = arg;
     272           0 :   for( ulong i=scan->idx; i<scan->pid_cnt; i+=SCAN_THREADS ) {
     273             :     /* Bind identity before inspecting: (pid, starttime) is unique,
     274             :        pids recycle.  0 (gone) drops the match, sidestepping reuse. */
     275           0 :     ulong start_time = proc_start_time( scan->pids[ i ] );
     276           0 :     if( FD_UNLIKELY( !start_time ) ) continue;
     277           0 :     int err = check_kill( scan->config, scan->pids[ i ] );
     278           0 :     if( FD_UNLIKELY( err ) ) {
     279           0 :       if( FD_UNLIKELY( scan->matched_cnt==MATCHED_MAX ) ) FD_LOG_ERR(( "too many processes to kill" ));
     280           0 :       scan->match_err    [ scan->matched_cnt ] = err;
     281           0 :       scan->matched_start[ scan->matched_cnt ] = start_time;
     282           0 :       scan->matched      [ scan->matched_cnt++ ] = scan->pids[ i ];
     283           0 :     }
     284           0 :   }
     285           0 :   return NULL;
     286           0 : }
     287             : 
     288             : /* kill_scan runs check_kill over every pid in /proc on SCAN_THREADS
     289             :    threads (the per-process checks are independent kernel reads).
     290             :    Writes up to MATCHED_MAX (pid, starttime, reason) triples; returns
     291             :    the count. */
     292             : 
     293             : static ulong
     294             : kill_scan( config_t const * config,
     295             :            ulong            matched[ static MATCHED_MAX ],
     296             :            ulong            matched_start[ static MATCHED_MAX ],
     297           0 :            int              match_err[ static MATCHED_MAX ] ) {
     298           0 :   DIR * dir = opendir( "/proc" );
     299           0 :   if( FD_UNLIKELY( !dir ) ) FD_LOG_ERR(( "error opening `/proc` (%i-%s)", errno, fd_io_strerror( errno ) ));
     300             : 
     301           0 :   static ulong pids[ SCAN_PIDS_MAX ];
     302           0 :   ulong matched_cnt = 0UL;
     303             : 
     304           0 :   int done = 0;
     305           0 :   while( !done ) {
     306           0 :     ulong pid_cnt = 0UL;
     307           0 :     for(;;) {
     308           0 :       errno = 0;
     309           0 :       struct dirent * entry = readdir( dir );
     310           0 :       if( FD_UNLIKELY( !entry ) ) { done = 1; break; }
     311           0 :       if( FD_UNLIKELY( entry->d_name[0] == '.' ) ) continue;
     312           0 :       char * endptr;
     313           0 :       ulong pid = strtoul( entry->d_name, &endptr, 10 );
     314           0 :       if( FD_UNLIKELY( *endptr || pid==(ulong)getpid() ) ) continue;
     315           0 :       pids[ pid_cnt++ ] = pid;
     316           0 :       if( FD_UNLIKELY( pid_cnt==SCAN_PIDS_MAX ) ) break;
     317           0 :     }
     318           0 :     if( FD_UNLIKELY( errno ) ) FD_LOG_ERR(( "readdir() (%i-%s)", errno, fd_io_strerror( errno ) ));
     319           0 :     if( FD_UNLIKELY( !pid_cnt ) ) break;
     320             : 
     321           0 :     static struct kill_scan scans[ SCAN_THREADS ];
     322           0 :     pthread_t threads[ SCAN_THREADS ];
     323           0 :     for( ulong t=0UL; t<SCAN_THREADS; t++ ) {
     324             :       /* Scalars only: a struct assignment would memset the ~20 KiB
     325             :          match arrays per thread per batch for nothing (matched_cnt
     326             :          bounds all reads). */
     327           0 :       scans[ t ].config      = config;
     328           0 :       scans[ t ].pids        = pids;
     329           0 :       scans[ t ].pid_cnt     = pid_cnt;
     330           0 :       scans[ t ].idx         = t;
     331           0 :       scans[ t ].matched_cnt = 0UL;
     332           0 :       if( FD_UNLIKELY( pthread_create( &threads[ t ], NULL, kill_scan_thread, &scans[ t ] ) ) ) FD_LOG_ERR(( "pthread_create failed" ));
     333           0 :     }
     334             : 
     335           0 :     for( ulong t=0UL; t<SCAN_THREADS; t++ ) {
     336           0 :       if( FD_UNLIKELY( pthread_join( threads[ t ], NULL ) ) ) FD_LOG_ERR(( "pthread_join failed" ));
     337           0 :       for( ulong i=0UL; i<scans[ t ].matched_cnt; i++ ) {
     338           0 :         if( FD_UNLIKELY( matched_cnt==MATCHED_MAX ) ) FD_LOG_ERR(( "too many processes to kill" ));
     339           0 :         match_err    [ matched_cnt ] = scans[ t ].match_err    [ i ];
     340           0 :         matched_start[ matched_cnt ] = scans[ t ].matched_start[ i ];
     341           0 :         matched      [ matched_cnt++ ] = scans[ t ].matched    [ i ];
     342           0 :       }
     343           0 :     }
     344           0 :   }
     345             : 
     346           0 :   if( FD_UNLIKELY( -1==closedir( dir ) ) ) FD_LOG_ERR(( "closedir (%i-%s)", errno, fd_io_strerror( errno ) ));
     347           0 :   return matched_cnt;
     348           0 : }
     349             : 
     350             : static void
     351           0 : init( config_t const * config ) {
     352           0 :   ulong matched[ MATCHED_MAX ];
     353           0 :   ulong matched_start[ MATCHED_MAX ];
     354           0 :   int   match_err[ MATCHED_MAX ];
     355           0 :   ulong matched_cnt = kill_scan( config, matched, matched_start, match_err );
     356             : 
     357           0 :   for( ulong i=0UL; i<matched_cnt; i++ ) {
     358             :     /* Revalidate identity right before the signal: if the pid was
     359             :        recycled since the scan, the new owner is not our target. */
     360           0 :     if( FD_UNLIKELY( proc_start_time( matched[ i ] )!=matched_start[ i ] ) ) continue;
     361           0 :     char proc_cmdline[ PATH_MAX ];
     362           0 :     cmdline( proc_cmdline, PATH_MAX, matched[ i ] );
     363           0 :     FD_LOG_NOTICE(( "killing process `%s` (%lu): %s", proc_cmdline, matched[ i ], kill_reason( match_err[ i ] ) ));
     364           0 :     if( FD_UNLIKELY( -1==kill( (int)matched[ i ], SIGKILL ) && errno!=ESRCH ) ) FD_LOG_ERR(( "kill failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     365           0 :   }
     366             : 
     367           0 :   long started = fd_log_wallclock();
     368           0 :   for( ulong i=0; i<matched_cnt; i++ ) wait_dead( started, matched[ i ], matched_start[ i ] );
     369           0 : }
     370             : 
     371             : static configure_result_t
     372             : check( config_t const * config,
     373           0 :        int              check_type FD_PARAM_UNUSED ) {
     374           0 :   ulong matched[ MATCHED_MAX ];
     375           0 :   ulong matched_start[ MATCHED_MAX ];
     376           0 :   int   match_err[ MATCHED_MAX ];
     377           0 :   ulong matched_cnt = kill_scan( config, matched, matched_start, match_err );
     378             : 
     379           0 :   if( FD_UNLIKELY( matched_cnt ) ) {
     380           0 :     char proc_cmdline[ PATH_MAX ];
     381           0 :     cmdline( proc_cmdline, PATH_MAX, matched[ 0 ] );
     382           0 :     NOT_CONFIGURED( "process `%s` (%lu) %s", proc_cmdline, matched[ 0 ], kill_reason( match_err[ 0 ] ) );
     383           0 :   }
     384             : 
     385           0 :   CONFIGURE_OK();
     386           0 : }
     387             : 
     388             : configure_stage_t fd_cfg_stage_kill = {
     389             :   .name            = NAME,
     390             :   .always_recreate = 0,
     391             :   .enabled         = NULL,
     392             :   .init_perm       = init_perm,
     393             :   .fini_perm       = NULL,
     394             :   .init            = init,
     395             :   .fini            = NULL,
     396             :   .check           = check,
     397             : };
     398             : 
     399             : #undef NAME

Generated by: LCOV version 1.14