import rpm, os
import iutil, isys
from lilo import LiloConfiguration
import string
import socket
import crypt
import whrandom
import pcmcia
import _balkan
from simpleconfig import SimpleConfigFile
from mouse import Mouse
from xf86config import XF86Config
def _(x):
return x
class FakeDDruid:
"""A disk druid looking thing for upgrades"""
def partitionList (self):
return (self.partitions, None)
def append (self, name, table):
for i in range (len (table)):
(type, sector, size) = table[i]
if size and type != -1:
self.partitions.append ((name + str (i + 1)),
"Existing000" + str(len (self.partitions)),
type)
def __init__ (self):
self.partitions = []
class LogFile:
def __init__ (self):
self.logFile = open("/dev/tty3", "w")
def __call__ (self, format, *args):
if args:
self.logFile.write ("* %s\n" % (format % args))
else:
self.logFile.write ("* %s\n" % format)
def getFile (self):
return self.logFile.fileno ()
class NetworkDevice (SimpleConfigFile):
def __str__ (self):
s = ""
s = s + "DEVICE=" + self.info["DEVICE"] + "\n"
keys = self.info.keys ()
keys.sort ()
keys.remove ("DEVICE")
for key in keys:
s = s + key + "=" + self.info[key] + "\n"
return s
class Network:
def __init__ (self):
self.netdevices = {}
self.gateway = ""
self.primaryNS = ""
self.secondaryNS = ""
self.ternaryNS = ""
self.domains = []
self.readData = 0
self.hostname = "localhost.localdomain"
try:
f = open ("/tmp/netinfo", "r")
except:
pass
else:
lines = f.readlines ()
f.close ()
info = {}
for line in lines:
netinf = string.splitfields (line, '=')
info [netinf[0]] = string.strip (netinf[1])
self.netdevices [info["DEVICE"]] = NetworkDevice (info["DEVICE"])
if info.has_key ("IPADDR"):
self.netdevices [info["DEVICE"]].set (("IPADDR", info["IPADDR"]))
if info.has_key ("NETMASK"):
self.netdevices [info["DEVICE"]].set (("NETMASK", info["NETMASK"]))
if info.has_key ("BOOTPROTO"):
self.netdevices [info["DEVICE"]].set (("BOOTPROTO", info["BOOTPROTO"]))
if info.has_key ("GATEWAY"):
self.gateway = info["GATEWAY"]
if info.has_key ("NS1"):
self.primaryNS = info["NS1"]
if info.has_key ("DOMAIN"):
self.domains.append(info["DOMAIN"])
if info.has_key ("HOSTNAME"):
self.hostname = info["HOSTNAME"]
self.readData = 1
def available (self):
f = open ("/proc/net/dev")
lines = f.readlines()
f.close ()
# skip first two lines, they are header
lines = lines[2:]
for line in lines:
dev = string.strip (line[0:6])
if dev != "lo" and not self.netdevices.has_key (dev):
self.netdevices[dev] = NetworkDevice (dev)
return self.netdevices
def guessHostnames (self):
# guess the hostname for the first device with an IP
# XXX fixme - need to set up resolv.conf
self.domains = []
for dev in self.netdevices.values ():
ip = dev.get ("ipaddr")
if ip:
try:
(hostname, aliases, ipaddrs) = socket.gethostbyaddr (ip)
except socket.error:
hostname = ""
if hostname:
dev.hostname = hostname
if '.' in hostname:
# chop off everything before the leading '.'
self.domains.append (hostname[(string.find (hostname, '.') + 1):])
#if self.hostname == "localhost.localdomain":
self.hostname = hostname
else:
dev.hostname = "localhost.localdomain"
if not self.domains:
self.domains = [ "localdomain" ]
def getLiloOptions(self):
if self.mounts.has_key ('/boot'):
bootpart = self.mounts['/boot'][0]
else:
bootpart = self.mounts['/'][0]
i = len (bootpart) - 1
while i < 0 and bootpart[i] in digits:
i = i - 1
drives = self.drives.available().keys()
drives.sort(isys.compareDrives)
boothd = drives[0]
def getLiloImages(self):
if not self.ddruid:
raise RuntimeError, "No disk druid object"
(drives, raid) = self.ddruid.partitionList()
# rearrange the fstab so it's indexed by device
mountsByDev = {}
for loc in self.mounts.keys():
(device, fsystem, reformat) = self.mounts[loc]
mountsByDev[device] = loc
oldImages = {}
for dev in self.liloImages.keys():
oldImages[dev] = self.liloImages[dev]
self.liloImages = {}
foundDos = 0
for (dev, devName, type) in drives:
# ext2 partitions get listed if
# 1) they're /
# 2) they're not mounted
# only list dos and ext2 partitions
if type != 1 and type != 2:
continue
if (mountsByDev.has_key(dev)):
if mountsByDev[dev] == '/':
self.liloImages[dev] = ("linux", 2)
else:
if not oldImages.has_key(dev):
self.liloImages[dev] = ("", type)
else:
self.liloImages[dev] = oldImages[dev]
if type == 1:
if foundDos: continue
foundDos = 1
self.liloImages[dev] = ("dos", type)
return self.liloImages
def createRaidTab(self, file, devPrefix, createDevices = 0):
(devices, raid) = self.ddruid.partitionList()
if not raid: return
deviceDict = {}
for (device, name, type) in devices:
deviceDict[name] = device
rt = open(file, "w")
for (mntpoint, device, fstype, raidType, makeup) in raid:
if createDevices:
isys.makeDevInode(device, devPrefix + '/' + device)
rt.write("raiddev %s/%s\n" % (devPrefix, device,))
rt.write("raid-level %d\n" % (raidType,))
rt.write("nr-raid-disks %d\n" % (len(makeup),))
rt.write("chunk-size 64k\n")
rt.write("persistent-superblock 1\n");
rt.write("#nr-spare-disks 0\n")
i = 0
for subDevName in makeup:
isys.makeDevInode(deviceDict[subDevName], '%s/%s' %
(devPrefix, deviceDict[subDevName]))
rt.write(" device %s/%s\n" %
(devPrefix, deviceDict[subDevName],))
rt.write(" raid-disk %d\n" % (i,))
i = i + 1
rt.write("\n")
rt.close()
def mountFilesystems(self):
if (not self.setupFilesystems): return
def readFstab (self, path):
f = open (path, "r")
lines = f.readlines ()
f.close
fstab = {}
for line in lines:
fields = string.split (line)
# skip comments
if fields and fields[0][0] == '#':
continue
# all valid fstab entries have 6 fields
if not len (fields) < 4 and len (fields) <= 6:
if fields and (fields[2] == "ext2" or fields[2] == "swap") \
and fields[3] == "defaults":
format = 0
# XXX always format swap.
if fields[2] == "swap": format = 1
fstab[fields[1]] = (fields[0][5:], fields[2], format)
return fstab
def installLilo (self):
lilo = LiloConfiguration ()
if not self.liloImages:
self.setLiloImages(self.getLiloImages())
# OK - for this release we need to just blow away the old lilo.conf
# just like we used to.
## # on upgrade read in the lilo config file
## if os.access (self.instPath + '/etc/lilo.conf', os.R_OK):
## lilo.read (self.instPath + '/etc/lilo.conf')
## elif not self.liloDevice: return
smpInstalled = (self.hdList.has_key('kernel-smp') and
self.hdList['kernel-smp'].selected)
if (self.upgrade and not isys.smpAvailable()):
self.log("upgrading to a smp kernel on a up system; configuring "
"up in lilo")
smpInstalled = 0
if self.mounts.has_key ('/'):
(dev, fstype, format) = self.mounts['/']
rootDev = dev
else:
raise RuntimeError, "Installing lilo, but there is no root device"
kernelList = []
otherList = []
main = "linux"
for (drive, (label, liloType)) in self.liloImages.items ():
if (drive == rootDev) and label:
main = label
elif label:
otherList.append (label, "/dev/" + drive)
lilo.addEntry("default", main)
label = main
if (smpInstalled):
kernelList.append((main, self.hdList['kernel-smp'], "smp"))
label = main + "-up"
for (label, device) in otherList:
sl = LiloConfiguration()
sl.addEntry("label", label)
lilo.addImage ("other", device, sl)
for (liloType, name, config) in lilo.images:
# remove entries for missing kernels (upgrade)
if liloType == "image":
if not os.access (self.instPath + name, os.R_OK):
lilo.delImage (name)
# remove entries for unbootable partitions
elif liloType == "other":
device = name[5:]
isys.makeDevInode(device, '/tmp/' + device)
if not isys.checkBoot ('/tmp/' + device):
lilo.delImage (name)
os.remove ('/tmp/' + device)
# pass 2, remove duplicate entries
labels = []
for (liloType, name, config) in lilo.images:
if not name in labels:
labels.append (name)
else: # duplicate entry, first entry wins
lilo.delImage (name)
lilo.write(self.instPath + "/etc/lilo.conf")
# XXX make me "not test mode"
if self.setupFilesystems:
iutil.execWithRedirect(self.instPath + '/sbin/lilo' ,
[ "lilo", "-r", self.instPath ],
stdout = None)
def freeHeaderList(self):
if (self.hdList):
self.hdList = None
def getHeaderList(self):
if (not self.hdList):
w = self.intf.waitWindow(_("Reading"),
_("Reading package information..."))
self.hdList = self.method.readHeaders()
w.pop()
return self.hdList
def getCompsList(self):
if (not self.comps):
self.getHeaderList()
self.comps = self.method.readComps(self.hdList)
for comp in self.comps:
if comp.selected:
comp.select (1)
self.comps['Base'].select(1)
self.updateInstClassComps()
return self.comps
def updateInstClassComps(self):
# don't load it just for this
if (not self.comps): return
group = self.instClass.getGroups()
packages = self.instClass.getPackages()
if (group == None and packages == None): return 0
for n in self.comps.keys():
self.comps[n].unselect(0)
self.comps['Base'].select(1)
if group:
for n in group:
self.comps[n].select(1)
if packages:
for n in packages:
self.selectPackage(n)
if self.x.server:
self.selectPackage('XFree86-' + self.x.server)
for p in self.hdList.packages.values ():
if p.selected:
ts.add(p.h, (p.h, p.h[rpm.RPMTAG_NAME]))
else:
ts.add(p.h, (p.h, p.h[rpm.RPMTAG_NAME]), "a")
ts.order()
deps = ts.depcheck()
rc = []
if deps:
for ((name, version, release),
(reqname, reqversion),
flags, suggest, sense) in deps:
if sense == rpm.RPMDEP_SENSE_REQUIRES:
if suggest:
(header, sugname) = suggest
else:
sugname = _("no suggestion")
if not (name, sugname) in rc:
rc.append ((name, sugname))
return rc
else:
return None
def selectDeps (self, deps):
if deps:
for (who, dep) in deps:
if dep != _("no suggestion"):
self.hdList[dep].selected = 1
def upgradeFindRoot (self):
rootparts = []
if not self.setupFilesystems: return [ self.instPath ]
win = self.intf.waitWindow (_("Searching"),
_("Searching for Red Hat Linux installations..."))
drives = self.drives.available ().keys ()
self.ddruid = FakeDDruid ()
for drive in drives:
isys.makeDevInode(drive, '/tmp/' + drive)
try:
table = _balkan.readTable ('/tmp/' + drive)
except SystemError:
pass
else:
self.ddruid.append (drive, table)
for i in range (len (table)):
(type, sector, size) = table[i]
# 2 is ext2 in balkan speek
if size and type == 2:
# for RAID arrays of format c0d0p1
if drive [:3] == "rd/" or drive [:4] == "ida/":
dev = drive + 'p' + str (i + 1)
else:
dev = drive + str (i + 1)
isys.makeDevInode(dev, '/tmp/' + dev)
try:
isys.mount('/tmp/' + dev, '/mnt/sysimage')
except SystemError, (errno, msg):
self.intf.messageWindow(_("Error"),
_("Error mounting ext2 filesystem on %s: %s") % (dev, msg))
if os.access ('/mnt/sysimage/etc/fstab', os.R_OK):
rootparts.append (dev)
isys.umount('/mnt/sysimage')
os.remove ('/tmp/' + dev)
if size and type == 5:
dev = drive + str (i + 1)
isys.makeDevInode(dev, '/tmp/' + dev)
try:
isys.swapon ('/tmp/' + dev)
except SystemError, (error, msg):
self.log ("Error in swapon of %s: %s", dev, msg)
os.remove ('/tmp/' + dev)
os.remove ('/tmp/' + drive)
win.pop ()
return rootparts
# unselect all packages
for package in self.hdList.packages.values ():
package.selected = 0
# always upgrade all packages in Base package group
self.comps['Base'].select(1)
hasX = 0
hasgmc = 0
# turn on the packages in the upgrade set
for package in packages:
self.hdList[package[rpm.RPMTAG_NAME]].selected = 1
if package[rpm.RPMTAG_NAME] == "XFree86":
hasX = 1
if package[rpm.RPMTAG_NAME] == "gmc":
hasgmc = 1
# yes, this is rude
if hasX and not hasgmc:
self.comps['GNOME'].select(1)
# new package dependency fixup
self.selectDeps (self.verifyDeps ())
win.pop ()
for (mntpoint, (dev, fstype, reformat)) in todo.instClass.fstab:
todo.addMount(dev, mntpoint, fstype, reformat)
if todo.ddruid:
todo.ddruid = None
todo.mounts = {}
todo.users = []
if todo.instClass.rootPassword:
todo.rootpassword.set(todo.instClass.rootPassword)
if todo.instClass.language:
todo.language.setByAbbrev(todo.instClass.language)
if todo.instClass.keyboard:
todo.keyboard.set(todo.instClass.keyboard)
if todo.instClass.keyboard != "us":
xkb = todo.keyboard.getXKB ()
if xkb:
apply (todo.x.setKeyboard, xkb)
devices = todo.network.available ()
if (devices and bootProto):
list = devices.keys ()
list.sort()
dev = devices[list[0]]
dev.set (("bootproto", bootProto))
if bootProto == "static":
if (ip):
dev.set (("ipaddr", ip))
if (netmask):
dev.set (("netmask", netmask))
def setDefaultRunlevel (self):
inittab = open (self.instPath + '/etc/inittab', 'r')
lines = inittab.readlines ()
inittab.close ()
inittab = open (self.instPath + '/etc/inittab', 'w')
for line in lines:
if len (line) > 3 and line[:3] == "id:":
fields = string.split (line, ':')
fields[1] = str (self.initlevel)
line = string.join (fields, ':')
inittab.write (line)
inittab.close ()
def instCallback(self, what, amount, total, h, intf):
if (what == rpm.RPMCALLBACK_TRANS_START):
# step 6 is the bulk of the transaction set
# processing time
if amount == 6:
self.progressWindow = \
self.intf.progressWindow (_("Processing"),
_("Preparing to install..."),
total)
if (what == rpm.RPMCALLBACK_TRANS_PROGRESS):
if self.progressWindow:
self.progressWindow.set (amount)
if (what == rpm.RPMCALLBACK_TRANS_STOP and self.progressWindow):
self.progressWindow.pop ()
if (self.hdList.has_key('kernel-smp') and
self.hdList['kernel-smp'].selected):
version = (self.hdList['kernel-smp']['version'] + "-" +
self.hdList['kernel-smp']['release'] + "smp")
kernelVersions.append(version)
version = (self.hdList['kernel']['version'] + "-" +
self.hdList['kernel']['release'])
kernelVersions.append(version)
for (path, subdir, name) in self.extraModules:
pattern = ""
names = ""
for n in kernelVersions:
pattern = pattern + " " + n + "/" + name + ".o"
names = names + " " + name + ".o"
command = ("cd %s/lib/modules; gunzip < %s/modules.cgz | " +
"%s/bin/cpio --quiet -iumd %s") % \
(self.instPath, path, self.instPath, pattern)
self.log("running: '%s'" % (command, ))
os.system(command)
for n in kernelVersions:
self.log("from %s/lib/modules/%s/%s.o" % (self.instPath, n, name))
self.log("to %s/lib/modules/%s/%s/%s.o" % (self.instPath, n,
subdir, name))
os.rename("%s/lib/modules/%s/%s.o" % (self.instPath, n, name),
"%s/lib/modules/%s/%s/%s.o" % (self.instPath, n,
subdir, name))
def doInstall(self):
# make sure we have the header list and comps file
self.getHeaderList()
self.getCompsList()
# this is NICE and LATE. It lets kickstart/server/workstation
# installs detect this properly
if (self.hdList.has_key('kernel-smp') and isys.smpAvailable()):
self.hdList['kernel-smp'].selected = 1
# we *always* need a kernel installed
if (self.hdList.has_key('kernel')):
self.hdList['kernel'].selected = 1
if self.x.server:
self.selectPackage ('XFree86-' + self.x.server)
# make sure that all comps that include other comps are
# selected (i.e. - recurse down the selected comps and turn
# on the children
if self.setupFilesystems:
if not self.upgrade:
if (self.ddruidAlreadySaved):
self.makeFilesystems (createSwap = 0)
else:
self.ddruid.save ()
self.makeFilesystems (createSwap = (not self.swapCreated))
else:
(drives, raid) = self.ddruid.partitionList()
self.mountFilesystems ()
if self.upgrade:
w = self.intf.waitWindow(_("Rebuilding"),
_("Rebuilding RPM database..."))
rc = rpm.rebuilddb (self.instPath)
w.pop ()
if rc:
self.intf.messageWindow (_("Error"),
_("Rebuild of RPM "
"database failed. You may be out of disk space?"));
# XXX do something sane here.
raise RuntimeError, "panic"
self.method.targetFstab (self.mounts)
if not self.installSystem:
return
for i in [ '/var', '/var/lib', '/var/lib/rpm', '/tmp', '/dev' ]:
try:
os.mkdir(self.instPath + i)
except os.error, (errno, msg):
# self.intf.messageWindow("Error", "Error making directory %s: %s" % (i, msg))
pass
db = rpm.opendb(1, self.instPath)
ts = rpm.TransactionSet(self.instPath, db)
total = 0
totalSize = 0
if self.upgrade:
how = "u"
else:
how = "i"
for p in self.hdList.selected():
ts.add(p.h, p.h, how)
total = total + 1
totalSize = totalSize + p.h[rpm.RPMTAG_SIZE]
ts.order()
if self.upgrade:
logname = '/tmp/upgrade.log'
else:
logname = '/tmp/install.log'
if problems:
needed = {}
size = 12
for (descr, (type, mount, need)) in problems:
idx = string.find (mount, "/mnt/sysimage")
if idx != -1:
# 13 chars in /mnt/sysimage
mount = mount[13:]
if needed.has_key (mount) and needed[mount] < need:
needed[mount] = need
else:
needed[mount] = need
probs = _("You don't appear to have enough disk space to install "
"the packages you've selected. You need more space on the "
"following filesystems:\n\n")
probs = probs + ("%-15s %s\n") % (_("Mount Point"), _("Space Needed"))
for (mount, need) in needed.items ():
if need > (1024*1024):
need = (need + 1024 * 1024 - 1) / (1024 * 1024)
suffix = "M"
else:
need = (need + 1023) / 1024,
suffix = "k"