0 | |
#!/usr/bin/python
|
|
0 |
#!/usr/bin/python3
|
1 | 1 |
|
2 | 2 |
# Copyright (C) 2001 Matt Zimmerman <mdz@debian.org>
|
3 | 3 |
# Copyright (C) 2007,2010-2015 Javier Fernandez-Sanguino <jfs@debian.org>
|
|
85 | 85 |
# Process options
|
86 | 86 |
try:
|
87 | 87 |
opts, args = getopt.getopt(sys.argv[1:], "hvpab:i:ne:", ["help", "verbose", "packages", "all", "blacklist", "ignore", "nolsof", "excludepid"])
|
88 | |
except getopt.GetoptError, err:
|
|
88 |
except getopt.GetoptError as err:
|
89 | 89 |
# print help information and exit:
|
90 | |
print str(err) # will print something like "option -x not recognized"
|
|
90 |
print(err) # will print something like "option -x not recognized"
|
91 | 91 |
usage()
|
92 | 92 |
sys.exit(2)
|
93 | 93 |
|
|
142 | 142 |
# Check if we have lsof, if not, use an alternative mechanism
|
143 | 143 |
if not find_cmd('lsof') or not useLsof:
|
144 | 144 |
if verbose and not find_cmd('lsof'):
|
145 | |
print "[DEBUG] Lsof is not available in the system. Using alternative mechanism."
|
|
145 |
print("[DEBUG] Lsof is not available in the system. Using alternative mechanism.")
|
146 | 146 |
toRestart = procfilescheck(blacklist = blacklist, excludepidlist = excludepidlist)
|
147 | 147 |
else:
|
148 | 148 |
toRestart = lsoffilescheck(blacklist = blacklist)
|
149 | 149 |
|
150 | 150 |
|
151 | |
print "Found %d processes using old versions of upgraded files" % len(toRestart)
|
|
151 |
print("Found %d processes using old versions of upgraded files" % len(toRestart))
|
152 | 152 |
|
153 | 153 |
if len(toRestart) == 0:
|
154 | 154 |
sys.exit(0)
|
|
159 | 159 |
programs[process.program].append(process)
|
160 | 160 |
|
161 | 161 |
if len(programs) == 1:
|
162 | |
print "(%d distinct program)" % len(programs)
|
|
162 |
print("(%d distinct program)" % len(programs))
|
163 | 163 |
else:
|
164 | |
print "(%d distinct programs)" % len(programs)
|
|
164 |
print("(%d distinct programs)" % len(programs))
|
165 | 165 |
|
166 | 166 |
#services Verbose information
|
167 | 167 |
if verbose:
|
168 | 168 |
for process in toRestart:
|
169 | |
print "[DEBUG] Process %s (PID: %d) " % (process.program, process.pid)
|
|
169 |
print("[DEBUG] Process %s (PID: %d) " % (process.program, process.pid))
|
170 | 170 |
process.listDeleted()
|
171 | 171 |
|
172 | 172 |
packages = {}
|
173 | 173 |
diverted = None
|
174 | 174 |
|
175 | |
dpkgQuery = ["dpkg-query", "--search"] + programs.keys()
|
|
175 |
dpkgQuery = ["dpkg-query", "--search"] + list(programs.keys())
|
176 | 176 |
if verbose:
|
177 | |
print "[DEBUG] Running:%s" % dpkgQuery
|
|
177 |
print("[DEBUG] Running:%s" % dpkgQuery)
|
178 | 178 |
dpkgProc = subprocess.Popen(dpkgQuery, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
179 | 179 |
env = lc_all_c_env)
|
180 | 180 |
while True:
|
|
182 | 182 |
if not line:
|
183 | 183 |
break
|
184 | 184 |
if verbose:
|
185 | |
print "[DEBUG] Reading line from dpkg-query: %s" % line
|
|
185 |
print("[DEBUG] Reading line from dpkg-query: %s" % line)
|
186 | 186 |
if line.startswith('local diversion'):
|
187 | 187 |
continue
|
188 | 188 |
if not ':' in line:
|
|
207 | 207 |
try:
|
208 | 208 |
packages[packagename].processes.extend(programs[program])
|
209 | 209 |
if verbose:
|
210 | |
print "[DEBUG] Found package %s for program %s" % (packagename, program)
|
|
210 |
print("[DEBUG] Found package %s for program %s" % (packagename, program))
|
211 | 211 |
except KeyError:
|
212 | 212 |
sys.stderr.write ('checkrestart (program not found): %s: %s\n' % (packagename, program))
|
213 | 213 |
sys.stdout.flush()
|
|
220 | 220 |
for i in ignorelist:
|
221 | 221 |
if i in packages:
|
222 | 222 |
if verbose:
|
223 | |
print "[DEBUG] Removing %s from the package list (ignored)" % (i)
|
|
223 |
print("[DEBUG] Removing %s from the package list (ignored)" % (i))
|
224 | 224 |
try:
|
225 | 225 |
del packages[i]
|
226 | 226 |
except KeyError:
|
227 | 227 |
continue
|
228 | 228 |
|
229 | |
print "(%d distinct packages)" % len(packages)
|
|
229 |
print("(%d distinct packages)" % len(packages))
|
230 | 230 |
|
231 | 231 |
if len(packages) == 0:
|
232 | |
print "No packages seem to need to be restarted."
|
233 | |
print "(please read checkrestart(1))"
|
|
232 |
print("No packages seem to need to be restarted.")
|
|
233 |
print("(please read checkrestart(1))")
|
234 | 234 |
sys.exit(0)
|
235 | 235 |
|
236 | |
for package in packages.values():
|
|
236 |
for package in list(packages.values()):
|
237 | 237 |
dpkgQuery = ["dpkg-query", "--listfiles", package.name]
|
238 | 238 |
if verbose:
|
239 | |
print "[DEBUG] Running:%s" % dpkgQuery
|
|
239 |
print("[DEBUG] Running:%s" % dpkgQuery)
|
240 | 240 |
dpkgProc = subprocess.Popen(dpkgQuery, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
241 | 241 |
env = lc_all_c_env)
|
242 | 242 |
while True:
|
|
251 | 251 |
# If running on a systemd system, extract the systemd's service files from the package
|
252 | 252 |
if is_systemd and path.startswith('/lib/systemd/system/') and path.endswith('.service') and path.find('.wants') == -1:
|
253 | 253 |
# Read the service file and make sure it is not of type 'oneshot'
|
254 | |
servicefile = open (path)
|
|
254 |
servicefile = open (path)
|
255 | 255 |
is_oneshot = False
|
256 | |
for line in servicefile.readlines ():
|
257 | |
if line.find ('Type=oneshot') > 0:
|
258 | |
is_oneshot = True
|
259 | |
continue
|
260 | |
servicefile.close ()
|
|
256 |
for line in servicefile.readlines():
|
|
257 |
if line.find ('Type=oneshot') > 0:
|
|
258 |
is_oneshot = True
|
|
259 |
continue
|
|
260 |
servicefile.close ()
|
261 | 261 |
if not is_oneshot:
|
262 | 262 |
package.systemdservice.add(path[20:])
|
263 | 263 |
sys.stdout.flush()
|
|
274 | 274 |
nonrestartable = []
|
275 | 275 |
restartInitCommands = []
|
276 | 276 |
restartServiceCommands = []
|
277 | |
for package in packages.values():
|
|
277 |
for package in list(packages.values()):
|
278 | 278 |
if len(package.initscripts) > 0:
|
279 | 279 |
restartable.append(package)
|
280 | |
restartInitCommands.extend(map(lambda s: 'service ' + s + ' restart', package.initscripts))
|
|
280 |
restartInitCommands.extend(['service ' + s + ' restart' for s in package.initscripts])
|
281 | 281 |
elif len(package.systemdservice) > 0:
|
282 | 282 |
restartable.append(package)
|
283 | |
restartServiceCommands.extend(map(lambda s: 'systemctl restart ' + s, package.systemdservice))
|
|
283 |
restartServiceCommands.extend(['systemctl restart ' + s for s in package.systemdservice])
|
284 | 284 |
else:
|
285 | 285 |
nonrestartable.append(package)
|
286 | 286 |
|
287 | 287 |
if len(restartable) > 0:
|
288 | |
print
|
289 | |
print "Of these, %d seem to contain systemd service definitions or init scripts which can be used to restart them." % len(restartable)
|
|
288 |
print()
|
|
289 |
print("Of these, %d seem to contain systemd service definitions or init scripts which can be used to restart them." % len(restartable))
|
290 | 290 |
# TODO - consider putting this in a --verbose option
|
291 | |
print "The following packages seem to have definitions that could be used\nto restart their services:"
|
|
291 |
print("The following packages seem to have definitions that could be used\nto restart their services:")
|
292 | 292 |
for package in restartable:
|
293 | |
print package.name + ':'
|
|
293 |
print(package.name + ':')
|
294 | 294 |
for process in package.processes:
|
295 | |
print "\t%s\t%s" % (process.pid,process.program)
|
|
295 |
print("\t%s\t%s" % (process.pid,process.program))
|
296 | 296 |
|
297 | 297 |
if len(restartServiceCommands)>0:
|
298 | |
print
|
299 | |
print "These are the systemd services:"
|
300 | |
print '\n'.join(restartServiceCommands)
|
301 | |
print
|
|
298 |
print()
|
|
299 |
print("These are the systemd services:")
|
|
300 |
print('\n'.join(restartServiceCommands))
|
|
301 |
print()
|
302 | 302 |
|
303 | 303 |
if len(restartInitCommands)>0:
|
304 | |
print "These are the initd scripts:"
|
305 | |
print '\n'.join(restartInitCommands)
|
306 | |
print
|
|
304 |
print("These are the initd scripts:")
|
|
305 |
print('\n'.join(restartInitCommands))
|
|
306 |
print()
|
307 | 307 |
|
308 | 308 |
if len(nonrestartable) == 0:
|
309 | 309 |
sys.exit(0)
|
310 | 310 |
|
311 | 311 |
# TODO - consider putting this in a --verbose option
|
312 | |
print "These processes (%d) do not seem to have an associated init script to restart them:" %len(nonrestartable)
|
|
312 |
print("These processes (%d) do not seem to have an associated init script to restart them:" %len(nonrestartable))
|
313 | 313 |
for package in nonrestartable:
|
314 | |
print package.name + ':'
|
|
314 |
print(package.name + ':')
|
315 | 315 |
for process in package.processes:
|
316 | |
print "\t%s\t%s" % (process.pid,process.program)
|
|
316 |
print("\t%s\t%s" % (process.pid,process.program))
|
317 | 317 |
|
318 | 318 |
def lsoffilescheck(blacklist = None):
|
319 | 319 |
# Use LSOF to extract the list of deleted files
|
|
354 | 354 |
# Save the descriptor for later comparison
|
355 | 355 |
process.descriptors.append(data)
|
356 | 356 |
|
357 | |
toRestart = filter(lambda process: process.needsRestart(blacklist),
|
358 | |
processes.values())
|
|
357 |
toRestart = [process for process in list(processes.values()) if process.needsRestart(blacklist)]
|
359 | 358 |
return toRestart
|
360 | 359 |
|
361 | 360 |
def procfilescheck(blacklist = None, excludepidlist = None):
|
|
395 | 394 |
# print pid + ': ' + ', '.join(foundfiles)
|
396 | 395 |
process.files = foundfiles
|
397 | 396 |
|
398 | |
toRestart = filter(lambda process: process.needsRestart(blacklist),
|
399 | |
processes.values())
|
|
397 |
toRestart = [process for process in list(processes.values()) if process.needsRestart(blacklist)]
|
400 | 398 |
return toRestart
|
401 | 399 |
|
402 | 400 |
|
|
409 | 407 |
file_in_package = False
|
410 | 408 |
file_regexp = False
|
411 | 409 |
if verbose:
|
412 | |
print "[DEBUG] Checking if file %s belongs to any package" % f
|
|
410 |
print("[DEBUG] Checking if file %s belongs to any package" % f)
|
413 | 411 |
# First check if the file exists
|
414 | 412 |
if not os.path.exists(f):
|
415 | 413 |
if ( f.startswith('/lib/') or f.startswith('/usr/lib/') ) and re.compile("\.so[\d.]+$"):
|
|
428 | 426 |
# If it exists, run dpkg-query
|
429 | 427 |
dpkgQuery = ["dpkg-query", "--search", f ]
|
430 | 428 |
if verbose:
|
431 | |
print "[DEBUG] Running:%s" % dpkgQuery
|
|
429 |
print("[DEBUG] Running:%s" % dpkgQuery)
|
432 | 430 |
dpkgProc = subprocess.Popen(dpkgQuery, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
433 | 431 |
env = lc_all_c_env, close_fds=True)
|
434 | 432 |
dpkgProc.wait()
|
435 | 433 |
if verbose:
|
436 | |
print "[DEBUG] Running:%s" % dpkgQuery
|
|
434 |
print("[DEBUG] Running:%s" % dpkgQuery)
|
437 | 435 |
for line in dpkgProc.stdout.readlines():
|
438 | 436 |
line = line.strip()
|
439 | 437 |
if line.find('no path found matching pattern ' + f) > 0:
|
|
445 | 443 |
break
|
446 | 444 |
|
447 | 445 |
if file_in_package and verbose:
|
448 | |
print "[DEBUG] YES: File belongs to package %s" % package
|
|
446 |
print("[DEBUG] YES: File belongs to package %s" % package)
|
449 | 447 |
if not file_in_package and verbose:
|
450 | |
print "[DEBUG] NO: File does not belongs to any package"
|
|
448 |
print("[DEBUG] NO: File does not belongs to any package")
|
451 | 449 |
return file_in_package
|
452 | 450 |
|
453 | 451 |
# Tells if a file has to be considered a deleted file
|
|
503 | 501 |
return 0
|
504 | 502 |
# Skip nagios spool files
|
505 | 503 |
if f.startswith('/var/lib/nagios3/spool/checkresults/'):
|
506 | |
return 0
|
|
504 |
return 0
|
507 | 505 |
# Skip Postgresql files
|
508 | 506 |
if f.startswith('/var/lib/postgresql/'):
|
509 | 507 |
return 0
|
|
546 | 544 |
# <http://bugs.debian.org/264985> for more information.
|
547 | 545 |
|
548 | 546 |
numeric = re.compile(r'\d+')
|
549 | |
toRestart = map (delmaps, map (string.atoi, filter (numeric.match, os.listdir('/proc'))))
|
|
547 |
toRestart = list(map (delmaps, list(map (string.atoi, list(filter (numeric.match, os.listdir('/proc')))))))
|
550 | 548 |
return toRestart
|
551 | 549 |
|
552 | 550 |
def delmaps (pid):
|
|
575 | 573 |
try:
|
576 | 574 |
if os.stat (file)[stat.ST_INO] != inode:
|
577 | 575 |
process = processes.setdefault(pid,Process(int(pid)))
|
578 | |
except OSError, (e, strerror):
|
|
576 |
except OSError as e_tuple:
|
|
577 |
(e, strerror) = e_tuple.args
|
579 | 578 |
if e == errno.ENOENT:
|
580 | 579 |
process = processes.setdefault(pid,Process(int(pid)))
|
581 | 580 |
else:
|
582 | 581 |
sys.stderr.write ('checkrestart (psdel): %s %s: %s\n' % (SysProcess.get(pid).info (), file, os.strerror (e)))
|
583 | 582 |
else:
|
584 | |
print 'checkrestart (psdel): Error parsing "%s"' % (line [0:-1])
|
|
583 |
print('checkrestart (psdel): Error parsing "%s"' % (line [0:-1]))
|
585 | 584 |
maps.close ()
|
586 | 585 |
|
587 | 586 |
return process
|
|
663 | 662 |
if m:
|
664 | 663 |
# store the real full path of script as the program
|
665 | 664 |
self.program = m.group(1)
|
666 | |
except OSError, e:
|
|
665 |
except OSError as e:
|
667 | 666 |
if e.errno != errno.ENOENT:
|
668 | 667 |
if self.pid == 1:
|
669 | 668 |
sys.stderr.write("Found unreadable pid 1. Assuming we're under vserver and continuing.\n")
|
|
711 | 710 |
if isdeletedFile(f):
|
712 | 711 |
listfiles.append(f)
|
713 | 712 |
if listfiles != []:
|
714 | |
print "List of deleted files in use:"
|
|
713 |
print("List of deleted files in use:")
|
715 | 714 |
for file in listfiles:
|
716 | |
print "\t" + file
|
|
715 |
print("\t" + file)
|
717 | 716 |
|
718 | 717 |
# Check if a process needs to be restarted, previously we would
|
719 | 718 |
# just check if it used libraries named '.dpkg-new' since that's
|
|
724 | 723 |
def needsRestart(self, blacklist = None):
|
725 | 724 |
for f in self.files:
|
726 | 725 |
if isdeletedFile(f, blacklist):
|
727 | |
return 1
|
728 | |
for f in self.links:
|
729 | |
if f == 0:
|
730 | |
return 1
|
|
726 |
return 1
|
|
727 |
for f in self.links:
|
|
728 |
if f == 0:
|
|
729 |
return 1
|
731 | 730 |
return 0
|
732 | 731 |
|
733 | 732 |
class Package:
|