summaryrefslogtreecommitdiffstats
path: root/silo.py
blob: b9193f3d1930bf8d02ae3845b44d7ee6f753785e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
import string
import os
from lilo import LiloConfigFile
import _silo
import iutil
import isys

class SiloInstall:
    def allowSiloLocationConfig(self, fstab):
	bootDevice = fstab.getBootDevice()
	if bootDevice[0:2] == "md":
	    self.setDevice(("raid", bootDevice))
	    return None
	return 1

    def checkUFS(self, dev):
	f = open("/proc/mounts","r")
	lines = f.readlines ()
	f.close ()
	mounted = None
	ufstype = None
	for line in lines:
	    fields = string.split (line)
	    if fields[0] == '/dev/' + dev and fields[2] == 'ufs':
		mounted = fields[1]
	if not mounted:
	    try:
		os.mkdir ("/tmp/ufsmntpoint")
		isys.makeDevInode (dev, "/tmp/" + dev)
		isys.mount ("/tmp/" + dev, "/tmp/ufsmntpoint", "ufs")
	    except:
		try:
		    os.remove ("/tmp/" + dev)
		except:
		    pass
		try:
		    os.rmdir ("/tmp/ufsmntpoint")
		except:
		    pass
		return None
	    root = "/tmp/ufsmntpoint"
	else:
	    root = mounted
	if os.access (root + "/etc/system", os.X_OK):
	    if os.access (root + "/kernel/unix", os.X_OK):
		ufstype = "Solaris"
	    elif os.access (root + "/kernel/genunix", os.X_OK):
		ufstype = "Solaris"
	if os.access (root + "/vmunix", os.X_OK) or os.access (root + "/stand", os.X_OK):
	    if os.access (root + "/bin/sh", os.X_OK):
		# Check if /bin/sh is a.out SPARC binary
		aout = None
		try:
		    f = open (root + "/bin/sh", "r")
		    aout = f.read(4)
		    f.close()
		except:
		    pass
		if aout and len(aout) == 4 and aout[1] == "\x03" and aout[2] == "\x01":
		    if aout[3] == "\x07" or aout[3] == "\x08" or aout[3] == "\x0b":
			ufstype = "SunOS"
	if not mounted:
	    try:
		isys.umount ("/tmp/ufsmntpoint")
	    except:
		pass
	    try:
		os.rmdir ("/tmp/ufsmntpoint")
	    except:
		pass
	    try:
		os.remove ("/tmp/" + dev)
	    except:
		pass
	return ufstype

    def setSiloImages(self, images):
	self.siloImages = images

    def getSiloImages(self, fstab):
	(drives, raid) = fstab.raidList()

	# rearrange the fstab so it's indexed by device
	mountsByDev = {}
	for (mntpoint, device, fsystem, doFormat, size) in \
		fstab.mountList():
	    mountsByDev[device] = mntpoint

	for (mntpoint, device, fstype, raidType, start, size, makeup) in raid:
	    mountsByDev[device] = mntpoint
	    drives.append(device, "", 2, 0, 0)

	for (device, mntpoint, fsystem, makeup) in fstab.existingRaidList():
	    mountsByDev[device] = mntpoint
	    drives.append(device, "", 2, 0, 0)

	oldImages = {}
	for dev in self.siloImages.keys():
	    oldImages[dev] = self.siloImages[dev]

	self.siloImages = {}
	nSolaris = 0
	nSunOS = 0
	for (dev, devName, type, start, size) in drives:
	    # ext2 and raid partitions get listed if 
	    #	    1) they're /
	    #	    2) they're not mounted
	    #	       and contain /boot of
	    #	       some Linux installation
	    # FIXME: For now only list / and UFS partitions,
	    # for 7.0 write code which will read and parse silo.conf from other
	    # Linux partitions and merge it in (after required device
	    # substitions etc.

	    # only list ext2 and ufs partitions
	    if type != 2 and type != 6:
		continue

	    if (mountsByDev.has_key(dev)):
		if mountsByDev[dev] == '/':
		    self.siloImages[dev] = ("linux", 2)
	    elif type == 6:
		if not oldImages.has_key(dev):
		    self.siloImages[dev] = ("", type)
		else:
		    self.siloImages[dev] = oldImages[dev]
		ostype = self.checkUFS(dev)
		if ostype == "Solaris":
		    if nSolaris == 0:
			self.siloImages[dev] = ("solaris", type)
		    else:
			self.siloImages[dev] = ("solaris%d" % nSolaris, type)
		    nSolaris = nSolaris + 1
		elif ostype == "SunOS":
		    if nSunOS == 0:
			self.siloImages[dev] = ("sunos", type)
		    else:
			self.siloImages[dev] = ("sunos%d" % nSunOS, type)
		    nSunOS = nSunOS + 1

	return (self.siloImages, self.default)

    def getSiloMbrDefault(self, fstab):
	# Check partition at cylinder 0 on the boot disk
	# is /, /boot or Linux swap
	bootpart = fstab.getBootDevice()
	if bootpart[:2] == "md":
	    return "mbr"
	i = len (bootpart) - 1
	while i > 0 and bootpart[i] in string.digits:
	    i = i - 1
	boothd = bootpart[:i+1]
	(drives, raid) = fstab.partitionList()
	for (dev, devName, type, start, size) in drives:
	    i = len (dev) - 1
	    while i > 0 and dev[i] in string.digits:
		i = i - 1
	    devhd = dev[:i+1]
	    if devhd == boothd and start == 0:
		if type == 5:
		    return "mbr"
		elif type == 2:
		    if dev == bootpart:
			return "mbr"
		    elif dev == fstab.getRootDevice()[0]:
			return "mbr"
		return "partition"
	return "partition"

    def hasUsableFloppy(self):
	try:
	    f = open("/proc/devices", "r")
	except:
	    return 0
	lines = f.readlines ()
	f.close ()
	for line in lines:
	    if string.strip (line) == "2 fd":
		name = _silo.promRootName()
		if name and name[0:10] == 'SUNW,Ultra' and string.find(name, "Engine") == -1:
		    # Seems like SMCC Ultra box. It is highly probable
		    # the floppies will be unbootable
		    return 1
		return 2
	return 0

    def setPROM(self, linuxAlias, bootDevice):
	self.linuxAlias = linuxAlias
	self.bootDevice = bootDevice

    def hasAliases(self):
	return _silo.hasAliases()

    def disk2PromPath(self,dev):
	return _silo.disk2PromPath(dev)

    def makeInitrd (self, kernelTag, instRoot):
	initrd = "/boot/initrd%s.img" % (kernelTag, )
	if not self.initrdsMade.has_key(initrd):
	    iutil.execWithRedirect("/sbin/mkinitrd",
				  [ "/sbin/mkinitrd",
				    "--ifneeded",
				    initrd,
				    kernelTag[1:] ],
				  stdout = None, stderr = None, searchPath = 1,
				  root = instRoot)
	    self.initrdsMade[kernelTag] = 1
	return initrd

    def getMbrDevices(self, fstab):
	bootpart = fstab.getBootDevice()
	mbrdevs = []
	if bootpart[:2] == "md":
	    (devices, raid) = fstab.raidList()
	    for (raidMntPoint, raidDevice, fsType, raidType, raidStart, raidSize, raidDevs) in raid:
		if raidDevice != bootpart: continue
		for raidDev in raidDevs:
		    for (device, name, type, start, size) in devices:
			if name == raidDev:
			    i = len(device) - 1
			    while i > 0 and device[i] in string.digits:
				i = i - 1
			    mbrdevs.append(device[:i+1])
	else:
	    # Do not use fstab.getMbrDevice() here
	    i = len (bootpart) - 1
	    while i > 0 and bootpart[i] in string.digits:
		i = i - 1
	    mbrdevs.append(bootpart[:i+1])
	return mbrdevs

    def getMbrDevice(self, fstab):
	return self.getMbrDevices(fstab)[0]

    def install(self, fstab, instRoot, hdList, upgrade):
	if not self.siloDevice: return

	silo = LiloConfigFile ()

	if not self.siloImages:
	    (images, default) = self.getSiloImages(fstab)
	    self.setSiloImages(images)

	bootpart = fstab.getBootDevice()
	boothd = self.getMbrDevice(fstab)
	smpInstalled = (hdList.has_key('kernel-smp') and 
			hdList['kernel-smp'].selected)

	rootDev = fstab.getRootDevice ()
	if rootDev:
	    # strip off the filesystem; we don't need it
	    rootDev = rootDev[0]
	else:
	    raise RuntimeError, "Installing silo, but there is no root device"

	args = [ "silo" ]

	if bootpart[:2] == "md":
	    self.siloDevice = "mbr"
	else:
	    if self.siloDevice != "mbr":
		args.append("-t")

	    i = len (bootpart) - 1
	    while i > 0 and bootpart[i] in string.digits:
		i = i - 1
            silo.addEntry("partition", bootpart[i+1:])

	silo.addEntry("timeout", "50")
	silo.addEntry("root", '/dev/' + rootDev)
	silo.addEntry("read-only")

	kernelList = []
	otherList = []

	main = "linux"

	for (drive, (label, siloType)) in self.siloImages.items ():
	    if (drive == rootDev) and label:
		main = label
	    elif label:
		i = len(drive) - 1
		while i > 0 and drive[i] in string.digits:
		    i = i - 1
		prompath = drive[:i+1]
		if bootpart[:2] != "md" and prompath == boothd:
		    prompath = drive[i+1:]
		else:
		    prompath = self.disk2PromPath(prompath)
		    if prompath:
			if prompath[:3] == 'sd(':
			    prompath = prompath + drive[i+1:]
			else:
			    prompath = prompath + ";" + drive[i+1:]
		if prompath:
		    otherList.append (label, prompath)

	silo.addEntry("default", main)

	label = main
	if (smpInstalled):
	    kernelList.append((main, hdList['kernel-smp'], "smp"))
	    label = main + "-up"

	kernelList.append((label, hdList['kernel'], ""))

	for (label, kernel, tag) in kernelList:
	    kernelTag = "-%s-%s%s" % (kernel['version'], kernel['release'], tag)
	    initrd = self.makeInitrd (kernelTag, instRoot)
	    if rootDev == bootpart:
		kernelFile = "/boot/vmlinuz" + kernelTag
		initrdFile = initrd
	    else:
		kernelFile = "/vmlinuz" + kernelTag
		initrdFile = initrd[5:]

	    try:
		(fsType, sl) = silo.getImage(label)
		silo.delImage(label)
	    except IndexError, msg:
		sl = LiloConfigFile(imageType = "image", path = kernelFile)

	    sl.addEntry("label", label)
	    if os.access (instRoot + initrd, os.R_OK):
		sl.addEntry("initrd", initrdFile)

	    if self.siloAppend:
		sl.addEntry('append', '"%s"' % self.siloAppend)

	    silo.addImage ("image", kernelFile, sl)

	for (label, device) in otherList:
	    try:
		(fsType, sl) = silo.getImage(label)
		silo.delImage(label)
	    except IndexError:
                sl = LiloConfigFile(imageType = "other", path = device)
	    sl.addEntry("label", label)
	    silo.addImage (sl)

	# for (siloType, name, config) in silo.images:
	#    # remove entries for missing kernels (upgrade)
	#    if siloType == "image":
	#	if not os.access (todo.instPath + name, os.R_OK):
	#	    silo.delImage (name)
	#    # remove entries for unbootable partitions
	#    elif siloType == "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 (siloType, name, config) in silo.images:
	    if not name in labels:
		labels.append (name)
	    else: # duplicate entry, first entry wins
		silo.delImage (name)

	if fstab.getBootDevice() != fstab.getRootDevice()[0]:
	    silo.write(instRoot + "/boot/silo.conf")
	    try:
		os.remove(instRoot + "/etc/silo.conf")
	    except:
		pass
	    os.symlink("../boot/silo.conf", instRoot + "/etc/silo.conf")
	else:
	    silo.write(instRoot + "/etc/silo.conf")

	if self.serial:
	    messages = "/tmp/silo.log"
	else:
	    messages = "/dev/tty3"
	iutil.execWithRedirect('/sbin/silo',
			       args,
			       stdout = None,
			       root = instRoot)

	if bootpart[:2] == "md":
	    mbrdevs = self.getMbrDevices(fstab)
	    linuxAliases = []
	    for mbrdev in mbrdevs:
		device = mbrdev
		try:
		    num = _silo.zeroBasedPart(instRoot + "/dev/" + mbrdev)
		    if num:
			device = mbrdev + "%d" % num
		except:
		    pass
		linuxAliases.append(self.disk2PromPath(device))
	    bootDevice = linuxAliases[0]
	    linuxAlias = ""
	    for alias in linuxAliases:
		if alias and alias != "":
		    if linuxAlias != "":
			linuxAlias = linuxAlias + ";"
		    linuxAlias = linuxAlias + alias
	elif self.siloDevice == "mbr":
	    device = boothd
	    try:
		num = _silo.zeroBasedPart(instRoot + "/dev/" + boothd)
		if num:
		    device = boothd + "%d" % num
	    except:
		pass
	    linuxAlias = self.disk2PromPath(device)
	    bootDevice = linuxAlias
	else:
	    device = bootpart
	    linuxAlias = self.disk2PromPath(device)
	    bootDevice = linuxAlias

	if not (self.linuxAlias and self.hasAliases()):
	    linuxAlias = ""
	if not self.bootDevice:
	    bootDevice = ""
	if not linuxAlias:
	    linuxAlias = ""
	_silo.setPromVars(linuxAlias,bootDevice)

    def setDevice(self, device):
	if (type(device) == type((1,))):
	    self.siloDevice = device
	elif device != "mbr" and device != "partition" and device:
	    raise ValueError, "device must be raid, mbr, partition, or None"
	self.siloDevice = device

    def setAppend(self, append):
	self.siloAppend = append

    def setDefault(self, default):
	for (label, fsType) in self.siloImages.values():
	    if label == default:
		self.default = default
		return
	raise IndexError, "unknown silo label %s" % (default,)

    def getLinear(self):
	return self.siloLinear

    def getDevice(self):
	return self.siloDevice

    def getAppend(self):
	return self.siloAppend

    def __init__(self, serial = 0):
	self.siloImages = {}
	self.siloDevice = 'mbr'
	self.siloLinear = 1
	self.siloAppend = None
	self.default = None
	self.initrdsMade = {}
	self.serial = serial
	self.linuxAlias = 1
	self.bootDevice = 1