#!/usr/bin/env python import os, os.path, signal, popen2, fcntl, select, re def make_non_blocking(fd): fl = fcntl.fcntl(fd, fcntl.F_GETFL) try: fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NDELAY) except AttributeError: fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.FNDELAY) # Take advice from "Python Cookbook" on avoiding potential dead locks # reading stdout and stderr from sub process def run_cmd(cmd, input=None): savedsh = signal.getsignal(signal.SIGPIPE) signal.signal(signal.SIGPIPE, signal.SIG_DFL) sub = popen2.Popen3(cmd, True) if not input is None: sub.tochild.write(input) sub.tochild.close() outfd = sub.fromchild.fileno() errfd = sub.childerr.fileno() make_non_blocking(outfd) make_non_blocking(errfd) outd, errd = [], [] outeof = erreof = False while True: to_check = [outfd] * (not outeof) + [errfd] * (not erreof) ready = select.select(to_check, [], []) if outfd in ready[0]: outchunk = sub.fromchild.read() if outchunk == '': outeof = True else: outd.append(outchunk) if errfd in ready[0]: outchunk = sub.childerr.read() if outchunk == '': erreof = True else: errd.append(outchunk) if outeof and erreof: break try: select.select([], [], [], 0.05) except select.error, data: if data[0] is errno.EINTR: pass else: return [ data[0], "", data[1] ] res = sub.wait() signal.signal(signal.SIGPIPE, savedsh) return [ res, ''.join(outd), ''.join(errd) ] def file_is_known_to_rpm(file): res, so, se = run_cmd("rpm -qf " + file) return res == 0 def remove_rpm_kernel(kernel): kfile = kernel_file(kernel) run_cmd("rpm -e --nodeps `rpm -qf " + kfile + "`") def modules_dir(kernel): return "/lib/modules/" + kernel def kernel_file(kernel): return "/boot/vmlinuz-" + kernel def system_map_file(kernel): return "/boot/System.map-" + kernel def initrd_file(kernel): return "/boot/initrd-" + kernel + ".img" def remove_kernel_modules(kernel): kmdir = modules_dir(kernel) if os.path.isdir(kmdir): os.system("/bin/rm -r " + kmdir) def _remove_files(file): if os.path.exists(file): os.remove(file) if os.path.exists(file + ".old"): os.remove(file + ".old") def remove_kernel_file(kernel): _remove_files(kernel_file(kernel)) def remove_system_map_file(kernel): _remove_files(system_map_file(kernel)) def remove_initrd_file(kernel): _remove_files(initrd_file(kernel)) def remove_kernel_from_grub(kernel): kfile = kernel_file(kernel) if run_cmd("sudo /sbin/grubby --info=" + kfile)[0] == 0: run_cmd("/sbin/grubby --remove-kernel=" + kfile) def remove_kernel(kernel, verbose=False): if verbose: print "Removing", kernel, if file_is_known_to_rpm(kernel_file(kernel)): remove_rpm_kernel(kernel) if verbose: print "done via rpm." else: remove_kernel_file(kernel) remove_system_map_file(kernel) remove_initrd_file(kernel) remove_kernel_modules(kernel) remove_kernel_from_grub(kernel) if verbose: print "done." def find_kernels(): kernels = os.listdir("/lib/modules") kre = re.compile("^vmlinuz-(.*?)(.old)?$") for f in os.listdir("/boot"): m = kre.match(f) if m: k = m.group(1) if k not in kernels: kernels.append(m.group(1)) return kernels if __name__ == "__main__": import getopt, sys, fnmatch syntax_error = False interactive = False verbose = False try: optlist, args = getopt.getopt(sys.argv[1:], "iv") except getopt.GetoptError: syntax_error = True if syntax_error or len(args) == 0: print "Usage: rmkernel.py [-i] [-v] ..." sys.exit(1) for o, a in optlist: if o == "-i": interactive = True import tty, termios def getch(): fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) try: tty.setraw(fd) ch = sys.stdin.read(1) finally: termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) return ch if o == "-v": verbose = True kernels = find_kernels() for g in args: klist = fnmatch.filter(kernels, g) for k in klist: if not interactive: remove_kernel(k, verbose) else: print "Delete", k, "?" while True: response = getch() print response if response in ["y", "n"]: break else: beep() if response == "y": remove_kernel(k, verbose) del kernels[kernels.index(k)]