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