LCOV - code coverage report
Current view: top level - app/fddev/configure - kill.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 107 0.0 %
Date: 2025-03-10 12:29:05 Functions: 0 6 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "../../fdctl/configure/configure.h"
       3             : 
       4             : #include <stdio.h>
       5             : #include <dirent.h>
       6             : #include <signal.h>
       7             : #include <sys/stat.h>
       8             : #include <sys/types.h>
       9             : 
      10           0 : #define NAME "kill"
      11             : 
      12             : static void
      13             : init_perm( fd_caps_ctx_t *  caps,
      14           0 :            config_t const * config FD_PARAM_UNUSED ) {
      15           0 :   fd_caps_check_root( caps, NAME, "check all open file descriptors in `/proc/`" );
      16           0 : }
      17             : 
      18             : static void
      19             : cmdline( char * buf,
      20             :          size_t len,
      21           0 :          ulong  pid ) {
      22           0 :   char path[ PATH_MAX ];
      23           0 :   FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/proc/%lu/cmdline", pid ) );
      24             : 
      25           0 :   FILE * fp = fopen( path, "r" );
      26           0 :   if( FD_UNLIKELY( !fp && errno==ENOENT ) ) {
      27           0 :     buf[ 0 ] = '\0';
      28           0 :     return;
      29           0 :   }
      30           0 :   if( FD_UNLIKELY( !fp ) ) FD_LOG_ERR(( "error opening `/proc/%lu/cmdline` (%i-%s)", pid, errno, fd_io_strerror( errno ) ));
      31             : 
      32           0 :   ulong read = fread( buf, 1, len - 1, fp );
      33           0 :   if( FD_UNLIKELY( ferror( fp ) ) ) FD_LOG_ERR(( "error reading `/proc/%lu/cmdline` (%i-%s)", pid, errno, fd_io_strerror( errno ) ));
      34           0 :   if( FD_UNLIKELY( fclose( fp ) ) ) FD_LOG_ERR(( "error closing `/proc/%lu/cmdline` (%i-%s)", pid, errno, fd_io_strerror( errno ) ));
      35             : 
      36           0 :   buf[ read ] = '\0';
      37           0 : }
      38             : 
      39             : static int
      40             : maybe_kill( config_t * config,
      41           0 :             ulong      pid ) {
      42           0 :   int killed = 0;
      43             : 
      44           0 :   char proc_cmdline[ PATH_MAX ];
      45           0 :   cmdline( proc_cmdline, PATH_MAX, pid );
      46             : 
      47           0 :   ulong cmdline_len = strlen( proc_cmdline );
      48           0 :   if( FD_LIKELY( cmdline_len>=5UL ) ) {
      49           0 :     if( FD_UNLIKELY( !strcmp( proc_cmdline + (cmdline_len-5), "fddev" ) ) ) {
      50           0 :       killed = 1;
      51           0 :       FD_LOG_NOTICE(( "killing process `%s` (%lu): is fddev", proc_cmdline, pid ));
      52           0 :       if( FD_UNLIKELY( -1==kill( (int)pid, SIGKILL ) && errno!=ESRCH ) ) FD_LOG_ERR(( "kill failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      53           0 :     } else if( FD_UNLIKELY( !strcmp( proc_cmdline + (cmdline_len-5), "fdctl" ) ) ) {
      54           0 :       killed = 1;
      55           0 :       FD_LOG_NOTICE(( "killing process `%s` (%lu): is fdctl", proc_cmdline, pid ));
      56           0 :       if( FD_UNLIKELY( -1==kill( (int)pid, SIGKILL ) && errno!=ESRCH ) ) FD_LOG_ERR(( "kill failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      57           0 :     }
      58           0 :   }
      59             : 
      60           0 :   if( FD_UNLIKELY( killed ) ) return killed;
      61             : 
      62           0 :   char path[ PATH_MAX ];
      63           0 :   FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/proc/%lu/maps", pid ) );
      64           0 :   FILE * fp = fopen( path, "r" );
      65           0 :   if( FD_UNLIKELY( !fp && errno==ENOENT ) ) return 0;
      66           0 :   else if( FD_UNLIKELY( !fp ) ) FD_LOG_ERR(( "error opening `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      67             : 
      68           0 :   char line[ 4096 ];
      69           0 :   while( FD_LIKELY( fgets( line, 4096, fp ) ) ) {
      70           0 :     if( FD_UNLIKELY( strlen( line ) == 4095 ) ) FD_LOG_ERR(( "line too long in `%s`", path ));
      71           0 :     if( FD_UNLIKELY( strstr( line, config->hugetlbfs.gigantic_page_mount_path ) ||
      72           0 :                       strstr( line, config->hugetlbfs.huge_page_mount_path ) ) ) {
      73           0 :       killed = 1;
      74           0 :       FD_LOG_NOTICE(( "killing process `%s` (%lu): has a workspace file descriptor open", proc_cmdline, pid ));
      75           0 :       if( FD_UNLIKELY( -1==kill( (int)pid, SIGKILL ) && errno!=ESRCH ) ) FD_LOG_ERR(( "kill failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      76           0 :       break;
      77           0 :     }
      78           0 :   }
      79           0 :   if( FD_UNLIKELY( ferror( fp ) ) )
      80           0 :     FD_LOG_ERR(( "error reading `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      81           0 :   if( FD_LIKELY( fclose( fp ) ) )
      82           0 :     FD_LOG_ERR(( "error closing `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      83             : 
      84           0 :   if( FD_UNLIKELY( killed ) ) return killed;
      85             : 
      86           0 :   FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/proc/%lu/numa_maps", pid ) );
      87           0 :   fp = fopen( path, "r" );
      88           0 :   if( FD_UNLIKELY( !fp ) ) FD_LOG_ERR(( "error opening `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      89             : 
      90           0 :   while( FD_LIKELY( fgets( line, 4096, fp ) ) ) {
      91           0 :     if( FD_UNLIKELY( strlen( line ) == 4095 ) ) FD_LOG_ERR(( "line too long in `%s`", path ));
      92           0 :     if( FD_UNLIKELY( strstr( line, "huge" ) && strstr( line, "anon" ) ) ) {
      93           0 :       killed = 1;
      94           0 :       FD_LOG_NOTICE(( "killing process `%s` (%lu): has anonymous hugepages mapped", proc_cmdline, pid ));
      95           0 :       if( FD_UNLIKELY( -1==kill( (int)pid, SIGKILL ) && errno!=ESRCH ) ) FD_LOG_ERR(( "kill failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      96           0 :       break;
      97           0 :     }
      98           0 :   }
      99           0 :   if( FD_UNLIKELY( ferror( fp ) ) )
     100           0 :     FD_LOG_ERR(( "error reading `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
     101           0 :   if( FD_LIKELY( fclose( fp ) ) )
     102           0 :     FD_LOG_ERR(( "error closing `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
     103             : 
     104           0 :   return killed;
     105           0 : }
     106             : 
     107             : static void
     108             : wait_dead( long  started,
     109           0 :            ulong pid ) {
     110             :   /* We need to do this to prevent a race condition, since kill(SIGKILL) returns
     111             :      before the kernel actually terminates and reclaims the resources from the
     112             :      process. */
     113           0 :   while( 1 ) {
     114           0 :     int err = kill( (int)pid, 0 );
     115           0 :     if( FD_LIKELY( err==-1 && errno==ESRCH) ) return;
     116           0 :     else if( FD_LIKELY( err==-1 ) ) FD_LOG_ERR(( "kill failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     117             : 
     118           0 :     if( FD_UNLIKELY( fd_log_wallclock() - started >= (long)1e9 ) )
     119           0 :       FD_LOG_ERR(( "waited too long for process to exit" ));
     120           0 :   }
     121           0 : }
     122             : 
     123             : static void
     124           0 : init( config_t * config ) {
     125           0 :   DIR * dir = opendir( "/proc" );
     126           0 :   if( FD_UNLIKELY( !dir ) ) FD_LOG_ERR(( "error opening `/proc` (%i-%s)", errno, fd_io_strerror( errno ) ));
     127             : 
     128           0 :   ulong wait_killed_cnt = 0UL;
     129           0 :   ulong wait_killed[ 1024 ] = { 0 };
     130             : 
     131           0 :   struct dirent * entry;
     132           0 :   while(( FD_LIKELY( entry = readdir( dir ) ) )) {
     133           0 :     if( FD_UNLIKELY( entry->d_name[0] == '.' ) ) continue;
     134           0 :     char * endptr;
     135           0 :     ulong pid = strtoul( entry->d_name, &endptr, 10 );
     136           0 :     if( FD_UNLIKELY( *endptr || pid==(ulong)getpid() ) ) continue;
     137             : 
     138           0 :     int killed = maybe_kill( config, pid );
     139           0 :     if( FD_UNLIKELY( killed ) ) {
     140           0 :       if( FD_UNLIKELY( wait_killed_cnt==sizeof(wait_killed) ) ) FD_LOG_ERR(( "too many processes to kill" ));
     141           0 :       wait_killed[ wait_killed_cnt ] = pid;
     142           0 :     }
     143           0 :   }
     144             : 
     145           0 :   if( FD_UNLIKELY( -1==closedir( dir ) ) ) FD_LOG_ERR(( "closedir (%i-%s)", errno, fd_io_strerror( errno ) ));
     146             : 
     147           0 :   long started = fd_log_wallclock();
     148           0 :   for( ulong i=0; i<wait_killed_cnt; i++ ) wait_dead( started, wait_killed[ i ] );
     149           0 : }
     150             : 
     151             : static configure_result_t
     152           0 : check( config_t const * config FD_PARAM_UNUSED ) {
     153           0 :   PARTIALLY_CONFIGURED( "kill existing instances" );
     154           0 : }
     155             : 
     156             : configure_stage_t fd_cfg_stage_kill = {
     157             :   .name            = NAME,
     158             :   .always_recreate = 1,
     159             :   .enabled         = NULL,
     160             :   .init_perm       = init_perm,
     161             :   .fini_perm       = NULL,
     162             :   .init            = init,
     163             :   .fini            = NULL,
     164             :   .check           = check,
     165             : };
     166             : 
     167             : #undef NAME

Generated by: LCOV version 1.14