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