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
|