Skip to content

Commit aa46c28

Browse files
authored
Merge pull request #12153 from benjarobin/killall-show-not-killed
shutdown/killall: Show in the console the processes not yet killed
2 parents 3f0e934 + 763e7b5 commit aa46c28

File tree

3 files changed

+115
-20
lines changed

3 files changed

+115
-20
lines changed

src/core/killall.c

+67-19
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,46 @@ static bool ignore_proc(pid_t pid, bool warn_rootfs) {
7777
return true;
7878
}
7979

80-
static void wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
80+
static void log_children_no_yet_killed(Set *pids) {
81+
void *p;
82+
Iterator i;
83+
_cleanup_free_ char *lst_child = NULL;
84+
85+
SET_FOREACH(p, pids, i) {
86+
_cleanup_free_ char *s = NULL;
87+
88+
if (get_process_comm(PTR_TO_PID(p), &s) == 0) {
89+
if (!strextend(&lst_child, ", ", s, NULL))
90+
break;
91+
}
92+
}
93+
94+
if (!isempty(lst_child))
95+
log_notice("Waiting for process:%s", lst_child + 1);
96+
}
97+
98+
static int wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
8199
usec_t until;
100+
usec_t date_log_child;
101+
usec_t n;
82102

83103
assert(mask);
84104

105+
/* Return the number of children remaining in the pids set: That correspond to the number
106+
* of processes still "alive" after the timeout */
107+
85108
if (set_isempty(pids))
86-
return;
109+
return 0;
110+
111+
n = now(CLOCK_MONOTONIC);
112+
until = usec_add(n, timeout);
113+
date_log_child = usec_add(n, 10u * USEC_PER_SEC);
114+
if (date_log_child > until)
115+
date_log_child = usec_add(n, timeout / 2u);
87116

88-
until = now(CLOCK_MONOTONIC) + timeout;
89117
for (;;) {
90118
struct timespec ts;
91119
int k;
92-
usec_t n;
93120
void *p;
94121
Iterator i;
95122

@@ -107,8 +134,7 @@ static void wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
107134
if (errno == ECHILD)
108135
break;
109136

110-
log_error_errno(errno, "waitpid() failed: %m");
111-
return;
137+
return log_error_errno(errno, "waitpid() failed: %m");
112138
}
113139

114140
(void) set_remove(pids, PID_TO_PTR(pid));
@@ -130,20 +156,28 @@ static void wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
130156
}
131157

132158
if (set_isempty(pids))
133-
return;
159+
return 0;
134160

135161
n = now(CLOCK_MONOTONIC);
162+
if (date_log_child > 0 && n >= date_log_child) {
163+
log_children_no_yet_killed(pids);
164+
/* Log the children not yet killed only once */
165+
date_log_child = 0;
166+
}
167+
136168
if (n >= until)
137-
return;
169+
return set_size(pids);
170+
171+
if (date_log_child > 0)
172+
timespec_store(&ts, MIN(until - n, date_log_child - n));
173+
else
174+
timespec_store(&ts, until - n);
138175

139-
timespec_store(&ts, until - n);
140176
k = sigtimedwait(mask, NULL, &ts);
141177
if (k != SIGCHLD) {
142178

143-
if (k < 0 && errno != EAGAIN) {
144-
log_error_errno(errno, "sigtimedwait() failed: %m");
145-
return;
146-
}
179+
if (k < 0 && errno != EAGAIN)
180+
return log_error_errno(errno, "sigtimedwait() failed: %m");
147181

148182
if (k >= 0)
149183
log_warning("sigtimedwait() returned unexpected signal.");
@@ -154,10 +188,14 @@ static void wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
154188
static int killall(int sig, Set *pids, bool send_sighup) {
155189
_cleanup_closedir_ DIR *dir = NULL;
156190
struct dirent *d;
191+
int n_killed = 0;
192+
193+
/* Send the specified signal to all remaining processes, if not excluded by ignore_proc().
194+
* Returns the number of processes to which the specified signal was sent */
157195

158196
dir = opendir("/proc");
159197
if (!dir)
160-
return -errno;
198+
return log_warning_errno(errno, "opendir(/proc) failed: %m");
161199

162200
FOREACH_DIRENT_ALL(d, dir, break) {
163201
pid_t pid;
@@ -180,6 +218,7 @@ static int killall(int sig, Set *pids, bool send_sighup) {
180218
}
181219

182220
if (kill(pid, sig) >= 0) {
221+
n_killed++;
183222
if (pids) {
184223
r = set_put(pids, PID_TO_PTR(pid));
185224
if (r < 0)
@@ -205,13 +244,20 @@ static int killall(int sig, Set *pids, bool send_sighup) {
205244
}
206245
}
207246

208-
return set_size(pids);
247+
return n_killed;
209248
}
210249

211-
void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout) {
250+
int broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout) {
251+
int n_children_left;
212252
sigset_t mask, oldmask;
213253
_cleanup_set_free_ Set *pids = NULL;
214254

255+
/* Send the specified signal to all remaining processes, if not excluded by ignore_proc().
256+
* Return:
257+
* - The number of processes still "alive" after the timeout (that should have been killed)
258+
* if the function needs to wait for the end of the processes (wait_for_exit).
259+
* - Otherwise, the number of processes to which the specified signal was sent */
260+
215261
if (wait_for_exit)
216262
pids = set_new(NULL);
217263

@@ -222,13 +268,15 @@ void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t time
222268
if (kill(-1, SIGSTOP) < 0 && errno != ESRCH)
223269
log_warning_errno(errno, "kill(-1, SIGSTOP) failed: %m");
224270

225-
killall(sig, pids, send_sighup);
271+
n_children_left = killall(sig, pids, send_sighup);
226272

227273
if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
228274
log_warning_errno(errno, "kill(-1, SIGCONT) failed: %m");
229275

230-
if (wait_for_exit)
231-
wait_for_children(pids, &mask, timeout);
276+
if (wait_for_exit && n_children_left > 0)
277+
n_children_left = wait_for_children(pids, &mask, timeout);
232278

233279
assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
280+
281+
return n_children_left;
234282
}

src/core/killall.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33

44
#include "time-util.h"
55

6-
void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout);
6+
int broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout);

src/shutdown/shutdown.c

+47
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "signal-util.h"
3333
#include "string-util.h"
3434
#include "switch-root.h"
35+
#include "sysctl-util.h"
3536
#include "terminal-util.h"
3637
#include "umount.h"
3738
#include "util.h"
@@ -255,6 +256,42 @@ static void sync_with_progress(void) {
255256
(void) kill(pid, SIGKILL);
256257
}
257258

259+
static int read_current_sysctl_printk_log_level(void) {
260+
_cleanup_free_ char *sysctl_printk_vals = NULL, *sysctl_printk_curr = NULL;
261+
unsigned current_lvl = 0;
262+
const char *p;
263+
int r;
264+
265+
r = sysctl_read("kernel/printk", &sysctl_printk_vals);
266+
if (r < 0)
267+
return log_debug_errno(r, "Cannot read sysctl kernel.printk: %m");
268+
269+
p = sysctl_printk_vals;
270+
r = extract_first_word(&p, &sysctl_printk_curr, NULL, 0);
271+
if (r > 0)
272+
r = safe_atou(sysctl_printk_curr, &current_lvl);
273+
else if (r == 0)
274+
r = -EINVAL;
275+
276+
if (r < 0)
277+
return log_debug_errno(r, "Unexpected sysctl kernel.printk content: %s", sysctl_printk_vals);
278+
279+
return current_lvl;
280+
}
281+
282+
static void bump_sysctl_printk_log_level(int min_level) {
283+
/* Set the logging level to be able to see messages with log level smaller or equal to min_level */
284+
285+
int current_lvl = read_current_sysctl_printk_log_level();
286+
if (current_lvl >= 0 && current_lvl <= min_level) {
287+
char buf[DECIMAL_STR_MAX(int)];
288+
xsprintf(buf, "%d", min_level + 1);
289+
int r = sysctl_write("kernel/printk", buf);
290+
if (r < 0)
291+
log_debug_errno(r, "Failed to bump kernel.printk to %s: %m", buf);
292+
}
293+
}
294+
258295
int main(int argc, char *argv[]) {
259296
bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
260297
bool in_container, use_watchdog = false, can_initrd;
@@ -305,6 +342,16 @@ int main(int argc, char *argv[]) {
305342
(void) cg_get_root_path(&cgroup);
306343
in_container = detect_container() > 0;
307344

345+
/* If the logging messages are going to KMSG, and if we are not running from a container,
346+
* then try to update the sysctl kernel.printk current value in order to see "info" messages;
347+
* This current log level is not updated if already big enough.
348+
*/
349+
if (!in_container && IN_SET(log_get_target(), LOG_TARGET_AUTO,
350+
LOG_TARGET_JOURNAL_OR_KMSG,
351+
LOG_TARGET_SYSLOG_OR_KMSG,
352+
LOG_TARGET_KMSG))
353+
bump_sysctl_printk_log_level(LOG_INFO);
354+
308355
use_watchdog = getenv("WATCHDOG_USEC");
309356
watchdog_device = getenv("WATCHDOG_DEVICE");
310357
if (watchdog_device) {

0 commit comments

Comments
 (0)