/usr/sbin
NameSizeModeActions
a2disconf162760755editdlrm
a2dismod162760755editdlrm
a2dissite162760755editdlrm
a2enconf162760755editdlrm
a2enmod162760755editdlrm
a2ensite162760755editdlrm
a2query98700755editdlrm
aa-remove-unknown30680755editdlrm
aa-status641200755editdlrm
aa-teardown1370755editdlrm
accessdb149040755editdlrm
add-shell10510755editdlrm
addgnupghome30750755editdlrm
addgroup382470755editdlrm
adduser382470755editdlrm
agetty568960755editdlrm
apache27587360755editdlrm
apache2ctl72290755editdlrm
apachectl72290755editdlrm
apparmor_parser15480640755editdlrm
apparmor_status641200755editdlrm
applygnupgdefaults22170755editdlrm
arp630880755editdlrm
arpd269600755editdlrm
arptables2242960755editdlrm
arptables-nft2242960755editdlrm
arptables-nft-restore2242960755editdlrm
arptables-nft-save2242960755editdlrm
arptables-restore2242960755editdlrm
arptables-save2242960755editdlrm
badblocks351440755editdlrm
bcache-super-show146480755editdlrm
biosdecode237600755editdlrm
blkdeactivate163510755editdlrm
blkdiscard229120755editdlrm
blkid516240755editdlrm
blkzone352000755editdlrm
blockdev311040755editdlrm
bridge947120755editdlrm
cache_check13896080755editdlrm
cache_dump13896080755editdlrm
cache_metadata_size13896080755editdlrm
cache_repair13896080755editdlrm
cache_restore13896080755editdlrm
cache_writeback13896080755editdlrm
capsh310320755editdlrm
cfdisk970080755editdlrm
cgdisk1540960755editdlrm
chcpu311040755editdlrm
check_forensic9520755editdlrm
chgpasswd595280755editdlrm
chmem352000755editdlrm
chpasswd554640755editdlrm
chroot394320755editdlrm
cpgr494480755editdlrm
cppw494480755editdlrm
cron517920755editdlrm
cryptdisks_start15440755editdlrm
cryptdisks_stop8440755editdlrm
cryptsetup1736160755editdlrm
cryptsetup-reencrypt925440755editdlrm
cryptsetup-ssh240960755editdlrm
ctrlaltdel147200755editdlrm
dbconfig-generate-include126560755editdlrm
dbconfig-load-include57040755editdlrm
dcb824480755editdlrm
debugfs2353200755editdlrm
delgroup164950755editdlrm
deluser164950755editdlrm
depmod1703520755editdlrm
devlink1462880755editdlrm
dhclient4532800755editdlrm
dhclient-script163040755editdlrm
dmeventd515920755editdlrm
dmidecode1259360755editdlrm
dmsetup1751280755editdlrm
dmstats1751280755editdlrm
dosfsck843600755editdlrm
dosfslabel393040755editdlrm
dpkg-preconfigure36630755editdlrm
dpkg-reconfigure44850755editdlrm
dumpe2fs310400755editdlrm
e2freefrag146480755editdlrm
e2fsck3602800755editdlrm
e2image433280755editdlrm
e2label1050160755editdlrm
e2mmpstatus310400755editdlrm
e2scrub72960755editdlrm
e2scrub_all53950755editdlrm
e2undo228400755editdlrm
e4crypt311040755editdlrm
e4defrag310320755editdlrm
ebtables2242960755editdlrm
ebtables-nft2242960755editdlrm
ebtables-nft-restore2242960755editdlrm
ebtables-nft-save2242960755editdlrm
ebtables-restore2242960755editdlrm
ebtables-save2242960755editdlrm
era_check13896080755editdlrm
era_dump13896080755editdlrm
era_invalidate13896080755editdlrm
era_restore13896080755editdlrm
escapesrc229920755editdlrm
ethtool5647120755editdlrm
faillock144880755editdlrm
fatlabel393040755editdlrm
fdisk1130720755editdlrm
filefrag187600755editdlrm
findfs147200755editdlrm
fixparts598800755editdlrm
fsadm245190755editdlrm
fsck434400755editdlrm
fsck.btrfs11850755editdlrm
fsck.cramfs311680755editdlrm
fsck.ext23602800755editdlrm
fsck.ext33602800755editdlrm
fsck.ext43602800755editdlrm
fsck.fat843600755editdlrm
fsck.minix557120755editdlrm
fsck.msdos843600755editdlrm
fsck.vfat843600755editdlrm
fsck.xfs19400755editdlrm
fsfreeze147200755editdlrm
fstab-decode187440755editdlrm
fstrim433920755editdlrm
gdisk1786720755editdlrm
genccode150880755editdlrm
gencmn150880755editdlrm
genl926080755editdlrm
gennorm2644080755editdlrm
gensprep274480755editdlrm
getcap146480755editdlrm
getpcaps146480755editdlrm
getty568960755editdlrm
groupadd685200755editdlrm
groupdel642320755editdlrm
groupmems554880755editdlrm
groupmod684240755editdlrm
grpck595280755editdlrm
grpconv512080755editdlrm
grpunconv512080755editdlrm
grub-bios-setup9640160755editdlrm
grub-install12041280755editdlrm
grub-macbless9514080755editdlrm
grub-mkconfig88050755editdlrm
grub-mkdevicemap2208800755editdlrm
grub-probe9639520755editdlrm
grub-reboot48410755editdlrm
grub-set-default35560755editdlrm
halt11198560755editdlrm
hdparm1427760755editdlrm
httxt2dbm146480755editdlrm
hwclock517120755editdlrm
iconvconfig311280755editdlrm
icupkg236560755editdlrm
ifconfig790240755editdlrm
init18499920755editdlrm
insmod1703520755editdlrm
installkernel26590755editdlrm
integritysetup553680755editdlrm
invoke-rc.d165070755editdlrm
ip7188960755editdlrm
ip6tables2242960755editdlrm
ip6tables-apply70570755editdlrm
ip6tables-legacy992720755editdlrm
ip6tables-legacy-restore992720755editdlrm
ip6tables-legacy-save992720755editdlrm
ip6tables-nft2242960755editdlrm
ip6tables-nft-restore2242960755editdlrm
ip6tables-nft-save2242960755editdlrm
ip6tables-restore2242960755editdlrm
ip6tables-restore-translate2242960755editdlrm
ip6tables-save2242960755editdlrm
ip6tables-translate2242960755editdlrm
ipmaddr187440755editdlrm
iptables2242960755editdlrm
iptables-apply70570755editdlrm
iptables-legacy992720755editdlrm
iptables-legacy-restore992720755editdlrm
iptables-legacy-save992720755editdlrm
iptables-nft2242960755editdlrm
iptables-nft-restore2242960755editdlrm
iptables-nft-save2242960755editdlrm
iptables-restore2242960755editdlrm
iptables-restore-translate2242960755editdlrm
iptables-save2242960755editdlrm
iptables-translate2242960755editdlrm
iptunnel187440755editdlrm
irqbalance684640755editdlrm
irqbalance-ui352080755editdlrm
iscsi-iname146480755editdlrm
iscsiadm4080240755editdlrm
iscsid3057200755editdlrm
iscsistart2852480755editdlrm
iscsi_discovery52930755editdlrm
isosize147200755editdlrm
iucode-tool597360755editdlrm
iucode_tool597360755editdlrm
kbdrate186000755editdlrm
killall5311120755editdlrm
kpartx472720755editdlrm
ldattach270080755editdlrm
ldconfig3870755editdlrm
ldconfig.real12139600755editdlrm
locale-gen43980755editdlrm
logrotate1046960755editdlrm
logsave144960755editdlrm
losetup722080755editdlrm
lsmod1703520755editdlrm
luksformat34010755editdlrm
lvchange30275440755editdlrm
lvconvert30275440755editdlrm
lvcreate30275440755editdlrm
lvdisplay30275440755editdlrm
lvextend30275440755editdlrm
lvm30275440755editdlrm
lvmconfig30275440755editdlrm
lvmdiskscan30275440755editdlrm
lvmdump103120755editdlrm
lvmpolld2418640755editdlrm
lvmsadc30275440755editdlrm
lvmsar30275440755editdlrm
lvreduce30275440755editdlrm
lvremove30275440755editdlrm
lvrename30275440755editdlrm
lvresize30275440755editdlrm
lvs30275440755editdlrm
lvscan30275440755editdlrm
make-bcache229120755editdlrm
make-ssl-cert68120755editdlrm
mdadm6157440755editdlrm
mdmon2646400755editdlrm
mii-tool273760755editdlrm
mkdosfs520480755editdlrm
mke2fs1337520755editdlrm
mkfs147200755editdlrm
mkfs.bfs229120755editdlrm
mkfs.btrfs4825600755editdlrm
mkfs.cramfs351440755editdlrm
mkfs.ext21337520755editdlrm
mkfs.ext31337520755editdlrm
mkfs.ext41337520755editdlrm
mkfs.fat520480755editdlrm
mkfs.minix434080755editdlrm
mkfs.msdos520480755editdlrm
mkfs.ntfs720720755editdlrm
mkfs.vfat520480755editdlrm
mkfs.xfs3919600755editdlrm
mkhomedir_helper227040755editdlrm
mkinitramfs124530755editdlrm
mklost+found146480755editdlrm
mkntfs720720755editdlrm
mkswap474960755editdlrm
ModemManager21942400755editdlrm
modinfo1703520755editdlrm
modprobe1703520755editdlrm
mount.fuse187360755editdlrm
mount.fuse3187360755editdlrm
mount.lowntfs-3g1177360755editdlrm
mount.ntfs1628240755editdlrm
mount.ntfs-3g1628240755editdlrm
mpathpersist318000755editdlrm
multipath349680755editdlrm
multipathd1374800755editdlrm
mysqld556047280755editdlrm
nameif148240755editdlrm
needrestart396580755editdlrm
netplan7980755editdlrm
netwatch3376640755editdlrm
newusers765200755editdlrm
nfnl_osf187360755editdlrm
nft268560755editdlrm
nginx12405520755editdlrm
nologin146400755editdlrm
ntfsclone515920755editdlrm
ntfscp352000755editdlrm
ntfslabel229120755editdlrm
ntfsresize638880755editdlrm
ntfsundelete515920755editdlrm
on_ac_power37880755editdlrm
overlayroot-chroot25100755editdlrm
ownership147920755editdlrm
pam-auth-update209920755editdlrm
pam_extrausers_chkpwd226802755editdlrm
pam_extrausers_update308720755editdlrm
pam_getenv28900755editdlrm
pam_timestamp_check144880755editdlrm
paperconfig41700755editdlrm
parted884720755editdlrm
partprobe147200755editdlrm
pdata_tools13896080755editdlrm
php-fpm8.155534480755editdlrm
php-fpm8.357803040755editdlrm
php-fpm8.5102804400755editdlrm
phpdismod72780755editdlrm
phpenmod72780755editdlrm
phpquery63890755editdlrm
pivot_root147200755editdlrm
plipconfig146480755editdlrm
plymouthd1541680755editdlrm
postalias228320755editdlrm
postcat229040755editdlrm
postconf1882080755editdlrm
postdrop229602555editdlrm
postfix188160755editdlrm
postfix-add-filter49540755editdlrm
postfix-add-policy38600755editdlrm
postfix-collate29420755editdlrm
postkick146400755editdlrm
postlock146400755editdlrm
postlog148000755editdlrm
postmap228320755editdlrm
postmulti314240755editdlrm
postqueue229122555editdlrm
postsuper313280755editdlrm
posttls-finger434000755editdlrm
poweroff11198560755editdlrm
pvchange30275440755editdlrm
pvck30275440755editdlrm
pvcreate30275440755editdlrm
pvdisplay30275440755editdlrm
pvmove30275440755editdlrm
pvremove30275440755editdlrm
pvresize30275440755editdlrm
pvs30275440755editdlrm
pvscan30275440755editdlrm
pwck513360755editdlrm
pwconv471120755editdlrm
pwunconv430160755editdlrm
qmqp-sink187360755editdlrm
qmqp-source228480755editdlrm
qshape128490755editdlrm
rarp331040755editdlrm
readprofile229440755editdlrm
reboot11198560755editdlrm
remove-shell10990755editdlrm
resize2fs678960755editdlrm
rmail187360755editdlrm
rmmod1703520755editdlrm
rmt599760755editdlrm
rmt-tar599760755editdlrm
route658080755editdlrm
rsyslogd7856000755editdlrm
rtacct289920755editdlrm
rtcwake352000755editdlrm
rtmon925600755editdlrm
runlevel11198560755editdlrm
runuser556800755editdlrm
sendmail311840755editdlrm
service90970755editdlrm
setcap146480755editdlrm
setvesablank145680755editdlrm
setvtrgb146320755editdlrm
sfdisk1048320755editdlrm
sgdisk1663840755editdlrm
shadowconfig8850755editdlrm
shutdown11198560755editdlrm
slattach369440755editdlrm
smtp-sink361120755editdlrm
smtp-source310480755editdlrm
split-logfile24150755editdlrm
sshd9212880755editdlrm
start-stop-daemon484880755editdlrm
statnetd350320755editdlrm
sudo_logsrvd2049040755editdlrm
sudo_sendlog1099120755editdlrm
sulogin433920755editdlrm
swaplabel188160755editdlrm
swapoff229120755editdlrm
swapon433920755editdlrm
switch_root229120755editdlrm
sysctl309600755editdlrm
tarcat9360755editdlrm
tc6288160755editdlrm
tcpblast354560755editdlrm
telinit11198560755editdlrm
thermald5679120755editdlrm
thin_check13896080755editdlrm
thin_delta13896080755editdlrm
thin_dump13896080755editdlrm
thin_ls13896080755editdlrm
thin_metadata_size13896080755editdlrm
thin_repair13896080755editdlrm
thin_restore13896080755editdlrm
thin_rmap13896080755editdlrm
thin_trim13896080755editdlrm
tipc926080755editdlrm
trafshow1305920755editdlrm
tune2fs1050160755editdlrm
tzconfig1060755editdlrm
udpblast354560755editdlrm
ufw49380755editdlrm
umount.udisks2146400755editdlrm
unix_chkpwd267762755editdlrm
unix_update308720755editdlrm
update-ca-certificates54180755editdlrm
update-grub640755editdlrm
update-grub-gfxpayload3010755editdlrm
update-grub2640755editdlrm
update-gsfontmap4700755editdlrm
update-info-dir17000755editdlrm
update-initramfs69060755editdlrm
update-locale30630755editdlrm
update-mime96130755editdlrm
update-passwd353920755editdlrm
update-pciids17530755editdlrm
update-rc.d173240755editdlrm
update-secureboot-policy76050755editdlrm
update-shells38060755editdlrm
upgrade-from-grub-legacy15960755editdlrm
usbmuxd886800755editdlrm
usb_modeswitch610960755editdlrm
usb_modeswitch_dispatcher274180755editdlrm
useradd1307200755editdlrm
userdel889360755editdlrm
usermod1264240755editdlrm
uuidd315920755editdlrm
validlocale17730755editdlrm
vcstime144880755editdlrm
vdpa312960755editdlrm
veritysetup448080755editdlrm
vgcfgbackup30275440755editdlrm
vgcfgrestore30275440755editdlrm
vgchange30275440755editdlrm
vgck30275440755editdlrm
vgconvert30275440755editdlrm
vgcreate30275440755editdlrm
vgdisplay30275440755editdlrm
vgexport30275440755editdlrm
vgextend30275440755editdlrm
vgimport30275440755editdlrm
vgimportclone30275440755editdlrm
vgmerge30275440755editdlrm
vgmknodes30275440755editdlrm
vgreduce30275440755editdlrm
vgremove30275440755editdlrm
vgrename30275440755editdlrm
vgs30275440755editdlrm
vgscan30275440755editdlrm
vgsplit30275440755editdlrm
vigr578880755editdlrm
vipw578880755editdlrm
visudo2250640755editdlrm
vpddecode149280755editdlrm
wipefs392960755editdlrm
xfs_admin14070755editdlrm
xfs_bmap6950755editdlrm
xfs_copy844640755editdlrm
xfs_db6680960755editdlrm
xfs_estimate145040755editdlrm
xfs_freeze8000755editdlrm
xfs_fsr431920755editdlrm
xfs_growfs392000755editdlrm
xfs_info12940755editdlrm
xfs_io2043440755editdlrm
xfs_logprint802080755editdlrm
xfs_mdrestore268000755editdlrm
xfs_metadump7820755editdlrm
xfs_mkfile10400755editdlrm
xfs_ncheck6850755editdlrm
xfs_quota923280755editdlrm
xfs_repair6137680755editdlrm
xfs_rtcp185840755editdlrm
xfs_scrub1088160755editdlrm
xfs_scrub_all60060755editdlrm
xfs_spaceman433200755editdlrm
xtables-legacy-multi992720755editdlrm
xtables-monitor2242960755editdlrm
xtables-nft-multi2242960755editdlrm
zerofree144880755editdlrm
zic638160755editdlrm
zramctl558240755editdlrm
Edit: /usr/sbin/needrestart (39658B)
#!/usr/bin/perl # nagios: -epn # needrestart - Restart daemons after library updates. # # Authors: # Thomas Liske # # Copyright Holder: # 2013 - 2020 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] # # License: # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # use Cwd qw(realpath); use Getopt::Std; use NeedRestart; use NeedRestart::UI; use NeedRestart::Interp; use NeedRestart::Kernel; use NeedRestart::uCode; use NeedRestart::Utils; use Sort::Naturally; use Locale::TextDomain 'needrestart'; use List::Util qw(sum); use warnings; use strict; $|++; $Getopt::Std::STANDARD_HELP_VERSION++; my $LOGPREF = '[main]'; my $is_systemd = -d q(/run/systemd/system); my $is_runit = -e q(/run/runit.stopit); my $is_tty = (-t *STDERR || -t *STDOUT || -t *STDIN); my $is_vm; my $is_container; if($is_systemd && -x q(/usr/bin/systemd-detect-virt)) { # check if we are inside of a vm my $ret = system(qw(/usr/bin/systemd-detect-virt --vm --quiet)); unless($? == -1 || $? & 127) { $is_vm = ($? >> 8) == 0; } # check if we are inside of a container $ret = system(qw(/usr/bin/systemd-detect-virt --container --quiet)); unless($? == -1 || $? & 127) { $is_container = ($? >> 8) == 0; } } elsif (-r "/proc/1/environ") { # check if we are inside of a container (fallback) local $/; open(HENV, '<', '/proc/1/environ'); $is_container = scalar(grep {/^container=/;} unpack("(Z*)*", )); close(HENV) } sub HELP_MESSAGE { print <] [-r ] [-f ] [-u ] [-bkl] -v be more verbose -q be quiet -m set detail level e (e)asy mode a (a)dvanced mode -n set default answer to 'no' -c config filename -r set restart mode l (l)ist only i (i)nteractive restart a (a)utomatically restart -b enable batch mode -p enable nagios plugin mode -f override debconf frontend (DEBIAN_FRONTEND, debconf(7)) -t tolerate interpreter process start times within this value -u use preferred UI package (-u ? shows available packages) By using the following options only the specified checks are performed: -k check for obsolete kernel -l check for obsolete libraries -w check for obsolete CPU microcode --help show this help --version show version information USG } sub VERSION_MESSAGE { print < Copyright Holder: 2013 - 2020 (C) Thomas Liske [http://fiasko-nw.net/~thomas/] Upstream: https://github.com/liske/needrestart This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. LIC #/ } our %nrconf = ( verbosity => 1, hook_d => '/etc/needrestart/hook.d', notify_d => '/etc/needrestart/notify.d', restart_d => '/etc/needrestart/restart.d', sendnotify => 1, restart => 'i', defno => 0, ui_mode => 'a', systemctl_combine => 0, blacklist => [], blacklist_interp => [], blacklist_rc => [], blacklist_mappings => [], override_rc => {}, override_cont => {}, skip_mapfiles => -1, interpscan => 1, kernelhints => 1, kernelfilter => qr(.), ucodehints => 1, q(nagios-status) => { services => 1, kernel => 2, ucode => 2, sessions => 2, containers => 1, }, has_pam_systemd => 1, tolerance => 2, ); # backup ARGV (required for Debconf) my @argv = @ARGV; our $opt_c = '/etc/needrestart/needrestart.conf'; our $opt_v; our $opt_r; our $opt_n; our $opt_m; our $opt_b; our $opt_f; our $opt_k; our $opt_l; our $opt_p; our $opt_q; our $opt_t; our $opt_u; our $opt_w; unless(getopts('c:vr:nm:bf:klpqt:u:w')) { HELP_MESSAGE; exit 1; } # disable exiting and STDOUT in Getopt::Std for further use of getopts $Getopt::Std::STANDARD_HELP_VERSION = undef; # restore ARGV @ARGV = @argv; die "ERROR: Could not read config file '$opt_c'!\n" unless(-r $opt_c || $opt_b); # override debconf frontend $ENV{DEBIAN_FRONTEND} = $opt_f if($opt_f); my $debian_noninteractive = (exists($ENV{DEBIAN_FRONTEND}) && $ENV{DEBIAN_FRONTEND} eq 'noninteractive'); # be quiet if($opt_q) { $nrconf{verbosity} = 0; } # be verbose elsif($opt_v) { $nrconf{verbosity} = 2; } # slurp config file print STDERR "$LOGPREF eval $opt_c\n" if($nrconf{verbosity} > 1); eval do { local $/; open my $fh, $opt_c or die "ERROR: $!\n"; my $cfg = <$fh>; close($fh); $cfg; }; die "Error parsing $opt_c: $@" if($@); # fallback to stdio on verbose mode $nrconf{ui} = qq(NeedRestart::UI::stdio) if($nrconf{verbosity} > 1); die "Hook directory '$nrconf{hook_d}' is invalid!\n" unless(-d $nrconf{hook_d} || $opt_b); $opt_r = $ENV{NEEDRESTART_MODE} if(!defined($opt_r) && exists($ENV{NEEDRESTART_MODE})); $opt_r = $nrconf{restart} unless(defined($opt_r)); die "ERROR: Unknown restart option '$opt_r'!\n" unless($opt_r =~ /^(l|i|a)$/); $is_tty = 0 if($opt_r eq 'i' && $debian_noninteractive); $opt_r = 'l' if(!$is_tty && $opt_r eq 'i'); $opt_m = $nrconf{ui_mode} unless(defined($opt_m)); die "ERROR: Unknown UI mode '$opt_m'!\n" unless($opt_m =~ /^(e|a)$/); $opt_r = 'l' if($opt_m eq 'e'); $opt_t = $nrconf{tolerance} unless(defined($opt_t)); $nrconf{defno}++ if($opt_n); $opt_b++ if($opt_p); # print version in verbose mode print STDERR "$LOGPREF needrestart v$NeedRestart::VERSION\n" if($nrconf{verbosity} > 1); # running mode (user or root) my $uid = $<; if($uid) { if($opt_p) { print "UNKN - This plugin needs to be run as root!\n"; exit 3; } print STDERR "$LOGPREF running in user mode\n" if($nrconf{verbosity} > 1); } else { print STDERR "$LOGPREF running in root mode\n" if($nrconf{verbosity} > 1); } # get current runlevel, fallback to '2' my $runlevel = `who -r` || ''; chomp($runlevel); $runlevel = 2 unless($runlevel =~ s/^.+run-level (\S)\s.+$/$1/); # get UI if(defined($opt_u)) { if ($opt_u eq '?') { print STDERR join("\n\t", __(q(Available UI packages:)), needrestart_ui_list($nrconf{verbosity}, ($is_tty ? $nrconf{ui} : 'NeedRestart::UI::stdio')))."\n"; exit 0; } else { $nrconf{ui} = $opt_u; } } my $ui = ($opt_b ? NeedRestart::UI->new(0) : needrestart_ui($nrconf{verbosity}, ($is_tty ? $nrconf{ui} : 'NeedRestart::UI::stdio'))); die "Error: no UI class available!\n" unless(defined($ui)); # Disable UI interactiveness $ui->interactive(0) if ($ui->can("interactive") && $debian_noninteractive); # enable/disable checks unless(defined($opt_k) || defined($opt_l) || defined($opt_w)) { $opt_k = ($uid ? undef : 1); $opt_l = 1; $opt_w = ($uid ? undef : $nrconf{ucodehints}); } sub parse_lsbinit($) { my $rc = '/etc/init.d/'.shift; # ignore upstart-job magic if(-l $rc && readlink($rc) eq '/lib/init/upstart-job') { print STDERR "$LOGPREF ignoring $rc since it is a converted upstart job\n" if($nrconf{verbosity} > 1); return (); } open(HLSB, '<', $rc) || die "Can't open $rc: $!\n"; my %lsb; my $found_lsb; my %chkconfig; my $found_chkconfig; while(my $line = ) { chomp($line); unless($found_chkconfig) { if($line =~ /^# chkconfig: (\d+) /) { $chkconfig{runlevels} = $1; $found_chkconfig++ } } elsif($line =~ /^# (\S+): (.+)$/) { $chkconfig{lc($1)} = $2; } unless($found_lsb) { $found_lsb++ if($line =~ /^### BEGIN INIT INFO/); next; } elsif($line =~ /^### END INIT INFO/) { last; } $lsb{lc($1)} = $2 if($line =~ /^# ([^:]+):\s+(.+)$/); } # convert chkconfig tags to LSB tags if($found_chkconfig && !$found_lsb) { print STDERR "$LOGPREF $rc is missing LSB tags, found chkconfig tags instead\n" if($nrconf{verbosity} > 1); $found_lsb++; $lsb{pidfiles} = [$chkconfig{pidfile}]; $lsb{q(default-start)} = $chkconfig{runlevels}; } unless($found_lsb) { print STDERR "WARNING: $rc has no LSB tags!\n" unless(%lsb); return (); } # pid file heuristic unless(exists($lsb{pidfiles})) { my $found = 0; my %pidfiles; while(my $line = ) { if($line =~ m@(\S*/run/[^/]+.pid)@ && -r $1) { $pidfiles{$1}++; $found++; } } $lsb{pidfiles} = [keys %pidfiles] if($found); } close(HLSB); return %lsb; } print STDERR "$LOGPREF systemd detected\n" if($nrconf{verbosity} > 1 && $is_systemd); print STDERR "$LOGPREF vm detected\n" if($nrconf{verbosity} > 1 && $is_vm); print STDERR "$LOGPREF container detected\n" if($nrconf{verbosity} > 1 && $is_container); sub systemd_refuse_restart { my $svc = shift; my $systemctl = nr_fork_pipe($nrconf{verbosity} > 1, qq(systemctl), qq(show), qq(--property=RefuseManualStop), $svc); my $ret = <$systemctl>; close($systemctl); if($ret && $ret =~ /^RefuseManualStop=yes/) { print STDERR "$LOGPREF systemd refuses restarts of $svc\n" if($nrconf{verbosity} > 1); return 1; } return 0; } my @systemd_restart; sub restart_cmd($) { my $rc = shift; my $restcmd = "$nrconf{restart_d}/$rc"; if(-x $restcmd) { print STDERR "$LOGPREF using restart.d file $rc\n" if($nrconf{verbosity} > 1); ($restcmd); } elsif($rc =~ /.+\.service$/) { if($nrconf{systemctl_combine}) { push(@systemd_restart, $rc); (); } else { (qw(systemctl restart), $rc); } } else { if($is_systemd) { if($nrconf{systemctl_combine}) { push(@systemd_restart, qq($rc.service)); (); } else { (qw(systemctl restart), qq($rc.service)); } } elsif($is_runit && -d qq(/etc/sv/$rc)) { if(-e qq(/etc/service/$rc)) { (qw(sv restart), $rc); } else { (q(service), $rc, q(restart)); } } else { (q(invoke-rc.d), $rc, q(restart)); } } } # map UID to username (cached) my %uidcache; sub uid2name($) { my $uid = shift; return $uidcache{$uid} if(exists($uidcache{$uid})); return $uidcache{$uid} = getpwuid($uid) || $uid; } my %nagios = ( # kernel kstr => q(unknown), kret => 3, kperf => q(U), # uCode mstr => q(unknown), mret => 3, mperf => q(U), # services sstr => q(unknown), sret => 3, sperf => q(U), # sessions ustr => q(unknown), uret => 3, uperf => q(U), ); print "NEEDRESTART-VER: $NeedRestart::VERSION\n" if($opt_b && !$opt_p); my %restart; my %sessions; my @guests; my @easy_hints; if(defined($opt_l)) { my @ign_pids=($$, getppid()); # inspect only pids my $ptable = nr_ptable(); # find session parent sub findppid($@) { my $uid = shift; my ($pid, @pids) = @_; if($ptable->{$pid}->{ppid} == 1) { return $pid if($ptable->{$pid}->{uid} == $uid); return undef; } foreach my $pid (@pids) { my $ppid = &findppid($uid, $pid); return $ppid if($ppid); } return $pid; } $ui->progress_prep(scalar keys %$ptable, __ 'Scanning processes...'); my %stage2; for my $pid (sort {$a <=> $b} keys %$ptable) { $ui->progress_step; # user-mode: skip foreign processes next if($uid && $ptable->{$pid}->{uid} != $uid); # skip myself next if(grep {$pid == $_} @ign_pids); my $restart = 0; my $exe = nr_readlink($pid); # ignore kernel threads next unless(defined($exe)); # orphaned binary $restart++ if (defined($exe) && $exe =~ s/ \(deleted\)$//); # Linux $restart++ if (defined($exe) && $exe =~ s/^\(deleted\)//); # Linux VServer print STDERR "$LOGPREF #$pid uses obsolete binary $exe\n" if($restart && $nrconf{verbosity} > 1); # ignore blacklisted binaries next if(grep { $exe =~ /$_/; } @{$nrconf{blacklist}}); # Sync $exe with the initial value from Proc::ProcessTable to prevent race # conditions in later checks. if(defined($ptable->{$pid}->{exec})) { $exe = $ptable->{$pid}->{exec}; } # Proc::ProcessTable's exec field is undef if the file is not accessible in # the root mountns, so the value of $exe is used instead. else { $ptable->{$pid}->{exec} = $exe; } # read file mappings (Linux 2.0+) unless($restart) { if(open(HMAP, '<', "/proc/$pid/maps")) { while() { chomp; my ($maddr, $mperm, $moffset, $mdev, $minode, $path) = split(/\s+/, $_, 6); # skip special handles and non-executable mappings next unless(defined($path) && $minode != 0 && $path ne '' && $mperm =~ /x/); # skip special device paths next if(scalar grep { $path =~ /$_/; } @{$nrconf{blacklist_mappings}}); # removed executable mapped files if($path =~ s/ \(deleted\)$// || # Linux $path =~ s/^\(deleted\)//) { # Linux VServer print STDERR "$LOGPREF #$pid uses deleted $path\n" if($nrconf{verbosity} > 1); $restart++; last; } # check for outdated lib mappings unless($nrconf{skip_mapfiles} == 1) { $maddr =~ s/^0+([^-])/$1/; $maddr =~ s/-0+(.)/-$1/; my @paths = ("/proc/$pid/map_files/$maddr", "/proc/$pid/root/$path"); my ($testp) = grep { -e $_; } @paths; unless($testp) { unless($nrconf{skip_mapfiles} == -1) { print STDERR "$LOGPREF #$pid uses non-existing $path\n" if($nrconf{verbosity} > 1); $restart++; last; } next; } # get on-disk info my ($sdev, $sinode) = stat($testp); my @sdevs = ( # glibc gnu_dev_* definition from sysmacros.h sprintf("%02x:%02x", (($sdev >> 8) & 0xfff) | (($sdev >> 32) & ~0xfff), (($sdev & 0xff) | (($sdev >> 12) & ~0xff))), # Traditional definition of major(3) and minor(3) sprintf("%02x:%02x", $sdev >> 8, $sdev & 0xff), # kFreeBSD: /proc//maps does not contain device IDs qq(00:00) ); # Don't compare device numbers on anon filesystems # w/o a backing device (like OpenVZ's simfs). my $major = (($sdev >> 8) & 0xfff) | (($sdev >> 32) & ~0xfff); $mdev = "00:00" if ($major == 0 || $major == 144 || $major == 145 || $major == 146); # compare maps content vs. on-disk unless($minode eq $sinode && ((grep {$mdev eq $_} @sdevs) || # BTRFS breaks device ID mapping completely... # ignoring unnamed device IDs for now $mdev =~ /^00:/)) { print STDERR "$LOGPREF #$pid uses obsolete $path\n" if($nrconf{verbosity} > 1); $restart++; last; } } } close(HMAP); } else { print STDERR "$LOGPREF #$pid could not open maps: $!\n" if($nrconf{verbosity} > 1); } } unless($restart || !$nrconf{interpscan}) { $restart++ if(needrestart_interp_check($nrconf{verbosity} > 1, $pid, $exe, $nrconf{blacklist_interp}, $opt_t)); } # handle containers (LXC, docker, etc.) next if($restart && needrestart_cont_check($nrconf{verbosity} > 1, $pid, $exe, $opt_t)); # restart needed? next unless($restart); # handle user sessions if($ptable->{$pid}->{ttydev} ne '' && (!$is_systemd || !$nrconf{has_pam_systemd})) { my $ttydev = realpath( $ptable->{$pid}->{ttydev} ); print STDERR "$LOGPREF #$pid part of user session: uid=$ptable->{$pid}->{uid} sess=$ttydev\n" if($nrconf{verbosity} > 1); push(@{ $sessions{ $ptable->{$pid}->{uid} }->{ $ttydev }->{ $ptable->{$pid}->{fname} } }, $pid); # add session processes to stage2 only in user mode $stage2{$pid} = $exe if($uid); next; } # find parent process my $ppid = $ptable->{$pid}->{ppid}; if($ppid != $pid && $ppid > 1 && !$uid) { print STDERR "$LOGPREF #$pid is a child of #$ppid\n" if($nrconf{verbosity} > 1); if($uid && $ptable->{$ppid}->{uid} != $uid) { print STDERR "$LOGPREF #$ppid is a foreign process\n" if($nrconf{verbosity} > 1); $stage2{$pid} = $exe; } else { unless(exists($stage2{$ppid})) { my $pexe = nr_readlink($ppid); # ignore kernel threads next unless(defined($pexe)); $stage2{$ppid} = $pexe; } } } else { print STDERR "$LOGPREF #$pid is not a child\n" if($nrconf{verbosity} > 1 && !$uid); $stage2{$pid} = $exe; } } $ui->progress_fin; if(scalar keys %stage2 && !$uid) { $ui->progress_prep(scalar keys %stage2, __ 'Scanning candidates...'); PIDLOOP: foreach my $pid (sort {$a <=> $b} keys %stage2) { $ui->progress_step; # skip myself next if(grep {$pid == $_} @ign_pids); my $exe = nr_readlink($pid); $exe =~ s/ \(deleted\)$//; # Linux $exe =~ s/^\(deleted\)//; # Linux VServer print STDERR "$LOGPREF #$pid exe => $exe\n" if($nrconf{verbosity} > 1); # try to find interpreter source file ($exe) = (needrestart_interp_source($nrconf{verbosity} > 1, $pid, $exe), $exe); # ignore blacklisted binaries next if(grep { $exe =~ /$_/; } @{$nrconf{blacklist}}); if($is_systemd) { # systemd manager if($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; } # get unit name from /proc//cgroup if(open(HCGROUP, qq(/proc/$pid/cgroup))) { my ($rc) = map { chomp; my ($id, $type, $value) = split(/:/); if($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; } } } } 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); (); } } } ; close(HCGROUP); if($rc) { print STDERR "$LOGPREF #$pid is $rc\n" if($nrconf{verbosity} > 1); $restart{$rc}++; next; } } # did not get the unit name, yet - try systemctl status print STDERR "$LOGPREF /proc/$pid/cgroup: $!\n" if($nrconf{verbosity} > 1 && $!); print STDERR "$LOGPREF trying systemctl status\n" if($nrconf{verbosity} > 1); my $systemctl = nr_fork_pipe($nrconf{verbosity} > 1, qq(systemctl), qq(-n), qq(0), qq(--full), qq(status), $pid); my $ret = <$systemctl>; close($systemctl); if(defined($ret) && $ret =~ /([^\s]+\.service)( |$)/) { my $s = $1; print STDERR "$LOGPREF #$pid is $s\n" if($nrconf{verbosity} > 1); $restart{$s}++; $s =~ s/\.service$//; delete($restart{$s}); next; } } else { # sysv init if($pid == 1 && $exe =~ m@^/sbin/init@) { print STDERR "$LOGPREF #$pid is sysv init\n" if($nrconf{verbosity} > 1); $restart{q(sysv-init)}++; next; } } my $pkg; foreach my $hook (nsort <$nrconf{hook_d}/*>) { print STDERR "$LOGPREF #$pid running $hook\n" if($nrconf{verbosity} > 1); my $found = 0; my $prun = nr_fork_pipe($nrconf{verbosity} > 1, $hook, ($nrconf{verbosity} > 1 ? qw(-v) : ()), $exe); my @nopids; while(<$prun>) { chomp; my @v = split(/\|/); if($v[0] eq 'PACKAGE' && $v[1]) { $pkg = $v[1]; print STDERR "$LOGPREF #$pid package: $v[1]\n" if($nrconf{verbosity} > 1); next; } if($v[0] eq 'RC') { my %lsb = parse_lsbinit($v[1]); unless(%lsb && exists($lsb{'default-start'})) { # If the script has no LSB tags we consider to call it later - they # are broken anyway. print STDERR "$LOGPREF no LSB headers found at $v[1]\n" if($nrconf{verbosity} > 1); push(@nopids, $v[1]); } # In the run-levels S and 1 no daemons are being started (normally). # We don't call any rc.d script not started in the current run-level. elsif($lsb{'default-start'} =~ /$runlevel/) { # If a pidfile has been found, try to look for the daemon and ignore # any forked/detached childs (just a heuristic due Debian Bug#721810). if(exists($lsb{pidfiles})) { foreach my $pidfile (@{ $lsb{pidfiles} }) { open(HPID, '<', "$pidfile") || next; my $p = ; close(HPID); if(int($p) == $pid) { print STDERR "$LOGPREF #$pid has been started by $v[1] - triggering\n" if($nrconf{verbosity} > 1); $restart{$v[1]}++; $found++; last; } } } else { print STDERR "$LOGPREF no pidfile reference found at $v[1]\n" if($nrconf{verbosity} > 1); push(@nopids, $v[1]); } } else { print STDERR "$LOGPREF #$pid rc.d script $v[1] should not start in the current run-level($runlevel)\n" if($nrconf{verbosity} > 1); } } } # No perfect hit - call any rc scripts instead. print STDERR "$LOGPREF #$pid running $hook no perfect hit found $found pids $#nopids\n" if($nrconf{verbosity} > 1); if(!$found && $#nopids > -1) { foreach my $rc (@nopids) { if($is_systemd && exists($restart{"$rc.service"})) { print STDERR "$LOGPREF #$pid rc.d script $rc seems to be superseded by $rc.service\n" if($nrconf{verbosity} > 1); } else { $restart{$rc}++; } } $found++; } last if($found); } } $ui->progress_fin; } # List user's processes in user-mode if($uid && scalar %stage2) { my %fnames; foreach my $pid (keys %stage2) { push(@{$fnames{ $ptable->{$pid}->{fname} }}, $pid); } if($opt_b) { print map { "NEEDRESTART-PID: $_=".join(',', @{ $fnames{$_} })."\n"; } nsort keys %fnames; } else { $ui->notice(__ 'Your outdated processes:'); $ui->notice(join(', ',map { $_.'['.join(', ', @{ $fnames{$_} }).']'; } nsort keys %fnames)); } } } # Apply rc/service blacklist foreach my $rc (keys %restart) { next unless(scalar grep { $rc =~ /$_/; } @{$nrconf{blacklist_rc}}); print STDERR "$LOGPREF $rc is blacklisted -> ignored\n" if($nrconf{verbosity} > 1); delete($restart{$rc}); } # Skip kernel stuff within container if($is_container || needrestart_cont_check($nrconf{verbosity} > 1, 1, nr_readlink(1), 1)) { print STDERR "$LOGPREF inside container, skipping kernel checks\n" if($nrconf{verbosity} > 1); $opt_k = undef; } # Skip uCode stuff within container or vm if($is_container || $is_vm || needrestart_cont_check($nrconf{verbosity} > 1, 1, nr_readlink(1), 1)) { print STDERR "$LOGPREF inside container or vm, skipping microcode checks\n" if($nrconf{verbosity} > 1); $opt_w = undef; } my ($ucode_result, %ucode_vars) = (NRM_UNKNOWN); if(defined($opt_w)) { ($ucode_result, %ucode_vars) = ($nrconf{ucodehints} || $opt_w ? nr_ucode_check($nrconf{verbosity} > 1, $ui) : ()); } if(defined($opt_k)) { my ($kresult, %kvars) = ($nrconf{kernelhints} || $opt_b ? nr_kernel_check($nrconf{verbosity} > 1, $nrconf{kernelfilter}, $ui) : ()); if(defined($kresult)) { if($opt_b) { unless($opt_p) { print "NEEDRESTART-KCUR: $kvars{KVERSION}\n"; print "NEEDRESTART-KEXP: $kvars{EVERSION}\n" if(defined($kvars{EVERSION})); print "NEEDRESTART-KSTA: $kresult\n"; } else { $nagios{kstr} = $kvars{KVERSION}; if($kresult == NRK_VERUPGRADE) { $nagios{kstr} .= "!=$kvars{EVERSION}"; $nagios{kret} = $nrconf{q(nagios-status)}->{kernel}; $nagios{kperf} = 2; } elsif($kresult == NRK_ABIUPGRADE) { $nagios{kret} = $nrconf{q(nagios-status)}->{kernel}; $nagios{kperf} = 1; } elsif($kresult == NRK_NOUPGRADE) { $nagios{kret} = 0; $nagios{kperf} = 0; } if($nagios{kret} == 1) { $nagios{kstr} .= " (!)"; } elsif($nagios{kret} == 2) { $nagios{kstr} .= " (!!)"; } } } else { if($kresult == NRK_NOUPGRADE) { unless($opt_m eq 'e') { $ui->vspace(); $ui->notice(($kvars{ABIDETECT} ? __('Running kernel seems to be up-to-date.') : __('Running kernel seems to be up-to-date (ABI upgrades are not detected).'))) } } elsif($kresult == NRK_ABIUPGRADE) { push(@easy_hints, __ 'an outdated kernel image') if($opt_m eq 'e'); if($nrconf{kernelhints} < 0) { $ui->vspace(); $ui->notice(__x( 'The currently running kernel version is {kversion} and there is an ABI compatible upgrade pending.', kversion => $kvars{KVERSION}, )); } else { $ui->announce_abi(%kvars); } } elsif($kresult == NRK_VERUPGRADE) { push(@easy_hints, __ 'an outdated kernel image') if($opt_m eq 'e'); if($nrconf{kernelhints} < 0) { $ui->vspace(); $ui->notice(__x( 'The currently running kernel version is {kversion} which is not the expected kernel version {eversion}.', kversion => $kvars{KVERSION}, eversion => $kvars{EVERSION}, )); } else { $ui->announce_ver(%kvars); } } else { $ui->vspace(); $ui->notice(__ 'Failed to retrieve available kernel versions.'); } } } } if($opt_w) { if($opt_b) { unless($opt_p) { print "NEEDRESTART-UCSTA: $ucode_result\n"; if($ucode_result != NRM_UNKNOWN) { print "NEEDRESTART-UCCUR: $ucode_vars{CURRENT}\n"; print "NEEDRESTART-UCEXP: $ucode_vars{AVAIL}\n"; } } else { if($ucode_result == NRM_OBSOLETE) { $nagios{mstr} = "OBSOLETE"; $nagios{mret} = $nrconf{q(nagios-status)}->{ucode}; $nagios{mperf} = 1; } elsif($ucode_result == NRM_CURRENT) { $nagios{mstr} = "CURRENT"; $nagios{mret} = 0; $nagios{mperf} = 0; } if($nagios{mret} == 1) { $nagios{mstr} .= " (!)"; } elsif($nagios{mret} == 2) { $nagios{mstr} .= " (!!)"; } } } else { if($ucode_result == NRM_CURRENT) { unless($opt_m eq 'e') { $ui->vspace(); $ui->notice(__('The processor microcode seems to be up-to-date.')); } } elsif($ucode_result == NRM_OBSOLETE) { push(@easy_hints, __ 'outdated processor microcode') if($opt_m eq 'e'); if($nrconf{ucodehints}) { $ui->announce_ucode(%ucode_vars); } } else { $ui->vspace(); $ui->notice(__ 'Failed to check for processor microcode upgrades.'); } } } if(defined($opt_l) && !$uid) { ## SERVICES $ui->vspace(); unless(scalar %restart) { $ui->notice(__ 'No services need to be restarted.') unless($opt_b || $opt_m eq 'e'); if($opt_p) { $nagios{sstr} = q(none); $nagios{sret} = 0; $nagios{sperf} = 0; } } else { if($opt_m eq 'e' && $opt_r ne 'i') { push(@easy_hints, __ 'outdated binaries'); } elsif($opt_b || $opt_r ne 'i') { my @skipped_services; my @refused_services; $ui->notice(__ 'Services to be restarted:') if($opt_r eq 'l'); $ui->notice(__ 'Restarting services...') if($opt_r eq 'a'); if($opt_p) { $nagios{sstr} = (scalar keys %restart); $nagios{sret} = $nrconf{q(nagios-status)}->{services}; $nagios{sperf} = (scalar keys %restart); if($nagios{sret} == 1) { $nagios{sstr} .= " (!)"; } elsif($nagios{sret} == 2) { $nagios{sstr} .= " (!!)"; } } foreach my $rc (sort { lc($a) cmp lc($b) } keys %restart) { # always combine restarts in one systemctl command local $nrconf{systemctl_combine} = 1 unless($opt_r eq 'l'); if($opt_b) { print "NEEDRESTART-SVC: $rc\n" unless($opt_p); next; } # record service which can not be restarted if($is_systemd && systemd_refuse_restart($rc)) { push(@refused_services, $rc); next; } # don't restart greylisted services... my $restart = !$nrconf{defno}; foreach my $re (keys %{$nrconf{override_rc}}) { next unless($rc =~ /$re/); $restart = $nrconf{override_rc}->{$re}; last; } # ...but complain about them unless($restart) { push(@skipped_services, $rc); next; } my @cmd = restart_cmd($rc); next unless($#cmd > -1); $ui->command(join(' ', '', @cmd)); $ui->runcmd(sub { system(@cmd) if($opt_r eq 'a'); }); } unless($#systemd_restart == -1) { my @cmd = (qq(systemctl), qq(restart), @systemd_restart); $ui->command(join(' ', '', @cmd)); $ui->runcmd(sub { system(@cmd) if($opt_r eq 'a'); }); } @systemd_restart = (); if($#skipped_services > -1) { $ui->vspace(); $ui->notice(__ 'Service restarts being deferred:'); foreach my $rc (sort @skipped_services) { my @cmd = restart_cmd($rc); $ui->command(join(' ', '', @cmd)) if($#cmd > -1); } unless($#systemd_restart == -1) { my @cmd = (qq(systemctl), qq(restart), @systemd_restart); $ui->command(join(' ', '', @cmd)); } } # report services restarts refused by systemd if($#refused_services > -1) { $ui->vspace(); $ui->notice(__ 'Service restarts being refused by systemd:'); foreach my $rc (sort @refused_services) { $ui->command(qq( $rc)); } } } else { my $o = 0; my @skipped_services = keys %restart; # filter service units which are refused to be restarted my @refused_services; my %rs = map { my $rc = $_; if($is_systemd) { if(systemd_refuse_restart($rc)) { push(@refused_services, $rc); @skipped_services = grep { $_ ne $rc; } @skipped_services; (); } else { ($rc => 1); } } else { ($rc => 1); } } keys %restart; $ui->notice(__ 'Restarting services...'); $ui->query_pkgs(__('Services to be restarted:'), $nrconf{defno}, \%rs, $nrconf{override_rc}, sub { # always combine restarts in one systemctl command local $nrconf{systemctl_combine} = 1; my $rc = shift; @skipped_services = grep { $_ ne $rc; } @skipped_services; my @cmd = restart_cmd($rc); return unless($#cmd > -1); $ui->command(join(' ', '', @cmd)); system(@cmd); }); if($#systemd_restart > -1) { my @cmd = (qw(systemctl restart), @systemd_restart); $ui->command(join(' ', '', @cmd)); $ui->runcmd(sub { system(@cmd); }); } @systemd_restart = (); if($#skipped_services > -1) { $ui->notice(__ 'Service restarts being deferred:'); foreach my $rc (sort @skipped_services) { my @cmd = restart_cmd($rc); $ui->command(join(' ', '', @cmd)) if($#cmd > -1); } unless($#systemd_restart == -1) { my @cmd = (qq(systemctl), qq(restart), @systemd_restart); $ui->command(join(' ', '', @cmd)); } } # report services restarts refused by systemd if($#refused_services > -1) { $ui->notice(__ 'Service restarts being refused by systemd:'); foreach my $rc (sort @refused_services) { $ui->command(qq( $rc)); } } } } ## CONTAINERS $ui->vspace(); @systemd_restart = (); my %conts = needrestart_cont_get($nrconf{verbosity} > 1); unless(scalar %conts) { $ui->notice(__ 'No containers need to be restarted.') unless($opt_b || $opt_m eq 'e'); if($opt_p) { $nagios{cstr} = q(none); $nagios{cret} = 0; $nagios{cperf} = 0; } } else { if($opt_m eq 'e' && $opt_r ne 'i') { push(@easy_hints, __ 'outdated containers'); } elsif($opt_b || $opt_r ne 'i') { my @skipped_containers; $ui->notice(__ 'Containers to be restarted:') if($opt_r eq 'l'); $ui->notice(__ 'Restarting containers...') if($opt_r eq 'a'); if($opt_p) { $nagios{cstr} = (scalar keys %conts); $nagios{cret} = $nrconf{q(nagios-status)}->{containers}; $nagios{cperf} = (scalar keys %conts); if($nagios{cret} == 1) { $nagios{cstr} .= " (!)"; } elsif($nagios{cret} == 2) { $nagios{cstr} .= " (!!)"; } } foreach my $cont (sort { lc($a) cmp lc($b) } keys %conts) { if($opt_b) { print "NEEDRESTART-CONT: $cont\n" unless($opt_p); next; } # don't restart greylisted containers... my $restart = !$nrconf{defno}; foreach my $re (keys %{$nrconf{override_cont}}) { next unless($cont =~ /$re/); $restart = $nrconf{override_cont}->{$re}; last; } # ...but complain about them unless($restart) { push(@skipped_containers, $cont); next; } $ui->command(join(' ', '', @{ $conts{$cont} })); $ui->runcmd(sub { system(@{ $conts{$cont} }) if($opt_r eq 'a'); }); } if($#skipped_containers > -1) { $ui->notice(__ 'Container restarts being deferred:'); foreach my $cont (sort @skipped_containers) { $ui->command(join(' ', '', @{ $conts{$cont} })); } } } else { my $o = 0; $ui->notice(__ 'Restarting containers...'); $ui->query_conts(__('Containers to be restarted:'), $nrconf{defno}, \%conts, $nrconf{override_cont}, sub { my $cont = shift; $ui->command(join(' ', '', @{ $conts{$cont} })); system(@{ $conts{$cont} }); }); } } ## SESSIONS $ui->vspace(); # list and notify user sessions unless(scalar keys %sessions) { $ui->notice(__ 'No user sessions are running outdated binaries.') unless($opt_b || $opt_m eq 'e'); if($opt_p) { $nagios{ustr} = 'none'; $nagios{uret} = 0; $nagios{uperf} = 0; } } else { if($opt_m eq 'e') { push(@easy_hints, __ 'outdated sessions'); } else { $ui->notice(__ 'User sessions running outdated binaries:'); } if($opt_p) { my $count = sum map { scalar keys %{ $sessions{$_} } } keys %sessions; $nagios{ustr} = $count; $nagios{uret} = $nrconf{q(nagios-status)}->{sessions}; $nagios{uperf} = $count; if($nagios{uret} == 1) { $nagios{ustr} .= " (!)"; } elsif($nagios{uret} == 2) { $nagios{ustr} .= " (!!)"; } } unless($opt_p || $opt_b) { foreach my $uid (sort { ncmp(uid2name($a), uid2name($b)); } keys %sessions) { foreach my $sess (sort keys %{ $sessions{$uid} }) { my $fnames = join(', ',map { $_.'['.join(',', @{ $sessions{$uid}->{$sess}->{$_} }).']'; } nsort keys %{ $sessions{$uid}->{$sess} }); $ui->notice(' '.uid2name($uid)." @ $sess: $fnames") unless($opt_m eq 'e'); if($nrconf{sendnotify}) { local %ENV; $ENV{NR_UID} = $uid; $ENV{NR_USERNAME} = uid2name($uid); $ENV{NR_SESSION} = $sess; $ENV{NR_SESSPPID} = findppid($uid, sort map { @$_; } values %{ $sessions{$uid}->{$sess} }); foreach my $bin (nsort <$nrconf{notify_d}/*>) { next unless(-x $bin); next if($bin =~ /(~|\.dpkg-[^.]+)$/); print STDERR "$LOGPREF run $bin\n" if($nrconf{verbosity} > 1); my $pipe = nr_fork_pipew($nrconf{verbosity} > 1, $bin); print $pipe "$fnames\n"; last if(close($pipe)); } } } } } } ## GUESTS $ui->vspace(); if (! @guests) { $ui->notice(__ 'No VM guests are running outdated hypervisor (qemu) binaries on this host.') unless($opt_b || $opt_m eq 'e'); } else { if($opt_m eq 'e') { push(@easy_hints, __ 'outdated VM guests'); } else { unless($opt_p || $opt_b) { $ui->notice(__ 'VM guests are running outdated hypervisor (qemu) binaries on this host:'); foreach ( @guests ) { $ui->notice(" $_"); } } } } } # easy mode: print hint on outdated stuff if(scalar @easy_hints) { my $t = pop(@easy_hints); my $h = join(', ', @easy_hints); $ui->announce_ehint(EHINT => ($h ? join(' ', $h, __ 'and', '') : '') . $t); } my @sessions_list; if(scalar %sessions) { # build a sorted list of user @ session strings # # used in the nagios and batch outputs below @sessions_list = map { my $uid = $_; my $user = uid2name($uid); my @ret; foreach my $sess (sort keys %{ $sessions{$uid} }) { push(@ret, "$user \@ $sess"); } @ret; } sort { ncmp(uid2name($a), uid2name($b)); } keys %sessions } # nagios plugin output if($opt_p) { my %states = ( 0 => q(OK), 1 => q(WARN), 2 => q(CRIT), 3 => q(UNKN), ); my ($ret) = reverse sort (($opt_k ? $nagios{kret} : ()), ($opt_w ? $nagios{mret} : ()), ($opt_l ? ($nagios{sret}, $nagios{cret}, $nagios{uret}) : ())); print "$states{$ret} - ", join(', ', ($opt_k ? "Kernel: $nagios{kstr}" : ()), ($opt_w ? "Microcode: $nagios{mstr}" : ()), ($opt_l ? "Services: $nagios{sstr}" : ()), ($opt_l ? "Containers: $nagios{cstr}" : ()), ($opt_l ? "Sessions: $nagios{ustr}" : ()), ), '|', join(' ', ( ($opt_k && $nagios{kret} != 3) ? "Kernel=$nagios{kperf};0;;0;2" : ()), ( ($opt_w && $nagios{mret} != 3) ? "Microcode=$nagios{mperf};0;;0;1" : ()), ( ($opt_l && $nagios{sret} != 3) ? "Services=$nagios{sperf};;0;0" : ()), ( ($opt_l && $nagios{cret} != 3) ? "Containers=$nagios{cperf};;0;0" : ()), ( ($opt_l && $nagios{uret} != 3) ? "Sessions=$nagios{uperf};0;;0" : ()), ), "\n"; if(scalar %restart) { print "Services:", join("\n- ", '', sort keys %restart), "\n"; } my %conts = needrestart_cont_get($nrconf{verbosity} > 1); if(scalar %conts) { print "Containers:", join("\n- ", '', sort keys %conts), "\n"; } if(scalar %sessions) { print "Sessions:", join("\n- ", '', @sessions_list), "\n"; } exit $ret; } if ($opt_b and scalar %sessions) { for my $sess (@sessions_list) { print "NEEDRESTART-SESS: $sess\n"; } }