]>
Commit | Line | Data |
---|---|---|
ff421541 MF |
1 | #!/usr/bin/python |
2 | # -*- coding: utf-8 -*- | |
3 | ||
4 | """Script for restarting services that refer to old/deleted libs.""" | |
5 | ||
6 | from __future__ import print_function | |
7 | ||
8 | import argparse | |
9 | import glob | |
10 | import os | |
11 | import signal | |
12 | import sys | |
13 | import time | |
14 | ||
15 | ||
16 | # Set of paths that are "OK" and safe to ignore. | |
17 | IGNORE_PATHS = set(( | |
18 | '/dev/zero', | |
19 | '/etc/ld.so.cache', | |
b24b65a3 MF |
20 | '/usr/share/icons/Adwaita/icon-theme.cache', |
21 | '/usr/share/icons/gnome/icon-theme.cache', | |
22 | '/usr/share/icons/hicolor/icon-theme.cache', | |
23 | '/usr/share/mime/mime.cache', | |
ff421541 MF |
24 | )) |
25 | ||
26 | ||
27 | def find_svcs(): | |
28 | """Find all programs w/deleted paths.""" | |
29 | svcs = {} | |
30 | for pid in os.listdir('/proc'): | |
31 | try: | |
32 | pid_nr = int(pid) | |
33 | except ValueError: | |
34 | continue | |
35 | ||
36 | map = '/proc/%s/maps' % pid | |
37 | if not os.path.exists(map): | |
38 | print('skipping %s' % pid) | |
39 | continue | |
40 | ||
41 | old_paths = set() | |
42 | for line in open(map): | |
43 | if not line.endswith(' (deleted)\n'): | |
44 | continue | |
45 | # b71c7000-b7307000 rw-s 00000000 00:04 17024337 /dev/zero (deleted) | |
e04a292f MF |
46 | addr, perm, offset, dev, inode, path = line.split(' ', 5) |
47 | # Handle paths with spaces. | |
967c0e54 | 48 | path = path.lstrip().rsplit(' ', 2)[0] |
ff421541 | 49 | if (path == '/[aio]' or |
b24b65a3 | 50 | path.startswith('/memfd:') or |
ff421541 | 51 | path.startswith('/SYSV') or |
967c0e54 MF |
52 | path.startswith('/dev/shm/') or |
53 | path.startswith('/tmp/')): | |
ff421541 MF |
54 | continue |
55 | old_paths.add(path) | |
56 | ||
57 | old_paths -= IGNORE_PATHS | |
58 | if not old_paths: | |
59 | continue | |
60 | ||
61 | cmdline = open('/proc/%s/cmdline' % pid).read().split('\0') | |
62 | try: | |
63 | while True: | |
64 | cmdline.remove('') | |
65 | except ValueError: | |
66 | pass | |
67 | svcs[pid_nr] = { | |
68 | 'cmdline': cmdline, | |
69 | 'old_paths': old_paths, | |
70 | } | |
71 | return svcs | |
72 | ||
73 | ||
74 | # Mapping of known programs to their init.d scripts. | |
75 | SERVICES = { | |
76 | '/usr/sbin/acpid': 'acpid', | |
77 | '/usr/sbin/apache2': 'apache2', | |
78 | '/usr/sbin/atd': 'atd', | |
79 | '/usr/sbin/bacula-fd': 'bacula-fd', | |
80 | '/usr/sbin/cron': 'vixie-cron', | |
81 | '/usr/sbin/crond': 'dcron', | |
43c455f3 | 82 | '/usr/sbin/ntpd': 'ntpd', |
ff421541 MF |
83 | '/usr/sbin/snmpd': 'snmpd', |
84 | '/usr/sbin/sshd': 'sshd', | |
85 | '/usr/sbin/syslog-ng': 'syslog-ng', | |
86 | '/usr/sbin/xinetd': 'xinetd', | |
5efa74ba | 87 | '/usr/bin/daisydog': 'daisydog', |
ff421541 MF |
88 | '/usr/bin/distccd': 'distccd', |
89 | '/usr/bin/monit': 'monit', | |
0734ffa6 | 90 | '/usr/bin/rsync': 'rsyncd', |
ff421541 MF |
91 | '/usr/bin/stunnel': 'stunnel', |
92 | '/usr/bin/tor': 'tor', | |
93 | '/usr/bin/transmission-daemon': 'transmission-daemon', | |
94 | '/usr/bin/mediatomb': 'mediatomb', | |
95 | '/lib/systemd/systemd-udevd': 'udev', | |
96 | '/usr/libexec/nrpe': 'nrpe', | |
43c455f3 | 97 | '//usr/libexec/postfix/master': 'postfix', |
ff421541 MF |
98 | 'denyhosts.py': 'denyhosts', |
99 | 'dropbear': 'dropbear', | |
100 | 'galileo': 'galileo', | |
101 | 'tlsdated': 'tlsdated', | |
102 | } | |
967c0e54 | 103 | def auto_restart(opts, svcs): |
ff421541 MF |
104 | kill = set() |
105 | restart = set() | |
106 | for pid, svc in svcs.items(): | |
107 | if svc['cmdline'][0] == '/sbin/agetty': | |
108 | kill.add(pid) | |
109 | elif 'postgres:' in svc['cmdline'][0]: | |
110 | p = os.path.basename(glob.glob('/etc/runlevels/default/postgresql-*')[0]) | |
111 | restart.add(p) | |
112 | elif svc['cmdline'][0].startswith('metalog'): | |
113 | restart.add('metalog') | |
114 | else: | |
115 | prog = svc['cmdline'][0] | |
116 | if prog.startswith('/usr/bin/python'): | |
117 | prog = os.path.basename(svc['cmdline'][1]) | |
118 | ||
119 | init = SERVICES.get(prog) | |
120 | if init: | |
121 | restart.add(init) | |
122 | ||
123 | if kill or restart: | |
124 | for pid in kill: | |
125 | print('killing %s (%s)' % (pid, svcs[pid]['cmdline'][0])) | |
967c0e54 MF |
126 | if not opts.dryrun: |
127 | os.kill(pid, signal.SIGTERM) | |
ff421541 MF |
128 | for init in restart: |
129 | print('restarting %s' % init) | |
967c0e54 MF |
130 | if not opts.dryrun: |
131 | os.system('/etc/init.d/%s -q restart' % init) | |
ff421541 | 132 | |
967c0e54 MF |
133 | if not opts.dryrun: |
134 | time.sleep(1) | |
135 | svcs = find_svcs() | |
ff421541 MF |
136 | |
137 | return svcs | |
138 | ||
139 | ||
140 | def summarize(svcs): | |
141 | print() | |
142 | sslh = False | |
143 | for pid in svcs.keys(): | |
144 | if svcs[pid]['cmdline'][0] == '/usr/sbin/sslh': | |
145 | del svcs[pid] | |
146 | sslh = True | |
147 | if sslh: | |
148 | print('sslh needs restart') | |
149 | ||
150 | print() | |
151 | for pid, svc in svcs.items(): | |
152 | print(pid, svc['cmdline']) | |
153 | print('\t%s' % '\n\t'.join(svc['old_paths'])) | |
154 | ||
155 | ||
156 | def get_parser(): | |
157 | parser = argparse.ArgumentParser(description=__doc__) | |
967c0e54 MF |
158 | parser.add_argument('-n', '--dry-run', dest='dryrun', action='store_true', |
159 | help='Show what would be restarted (and why)') | |
ff421541 MF |
160 | return parser |
161 | ||
162 | ||
163 | def main(argv): | |
164 | parser = get_parser() | |
165 | opts = parser.parse_args(argv) | |
166 | ||
167 | svcs = find_svcs() | |
967c0e54 | 168 | svcs = auto_restart(opts, svcs) |
ff421541 MF |
169 | summarize(svcs) |
170 | ||
171 | ||
172 | if __name__ == '__main__': | |
173 | exit(main(sys.argv[1:])) |