aboutsummaryrefslogtreecommitdiff
path: root/systemd-dashboard
blob: e5db7c179b95fdcf03a9aa27acfd4b38ed82a739 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import itertools as it, operator as op, functools as ft
import os, sys, subprocess, unicodedata

import dbus


def main(argv=None):
	import argparse
	parser = argparse.ArgumentParser(
		description='Tool to compare the set of enabled'
			' systemd services against currently running ones.\n'
		'If started without parameters, it\'ll just show all the enabled services'
			' that should be running (Type != oneshot) yet for some reason they aren\'t.')
	parser.add_argument('-s', '--status', action='store_true',
		help='Show status report on found services.')
	parser.add_argument('-n', '--not-enabled', action='store_true',
		help='Show list of services that are running but are not enabled directly.')
	parser.add_argument('-x', '--systemd-internals', action='store_true',
		help='Dont exclude systemd internal services from the output.')
	optz = parser.parse_args()

	bus = dbus.SystemBus()
	systemd = dbus.Interface(
		bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1'),
		'org.freedesktop.systemd1.Manager' )
	subproc_env = dict(LANG='C', LC_ALL='C')

	if optz.not_enabled:
		not_enabled = set( unit[0] for unit in systemd.ListUnits()
			if unit[0].endswith('.service') and unit[3] == 'active' and not unit[0].startswith('user@') )

	def show_status(unit_name):
		if not optz.systemd_internals and unit_name.startswith('systemd-'): return
		if not optz.status: print(unit_name)
		else:
			print()
			subprocess.run(['systemctl', 'status', unicode(unit_name)], env=subproc_env)

	proc = subprocess.run( ['systemctl', '--full', 'list-dependencies'],
		env=subproc_env, stdout=subprocess.PIPE, check=True, timeout=10.0 )

	for line in proc.stdout.decode().splitlines():
		for i,c in enumerate(line):
			if unicodedata.category(c) not in ['Zs', 'So'] and c not in '*|-` ': break
		else: continue
		unit_name = line[i:]

		# Not really interested in anything else
		if not unit_name.endswith('.service'): continue

		if optz.not_enabled:
			not_enabled.discard(unit_name)
			continue

		try:
			unit = dbus.Interface(
				bus.get_object('org.freedesktop.systemd1', systemd.GetUnit(unit_name)),
				'org.freedesktop.DBus.Properties' )
		except dbus.exceptions.DBusException as err:
			if err.get_dbus_name() != 'org.freedesktop.systemd1.NoSuchUnit': raise
			continue
		if unit.Get('org.freedesktop.systemd1.Service', 'Type') == 'oneshot': continue
		state = dict(
			( k.lower(),
				unit.Get('org.freedesktop.systemd1.Unit', '{}State'.format(k)) )
			for k in ['Load', 'Active', 'Sub'] )
		if state['load'] not in ['error', 'not-found'] and state['active'] != 'active':
			show_status(unit_name)

	if optz.not_enabled:
		for unit_name in not_enabled:
			unit = dbus.Interface(
				bus.get_object('org.freedesktop.systemd1', systemd.GetUnit(unit_name)),
				'org.freedesktop.DBus.Properties' )
			if unit.Get('org.freedesktop.systemd1.Service', 'Type') == 'oneshot': continue
			show_status(unit_name)


if __name__ == '__main__': sys.exit(main())