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_UNLIKELY( killed ) ) return killed;
63 :
64 0 : char path[ PATH_MAX ];
65 0 : FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/proc/%lu/maps", pid ) );
66 0 : FILE * fp = fopen( path, "r" );
67 0 : if( FD_UNLIKELY( !fp && errno==ENOENT ) ) return 0;
68 0 : else if( FD_UNLIKELY( !fp ) ) FD_LOG_ERR(( "error opening `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
69 :
70 0 : char line[ 4096 ];
71 0 : while( FD_LIKELY( fgets( line, 4096, fp ) ) ) {
72 0 : if( FD_UNLIKELY( strlen( line ) == 4095 ) ) FD_LOG_ERR(( "line too long in `%s`", path ));
73 0 : if( FD_UNLIKELY( strstr( line, config->hugetlbfs.gigantic_page_mount_path ) ||
74 0 : strstr( line, config->hugetlbfs.huge_page_mount_path ) ) ) {
75 0 : killed = 1;
76 0 : FD_LOG_NOTICE(( "killing process `%s` (%lu): has a workspace file descriptor open", proc_cmdline, pid ));
77 0 : if( FD_UNLIKELY( -1==kill( (int)pid, SIGKILL ) && errno!=ESRCH ) ) FD_LOG_ERR(( "kill failed (%i-%s)", errno, fd_io_strerror( errno ) ));
78 0 : break;
79 0 : }
80 0 : }
81 0 : if( FD_UNLIKELY( ferror( fp ) ) )
82 0 : FD_LOG_ERR(( "error reading `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
83 0 : if( FD_LIKELY( fclose( fp ) ) )
84 0 : FD_LOG_ERR(( "error closing `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
85 :
86 0 : if( FD_UNLIKELY( killed ) ) return killed;
87 :
88 0 : FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/proc/%lu/numa_maps", pid ) );
89 0 : fp = fopen( path, "r" );
90 0 : if( FD_UNLIKELY( !fp ) ) FD_LOG_ERR(( "error opening `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
91 :
92 0 : while( FD_LIKELY( fgets( line, 4096, fp ) ) ) {
93 0 : if( FD_UNLIKELY( strlen( line ) == 4095 ) ) FD_LOG_ERR(( "line too long in `%s`", path ));
94 0 : if( FD_UNLIKELY( strstr( line, "huge" ) && strstr( line, "anon" ) ) ) {
95 0 : killed = 1;
96 0 : FD_LOG_NOTICE(( "killing process `%s` (%lu): has anonymous hugepages mapped", proc_cmdline, pid ));
97 0 : if( FD_UNLIKELY( -1==kill( (int)pid, SIGKILL ) && errno!=ESRCH ) ) FD_LOG_ERR(( "kill failed (%i-%s)", errno, fd_io_strerror( errno ) ));
98 0 : break;
99 0 : }
100 0 : }
101 0 : if( FD_UNLIKELY( ferror( fp ) ) )
102 0 : FD_LOG_ERR(( "error reading `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
103 0 : if( FD_LIKELY( fclose( fp ) ) )
104 0 : FD_LOG_ERR(( "error closing `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
105 :
106 0 : return killed;
107 0 : }
108 :
109 : static void
110 : wait_dead( long started,
111 0 : ulong pid ) {
112 : /* We need to do this to prevent a race condition, since kill(SIGKILL) returns
113 : before the kernel actually terminates and reclaims the resources from the
114 : process. */
115 0 : while( 1 ) {
116 0 : int err = kill( (int)pid, 0 );
117 0 : if( FD_LIKELY( err==-1 && errno==ESRCH) ) return;
118 0 : else if( FD_LIKELY( err==-1 ) ) FD_LOG_ERR(( "kill failed (%i-%s)", errno, fd_io_strerror( errno ) ));
119 :
120 0 : if( FD_UNLIKELY( fd_log_wallclock() - started >= (long)1e9 ) )
121 0 : FD_LOG_ERR(( "waited too long for process to exit" ));
122 0 : }
123 0 : }
124 :
125 : static void
126 0 : init( config_t const * config ) {
127 0 : DIR * dir = opendir( "/proc" );
128 0 : if( FD_UNLIKELY( !dir ) ) FD_LOG_ERR(( "error opening `/proc` (%i-%s)", errno, fd_io_strerror( errno ) ));
129 :
130 0 : ulong wait_killed_cnt = 0UL;
131 0 : ulong wait_killed[ 1024 ] = { 0 };
132 :
133 0 : struct dirent * entry;
134 0 : while(( FD_LIKELY( entry = readdir( dir ) ) )) {
135 0 : if( FD_UNLIKELY( entry->d_name[0] == '.' ) ) continue;
136 0 : char * endptr;
137 0 : ulong pid = strtoul( entry->d_name, &endptr, 10 );
138 0 : if( FD_UNLIKELY( *endptr || pid==(ulong)getpid() ) ) continue;
139 :
140 0 : int killed = maybe_kill( config, pid );
141 0 : if( FD_UNLIKELY( killed ) ) {
142 0 : if( FD_UNLIKELY( wait_killed_cnt==sizeof(wait_killed) ) ) FD_LOG_ERR(( "too many processes to kill" ));
143 0 : wait_killed[ wait_killed_cnt ] = pid;
144 0 : }
145 0 : }
146 :
147 0 : if( FD_UNLIKELY( -1==closedir( dir ) ) ) FD_LOG_ERR(( "closedir (%i-%s)", errno, fd_io_strerror( errno ) ));
148 :
149 0 : long started = fd_log_wallclock();
150 0 : for( ulong i=0; i<wait_killed_cnt; i++ ) wait_dead( started, wait_killed[ i ] );
151 0 : }
152 :
153 : static configure_result_t
154 0 : check( config_t const * config FD_PARAM_UNUSED ) {
155 0 : PARTIALLY_CONFIGURED( "kill existing instances" );
156 0 : }
157 :
158 : configure_stage_t fd_cfg_stage_kill = {
159 : .name = NAME,
160 : .always_recreate = 1,
161 : .enabled = NULL,
162 : .init_perm = init_perm,
163 : .fini_perm = NULL,
164 : .init = init,
165 : .fini = NULL,
166 : .check = check,
167 : };
168 :
169 : #undef NAME
|