You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tde-guidance/grubconfig/grubconfig.py

698 lines
25 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

#!/usr/bin/python
# -*- coding: UTF-8 -*-
###########################################################################
# grubconfig.py - description #
# ------------------------------ #
# begin : Sun Dec 10 2006 #
# copyright : (C) 2006-2007 by Martin Böhm #
# email : martin.bohm@kubuntu.org #
# #
###########################################################################
# #
# 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; either version 2 of the License, or #
# (at your option) any later version. #
# #
###########################################################################
from qt import *
from kdeui import *
from kdecore import *
from kfile import *
import sys, os, string, re
import os.path
import shutil
import locale
import tempfile
programname = "Boot Loader Configuration"
version = "0.0.2"
standalone = __name__=='__main__'
if standalone:
programbase = KDialogBase
else:
programbase = KCModule
parsable = ["default","menu","color","timeout","hiddenmenu","title","root","kernel","initrd"]
cat1 = ["default","menu","color","timeout","hiddenmenu","root","initrd"]
cat2 = ["savedefault","makeactive","chainloader"]
cat3 = ["kernel"]
class GreyListViewItem(KListViewItem):
def paintCell(self, p, cg, column, width, align ):
cgGrey = cg
cgGrey.setColor(QColorGroup.Text,QColor("grey"))
KListViewItem.paintCell(self, p, cgGrey, column, width, align)
cg.restore()
class BoldListViewItem(KListViewItem):
def paintCell(self, p, cg, column, width, align ):
p.save()
f = p.font()
f.setBold(True)
KListViewItem.paintCell(self, p, cg, column, width, align)
p.restore()
class GrubConfigAppClass(programbase):
def __init__(self,parent=None,name=None):
if standalone:
KDialogBase.__init__(self,KJanusWidget.Tabbed,i18n("Boot Loader Configuration"),
KDialogBase.Help|KDialogBase.Ok|KDialogBase.Close, KDialogBase.Close)
# no need to include About button yet
self.menulstlocation = "/boot/grub/menu.lst"
self.readfilename = self.menulstlocation
self.globalvars = {}
self.itemslist = []
#--- Load menu.lst using the load_menulst() method
self.load_menulst()
print self.globalvars
print self.itemslist
# - GRUB Options Tab -
if standalone:
usershbox = self.addHBoxPage(i18n("Grub Options"))
vbox = QVBox(usershbox)
else:
vbox = QVBox(tabcontrol)
vbox.setMargin(KDialog.marginHint())
# -- Operating Systems List & MakeDefault Button --
horizontalbox = QHBox(vbox)
self.itemslistview = KListView(horizontalbox)
self.itemslistview.addColumn("")
self.itemslistview.setSorting(-1)
self.itemslistview.header().hide()
self.itemslistviewitems = []
arrowsbox = QVBox(horizontalbox)
self.upbutton = KPushButton(i18n("Move Up"),arrowsbox)
self.connect(self.upbutton,SIGNAL("clicked()"),self.slotUpButtonClicked)
self.downbutton = KPushButton(i18n("Move Down"),arrowsbox)
self.connect(self.downbutton,SIGNAL("clicked()"),self.slotDownButtonClicked)
self.defaultbutton = KPushButton(i18n("Make Default"),vbox)
self.connect(self.defaultbutton,SIGNAL("clicked()"),self.slotSetDefaultButtonClicked)
# -- Boot Options Group Box --
bootoptionsbasebox = QVGroupBox(vbox,"Boot Options")
bootoptionsbasebox.setTitle(i18n("Boot Options"));
bootoptionsbasevbox = QWidget(bootoptionsbasebox)
infogrid = QGridLayout(bootoptionsbasevbox,3,2)
infogrid.setSpacing(KDialog.spacingHint())
# --- Timeout ---
label = QLabel(i18n("Timeout:"),bootoptionsbasevbox)
infogrid.addWidget(label,0,0)
timeoutbox = QHBox(bootoptionsbasevbox)
timeoutbox.setSpacing(KDialog.spacingHint())
self.timeout = KIntSpinBox(timeoutbox,"Timeout")
if "timeout" in self.globalvars:
self.timeout.setValue(int(self.globalvars['timeout'][0]))
label = QLabel(i18n("seconds"),timeoutbox)
infogrid.addWidget(timeoutbox,0,1)
infogrid.addWidget(self.timeout,0,1)
# --- Hide Menu on Boot ---
self.hidemenuonboot = QCheckBox(i18n("Hide Menu on Boot"),bootoptionsbasevbox)
if 'hiddenmenu' in self.globalvars:
self.hidemenuonboot.setChecked(int(self.globalvars['hiddenmenu'][0]))
infogrid.addWidget(self.hidemenuonboot,1,1)
# --- Make Last OS Default ---
self.lastdefault = QCheckBox(i18n("Make Last Operating System Default"),bootoptionsbasevbox)
infogrid.addWidget(self.lastdefault,2,1)
# -- Security Group Box --
securitybox = QVGroupBox(vbox,"Security")
securitybox.setTitle(i18n("Security"));
securityvbox = QWidget(securitybox)
infogrid = QGridLayout(securityvbox,2,2)
infogrid.setSpacing(KDialog.spacingHint())
# --- Password ---
label = QLabel(i18n("Password:"),securityvbox)
infogrid.addWidget(label,0,0)
self.userpassword = KPasswordEdit(securityvbox)
infogrid.addWidget(self.userpassword,0,1)
# --- Repeat Password ---
label = QLabel(i18n("Repeat Password:"),securityvbox)
infogrid.addWidget(label,1,0)
self.userrepeatpassword = KPasswordEdit(securityvbox)
infogrid.addWidget(self.userrepeatpassword,1,1)
# -- Splash Screen Group Box --
splashbox = QVGroupBox(vbox,"Splash screen")
splashbox.setTitle(i18n("Splash screen"));
# --- Background Color ---
labelandeditbox = QHBox(splashbox)
label = QLabel(i18n("Background Color:"),labelandeditbox)
self.backgroundcolor = QComboBox(labelandeditbox)
# --- Highlight Color ---
labelandeditbox = QHBox(splashbox)
label = QLabel(i18n("Highlight Color:"),labelandeditbox)
self.highlightcolor = QComboBox(labelandeditbox)
# - Operating Systems Tab -
if standalone:
groupsvbox = self.addVBoxPage(i18n("Operating Systems"))
vb = QVBox(groupsvbox)
else:
groupsvbox = QVBox(tabcontrol)
roupsvbox.setMargin(KDialog.marginHint())
vb = QVBox(groupsvbox)
# -- Operating Systems List --
horizontalbox = QHBox(vb)
self.oslistview = KListView(horizontalbox)
self.oslistview.addColumn("")
self.oslistview.addColumn("")
self.oslistview.setSorting(-1)
self.oslistview.header().hide()
self.oslistviewitems = []
self.connect(self.oslistview,SIGNAL("selectionChanged()"),self.oslistviewitemSelected)
# -- Operating Systems Details Box --
osdetailsbox = QVGroupBox(vb,"Operating System Details")
# label = QLabel(i18n("Security"),securitybox)
detailsvbox = QWidget(osdetailsbox)
infogrid = QGridLayout(detailsvbox,7,2)
infogrid.setSpacing(KDialog.spacingHint())
osdetailsbox.setTitle(i18n("Operating System Details"));
# --- List in GRUB Menu ---
self.listingrub = QCheckBox(i18n("List in GRUB Menu"),detailsvbox)
infogrid.addWidget(self.listingrub,0,1)
# --- Display Name ---
label = QLabel(i18n("Display Name:"),detailsvbox)
infogrid.addWidget(label,1,0)
self.displaynamelabel = QLineEdit("",detailsvbox)
infogrid.addWidget(self.displaynamelabel,1,1)
self.connect(self.displaynamelabel,SIGNAL("textChanged(const QString &)"),self.slotDisplayNameLabelChanged)
# --- Operating System ---
label = QLabel(i18n("Operating System:"),detailsvbox)
infogrid.addWidget(label,2,0)
self.operatingsystem = QComboBox(detailsvbox)
infogrid.addWidget(self.operatingsystem,2,1)
# --- Kernel ---
label = QLabel(i18n("Kernel:"),detailsvbox)
infogrid.addWidget(label,3,0)
self.kernel = KURLRequester(detailsvbox)
infogrid.addWidget(self.kernel,3,1)
# --- Failsafe Kernel ---
# not sure if that is possible - requested by seele
label = QLabel(i18n("Failsafe Kernel:"),detailsvbox)
infogrid.addWidget(label,4,0)
self.failsafekernel = QComboBox(detailsvbox)
infogrid.addWidget(self.failsafekernel,4,1)
# --- Initial RAM Disk ---
label = QLabel(i18n("Initial RAM Disk:"),detailsvbox)
infogrid.addWidget(label,5,0)
self.initrd = KURLRequester(detailsvbox)
infogrid.addWidget(self.initrd,5,1)
# --- Root Filesystem ---
label = QLabel(i18n("Root Filesystem:"),detailsvbox)
infogrid.addWidget(label,6,0)
self.rootfilesystem = QComboBox(detailsvbox)
infogrid.addWidget(self.rootfilesystem,6,1)
# -- Boot Options Box --
bootoptionsbox = QVGroupBox(vb,"Boot Options")
# label = QLabel(i18n("Security"),securitybox)
bootoptionsbox.setTitle(i18n("Boot Options"));
self.acpibox = QCheckBox(i18n("Power Management (ACPI) "),bootoptionsbox)
self.debugbox = QCheckBox(i18n("Debugging Messages "),bootoptionsbox)
self.selinuxbox = QCheckBox(i18n("SELinux Support "),bootoptionsbox)
self.splashbox = QCheckBox(i18n("Splash Screen"),bootoptionsbox)
labelandeditbox = QHBox(bootoptionsbox)
label = QLabel(i18n("Custom Options:"),labelandeditbox)
self.customoptions = KLineEdit("",labelandeditbox)
# -- (static) UI finished --
self.reloadListViews("oslist")
self.reloadListViews("itemslist")
try:
self.oslistview.setSelected(self.oslistviewitems[int(self.globalvars['default'][0])],True)
except ValueError:
self.oslistview.setSelected(self.oslistviewitems[0],True)
ops_list = self.load_osprobe()
print ops_list # mhb debug
#######################################################################
# reload listviews, because they have changed
def reloadListViews(self,name):
print "reloaded"
# you should repaint the one that is not changed on screen
if name == "oslist":
self.oslistview.clear()
for item in self.itemslist:
try:
if self.itemslist.index(item) == int(self.globalvars['default'][0]):
self.oslistviewitems.append(BoldListViewItem(self.oslistview,self.oslistview.lastItem(),item['title'][0]))
else:
self.oslistviewitems.append(KListViewItem(self.oslistview,self.oslistview.lastItem(),item['title'][0]))
except ValueError:
self.oslistviewitems.append(KListViewItem(self.oslistview,self.oslistview.lastItem(),item['title'][0]))
# if it has a root option (other than 1 which means only root by itself), it is an OS
else:
self.itemslistview.clear()
#repaint main list
for item in self.itemslist:
try:
if self.itemslist.index(item) == int(self.globalvars['default'][0]):
print "bam!"
self.itemslistviewitems.append(BoldListViewItem(self.itemslistview,self.itemslistview.lastItem(),item['title'][0]))
else:
self.itemslistviewitems.append(KListViewItem(self.itemslistview,self.itemslistview.lastItem(),item['title'][0]))
except ValueError:
self.itemslistviewitems.append(KListViewItem(self.itemslistview,self.itemslistview.lastItem(),item['title'][0]))
#######################################################################
def slotUser1(self):
self.aboutus.show()
#######################################################################
# def slotClose(self):
# self.close()
#######################################################################
def slotOk(self):
self.save_menulst()
# mhb TODO: catching exceptions here would be useful
self.close()
#######################################################################
def slotCheckOsClicked(self):
self.OsProbedList = self.load_osprobe()
#######################################################################
def oslistviewitemSelected(self):
# save current item changes & select another one
i = self.oslistviewitems.index(self.oslistview.selectedItem())
self.updatingGUI = True
self.displaynamelabel.setText(self.itemslist[i]["title"][0])
# visible in GRUB reload
# kernel reload
try:
self.kernel.setURL(self.itemslist[i]["kernel"][0])
except KeyError:
self.initrd.setURL("unavailable") # mhb debug
# initrd reload
try:
self.initrd.setURL(self.itemslist[i]["initrd"][0])
except KeyError:
self.initrd.setURL("unavailable") # mhb debug
# custom options reload
customoptions = ""
for word in self.itemslist[i]["kernel"][1:-1]:
customoptions += word + " "
self.customoptions.setText(customoptions[:-1])
self.updatingGUI = False
print "oslistview item selected" #mhb debug
pass
#######################################################################
def slotDisplayNameLabelChanged(self, string):
if(self.updatingGUI == False):
print "display name changed" #mhb debug
i = self.oslistviewitems.index(self.oslistview.selectedItem())
self.itemslist[i]["title"][0] = string
self.oslistview.selectedItem().setText(0,string)
self.reloadListViews("itemslist")
pass
#######################################################################
def slotUpButtonClicked(self):
print "UpButton clicked" #mhb debug
i = self.itemslistviewitems.index(self.itemslistview.selectedItem())
self.itemslistview.selectedItem().itemAbove().moveItem(self.itemslistview.selectedItem())
# itemslist should have the same i for the same option
if(i != 0):
container = self.itemslist[i]
self.itemslist[i] = self.itemslist[i-1]
self.itemslist[i-1] = container
self.reloadListViews("oslist")
return "not working yet"
#######################################################################
def slotDownButtonClicked(self):
print "DownButton clicked" #mhb debug
i = self.itemslistviewitems.index(self.itemslistview.selectedItem())
self.itemslistview.selectedItem().moveItem(self.itemslistview.selectedItem().itemBelow())
if(i != len(self.itemslist)-1):
container = self.itemslist[i]
self.itemslist[i] = self.itemslist[i+1]
self.itemslist[i+1] = container
self.reloadListViews("oslist")
return "not working yet"
#######################################################################
def slotSetDefaultButtonClicked(self):
print "SetDefaultButton cliicked" #mhb debug
try:
defaultn = int(self.globalvars["default"][0])
except ValueError:
pass
else:
container = self.itemslistviewitems[defaultn]
self.itemslistviewitems[defaultn] = KListViewItem(self.itemslistview,container,self.itemslist[defaultn]['title'][0])
self.itemslistview.takeItem(container)
indexn = self.itemslistviewitems.index(self.itemslistview.selectedItem())
self.globalvars["default"] = str(indexn)
self.itemslistviewitems[indexn] = BoldListViewItem(self.itemslistview,self.itemslistview.selectedItem(),self.itemslist[indexn]['title'][0])
self.itemslistview.takeItem(self.itemslistview.selectedItem())
self.reloadListViews("oslist")
return "not working yet"
#######################################################################
# loop
def exec_loop(self):
global programbase
# self.__loadOptions()
self.updatingGUI = True
#self.__updateUserList()
#self.__updateGroupList()
self.updatingGUI = False
programbase.exec_loop(self)
print "done"
#######################################################################
# loads menu.lst
# NOT YET parsing:
#  fallback
# currently parsing: (type of the location number)
# default <int>
# timeout <int>
# hiddenmenu <int>
# color <int>
#  password (consider an md5 sum?) <int>
#  AUTOMAGIC KERNELS LIST <interval - two ints>
# GRUBCONFIG DISABLED ITEMS <interval - two ints>
# IMPORTANT note:
# any value that is not parsed MUST not be ommited at the end!
#  any value that is commented (parsed or not) MUST not be omitted at the end!
# not so important note:
# if a value we parse is not defined:
# apply defaults (how do find them out?)
# but specify it in the menu.lst when saving
# mhb TODO: somehow handle automagic kernel list (target: feisty)
# mhb TODO: adapt to more distributions, find menu.lst on different locations
def load_menulst(self):
self.modifiedlines = []
menufd = open(self.menulstlocation,"r")
linenum = 0
lock = 0
itemlock = 0
currentitem = 0
for line in menufd:
# Checks if the first non-white char in a line is a #
if re.search(r'^(/s)*#',line) or re.search(r'^(/s)*$',line):
print "a commented line" # mhb debug
if itemlock == 1:
itemlock = 0
currentitem += 1
# if it is a start of an area we parse, use a lock
if re.search(r'sumthin',line) and (lock == 0):
lock = 1
elif re.search(r'sumthin_other',line) and (lock == 0):
lock = 2
# else if it is an end of an area we parse, close the lock
elif re.search(r'sumthin_other_end',line) and (lock == 2):
lock = 0
elif re.search(r'sumthin_end',line) and (lock == 1):
lock = 0
# errors
# mhb TODO: exception catching
elif re.search(r'sumthin',line) and (lock == 0):
raise IdentationError
elif re.search(r'sumthin_other',line) and (lock == 1):
raise EndOfNotOpenedError
# if it is in the lock, do the mumbo-jumbo
# find out what kind of lock it is
# AUTOCONFIG
if lock == 1:
# automagic kernels list?
if re.search(r'sumthin',line):
pass
# or the other one (grubconfig disabled kernel's list )?
else:
self.modifiedlines.append(linenum)
# else save it as a commented line (does not save the locks)
# GRUBCONFiG commented item
elif lock == 2:
# remove leading spaces and one #
# the parse as a normal menu item
pass
# it's a commented, no need to do anything
else:
pass
# okay, it's not commented
else:
print "a not commented line" # mhb debug
self.modifiedlines.append(linenum)
# we presume the first character is already a name
var_name = line.split()[0]
#print "variable name is " + var_name # mhb debug
# var_value's last item is always the line that has to be changed
var_value = []
if var_name in parsable:
# cat 0 - a title - triggers itemlock, has a name and a value, which should be stored as text
if var_name == "title":
print line.split(None,1)
var_value.append(line.split(None,1)[1][:-1])
itemlock = 1
self.itemslist.append({})
# cat 1 - has a name and 1 value
elif var_name in cat1:
try:
var_value.append(line.split()[1])
except IndexError:
var_value.append(1)
# cat 2 - has a name, but no value ( implicit 1 )
elif var_name in cat2:
var_value.append(1)
# cat 3 - has a name, has multiple values, should be saved as list
elif var_name in cat3:
var_value = line.split()[1:]
# now, append the number
var_value.append(linenum)
if itemlock == 1:
self.itemslist[currentitem][var_name] = var_value
else:
self.globalvars[var_name] = var_value
#if var_name in parsable:
#print "variable name " + var_name + " is parsable " # mhb debug
#if var_name == "title":
#itemlock = 1
#self.itemslist.append({})
#if(len(line.split()) > 1):
#var_value = line.split()[1]
#if itemlock == 1:
#else:
#print "variable value is " + var_value # mhb debug
#else:
#if itemlock == 1:
#self.itemslist[currentitem][var_name] = var_value
#else:
#self.globalvars[var_name] = 1
#else:
#print "variable name " + var_name + " is currently not parsable" # mhb debug
#print "it has no value" # mhb debug
# print "parsed another line" # mhb debug
linenum += 1;
print "load_menulst() called" # mhb debug
return "not working yet"
#######################################################################
# writes menu.lst
def save_menulst(self):
delimeter = " "
# phase 1: preparing the values
lines = []
linecontent = []
# this consists of:
#  1. concatenating the list of lines that were modified
# 2. writing the lines in another list (or something more efficient
output = {}
# the globals first
for unit, value in self.globalvars.items():
lines.append(value[-1])
temp_str=""
temp_str+=(str(unit)+" ")
for index in range(len(value)-1):
temp_str+=(str(value[index])+" ")
linecontent.append(temp_str)
# itemslist next (abattoir)
for item in self.itemslist:
for unit, value in reversed(item.items()):
lines.append(value[-1])
temp_str=""
temp_str+=(str(unit)+" ")
for index in range(len(value)-1):
temp_str+=(str(value[index])+" ")
linecontent.append(temp_str)
# phase 2: writing the file
# by now we have a list of numbers (let's call it lines[])
# and a list of mofified lines (let's call it linecontent[] )
# lines[i] corresponds with linecontent[]
trfile = open(self.readfilename, "r" )
twfilename = tempfile.mkstemp("menulst")[1]
twfile = open(twfilename,"w")
# the current solution is:
# read the menu.lst again (or rather its copy, to prevent the file being changed)
# line by line write it in the output file (to be exact, to a file in /tmp)
linenum = 0
print linecontent
print lines
# foreach file as line:
for originalline in trfile:
# if its number isn't in the location list, simply write it
if linenum in lines:
twfile.writelines(linecontent[linenum])
else:
twfile.writelines(originalline)
linenum += 1;
# if there are any more lines to be written (newly detected options)
# write them at the end (now)
# when that process works out fine do a quick rewrite to /boot/grub/menu.lst
# mhb TODO: declare self.menulstlocation
twfile.close()
shutil.move(twfilename,self.menulstlocation)
# mhb TODO: Exception handling
os.remove(self.readfilename)
print "save_menulst() called" # mhb debug
return "not working yet"
#######################################################################
# loads output from os-probe
def load_osprobe(self):
detected = os.popen('os-prober').readlines()
ops_list = []
for ops in detected:
ops = string.replace(ops,"\n","")
temp_list = ops.split(':')
partition = temp_list[0]
temp_list[0] = string.replace(temp_list[0],"/dev/","")
re_obj = re.search(r'([sh]d)([a-z])([0-9])*$',temp_list[0])
disk = ord(re_obj.group(2))%97
part = int(re_obj.group(3))-1
if re_obj == None:
re_obj = re.search(r'(fd[0-9]*)$',temp_list[0])
if re_obj:
disk = temp_list[0]
part = ""
else : re_obj = re.search(r'(part[0-9]*$', temp_list[0])
if re_obj:
disk = '/disc'
part = temp_list[0]
temp_list[0] = '('+re_obj.group(1)+str(disk)+','+str(part)+')'
if temp_list[3].lower() == "linux":
mounted = os.popen('mount | grep '+partition).readlines()
if mounted:
linux_os = os.popen('linux-boot-prober --mounted '+partition).readlines()
else:
linux_os = os.popen('linux-boot-prober '+partition).readlines()
linux_list = []
for lops in linux_os:
lops = string.replace(lops,"\n","")
temp_linux_list = lops.split(':')
linux_list.append(temp_linux_list)
temp_list.append(linux_list)
ops_list.append(temp_list)
temp_list = []
return ops_list
############################################################################
# Factory function for KControl
def create_grubconfig(parent,name):
return GrubConfigAppClass(parent, name)
##########################################################################
def MakeAboutData():
aboutdata = KAboutData("guidance", programname, version,
unicode(i18n("Boot Loader Configuration Tool")).encode(locale.getpreferredencoding()),
KAboutData.License_GPL, "Copyright (C) 2006-2007 Martin Böhm")
aboutdata.addAuthor("Martin Böhm", "Developer", "martin.bohm@kubuntu.org", "http://mhb.ath.cx/")
aboutdata.addAuthor("Simon Edwards", "Developer", "simon@simonzone.com", "http://www.simonzone.com/software/")
aboutdata.addAuthor("Sebastian Kügler", "Developer", "sebas@kde.org", "http://vizZzion.org")
return aboutdata
if standalone:
aboutdata = MakeAboutData()
KCmdLineArgs.init(sys.argv,aboutdata)
kapp = KApplication()
grubconfigapp = GrubConfigAppClass()
grubconfigapp.exec_loop()