Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: better systemd --user integration #301

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion ex/restart.d/systemd-manager
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,9 @@ if [ "$NR_VERBOSE" = '1' ]; then
set -x
fi

exec systemctl daemon-reexec
trace() {
echo "-> $*" >&2
"$@"
}

trace systemctl daemon-reexec
27 changes: 27 additions & 0 deletions ex/restart.d/systemd-user
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/sh

# needrestart - Restart daemons after library updates.
#
# Restarting `systemd --user` using special systemctl call.
#

# enable xtrace if we should be verbose
if [ "$NR_VERBOSE" = '1' ]; then
set -x
fi

trace() {
echo "-> $*" >&2
"$@"
}

rc=0

systemctl show --state=active --property=User --value 'user@*.service' | while IFS='' read -r uid; do
# skip empty lines produced by `systemctl show` if the property
# did not exist or could not be queried
if [ -z "$uid" ]; then continue; fi
trace systemctl -M "$uid@.host" --user daemon-reexec || rc=1
done

exit $rc
101 changes: 49 additions & 52 deletions needrestart
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ if(defined($opt_l)) {

# find parent process
my $ppid = $ptable->{$pid}->{ppid};
if($ppid != $pid && $ppid > 1 && !$uid) {
if($ppid != $pid && $ppid > 1 && !($is_systemd && nr_is_systemd_manager($ppid))) {
print STDERR "$LOGPREF #$pid is a child of #$ppid\n" if($nrconf{verbosity} > 1);

if($uid && $ptable->{$ppid}->{uid} != $uid) {
Expand Down Expand Up @@ -655,67 +655,64 @@ if(defined($opt_l)) {
next if(grep { $exe =~ /$_/; } @{$nrconf{blacklist}});

if($is_systemd) {
# get unit name from /proc/<pid>/cgroup
my $cgroup = nr_get_cgroup($pid);
# systemd manager
if($pid == 1 && $exe =~ m@^(/usr)?/lib/systemd/systemd@) {
if($cgroup =~ m@^/init\.scope$@ || ($pid == 1 && $exe =~ m@^(/usr)?/lib/systemd/systemd@)) {
print STDERR "$LOGPREF #$pid is systemd manager\n" if($nrconf{verbosity} > 1);
$restart{q(systemd-manager)}++;
next;
}
# `systemd --user` manager
if($cgroup =~ m@/user\@(\d+)\.service/init\.scope$@ && $ptable->{$pid}->{fname} ne "(sd-pam)") {
print STDERR "$LOGPREF #$pid is user systemd manager: uid=$1\n" if($nrconf{verbosity} > 1);
# TODO: restart specific `systemd --user` instance?
$restart{q(systemd-user)}++;
next;
}

# get unit name from /proc/<pid>/cgroup
if(open(HCGROUP, qq(/proc/$pid/cgroup))) {
my ($rc) = map {
chomp;
my ($id, $type, $value) = split(/:/);
if($id != 0 && $type ne q(name=systemd)) {
();
}
else {
if($value =~ m@/user-(\d+)\.slice/session-(\d+)\.scope@) {
print STDERR "$LOGPREF #$pid part of user session: uid=$1 sess=$2\n" if($nrconf{verbosity} > 1);
push(@{ $sessions{$1}->{"session #$2"}->{ $ptable->{$pid}->{fname} } }, $pid);
next;
}
if($value =~ m@/user\@(\d+)\.service@) {
print STDERR "$LOGPREF #$pid part of user manager service: uid=$1\n" if($nrconf{verbosity} > 1);
push(@{ $sessions{$1}->{'user manager service'}->{ $ptable->{$pid}->{fname} } }, $pid);
next;
}
if($value =~ m@/machine.slice/machine.qemu(.*).scope@) {
for my $cmdlineidx (0 .. $#{$ptable->{$pid}->{cmdline}} ) {
if ( ${$ptable->{$pid}->{cmdline}}[$cmdlineidx] eq "-name") {
foreach ( split(/,/, ${$ptable->{$pid}->{cmdline}}[$cmdlineidx+1]) ) {
if ( index($_, "guest=") == 0 ) {
my @namearg = split(/=/, $_, 2);
if ($#{namearg} == 1) {
print STDERR "$LOGPREF #$pid detected as VM guest '$namearg[1]' in group '$value'\n" if($nrconf{verbosity} > 1);
push(@guests, __x("'{name}' with pid {pid}", name => $namearg[1], pid=>$pid) );
}
next PIDLOOP;
}
}
}
if($cgroup =~ m@/user-(\d+)\.slice/session-(\d+)\.scope@) {
print STDERR "$LOGPREF #$pid part of user session: uid=$1 sess=$2\n" if($nrconf{verbosity} > 1);
push(@{ $sessions{$1}->{"session #$2"}->{ $ptable->{$pid}->{fname} } }, $pid);
next;
}
if($cgroup =~ m@/user\@(\d+)\.service(/.+)?/([^/]+\.service)$@) {
print STDERR "$LOGPREF #$pid part of user service: uid=$1 unit=$3\n" if($nrconf{verbosity} > 1);
push(@{ $sessions{$1}->{'user service'}->{ $3 } }, $pid);
next;
}
if($cgroup =~ m@/user\@(\d+)\.service@) {
print STDERR "$LOGPREF #$pid part of user manageruid=$1\n" if($nrconf{verbosity} > 1);
push(@{ $sessions{$1}->{'user manager'}->{ $ptable->{$pid}->{fname} } }, $pid);
next;
}
if($cgroup =~ m@/machine.slice/machine.qemu(.*).scope@) {
for my $cmdlineidx (0 .. $#{$ptable->{$pid}->{cmdline}} ) {
if ( ${$ptable->{$pid}->{cmdline}}[$cmdlineidx] eq "-name") {
foreach ( split(/,/, ${$ptable->{$pid}->{cmdline}}[$cmdlineidx+1]) ) {
if ( index($_, "guest=") == 0 ) {
my @namearg = split(/=/, $_, 2);
if ($#{namearg} == 1) {
print STDERR "$LOGPREF #$pid detected as VM guest '$namearg[1]' in group '$cgroup'\n" if($nrconf{verbosity} > 1);
push(@guests, __x("'{name}' with pid {pid}", name => $namearg[1], pid=>$pid) );
}
next PIDLOOP;
}
print STDERR "$LOGPREF #$pid detected as VM guest with unknown name in group '$value'\n" if($nrconf{verbosity} > 1);
push(@guests, __x("'Unkown VM' with pid {pid}", pid=>$pid) );
next;
}
elsif($value =~ m@/([^/]+\.service)$@) {
($1);
}
else {
print STDERR "$LOGPREF #$pid unexpected cgroup '$value'\n" if($nrconf{verbosity} > 1);
();
}
}
} <HCGROUP>;
close(HCGROUP);

if($rc) {
print STDERR "$LOGPREF #$pid is $rc\n" if($nrconf{verbosity} > 1);
$restart{$rc}++;
next;
}
print STDERR "$LOGPREF #$pid detected as VM guest with unknown name in group '$cgroup'\n" if($nrconf{verbosity} > 1);
push(@guests, __x("'Unkown VM' with pid {pid}", pid=>$pid) );
next;
}
elsif($cgroup =~ m@/([^/]+\.service)$@) {
my $unit = $1;
print STDERR "$LOGPREF #$pid is $unit\n" if($nrconf{verbosity} > 1);
$restart{$unit}++;
next;
}
elsif($cgroup) {
print STDERR "$LOGPREF #$pid unexpected cgroup '$cgroup'\n" if($nrconf{verbosity} > 1);
}

# did not get the unit name, yet - try systemctl status
Expand Down
32 changes: 32 additions & 0 deletions perl/lib/NeedRestart/Utils.pm
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ our @EXPORT = qw(
nr_fork_pipe_stderr
nr_fork_pipew
nr_fork_pipe2
nr_get_cgroup
nr_is_systemd_manager
);

my %ptable;
Expand All @@ -61,6 +63,36 @@ sub nr_ptable_pid($) {
return $ptable{$pid};
}

sub nr_get_cgroup($) {
my $pid = shift;

# get unit name from /proc/<pid>/cgroup
if(open(HCGROUP, qq(/proc/$pid/cgroup))) {
my ($cgroup) = map {
chomp;
my ($id, $type, $value) = split(/:/);
if(($id == 0 && $type eq "") || ($type eq q(name=systemd))) {
($value);
} else {
();
}
} <HCGROUP>;
close(HCGROUP);

return $cgroup;
}

return undef;
}

sub nr_is_systemd_manager($) {
my $pid = shift;
my $cgroup = nr_get_cgroup($pid);

return $cgroup =~ m@(^|/user\@(\d+)\.service)/init\.scope$@ if($cgroup);
return 0;
}

sub nr_parse_cmd($) {
my $pid = shift;

Expand Down