lkml.org 
[lkml]   [2006]   [Feb]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
Subject[ANNOUNCE] rmkernel.py v0.2 -- a simple tool for deleting Linux kernels
As Steven Rostedt pointed out when announcing his clean-boot.pl tool, 
one can end up with quite a large number of installed kernels if
building and installing from a GIT playground. Attached is a Python
script that eases the burden of managing this problem by providing a
convenient mechanism for deleting kernels.

Usage: rmkernel.py [-i] [-v] <kernel> ....
rmkernel.py -l [<kernel> ...]
rmkernel.py -g

where <kernel> can be a glob expression (n.b. lists of expressions
accepted) describing which kernels to delete, the -i option selects
interactive mode where confirmation is requested for each deletion and
-v lists each kernel that has been deleted. This script uses grubby to
update grub (or lilo etc.) for the removal of the kernel. Additionally,
the script checks to see if the kernel was installed via rpm and if it
was uses rpm to do the removal. It will not delete the currently
running kernel and will silently skip it if it is in the list of kernels
to be deleted.

The -l option lists installed kernels that match the <kernel> glob
expression(s) or all installed kernels if no globs are provided. The
currently running kernel will be marked with "******" after its name.

The -g selects "GUI mode" (using PyGTK) and presents a list of installed
kernels which can be selected and deleted with the provided buttons.
The currently running kernel is not included in the list but is
displayed at the top of the window for information only.

Peter
--
Peter Williams pwil3058@bigpond.net.au

"Learning, n. The kind of ignorance distinguishing the studious."
-- Ambrose Bierce
#!/usr/bin/env python

### Copyright (C) 2005 Peter Williams <pwil3058@bigpond.net.au>

### This program is free software; you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
### the Free Software Foundation; version 2 of the License only.

### This program is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
### GNU General Public License for more details.

### A copy of the GNU General Public License is available at
### <http://www.gnu.org/licenses/gpl.txt>; if not, write to the Free Software
### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

## Version 0.2

import os, os.path, signal, popen2, fcntl, select, re, pygtk, gtk

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) ]

_kernel_re = re.compile("^(\d+)\.(\d+)\.(\d+)(.*)$")

def cmp_kernels(k1, k2):
m1 = _kernel_re.match(k1)
m2 = _kernel_re.match(k2)
for i in range(3):
res = cmp(int(m1.group(i+1)), int(m2.group(i+1)))
if res != 0:
return res
if len(m1.groups()) == 4:
if len(m2.groups()) == 4:
return cmp(m1.group(4), m2.group(4))
else:
return -1
elif len(m2.groups()) == 4:
return 1
return 0

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("/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

def get_current_kernel():
res, so, se = run_cmd("uname -r")
return so.strip()

class gui(gtk.Window):
def __init__(self):
gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
self.connect("destroy", self._quit)
self.set_title("rmkernel")
self.tooltips = gtk.Tooltips()
self.window = self.get_root_window()
vbox = gtk.VBox()
self.add(vbox)
self.current_kernel = get_current_kernel()
ck_label = gtk.Label(self.current_kernel + " :Current Kernel")
ck_label.set_padding(0, 0)
vbox.pack_start(ck_label, False, False, 0)
self.store = gtk.ListStore(str)
self.view = gtk.TreeView(self.store)
text_cell = gtk.CellRendererText()
tvcolumn = gtk.TreeViewColumn("Installed Kernels")
tvcolumn.pack_start(text_cell)
tvcolumn.set_attributes(text_cell, text=0)
self.view.append_column(tvcolumn)
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
sw.add(self.view)
vbox.add(sw)
self.selection = self.view.get_selection()
self.selection.set_mode(gtk.SELECTION_MULTIPLE)
self.update_kernels()
bbox = gtk.HButtonBox()
vbox.pack_start(bbox, False, False, 0)
qbutton = gtk.Button("Quit", gtk.STOCK_QUIT)
bbox.add(qbutton)
qbutton.connect("clicked", self._quit)
self.tooltips.set_tip(qbutton, "Quit this application")
rbutton = gtk.Button("Refresh", gtk.STOCK_REFRESH)
bbox.add(rbutton)
rbutton.connect("clicked", self.update_kernels)
self.tooltips.set_tip(rbutton, "Refresh the list of installed kernels")
dbutton = gtk.Button("Delete", gtk.STOCK_DELETE)
bbox.add(dbutton)
dbutton.connect("clicked", self.delete_selection)
self.tooltips.set_tip(dbutton, "Delete/uninstall the selected kernels")
self.selection.unselect_all()
self.show_all()
self.show()
def _show_busy(self):
self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
while gtk.events_pending():
gtk.main_iteration()
def _unshow_busy(self):
self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
def update_kernels(self, data=None):
self._show_busy()
kernels = find_kernels()
kernels.sort(cmp_kernels)
self.store.clear()
for k in kernels:
if k != self.current_kernel:
self.store.append([k])
self._unshow_busy()
def _get_selected_kernels_cb(self, store, path, iter, list):
list.append(store.get_value(iter, 0))
def delete_selection(self, data=None):
self._show_busy()
res = []
self.selection.selected_foreach(self._get_selected_kernels_cb, res)
for k in res:
try:
remove_kernel(k)
except OSError, msg:
dialog = gtk.Dialog("rmkernel", self, gtk.DIALOG_MODAL,
(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
dialog.vbox.add(gtk.Label("Error: " + str(msg)))
dialog.show_all()
dialog.run()
dialog.destroy()
break
self._unshow_busy()
self.update_kernels()
def _quit(self, widget):
gtk.main_quit()

if __name__ == "__main__":
def print_usage_and_exit(ev):
print "Usage: rmkernel.py [-i] [-v] <kernel> ..."
print " rmkernel.py -l [<kernel> ...]"
print " rmkernel.py -g"
sys.exit(ev)
import getopt, sys, fnmatch
syntax_error = False
interactive = False
verbose = False
list = False
use_gui = False
opts_ok = True
args_ok = True
try:
optlist, args = getopt.getopt(sys.argv[1:], "ivlg")
except getopt.GetoptError:
syntax_error = True
if syntax_error:
print_usage_and_exit(1)
for o, a in optlist:
if o == "-i":
interactive = True
opts_ok = opts_ok and not (list or use_gui)
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":
opts_ok = opts_ok and not (list or use_gui)
verbose = True
if o == "-l":
opts_ok = opts_ok and not (verbose or interactive or use_gui)
list = True
if o == "-g":
opts_ok = opts_ok and not (verbose or interactive or list)
args_ok = len(args) == 0
use_gui = True
args_ok = args_ok and ((list or use_gui) or len(args) > 0)
if not (args_ok and opts_ok):
print_usage_and_exit(2)
kernels = find_kernels()
current_kernel = get_current_kernel()
if list:
if len(args) == 0:
klist = kernels
klist.sort(cmp_kernels)
else:
klist = []
for g in args:
sublist = fnmatch.filter(kernels, g)
sublist.sort(cmp_kernels)
klist += sublist
for k in klist:
if k == current_kernel:
print k, "******"
else:
print k
elif use_gui:
app = gui()
gtk.main()
else:
for g in args:
klist = fnmatch.filter(kernels, g)
klist.sort(cmp_kernels)
for k in klist:
if k == current_kernel:
continue
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)]
\
 
 \ /
  Last update: 2006-02-15 03:32    [W:0.038 / U:0.264 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site