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