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