Fredrik Eriksson
2886e367b3
This is to be used in environments where reboot is strictly unneeded; such as when building packages in a chroot
156 lines
4.6 KiB
Python
Executable File
156 lines
4.6 KiB
Python
Executable File
#!/usr/bin/env python3.7
|
|
import configparser
|
|
import logging
|
|
import logging.handlers
|
|
import os
|
|
import platform
|
|
import sys
|
|
import time
|
|
|
|
import sau
|
|
import sau.errors
|
|
import sau.services
|
|
import sau.platforms
|
|
|
|
def init():
|
|
sau.config = configparser.ConfigParser()
|
|
conf = sau.config
|
|
|
|
if platform.system() == 'FreeBSD':
|
|
syslog_socket = '/var/run/log'
|
|
conf_file = '/usr/local/etc/sau.cfg'
|
|
else:
|
|
syslog_socket = '/dev/log'
|
|
conf_file = '/etc/sau.cfg'
|
|
|
|
if os.path.isfile(conf_file):
|
|
conf.read(conf_file)
|
|
|
|
log = logging.getLogger(sau.LOGNAME)
|
|
log.setLevel(logging.DEBUG)
|
|
|
|
conf_level = _conf_level_to_logging_level(conf.get('default', 'stderr_loglevel', fallback="debug"))
|
|
handler = logging.StreamHandler()
|
|
formatter = logging.Formatter(fmt='%(asctime)s %(levelname)s: %(message)s')
|
|
handler.setFormatter(formatter)
|
|
handler.setLevel(conf_level)
|
|
log.addHandler(handler)
|
|
|
|
|
|
conf_level = _conf_level_to_logging_level(conf.get('default', 'syslog_loglevel', fallback="debug"))
|
|
handler = logging.handlers.SysLogHandler(address=syslog_socket)
|
|
formatter = logging.Formatter(fmt='{}[%(process)s] %(message)s'.format(sau.LOGNAME))
|
|
handler.setFormatter(formatter)
|
|
handler.setLevel(conf_level)
|
|
log.addHandler(handler)
|
|
|
|
|
|
def fork_and_reboot(report_success=True):
|
|
log = logging.getLogger(sau.LOGNAME)
|
|
if report_success:
|
|
exit_code=0
|
|
else:
|
|
exit_code=1
|
|
|
|
if os.path.exists('/proc/1/comm'):
|
|
with open('/proc/1/comm', 'r') as f:
|
|
if f.readline().strip() == 'systemd':
|
|
os.execl('/usr/bin/systemctl', 'reboot')
|
|
log.error("Failed to execl?")
|
|
sys.exit(1)
|
|
try:
|
|
pid = os.fork()
|
|
if pid != 0:
|
|
sys.exit(exit_code)
|
|
except OSError as err:
|
|
log.error("Fork #1 failed when going for reboot: {}".format(err))
|
|
sys.exit(1)
|
|
|
|
os.chdir('/')
|
|
os.setsid()
|
|
os.umask(0)
|
|
|
|
try:
|
|
pid = os.fork()
|
|
if pid != 0:
|
|
sys.exit(0)
|
|
except OSError as err:
|
|
log.error("Fork #2 failed when going for reboot: {}".format(err))
|
|
sys.exit(1)
|
|
|
|
sys.stdout.flush()
|
|
sys.stderr.flush()
|
|
stdin = open(os.devnull, 'r')
|
|
stdout = open(os.devnull, 'a+')
|
|
stderr = open(os.devnull, 'a+')
|
|
|
|
os.dup2(stdin.fileno(), sys.stdin.fileno())
|
|
os.dup2(stdout.fileno(), sys.stdout.fileno())
|
|
os.dup2(stderr.fileno(), sys.stderr.fileno())
|
|
|
|
# sleep for a short while to give parent time to exit
|
|
time.sleep(30)
|
|
try:
|
|
#log.error('would reboot now')
|
|
os.execv('/sbin/reboot', ['/sbin/reboot'])
|
|
except OSError as err:
|
|
log.error('Could not reboot: {}'.format(err))
|
|
sys.exit(1)
|
|
|
|
def main():
|
|
conf = sau.config
|
|
log = logging.getLogger(sau.LOGNAME)
|
|
platform = sau.platforms.get_platform()
|
|
|
|
reboot_required = False
|
|
reboot_recommended = False
|
|
|
|
try:
|
|
if conf.getboolean('default', 'do_system_upgrade', fallback=True):
|
|
reboot_required = platform.system_upgrade()
|
|
|
|
if conf.getboolean('default', 'do_package_upgrade', fallback=True):
|
|
reboot_required = reboot_required or platform.pkg_upgrade()
|
|
except sau.errors.UpgradeError as e:
|
|
log.error(f'Upgrade failed: {e}')
|
|
return 1
|
|
|
|
if not conf.getboolean('default', 'live_system', True):
|
|
return 0
|
|
|
|
if conf.getboolean('default', 'do_service_restart', fallback=True):
|
|
reboot_recommended = sau.services.restart_services()
|
|
|
|
if conf.getboolean('default', 'do_reboot', fallback=False):
|
|
if reboot_required:
|
|
log.info('Rebooting because of a system upgrade')
|
|
elif reboot_recommended:
|
|
log.info('Rebooting because service restarts did not close all deleted files')
|
|
if reboot_required or reboot_recommended:
|
|
fork_and_reboot(report_success=conf.getboolean('default', 'reboot_is_success', fallback=True))
|
|
|
|
if reboot_required:
|
|
log.warning("Upgrade was success, but a reboot is required due to a system upgrade")
|
|
return 1
|
|
elif reboot_recommended:
|
|
log.warning("Some services still uses old, deleted, files. You probably want to reboot")
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
def _conf_level_to_logging_level(conf_level):
|
|
if conf_level.lower() == 'debug':
|
|
return logging.DEBUG
|
|
if conf_level.lower() == 'info':
|
|
return logging.INFO
|
|
if conf_level.lower() == 'warning':
|
|
return logging.WARNING
|
|
if conf_level.lower() == 'error':
|
|
return logging.error
|
|
return logging.DEBUG
|
|
|
|
if __name__ == '__main__':
|
|
init()
|
|
sys.exit(main())
|