Merge pull request #12153 from benjarobin/killall-show-not-killed
shutdown/killall: Show in the console the processes not yet killed
This commit is contained in:
commit
aa46c28418
|
@ -77,19 +77,46 @@ static bool ignore_proc(pid_t pid, bool warn_rootfs) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
|
||||
static void log_children_no_yet_killed(Set *pids) {
|
||||
void *p;
|
||||
Iterator i;
|
||||
_cleanup_free_ char *lst_child = NULL;
|
||||
|
||||
SET_FOREACH(p, pids, i) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
|
||||
if (get_process_comm(PTR_TO_PID(p), &s) == 0) {
|
||||
if (!strextend(&lst_child, ", ", s, NULL))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isempty(lst_child))
|
||||
log_notice("Waiting for process:%s", lst_child + 1);
|
||||
}
|
||||
|
||||
static int wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
|
||||
usec_t until;
|
||||
usec_t date_log_child;
|
||||
usec_t n;
|
||||
|
||||
assert(mask);
|
||||
|
||||
if (set_isempty(pids))
|
||||
return;
|
||||
/* Return the number of children remaining in the pids set: That correspond to the number
|
||||
* of processes still "alive" after the timeout */
|
||||
|
||||
if (set_isempty(pids))
|
||||
return 0;
|
||||
|
||||
n = now(CLOCK_MONOTONIC);
|
||||
until = usec_add(n, timeout);
|
||||
date_log_child = usec_add(n, 10u * USEC_PER_SEC);
|
||||
if (date_log_child > until)
|
||||
date_log_child = usec_add(n, timeout / 2u);
|
||||
|
||||
until = now(CLOCK_MONOTONIC) + timeout;
|
||||
for (;;) {
|
||||
struct timespec ts;
|
||||
int k;
|
||||
usec_t n;
|
||||
void *p;
|
||||
Iterator i;
|
||||
|
||||
|
@ -107,8 +134,7 @@ static void wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
|
|||
if (errno == ECHILD)
|
||||
break;
|
||||
|
||||
log_error_errno(errno, "waitpid() failed: %m");
|
||||
return;
|
||||
return log_error_errno(errno, "waitpid() failed: %m");
|
||||
}
|
||||
|
||||
(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) {
|
|||
}
|
||||
|
||||
if (set_isempty(pids))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
n = now(CLOCK_MONOTONIC);
|
||||
if (n >= until)
|
||||
return;
|
||||
if (date_log_child > 0 && n >= date_log_child) {
|
||||
log_children_no_yet_killed(pids);
|
||||
/* Log the children not yet killed only once */
|
||||
date_log_child = 0;
|
||||
}
|
||||
|
||||
if (n >= until)
|
||||
return set_size(pids);
|
||||
|
||||
if (date_log_child > 0)
|
||||
timespec_store(&ts, MIN(until - n, date_log_child - n));
|
||||
else
|
||||
timespec_store(&ts, until - n);
|
||||
|
||||
timespec_store(&ts, until - n);
|
||||
k = sigtimedwait(mask, NULL, &ts);
|
||||
if (k != SIGCHLD) {
|
||||
|
||||
if (k < 0 && errno != EAGAIN) {
|
||||
log_error_errno(errno, "sigtimedwait() failed: %m");
|
||||
return;
|
||||
}
|
||||
if (k < 0 && errno != EAGAIN)
|
||||
return log_error_errno(errno, "sigtimedwait() failed: %m");
|
||||
|
||||
if (k >= 0)
|
||||
log_warning("sigtimedwait() returned unexpected signal.");
|
||||
|
@ -154,10 +188,14 @@ static void wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
|
|||
static int killall(int sig, Set *pids, bool send_sighup) {
|
||||
_cleanup_closedir_ DIR *dir = NULL;
|
||||
struct dirent *d;
|
||||
int n_killed = 0;
|
||||
|
||||
/* Send the specified signal to all remaining processes, if not excluded by ignore_proc().
|
||||
* Returns the number of processes to which the specified signal was sent */
|
||||
|
||||
dir = opendir("/proc");
|
||||
if (!dir)
|
||||
return -errno;
|
||||
return log_warning_errno(errno, "opendir(/proc) failed: %m");
|
||||
|
||||
FOREACH_DIRENT_ALL(d, dir, break) {
|
||||
pid_t pid;
|
||||
|
@ -180,6 +218,7 @@ static int killall(int sig, Set *pids, bool send_sighup) {
|
|||
}
|
||||
|
||||
if (kill(pid, sig) >= 0) {
|
||||
n_killed++;
|
||||
if (pids) {
|
||||
r = set_put(pids, PID_TO_PTR(pid));
|
||||
if (r < 0)
|
||||
|
@ -205,13 +244,20 @@ static int killall(int sig, Set *pids, bool send_sighup) {
|
|||
}
|
||||
}
|
||||
|
||||
return set_size(pids);
|
||||
return n_killed;
|
||||
}
|
||||
|
||||
void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout) {
|
||||
int broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout) {
|
||||
int n_children_left;
|
||||
sigset_t mask, oldmask;
|
||||
_cleanup_set_free_ Set *pids = NULL;
|
||||
|
||||
/* Send the specified signal to all remaining processes, if not excluded by ignore_proc().
|
||||
* Return:
|
||||
* - The number of processes still "alive" after the timeout (that should have been killed)
|
||||
* if the function needs to wait for the end of the processes (wait_for_exit).
|
||||
* - Otherwise, the number of processes to which the specified signal was sent */
|
||||
|
||||
if (wait_for_exit)
|
||||
pids = set_new(NULL);
|
||||
|
||||
|
@ -222,13 +268,15 @@ void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t time
|
|||
if (kill(-1, SIGSTOP) < 0 && errno != ESRCH)
|
||||
log_warning_errno(errno, "kill(-1, SIGSTOP) failed: %m");
|
||||
|
||||
killall(sig, pids, send_sighup);
|
||||
n_children_left = killall(sig, pids, send_sighup);
|
||||
|
||||
if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
|
||||
log_warning_errno(errno, "kill(-1, SIGCONT) failed: %m");
|
||||
|
||||
if (wait_for_exit)
|
||||
wait_for_children(pids, &mask, timeout);
|
||||
if (wait_for_exit && n_children_left > 0)
|
||||
n_children_left = wait_for_children(pids, &mask, timeout);
|
||||
|
||||
assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
|
||||
|
||||
return n_children_left;
|
||||
}
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
|
||||
#include "time-util.h"
|
||||
|
||||
void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout);
|
||||
int broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "signal-util.h"
|
||||
#include "string-util.h"
|
||||
#include "switch-root.h"
|
||||
#include "sysctl-util.h"
|
||||
#include "terminal-util.h"
|
||||
#include "umount.h"
|
||||
#include "util.h"
|
||||
|
@ -255,6 +256,42 @@ static void sync_with_progress(void) {
|
|||
(void) kill(pid, SIGKILL);
|
||||
}
|
||||
|
||||
static int read_current_sysctl_printk_log_level(void) {
|
||||
_cleanup_free_ char *sysctl_printk_vals = NULL, *sysctl_printk_curr = NULL;
|
||||
unsigned current_lvl = 0;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
r = sysctl_read("kernel/printk", &sysctl_printk_vals);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Cannot read sysctl kernel.printk: %m");
|
||||
|
||||
p = sysctl_printk_vals;
|
||||
r = extract_first_word(&p, &sysctl_printk_curr, NULL, 0);
|
||||
if (r > 0)
|
||||
r = safe_atou(sysctl_printk_curr, ¤t_lvl);
|
||||
else if (r == 0)
|
||||
r = -EINVAL;
|
||||
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Unexpected sysctl kernel.printk content: %s", sysctl_printk_vals);
|
||||
|
||||
return current_lvl;
|
||||
}
|
||||
|
||||
static void bump_sysctl_printk_log_level(int min_level) {
|
||||
/* Set the logging level to be able to see messages with log level smaller or equal to min_level */
|
||||
|
||||
int current_lvl = read_current_sysctl_printk_log_level();
|
||||
if (current_lvl >= 0 && current_lvl <= min_level) {
|
||||
char buf[DECIMAL_STR_MAX(int)];
|
||||
xsprintf(buf, "%d", min_level + 1);
|
||||
int r = sysctl_write("kernel/printk", buf);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to bump kernel.printk to %s: %m", buf);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
|
||||
bool in_container, use_watchdog = false, can_initrd;
|
||||
|
@ -305,6 +342,16 @@ int main(int argc, char *argv[]) {
|
|||
(void) cg_get_root_path(&cgroup);
|
||||
in_container = detect_container() > 0;
|
||||
|
||||
/* If the logging messages are going to KMSG, and if we are not running from a container,
|
||||
* then try to update the sysctl kernel.printk current value in order to see "info" messages;
|
||||
* This current log level is not updated if already big enough.
|
||||
*/
|
||||
if (!in_container && IN_SET(log_get_target(), LOG_TARGET_AUTO,
|
||||
LOG_TARGET_JOURNAL_OR_KMSG,
|
||||
LOG_TARGET_SYSLOG_OR_KMSG,
|
||||
LOG_TARGET_KMSG))
|
||||
bump_sysctl_printk_log_level(LOG_INFO);
|
||||
|
||||
use_watchdog = getenv("WATCHDOG_USEC");
|
||||
watchdog_device = getenv("WATCHDOG_DEVICE");
|
||||
if (watchdog_device) {
|
||||
|
|
Loading…
Reference in a new issue