1 |
# |
2 |
# bootloaderInfo.py - bootloader config object used in creation of new |
3 |
# bootloader configs. Originally from anaconda |
4 |
# |
5 |
# Jeremy Katz <katzj@redhat.com> |
6 |
# Erik Troan <ewt@redhat.com> |
7 |
# Peter Jones <pjones@redhat.com> |
8 |
# |
9 |
# Copyright 2005 Red Hat, Inc. |
10 |
# |
11 |
# This software may be freely redistributed under the terms of the GNU |
12 |
# library public license. |
13 |
# |
14 |
# You should have received a copy of the GNU Library Public License |
15 |
# along with this program; if not, write to the Free Software |
16 |
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
17 |
# |
18 |
|
19 |
import os, sys |
20 |
import isys |
21 |
import crypt |
22 |
import random |
23 |
import butil |
24 |
import string |
25 |
|
26 |
from lilo import LiloConfigFile |
27 |
from rhpl.log import log |
28 |
from rhpl.translate import _, N_ |
29 |
import rhpl.executil |
30 |
|
31 |
import booty |
32 |
import checkbootloader |
33 |
|
34 |
dosFilesystems = ('FAT', 'fat16', 'fat32', 'ntfs', 'hpfs') |
35 |
|
36 |
if os.path.exists('edd'): |
37 |
sys.path.append('edd/') |
38 |
else: |
39 |
sys.path.append('/usr/lib/bootloader') |
40 |
|
41 |
if butil.getArch() == "i386": |
42 |
import edd |
43 |
|
44 |
def doesDualBoot(): |
45 |
if butil.getArch() == "i386" or butil.getArch() == "x86_64": |
46 |
return 1 |
47 |
return 0 |
48 |
|
49 |
# hack and a half |
50 |
# there's no guarantee that data is written to the disk and grub |
51 |
# reads both the filesystem and the disk. suck. |
52 |
def syncDataToDisk(dev, mntpt, instRoot = "/"): |
53 |
import isys, fsset |
54 |
isys.sync() |
55 |
isys.sync() |
56 |
isys.sync() |
57 |
|
58 |
# and xfs is even more "special" (#117968) |
59 |
if fsset.isValidXFS(dev): |
60 |
rhpl.executil.execWithRedirect( "/usr/sbin/xfs_freeze", |
61 |
["/usr/sbin/xfs_freeze", "-f", mntpt], |
62 |
stdout = "/dev/tty5", |
63 |
stderr = "/dev/tty5", |
64 |
root = instRoot) |
65 |
rhpl.executil.execWithRedirect( "/usr/sbin/xfs_freeze", |
66 |
["/usr/sbin/xfs_freeze", "-u", mntpt], |
67 |
stdout = "/dev/tty5", |
68 |
stderr = "/dev/tty5", |
69 |
root = instRoot) |
70 |
|
71 |
class BootyNoKernelWarning: |
72 |
def __init__ (self, value=""): |
73 |
self.value = value |
74 |
|
75 |
def __str__ (self): |
76 |
return self.value |
77 |
|
78 |
class KernelArguments: |
79 |
|
80 |
def get(self): |
81 |
return self.args |
82 |
|
83 |
def set(self, args): |
84 |
self.args = args |
85 |
|
86 |
def chandevget(self): |
87 |
return self.cargs |
88 |
|
89 |
def chandevset(self, args): |
90 |
self.cargs = args |
91 |
|
92 |
def append(self, args): |
93 |
if self.args: |
94 |
# don't duplicate the addition of an argument (#128492) |
95 |
if self.args.find(args) != -1: |
96 |
return |
97 |
self.args = self.args + " " |
98 |
self.args = self.args + "%s" % (args,) |
99 |
|
100 |
|
101 |
def __init__(self): |
102 |
str = "" |
103 |
|
104 |
if butil.getArch() == "s390": |
105 |
self.cargs = [] |
106 |
f = open("/tmp/install.cfg") |
107 |
lines = f.readlines() |
108 |
for line in lines: |
109 |
try: |
110 |
(vname,vparm) = line.split('=', 1) |
111 |
vname = vname.strip() |
112 |
vparm = vparm.replace('"','') |
113 |
vparm = vparm.strip() |
114 |
if vname == "DASD": |
115 |
str = str + "dasd=" + vparm |
116 |
if vname == "CHANDEV": |
117 |
self.cargs.append(vparm) |
118 |
if vname == "QETHPARM": |
119 |
self.cargs.append(vparm) |
120 |
except Exception, e: |
121 |
pass |
122 |
|
123 |
# look for kernel arguments we know should be preserved and add them |
124 |
ourargs = ["speakup_synth=", "apic", "noapic", "apm=", "ide=nodma", "noht", "acpi=", "video="] |
125 |
f = open("/proc/cmdline") |
126 |
cmdline = f.read()[:-1] |
127 |
f.close() |
128 |
cmdlineargs = cmdline.split(" ") |
129 |
for arg in cmdlineargs: |
130 |
for check in ourargs: |
131 |
if arg.startswith(check): |
132 |
if str: str = str + " " |
133 |
str = str + arg |
134 |
|
135 |
self.args = str |
136 |
|
137 |
class BootImages: |
138 |
# returns dictionary of (label, longlabel, devtype) pairs indexed by device |
139 |
def getImages(self): |
140 |
# return a copy so users can modify it w/o affecting us |
141 |
|
142 |
dict = {} |
143 |
for key in self.images.keys(): |
144 |
dict[key] = self.images[key] |
145 |
|
146 |
return dict |
147 |
|
148 |
def setImageLabel(self, dev, label, setLong = 0): |
149 |
if setLong: |
150 |
self.images[dev] = (self.images[dev][0], label, |
151 |
self.images[dev][2]) |
152 |
else: |
153 |
self.images[dev] = (label, self.images[dev][1], |
154 |
self.images[dev][2]) |
155 |
|
156 |
|
157 |
# default is a device |
158 |
def setDefault(self, default): |
159 |
self.default = default |
160 |
|
161 |
def getDefault(self): |
162 |
return self.default |
163 |
|
164 |
# XXX this has internal anaconda-ish knowledge. ick |
165 |
def setup(self, diskSet, fsset): |
166 |
devices = {} |
167 |
devs = self.availableBootDevices(diskSet, fsset) |
168 |
for (dev, type) in devs: |
169 |
devices[dev] = 1 |
170 |
|
171 |
# These partitions have disappeared |
172 |
for dev in self.images.keys(): |
173 |
if not devices.has_key(dev): del self.images[dev] |
174 |
|
175 |
# These have appeared |
176 |
for (dev, type) in devs: |
177 |
if not self.images.has_key(dev): |
178 |
if type in dosFilesystems and doesDualBoot(): |
179 |
self.images[dev] = ("Other", "Other", type) |
180 |
elif type in ("hfs", "hfs+") and butil.getPPCMachine() == "PMac": |
181 |
self.images[dev] = ("Other", "Other", type) |
182 |
else: |
183 |
self.images[dev] = (None, None, type) |
184 |
|
185 |
|
186 |
if not self.images.has_key(self.default): |
187 |
entry = fsset.getEntryByMountPoint('/') |
188 |
self.default = entry.device.getDevice() |
189 |
(label, longlabel, type) = self.images[self.default] |
190 |
if not label: |
191 |
self.images[self.default] = ("linux", |
192 |
butil.getProductName(), type) |
193 |
|
194 |
# XXX more internal anaconda knowledge |
195 |
def availableBootDevices(self, diskSet, fsset): |
196 |
devs = [] |
197 |
foundDos = 0 |
198 |
for (dev, type) in diskSet.partitionTypes(): |
199 |
if type in dosFilesystems and not foundDos and doesDualBoot(): |
200 |
import isys |
201 |
import partedUtils |
202 |
|
203 |
isys.makeDevInode(dev, '/tmp/' + dev) |
204 |
part = partedUtils.get_partition_by_name(diskSet.disks, dev) |
205 |
if part.native_type not in partedUtils.dosPartitionTypes: |
206 |
continue |
207 |
|
208 |
try: |
209 |
bootable = isys.checkBoot('/tmp/' + dev) |
210 |
devs.append((dev, type)) |
211 |
foundDos = 1 |
212 |
except Exception, e: |
213 |
log("exception checking %s: %s" %(dev, e)) |
214 |
pass |
215 |
elif ((type == 'ntfs' or type =='hpfs') and not foundDos |
216 |
and doesDualBoot()): |
217 |
devs.append((dev, type)) |
218 |
# maybe questionable, but the first ntfs or fat is likely to |
219 |
# be the correct one to boot with XP using ntfs |
220 |
foundDos = 1 |
221 |
elif type in ('hfs', 'hfs+') and butil.getPPCMachine() == "PMac": |
222 |
import isys |
223 |
import partedUtils |
224 |
|
225 |
part = partedUtils.get_partition_by_name(diskSet.disks, dev) |
226 |
if partedUtils.get_flags(part) != "boot": |
227 |
devs.append((dev, type)) |
228 |
|
229 |
slash = fsset.getEntryByMountPoint('/') |
230 |
if not slash or not slash.device or not slash.fsystem: |
231 |
raise ValueError, ("Trying to pick boot devices but do not have a " |
232 |
"sane root partition. Aborting install.") |
233 |
devs.append((slash.device.getDevice(), slash.fsystem.getName())) |
234 |
|
235 |
devs.sort() |
236 |
|
237 |
return devs |
238 |
|
239 |
|
240 |
|
241 |
def __init__(self): |
242 |
self.default = None |
243 |
self.images = {} |
244 |
|
245 |
|
246 |
class bootloaderInfo: |
247 |
def setUseGrub(self, val): |
248 |
pass |
249 |
|
250 |
def useGrub(self): |
251 |
return self.useGrubVal |
252 |
|
253 |
def setForceLBA(self, val): |
254 |
pass |
255 |
|
256 |
def setPassword(self, val, isCrypted = 1): |
257 |
pass |
258 |
|
259 |
def getPassword(self): |
260 |
pass |
261 |
|
262 |
def getDevice(self): |
263 |
return self.device |
264 |
|
265 |
def setDevice(self, device): |
266 |
self.device = device |
267 |
|
268 |
(dev, part) = getDiskPart(device) |
269 |
if part is None: |
270 |
self.defaultDevice = "mbr" |
271 |
else: |
272 |
self.defaultDevice = "partition" |
273 |
|
274 |
# XXX need to abstract out the requirement for a fsset to be able |
275 |
# to get it "on the fly" on a running system as well as being able |
276 |
# to get it how we do now from anaconda. probably by having the |
277 |
# first thing in the chain create a "fsset" object that has the |
278 |
# dictionary of mounted filesystems since that's what we care about |
279 |
def getBootloaderConfig(self, instRoot, fsset, bl, langs, kernelList, |
280 |
chainList, defaultDev): |
281 |
images = bl.images.getImages() |
282 |
|
283 |
# on upgrade read in the lilo config file |
284 |
lilo = LiloConfigFile () |
285 |
self.perms = 0600 |
286 |
if os.access (instRoot + self.configfile, os.R_OK): |
287 |
self.perms = os.stat(instRoot + self.configfile)[0] & 0777 |
288 |
lilo.read (instRoot + self.configfile) |
289 |
os.rename(instRoot + self.configfile, |
290 |
instRoot + self.configfile + '.rpmsave') |
291 |
# if it's an absolute symlink, just get it out of our way |
292 |
elif (os.path.islink(instRoot + self.configfile) and |
293 |
os.readlink(instRoot + self.configfile)[0] == '/'): |
294 |
os.rename(instRoot + self.configfile, |
295 |
instRoot + self.configfile + '.rpmsave') |
296 |
|
297 |
# Remove any invalid entries that are in the file; we probably |
298 |
# just removed those kernels. |
299 |
for label in lilo.listImages(): |
300 |
(fsType, sl, path, other) = lilo.getImage(label) |
301 |
if fsType == "other": continue |
302 |
|
303 |
if not os.access(instRoot + sl.getPath(), os.R_OK): |
304 |
lilo.delImage(label) |
305 |
|
306 |
lilo.addEntry("prompt", replace = 0) |
307 |
lilo.addEntry("timeout", "20", replace = 0) |
308 |
|
309 |
rootDev = fsset.getEntryByMountPoint("/").device.getDevice() |
310 |
if not rootDev: |
311 |
raise RuntimeError, "Installing lilo, but there is no root device" |
312 |
|
313 |
if rootDev == defaultDev: |
314 |
lilo.addEntry("default", kernelList[0][0]) |
315 |
else: |
316 |
lilo.addEntry("default", chainList[0][0]) |
317 |
|
318 |
for (label, longlabel, version) in kernelList: |
319 |
kernelTag = "-" + version |
320 |
kernelFile = self.kernelLocation + "vmlinuz" + kernelTag |
321 |
|
322 |
try: |
323 |
lilo.delImage(label) |
324 |
except IndexError, msg: |
325 |
pass |
326 |
|
327 |
sl = LiloConfigFile(imageType = "image", path = kernelFile) |
328 |
|
329 |
initrd = booty.makeInitrd (kernelTag, instRoot) |
330 |
|
331 |
sl.addEntry("label", label) |
332 |
if os.access (instRoot + initrd, os.R_OK): |
333 |
sl.addEntry("initrd", "%sinitrd%s.img" %(self.kernelLocation, |
334 |
kernelTag)) |
335 |
|
336 |
sl.addEntry("read-only") |
337 |
|
338 |
append = "%s" %(self.args.get(),) |
339 |
realroot = getRootDevName(initrd, fsset, rootDev, instRoot) |
340 |
if not realroot.startswith("LABEL="): |
341 |
sl.addEntry("root", '/dev/' + rootDev) |
342 |
else: |
343 |
if len(append) > 0: |
344 |
append = "%s root=%s" %(append,realroot) |
345 |
else: |
346 |
append = "root=%s" %(realroot,) |
347 |
|
348 |
if len(append) > 0: |
349 |
sl.addEntry('append', '"%s"' % (append,)) |
350 |
|
351 |
lilo.addImage (sl) |
352 |
|
353 |
for (label, longlabel, device) in chainList: |
354 |
if ((not label) or (label == "")): |
355 |
continue |
356 |
try: |
357 |
(fsType, sl, path, other) = lilo.getImage(label) |
358 |
lilo.delImage(label) |
359 |
except IndexError: |
360 |
sl = LiloConfigFile(imageType = "other", |
361 |
path = "/dev/%s" %(device)) |
362 |
sl.addEntry("optional") |
363 |
|
364 |
sl.addEntry("label", label) |
365 |
lilo.addImage (sl) |
366 |
|
367 |
# Sanity check #1. There could be aliases in sections which conflict |
368 |
# with the new images we just created. If so, erase those aliases |
369 |
imageNames = {} |
370 |
for label in lilo.listImages(): |
371 |
imageNames[label] = 1 |
372 |
|
373 |
for label in lilo.listImages(): |
374 |
(fsType, sl, path, other) = lilo.getImage(label) |
375 |
if sl.testEntry('alias'): |
376 |
alias = sl.getEntry('alias') |
377 |
if imageNames.has_key(alias): |
378 |
sl.delEntry('alias') |
379 |
imageNames[alias] = 1 |
380 |
|
381 |
# Sanity check #2. If single-key is turned on, go through all of |
382 |
# the image names (including aliases) (we just built the list) and |
383 |
# see if single-key will still work. |
384 |
if lilo.testEntry('single-key'): |
385 |
singleKeys = {} |
386 |
turnOff = 0 |
387 |
for label in imageNames.keys(): |
388 |
l = label[0] |
389 |
if singleKeys.has_key(l): |
390 |
turnOff = 1 |
391 |
singleKeys[l] = 1 |
392 |
if turnOff: |
393 |
lilo.delEntry('single-key') |
394 |
|
395 |
return lilo |
396 |
|
397 |
def write(self, instRoot, fsset, bl, langs, kernelList, chainList, |
398 |
defaultDev, justConfig, intf = None): |
399 |
if len(kernelList) >= 1: |
400 |
config = self.getBootloaderConfig(instRoot, fsset, bl, langs, |
401 |
kernelList, chainList, |
402 |
defaultDev) |
403 |
config.write(instRoot + self.configfile, perms = self.perms) |
404 |
else: |
405 |
self.noKernelsWarn(intf) |
406 |
|
407 |
return "" |
408 |
|
409 |
# XXX in the future we also should do some validation on the config |
410 |
# file that's already there |
411 |
# XXX concept of the intf isn't very well defined outside of anaconda... |
412 |
# probably should just pass back up an error |
413 |
def noKernelsWarn(self, intf): |
414 |
raise BootyNoKernelWarning |
415 |
|
416 |
def getArgList(self): |
417 |
args = [] |
418 |
|
419 |
if self.defaultDevice is None: |
420 |
args.append("--location=none") |
421 |
return args |
422 |
|
423 |
args.append("--location=%s" % (self.defaultDevice,)) |
424 |
args.append("--driveorder=%s" % (",".join(self.drivelist))) |
425 |
|
426 |
if self.args.get(): |
427 |
args.append("--append=\"%s\"" %(self.args.get())) |
428 |
|
429 |
return args |
430 |
|
431 |
def writeKS(self, f): |
432 |
f.write("bootloader") |
433 |
for arg in self.getArgList(): |
434 |
f.write(" " + arg) |
435 |
f.write("\n") |
436 |
|
437 |
def createDriveList(self): |
438 |
# create a drive list that we can use for drive mappings |
439 |
# XXX has anaconda internals knowledge |
440 |
import isys |
441 |
import flags |
442 |
drives = isys.hardDriveDict().keys() |
443 |
drives.sort (isys.compareDrives) |
444 |
|
445 |
# now filter out all of the removable media unless expert mode |
446 |
rc = [] |
447 |
for drive in drives: |
448 |
if not isys.driveIsRemovable(drive) or flags.flags.expert: |
449 |
rc.append(drive) |
450 |
return rc |
451 |
|
452 |
def __init__(self): |
453 |
self.args = KernelArguments() |
454 |
self.images = BootImages() |
455 |
self.device = None |
456 |
self.defaultDevice = None # XXX hack, used by kickstart |
457 |
self.useGrubVal = 0 # only used on x86 |
458 |
self.configfile = None |
459 |
self.kernelLocation = "/boot/" |
460 |
self.forceLBA32 = 0 |
461 |
self.password = None |
462 |
self.pure = None |
463 |
self.above1024 = 0 |
464 |
|
465 |
# this has somewhat strange semantics. if 0, act like a normal |
466 |
# "install" case. if 1, update lilo.conf (since grubby won't do that) |
467 |
# and then run lilo or grub only. |
468 |
# XXX THIS IS A HACK. implementation details are only there for x86 |
469 |
self.doUpgradeOnly = 0 |
470 |
self.kickstart = 0 |
471 |
|
472 |
self.drivelist = self.createDriveList() |
473 |
|
474 |
from flags import flags |
475 |
if flags.serial != 0: |
476 |
# now look at /proc/cmdline to pull any serial console |
477 |
# args |
478 |
f = open("/proc/cmdline", "r") |
479 |
cmdline = f.read()[:-1] |
480 |
f.close() |
481 |
|
482 |
options = "" |
483 |
device = None |
484 |
cmdlineargs = cmdline.split(" ") |
485 |
for arg in cmdlineargs: |
486 |
# found a console argument |
487 |
if arg.startswith("console="): |
488 |
(foo, console) = arg.split("=") |
489 |
# the options are everything after the comma |
490 |
comma = console.find(",") |
491 |
if comma != -1: |
492 |
options = console[comma:] |
493 |
device = console[:comma] |
494 |
else: |
495 |
options = "" |
496 |
device = console |
497 |
|
498 |
if device is None: |
499 |
self.serialDevice = "ttyS0" |
500 |
self.serialOptions = "" |
501 |
else: |
502 |
self.serialDevice = device |
503 |
# don't keep the comma in the options |
504 |
self.serialOptions = options[1:] |
505 |
|
506 |
self.args.append("console=%s%s" %(self.serialDevice, options)) |
507 |
|
508 |
self.serial = 1 |
509 |
else: |
510 |
self.serial = 0 |
511 |
self.serialDevice = None |
512 |
self.serialOptions = None |
513 |
|
514 |
if flags.virtpconsole is not None: |
515 |
if flags.virtpconsole.startswith("/dev/"): |
516 |
con = flags.virtpconsole[5:] |
517 |
else: |
518 |
con = flags.virtpconsole |
519 |
self.args.append("console=%s" %(con,)) |
520 |
|
521 |
|
522 |
class ia64BootloaderInfo(bootloaderInfo): |
523 |
# XXX wouldn't it be nice to have a real interface to use efibootmgr from? |
524 |
def removeOldEfiEntries(self, instRoot): |
525 |
p = os.pipe() |
526 |
rhpl.executil.execWithRedirect('/usr/sbin/efibootmgr', ["efibootmgr"], |
527 |
root = instRoot, stdout = p[1]) |
528 |
os.close(p[1]) |
529 |
|
530 |
c = os.read(p[0], 1) |
531 |
buf = c |
532 |
while (c): |
533 |
c = os.read(p[0], 1) |
534 |
buf = buf + c |
535 |
os.close(p[0]) |
536 |
lines = string.split(buf, '\n') |
537 |
for line in lines: |
538 |
fields = string.split(line) |
539 |
if len(fields) < 2: |
540 |
continue |
541 |
if string.join(fields[1:], " ") == butil.getProductName(): |
542 |
entry = fields[0][4:8] |
543 |
rhpl.executil.execWithRedirect('/usr/sbin/efibootmgr', |
544 |
["efibootmgr", "-b", entry, "-B"], |
545 |
root = instRoot, |
546 |
stdout="/dev/tty5", stderr="/dev/tty5") |
547 |
|
548 |
def getBootloaderConfig(self, instRoot, fsset, bl, langs, kernelList, |
549 |
chainList, defaultDev): |
550 |
config = bootloaderInfo.getBootloaderConfig(self, instRoot, fsset, |
551 |
bl, langs, |
552 |
kernelList, chainList, |
553 |
defaultDev) |
554 |
# altix boxes need relocatable (#120851) |
555 |
config.addEntry("relocatable") |
556 |
|
557 |
return config |
558 |
|
559 |
def writeLilo(self, instRoot, fsset, bl, langs, kernelList, |
560 |
chainList, defaultDev, justConfig): |
561 |
config = self.getBootloaderConfig(instRoot, fsset, bl, langs, |
562 |
kernelList, chainList, defaultDev) |
563 |
config.write(instRoot + self.configfile, perms = self.perms) |
564 |
|
565 |
return "" |
566 |
|
567 |
def write(self, instRoot, fsset, bl, langs, kernelList, chainList, |
568 |
defaultDev, justConfig, intf): |
569 |
if len(kernelList) >= 1: |
570 |
str = self.writeLilo(instRoot, fsset, bl, langs, kernelList, |
571 |
chainList, defaultDev, justConfig) |
572 |
else: |
573 |
self.noKernelsWarn(intf) |
574 |
|
575 |
bootdev = fsset.getEntryByMountPoint("/boot/efi").device.getDevice() |
576 |
if not bootdev: |
577 |
bootdev = fsset.getEntryByDeviceName("sda1").device.getDevice() |
578 |
|
579 |
if not os.access(instRoot + "/etc/elilo.conf", os.R_OK): |
580 |
os.symlink("../" + self.configfile, instRoot + "/etc/elilo.conf") |
581 |
|
582 |
ind = len(bootdev) |
583 |
try: |
584 |
while (bootdev[ind-1] in string.digits): |
585 |
ind = ind - 1 |
586 |
except IndexError: |
587 |
ind = len(bootdev) - 1 |
588 |
|
589 |
bootdisk = bootdev[:ind] |
590 |
bootpart = bootdev[ind:] |
591 |
if (bootdisk.startswith('ida/') or bootdisk.startswith('cciss/') or |
592 |
bootdisk.startswith('rd/') or bootdisk.startswith('sx8/')): |
593 |
bootdisk = bootdisk[:-1] |
594 |
|
595 |
self.removeOldEfiEntries(instRoot) |
596 |
|
597 |
argv = [ "/usr/sbin/efibootmgr", "-c" , "-w", "-L", |
598 |
butil.getProductName(), "-d", "/dev/%s" % bootdisk, |
599 |
"-p", bootpart, "-l", "EFI\\redhat\\elilo.efi" ] |
600 |
rhpl.executil.execWithRedirect(argv[0], argv, root = instRoot, |
601 |
stdout = "/dev/tty5", |
602 |
stderr = "/dev/tty5") |
603 |
|
604 |
|
605 |
def __init__(self): |
606 |
bootloaderInfo.__init__(self) |
607 |
self.useGrubVal = 1 |
608 |
self.kernelLocation = "" |
609 |
self.configfile = "/boot/efi/EFI/redhat/elilo.conf" |
610 |
|
611 |
|
612 |
class x86BootloaderInfo(bootloaderInfo): |
613 |
def setPassword(self, val, isCrypted = 1): |
614 |
if not val: |
615 |
self.password = val |
616 |
self.pure = val |
617 |
return |
618 |
|
619 |
if isCrypted and self.useGrubVal == 0: |
620 |
log("requested crypted password with lilo; ignoring") |
621 |
self.pure = None |
622 |
return |
623 |
elif isCrypted: |
624 |
self.password = val |
625 |
self.pure = None |
626 |
else: |
627 |
salt = "$1$" |
628 |
saltLen = 8 |
629 |
|
630 |
for i in range(saltLen): |
631 |
salt = salt + random.choice (string.letters + |
632 |
string.digits + './') |
633 |
|
634 |
self.password = crypt.crypt (val, salt) |
635 |
self.pure = val |
636 |
|
637 |
def getPassword (self): |
638 |
return self.pure |
639 |
|
640 |
def setForceLBA(self, val): |
641 |
self.forceLBA32 = val |
642 |
|
643 |
def setUseGrub(self, val): |
644 |
self.useGrubVal = val |
645 |
|
646 |
def getPhysicalDevices(self, device): |
647 |
# This finds a list of devices on which the given device name resides. |
648 |
# Accepted values for "device" are raid1 md devices (i.e. "md0"), |
649 |
# physical disks ("hda"), and real partitions on physical disks |
650 |
# ("hda1"). Volume groups/logical volumes are not accepted. |
651 |
# |
652 |
# XXX this has internal anaconda-ish knowledge. ick. |
653 |
import isys |
654 |
import lvm |
655 |
|
656 |
if string.split(device, '/', 1)[0] in map (lambda vg: vg[0], |
657 |
lvm.vglist()): |
658 |
return [] |
659 |
|
660 |
if device.startswith('md'): |
661 |
bootable = 0 |
662 |
parts = checkbootloader.getRaidDisks(device, 1, stripPart=0) |
663 |
parts.sort() |
664 |
return parts |
665 |
|
666 |
return [device] |
667 |
|
668 |
def writeGrub(self, instRoot, fsset, bl, langs, kernelList, chainList, |
669 |
defaultDev, justConfigFile): |
670 |
if len(kernelList) < 1: |
671 |
return "" |
672 |
|
673 |
images = bl.images.getImages() |
674 |
rootDev = fsset.getEntryByMountPoint("/").device.getDevice() |
675 |
|
676 |
if not os.path.isdir(instRoot + '/boot/grub/'): |
677 |
os.mkdir(instRoot + '/boot/grub', 0755) |
678 |
|
679 |
# XXX old config file should be read here for upgrade |
680 |
|
681 |
cf = '/boot/grub/grub.conf' |
682 |
self.perms = 0600 |
683 |
if os.access (instRoot + cf, os.R_OK): |
684 |
self.perms = os.stat(instRoot + cf)[0] & 0777 |
685 |
os.rename(instRoot + cf, |
686 |
instRoot + cf + '.rpmsave') |
687 |
|
688 |
grubTarget = bl.getDevice() |
689 |
target = "mbr" |
690 |
if grubTarget[-1].isdigit() and not grubTarget.startswith('md'): |
691 |
target = "partition" |
692 |
|
693 |
f = open(instRoot + cf, "w+") |
694 |
|
695 |
f.write("# grub.conf generated by anaconda\n") |
696 |
f.write("#\n") |
697 |
f.write("# Note that you do not have to rerun grub " |
698 |
"after making changes to this file\n") |
699 |
|
700 |
bootDev = fsset.getEntryByMountPoint("/boot") |
701 |
grubPath = "/grub" |
702 |
cfPath = "/" |
703 |
if not bootDev: |
704 |
bootDev = fsset.getEntryByMountPoint("/") |
705 |
grubPath = "/boot/grub" |
706 |
cfPath = "/boot/" |
707 |
f.write("# NOTICE: You do not have a /boot partition. " |
708 |
"This means that\n") |
709 |
f.write("# all kernel and initrd paths are relative " |
710 |
"to /, eg.\n") |
711 |
else: |
712 |
f.write("# NOTICE: You have a /boot partition. This means " |
713 |
"that\n") |
714 |
f.write("# all kernel and initrd paths are relative " |
715 |
"to /boot/, eg.\n") |
716 |
|
717 |
bootDevs = self.getPhysicalDevices(bootDev.device.getDevice()) |
718 |
bootDev = bootDev.device.getDevice() |
719 |
|
720 |
f.write('# root %s\n' % self.grubbyPartitionName(bootDevs[0])) |
721 |
f.write("# kernel %svmlinuz-version ro " |
722 |
"root=/dev/%s\n" % (cfPath, rootDev)) |
723 |
f.write("# initrd %sinitrd-version.img\n" % (cfPath)) |
724 |
f.write("#boot=/dev/%s\n" % (grubTarget)) |
725 |
|
726 |
# Check to see if smp kernel should be default or not |
727 |
if isys.smpAvailable() or isys.htavailable(): |
728 |
smpCapable=1 |
729 |
else: |
730 |
smpCapable=0 |
731 |
|
732 |
# get the default image to boot... we have to walk and find it |
733 |
# since grub indexes by where it is in the config file |
734 |
if defaultDev == rootDev: |
735 |
for kernel in range(0, len(kernelList)): |
736 |
default=kernel |
737 |
version=kernelList[kernel][2] |
738 |
if version.find('smp')<0 and not smpCapable: |
739 |
break |
740 |
if version.find('smp')>=0 and smpCapable: |
741 |
break |
742 |
else: |
743 |
# if the default isn't linux, it's the first thing in the |
744 |
# chain list |
745 |
default = len(kernelList) |
746 |
|
747 |
# keep track of which devices are used for the device.map |
748 |
usedDevs = {} |
749 |
|
750 |
f.write('default=%s\n' % (default)) |
751 |
if len(chainList) > 0: |
752 |
timeout = 5 |
753 |
else: |
754 |
timeout = 5 |
755 |
f.write('timeout=%d\n' %(timeout,)) |
756 |
|
757 |
if self.serial == 1: |
758 |
# grub the 0-based number of the serial console device |
759 |
unit = self.serialDevice[-1] |
760 |
|
761 |
# and we want to set the speed too |
762 |
speedend = 0 |
763 |
for char in self.serialOptions: |
764 |
if char not in string.digits: |
765 |
break |
766 |
speedend = speedend + 1 |
767 |
if speedend != 0: |
768 |
speed = self.serialOptions[:speedend] |
769 |
else: |
770 |
# reasonable default |
771 |
speed = "9600" |
772 |
|
773 |
f.write("serial --unit=%s --speed=%s\n" %(unit, speed)) |
774 |
f.write("terminal --timeout=5 serial console\n") |
775 |
else: |
776 |
# we only want splashimage if they're not using a serial console |
777 |
if os.access("%s/boot/grub/splash.xpm.gz" %(instRoot,), os.R_OK): |
778 |
f.write('splashimage=%s%sgrub/splash.xpm.gz\n' |
779 |
% (self.grubbyPartitionName(bootDevs[0]), cfPath)) |
780 |
f.write("hiddenmenu\n") |
781 |
|
782 |
for dev in self.getPhysicalDevices(grubTarget): |
783 |
usedDevs[dev] = 1 |
784 |
|
785 |
if self.password: |
786 |
f.write('password --md5 %s\n' %(self.password)) |
787 |
|
788 |
for (label, longlabel, version) in kernelList: |
789 |
kernelTag = "-" + version |
790 |
kernelFile = "%svmlinuz%s" % (cfPath, kernelTag) |
791 |
|
792 |
initrd = booty.makeInitrd (kernelTag, instRoot) |
793 |
|
794 |
f.write('title %s (%s)\n' % (longlabel, version)) |
795 |
f.write('\troot %s\n' % self.grubbyPartitionName(bootDevs[0])) |
796 |
|
797 |
realroot = getRootDevName(initrd, fsset, rootDev, instRoot) |
798 |
realroot = " root=%s" %(realroot,) |
799 |
|
800 |
f.write('\tkernel %s ro%s' % (kernelFile, realroot)) |
801 |
if self.args.get(): |
802 |
f.write(' %s' % self.args.get()) |
803 |
f.write('\n') |
804 |
|
805 |
if os.access (instRoot + initrd, os.R_OK): |
806 |
f.write('\tinitrd %sinitrd%s.img\n' % (cfPath, kernelTag)) |
807 |
|
808 |
for (label, longlabel, device) in chainList: |
809 |
if ((not longlabel) or (longlabel == "")): |
810 |
continue |
811 |
f.write('title %s\n' % (longlabel)) |
812 |
f.write('\trootnoverify %s\n' % self.grubbyPartitionName(device)) |
813 |
# f.write('\tmakeactive\n') |
814 |
f.write('\tchainloader +1') |
815 |
f.write('\n') |
816 |
usedDevs[device] = 1 |
817 |
|
818 |
f.close() |
819 |
os.chmod(instRoot + "/boot/grub/grub.conf", self.perms) |
820 |
|
821 |
try: |
822 |
# make symlink for menu.lst (default config file name) |
823 |
if os.access (instRoot + "/boot/grub/menu.lst", os.R_OK): |
824 |
os.rename(instRoot + "/boot/grub/menu.lst", |
825 |
instRoot + "/boot/grub/menu.lst.rpmsave") |
826 |
os.symlink("./grub.conf", instRoot + "/boot/grub/menu.lst") |
827 |
except: |
828 |
pass |
829 |
|
830 |
try: |
831 |
# make symlink for /etc/grub.conf (config files belong in /etc) |
832 |
if os.access (instRoot + "/etc/grub.conf", os.R_OK): |
833 |
os.rename(instRoot + "/etc/grub.conf", |
834 |
instRoot + "/etc/grub.conf.rpmsave") |
835 |
os.symlink("../boot/grub/grub.conf", instRoot + "/etc/grub.conf") |
836 |
except: |
837 |
pass |
838 |
|
839 |
for dev in self.getPhysicalDevices(rootDev): |
840 |
usedDevs[dev] = 1 |
841 |
|
842 |
for dev in bootDevs: |
843 |
usedDevs[dev] = 1 |
844 |
|
845 |
if not os.access(instRoot + "/boot/grub/device.map", os.R_OK): |
846 |
f = open(instRoot + "/boot/grub/device.map", "w+") |
847 |
f.write("# this device map was generated by anaconda\n") |
848 |
f.write("(fd0) /dev/fd0\n") |
849 |
devs = usedDevs.keys() |
850 |
usedDevs = {} |
851 |
for dev in devs: |
852 |
drive = getDiskPart(dev)[0] |
853 |
if usedDevs.has_key(drive): |
854 |
continue |
855 |
usedDevs[drive] = 1 |
856 |
devs = usedDevs.keys() |
857 |
devs.sort() |
858 |
for drive in devs: |
859 |
# XXX hack city. If they're not the sort of thing that'll |
860 |
# be in the device map, they shouldn't still be in the list. |
861 |
if not drive.startswith('md'): |
862 |
f.write("(%s) /dev/%s\n" % (self.grubbyDiskName(drive), |
863 |
drive)) |
864 |
f.close() |
865 |
|
866 |
if self.forceLBA32: |
867 |
forcelba = "--force-lba " |
868 |
else: |
869 |
forcelba = "" |
870 |
|
871 |
sysconf = '/etc/sysconfig/grub' |
872 |
if os.access (instRoot + sysconf, os.R_OK): |
873 |
self.perms = os.stat(instRoot + sysconf)[0] & 0777 |
874 |
os.rename(instRoot + sysconf, |
875 |
instRoot + sysconf + '.rpmsave') |
876 |
# if it's an absolute symlink, just get it out of our way |
877 |
elif (os.path.islink(instRoot + sysconf) and |
878 |
os.readlink(instRoot + sysconf)[0] == '/'): |
879 |
os.rename(instRoot + sysconf, |
880 |
instRoot + sysconf + '.rpmsave') |
881 |
f = open(instRoot + sysconf, 'w+') |
882 |
f.write("boot=/dev/%s\n" %(grubTarget,)) |
883 |
# XXX forcelba never gets read back... |
884 |
if self.forceLBA32: |
885 |
f.write("forcelba=1\n") |
886 |
else: |
887 |
f.write("forcelba=0\n") |
888 |
f.close() |
889 |
|
890 |
cmds = [] |
891 |
for bootDev in bootDevs: |
892 |
gtDisk = self.grubbyPartitionName(getDiskPart(bootDev)[0]) |
893 |
bPart = self.grubbyPartitionName(bootDev) |
894 |
|
895 |
stage1Target = gtDisk |
896 |
if target == "partition": |
897 |
stage1Target = self.grubbyPartitionName(bootDev) |
898 |
|
899 |
cmd = "root %s\nsetup %s" % (bPart, stage1Target) |
900 |
cmds.append(cmd) |
901 |
|
902 |
if not justConfigFile: |
903 |
log("GRUB commands:") |
904 |
for cmd in cmds: |
905 |
log("\t%s\n", cmd) |
906 |
|
907 |
# copy the stage files over into /boot |
908 |
rhpl.executil.execWithRedirect( "/sbin/grub-install", |
909 |
["/sbin/grub-install", "--just-copy"], |
910 |
stdout = "/dev/tty5", stderr = "/dev/tty5", |
911 |
root = instRoot) |
912 |
|
913 |
|
914 |
|
915 |
# FIXME: hack to try to make sure everything is written to the disk |
916 |
if cfPath == "/": |
917 |
syncDataToDisk(bootDev, "/boot", instRoot) |
918 |
else: |
919 |
syncDataToDisk(bootDev, "/", instRoot) |
920 |
|
921 |
# really install the bootloader |
922 |
p = os.pipe() |
923 |
for cmd in cmds: |
924 |
os.write(p[1], cmd + '\n') |
925 |
os.close(p[1]) |
926 |
rhpl.executil.execWithRedirect('/sbin/grub' , |
927 |
[ "grub", "--batch", "--no-floppy", |
928 |
"--device-map=/boot/grub/device.map" ], |
929 |
stdin = p[0], |
930 |
stdout = "/dev/tty5", stderr = "/dev/tty5", |
931 |
root = instRoot) |
932 |
os.close(p[0]) |
933 |
|
934 |
return "" |
935 |
|
936 |
def getMatchingPart(self, bootDev, target): |
937 |
bootName, bootPartNum = getDiskPart(bootDev) |
938 |
devices = self.getPhysicalDevices(target) |
939 |
for device in devices: |
940 |
name, partNum = getDiskPart(device) |
941 |
if name == bootName: |
942 |
return device |
943 |
return devices[0] |
944 |
|
945 |
def grubbyDiskName(self, name): |
946 |
return "hd%d" % self.drivelist.index(name) |
947 |
|
948 |
def grubbyPartitionName(self, dev): |
949 |
(name, partNum) = getDiskPart(dev) |
950 |
if partNum != None: |
951 |
return "(%s,%d)" % (self.grubbyDiskName(name), partNum) |
952 |
else: |
953 |
return "(%s)" %(self.grubbyDiskName(name)) |
954 |
|
955 |
|
956 |
def getBootloaderConfig(self, instRoot, fsset, bl, langs, kernelList, |
957 |
chainList, defaultDev): |
958 |
config = bootloaderInfo.getBootloaderConfig(self, instRoot, fsset, |
959 |
bl, langs, |
960 |
kernelList, chainList, |
961 |
defaultDev) |
962 |
|
963 |
liloTarget = bl.getDevice() |
964 |
|
965 |
config.addEntry("boot", '/dev/' + liloTarget, replace = 0) |
966 |
config.addEntry("map", "/boot/map", replace = 0) |
967 |
config.addEntry("install", "/boot/boot.b", replace = 0) |
968 |
message = "/boot/message" |
969 |
|
970 |
if self.pure is not None and not self.useGrubVal: |
971 |
config.addEntry("restricted", replace = 0) |
972 |
config.addEntry("password", self.pure, replace = 0) |
973 |
|
974 |
|
975 |
import language |
976 |
for lang in language.expandLangs(langs.getDefault()): |
977 |
fn = "/boot/message." + lang |
978 |
if os.access(instRoot + fn, os.R_OK): |
979 |
message = fn |
980 |
break |
981 |
|
982 |
if self.serial == 1: |
983 |
# grab the 0-based number of the serial console device |
984 |
unit = self.serialDevice[-1] |
985 |
# FIXME: we should probably put some options, but lilo |
986 |
# only supports up to 9600 baud so just use the defaults |
987 |
# it's better than nothing :( |
988 |
config.addEntry("serial=%s" %(unit,)) |
989 |
else: |
990 |
# message screws up serial console |
991 |
if os.access(instRoot + message, os.R_OK): |
992 |
config.addEntry("message", message, replace = 0) |
993 |
|
994 |
if not config.testEntry('lba32'): |
995 |
if self.forceLBA32 or (bl.above1024 and |
996 |
butil.getArch() != "x86_64" and |
997 |
edd.detect()): |
998 |
config.addEntry("lba32", replace = 0) |
999 |
|
1000 |
return config |
1001 |
|
1002 |
# this is a hackish function that depends on the way anaconda writes |
1003 |
# out the grub.conf with a #boot= comment |
1004 |
# XXX this falls into the category of self.doUpgradeOnly |
1005 |
def upgradeGrub(self, instRoot, fsset, bl, langs, kernelList, chainList, |
1006 |
defaultDev, justConfigFile): |
1007 |
if justConfigFile: |
1008 |
return "" |
1009 |
|
1010 |
theDev = None |
1011 |
for (fn, stanza) in [ ("/etc/sysconfig/grub", "boot="), |
1012 |
("/boot/grub/grub.conf", "#boot=") ]: |
1013 |
try: |
1014 |
f = open(instRoot + fn, "r") |
1015 |
except: |
1016 |
continue |
1017 |
|
1018 |
# the following bits of code are straight from checkbootloader.py |
1019 |
lines = f.readlines() |
1020 |
f.close() |
1021 |
for line in lines: |
1022 |
if line.startswith(stanza): |
1023 |
theDev = checkbootloader.getBootDevString(line) |
1024 |
break |
1025 |
if theDev is not None: |
1026 |
break |
1027 |
|
1028 |
if theDev is None: |
1029 |
# we could find the dev before, but can't now... cry about it |
1030 |
return "" |
1031 |
|
1032 |
# migrate info to /etc/sysconfig/grub |
1033 |
sysconf = '/etc/sysconfig/grub' |
1034 |
if not os.access(instRoot + sysconf, os.R_OK): |
1035 |
f = open(instRoot + sysconf, "w+") |
1036 |
f.write("boot=%s\n" %(theDev,)) |
1037 |
# XXX forcelba never gets read back at all... |
1038 |
if self.forceLBA32: |
1039 |
f.write("forcelba=1\n") |
1040 |
else: |
1041 |
f.write("forcelba=0\n") |
1042 |
f.close() |
1043 |
|
1044 |
# more suckage. grub-install can't work without a valid /etc/mtab |
1045 |
# so we have to do shenanigans to get updated grub installed... |
1046 |
# steal some more code above |
1047 |
bootDev = fsset.getEntryByMountPoint("/boot") |
1048 |
grubPath = "/grub" |
1049 |
cfPath = "/" |
1050 |
if not bootDev: |
1051 |
bootDev = fsset.getEntryByMountPoint("/") |
1052 |
grubPath = "/boot/grub" |
1053 |
cfPath = "/boot/" |
1054 |
|
1055 |
masterBootDev = bootDev.device.getDevice(asBoot = 0) |
1056 |
if masterBootDev[0:2] == 'md': |
1057 |
rootDevs = checkbootloader.getRaidDisks(masterBootDev, raidLevel=1, |
1058 |
stripPart = 0) |
1059 |
else: |
1060 |
rootDevs = [masterBootDev] |
1061 |
|
1062 |
if theDev[5:7] == 'md': |
1063 |
stage1Devs = checkbootloader.getRaidDisks(theDev[5:], raidLevel=1) |
1064 |
else: |
1065 |
stage1Devs = [theDev[5:]] |
1066 |
|
1067 |
for stage1Dev in stage1Devs: |
1068 |
# cross fingers; if we can't find a root device on the same |
1069 |
# hardware as this boot device, we just blindly hope the first |
1070 |
# thing in the list works. |
1071 |
|
1072 |
grubbyStage1Dev = self.grubbyPartitionName(stage1Dev) |
1073 |
|
1074 |
grubbyRootPart = self.grubbyPartitionName(rootDevs[0]) |
1075 |
|
1076 |
for rootDev in rootDevs: |
1077 |
testGrubbyRootDev = getDiskPart(rootDev)[0] |
1078 |
testGrubbyRootDev = self.grubbyPartitionName(testGrubbyRootDev) |
1079 |
|
1080 |
if grubbyStage1Dev == testGrubbyRootDev: |
1081 |
grubbyRootPart = self.grubbyPartitionName(rootDev) |
1082 |
break |
1083 |
|
1084 |
cmd = "root %s\nsetup %s" % (grubbyRootPart, grubbyStage1Dev) |
1085 |
|
1086 |
if not justConfigFile: |
1087 |
log("GRUB command %s", cmd) |
1088 |
|
1089 |
# copy the stage files over into /boot |
1090 |
rhpl.executil.execWithRedirect( "/sbin/grub-install", |
1091 |
["/sbin/grub-install", "--just-copy"], |
1092 |
stdout = "/dev/tty5", stderr = "/dev/tty5", |
1093 |
root = instRoot) |
1094 |
|
1095 |
# get the stage files synced to disk |
1096 |
import isys |
1097 |
isys.sync() |
1098 |
isys.sync() |
1099 |
isys.sync() |
1100 |
|
1101 |
# really install the bootloader |
1102 |
p = os.pipe() |
1103 |
os.write(p[1], cmd + '\n') |
1104 |
os.close(p[1]) |
1105 |
rhpl.executil.execWithRedirect('/sbin/grub' , |
1106 |
[ "grub", "--batch", "--no-floppy", |
1107 |
"--device-map=/boot/grub/device.map" ], |
1108 |
stdin = p[0], |
1109 |
stdout = "/dev/tty5", stderr = "/dev/tty5", |
1110 |
root = instRoot) |
1111 |
os.close(p[0]) |
1112 |
|
1113 |
return "" |
1114 |
|
1115 |
|
1116 |
def write(self, instRoot, fsset, bl, langs, kernelList, chainList, |
1117 |
defaultDev, justConfig, intf): |
1118 |
# XXX HACK ALERT - see declaration above |
1119 |
if self.doUpgradeOnly: |
1120 |
if self.useGrubVal: |
1121 |
self.upgradeGrub(instRoot, fsset, bl, langs, kernelList, |
1122 |
chainList, defaultDev, justConfig) |
1123 |
|
1124 |
# and the hacks continue. with 2.6, ide-scsi isn't used |
1125 |
# anymore (#116622) |
1126 |
import isys |
1127 |
cdrw = isys.ideCdRwList() |
1128 |
torem = [] |
1129 |
for device in cdrw: |
1130 |
torem.append("%s=ide-scsi" %(device,)) |
1131 |
|
1132 |
for fn in ("/etc/lilo.conf", "/boot/grub/grub.conf", |
1133 |
"/etc/lilo.conf.anaconda"): |
1134 |
if not os.path.exists(instRoot + fn): |
1135 |
continue |
1136 |
f = open(instRoot + fn, "r") |
1137 |
buf = f.read() |
1138 |
f.close() |
1139 |
for dev in torem: |
1140 |
buf = buf.replace(dev, "") |
1141 |
f = open(instRoot + fn, "w") |
1142 |
f.write(buf) |
1143 |
f.close() |
1144 |
return |
1145 |
if len(kernelList) < 1: |
1146 |
self.noKernelsWarn(intf) |
1147 |
|
1148 |
str = self.writeGrub(instRoot, fsset, bl, langs, kernelList, |
1149 |
chainList, defaultDev, |
1150 |
justConfig | (not self.useGrubVal)) |
1151 |
# XXX move the lilo.conf out of the way if they're using GRUB |
1152 |
# so that /sbin/installkernel does a more correct thing |
1153 |
if self.useGrubVal and os.access(instRoot + '/etc/lilo.conf', os.R_OK): |
1154 |
os.rename(instRoot + "/etc/lilo.conf", |
1155 |
instRoot + "/etc/lilo.conf.anaconda") |
1156 |
|
1157 |
|
1158 |
|
1159 |
def getArgList(self): |
1160 |
args = bootloaderInfo.getArgList(self) |
1161 |
|
1162 |
if self.forceLBA32: |
1163 |
args.append("--lba32") |
1164 |
if self.password: |
1165 |
args.append("--md5pass=%s" %(self.password)) |
1166 |
|
1167 |
|
1168 |
# XXX add location of bootloader here too |
1169 |
|
1170 |
return args |
1171 |
|
1172 |
def __init__(self): |
1173 |
bootloaderInfo.__init__(self) |
1174 |
# XXX use checkbootloader to determine what to default to |
1175 |
self.useGrubVal = 1 |
1176 |
self.kernelLocation = "/boot/" |
1177 |
self.configfile = "/etc/lilo.conf" |
1178 |
self.password = None |
1179 |
self.pure = None |
1180 |
|
1181 |
class s390BootloaderInfo(bootloaderInfo): |
1182 |
def getBootloaderConfig(self, instRoot, fsset, bl, langs, kernelList, |
1183 |
chainList, defaultDev): |
1184 |
images = bl.images.getImages() |
1185 |
|
1186 |
# on upgrade read in the lilo config file |
1187 |
lilo = LiloConfigFile () |
1188 |
self.perms = 0600 |
1189 |
if os.access (instRoot + self.configfile, os.R_OK): |
1190 |
self.perms = os.stat(instRoot + self.configfile)[0] & 0777 |
1191 |
lilo.read (instRoot + self.configfile) |
1192 |
os.rename(instRoot + self.configfile, |
1193 |
instRoot + self.configfile + '.rpmsave') |
1194 |
|
1195 |
# Remove any invalid entries that are in the file; we probably |
1196 |
# just removed those kernels. |
1197 |
for label in lilo.listImages(): |
1198 |
(fsType, sl, path, other) = lilo.getImage(label) |
1199 |
if fsType == "other": continue |
1200 |
|
1201 |
if not os.access(instRoot + sl.getPath(), os.R_OK): |
1202 |
lilo.delImage(label) |
1203 |
|
1204 |
rootDev = fsset.getEntryByMountPoint("/").device.getDevice() |
1205 |
if not rootDev: |
1206 |
raise RuntimeError, "Installing zipl, but there is no root device" |
1207 |
|
1208 |
if rootDev == defaultDev: |
1209 |
lilo.addEntry("default", kernelList[0][0]) |
1210 |
else: |
1211 |
lilo.addEntry("default", chainList[0][0]) |
1212 |
|
1213 |
for (label, longlabel, version) in kernelList: |
1214 |
kernelTag = "-" + version |
1215 |
kernelFile = self.kernelLocation + "vmlinuz" + kernelTag |
1216 |
|
1217 |
try: |
1218 |
lilo.delImage(label) |
1219 |
except IndexError, msg: |
1220 |
pass |
1221 |
|
1222 |
sl = LiloConfigFile(imageType = "image", path = kernelFile) |
1223 |
|
1224 |
initrd = booty.makeInitrd (kernelTag, instRoot) |
1225 |
|
1226 |
sl.addEntry("label", label) |
1227 |
if os.access (instRoot + initrd, os.R_OK): |
1228 |
sl.addEntry("initrd", |
1229 |
"%sinitrd%s.img" %(self.kernelLocation, kernelTag)) |
1230 |
|
1231 |
sl.addEntry("read-only") |
1232 |
sl.addEntry("root", '/dev/' + rootDev) |
1233 |
sl.addEntry("ipldevice", '/dev/' + rootDev[:-1]) |
1234 |
|
1235 |
if self.args.get(): |
1236 |
sl.addEntry('append', '"%s"' % self.args.get()) |
1237 |
|
1238 |
lilo.addImage (sl) |
1239 |
|
1240 |
for (label, longlabel, device) in chainList: |
1241 |
if ((not label) or (label == "")): |
1242 |
continue |
1243 |
try: |
1244 |
(fsType, sl, path, other) = lilo.getImage(label) |
1245 |
lilo.delImage(label) |
1246 |
except IndexError: |
1247 |
sl = LiloConfigFile(imageType = "other", |
1248 |
path = "/dev/%s" %(device)) |
1249 |
sl.addEntry("optional") |
1250 |
|
1251 |
sl.addEntry("label", label) |
1252 |
lilo.addImage (sl) |
1253 |
|
1254 |
# Sanity check #1. There could be aliases in sections which conflict |
1255 |
# with the new images we just created. If so, erase those aliases |
1256 |
imageNames = {} |
1257 |
for label in lilo.listImages(): |
1258 |
imageNames[label] = 1 |
1259 |
|
1260 |
for label in lilo.listImages(): |
1261 |
(fsType, sl, path, other) = lilo.getImage(label) |
1262 |
if sl.testEntry('alias'): |
1263 |
alias = sl.getEntry('alias') |
1264 |
if imageNames.has_key(alias): |
1265 |
sl.delEntry('alias') |
1266 |
imageNames[alias] = 1 |
1267 |
|
1268 |
# Sanity check #2. If single-key is turned on, go through all of |
1269 |
# the image names (including aliases) (we just built the list) and |
1270 |
# see if single-key will still work. |
1271 |
if lilo.testEntry('single-key'): |
1272 |
singleKeys = {} |
1273 |
turnOff = 0 |
1274 |
for label in imageNames.keys(): |
1275 |
l = label[0] |
1276 |
if singleKeys.has_key(l): |
1277 |
turnOff = 1 |
1278 |
singleKeys[l] = 1 |
1279 |
if turnOff: |
1280 |
lilo.delEntry('single-key') |
1281 |
|
1282 |
return lilo |
1283 |
|
1284 |
def writeChandevConf(self, bl, instroot): # S/390 only |
1285 |
cf = "/etc/chandev.conf" |
1286 |
self.perms = 0644 |
1287 |
if bl.args.chandevget(): |
1288 |
fd = os.open(instroot + "/etc/chandev.conf", |
1289 |
os.O_WRONLY | os.O_CREAT) |
1290 |
os.write(fd, "noauto\n") |
1291 |
for cdev in bl.args.chandevget(): |
1292 |
os.write(fd,'%s\n' % cdev) |
1293 |
os.close(fd) |
1294 |
return "" |
1295 |
|
1296 |
|
1297 |
def writeZipl(self, instRoot, fsset, bl, langs, kernelList, chainList, |
1298 |
defaultDev, justConfigFile): |
1299 |
images = bl.images.getImages() |
1300 |
rootDev = fsset.getEntryByMountPoint("/").device.getDevice() |
1301 |
|
1302 |
cf = '/etc/zipl.conf' |
1303 |
self.perms = 0600 |
1304 |
if os.access (instRoot + cf, os.R_OK): |
1305 |
self.perms = os.stat(instRoot + cf)[0] & 0777 |
1306 |
os.rename(instRoot + cf, |
1307 |
instRoot + cf + '.rpmsave') |
1308 |
|
1309 |
f = open(instRoot + cf, "w+") |
1310 |
|
1311 |
f.write('[defaultboot]\n') |
1312 |
f.write('default=' + kernelList[0][0] + '\n') |
1313 |
f.write('target=%s\n' % (self.kernelLocation)) |
1314 |
|
1315 |
cfPath = "/boot/" |
1316 |
for (label, longlabel, version) in kernelList: |
1317 |
kernelTag = "-" + version |
1318 |
kernelFile = "%svmlinuz%s" % (cfPath, kernelTag) |
1319 |
|
1320 |
initrd = booty.makeInitrd (kernelTag, instRoot) |
1321 |
f.write('[%s]\n' % (label)) |
1322 |
f.write('\timage=%s\n' % (kernelFile)) |
1323 |
if os.access (instRoot + initrd, os.R_OK): |
1324 |
f.write('\tramdisk=%sinitrd%s.img\n' %(self.kernelLocation, |
1325 |
kernelTag)) |
1326 |
realroot = getRootDevName(initrd, fsset, rootDev, instRoot) |
1327 |
f.write('\tparameters="root=%s' %(realroot,)) |
1328 |
if bl.args.get(): |
1329 |
f.write(' %s' % (bl.args.get())) |
1330 |
f.write('"\n') |
1331 |
|
1332 |
f.close() |
1333 |
|
1334 |
if not justConfigFile: |
1335 |
argv = [ "/sbin/zipl" ] |
1336 |
rhpl.executil.execWithRedirect(argv[0], argv, root = instRoot, |
1337 |
stdout = "/dev/stdout", |
1338 |
stderr = "/dev/stderr") |
1339 |
|
1340 |
return "" |
1341 |
|
1342 |
def write(self, instRoot, fsset, bl, langs, kernelList, chainList, |
1343 |
defaultDev, justConfig, intf): |
1344 |
str = self.writeZipl(instRoot, fsset, bl, langs, kernelList, |
1345 |
chainList, defaultDev, |
1346 |
justConfig | (not self.useZiplVal)) |
1347 |
str = self.writeChandevConf(bl, instRoot) |
1348 |
|
1349 |
def __init__(self): |
1350 |
bootloaderInfo.__init__(self) |
1351 |
self.useZiplVal = 1 # only used on s390 |
1352 |
self.kernelLocation = "/boot/" |
1353 |
self.configfile = "/etc/zipl.conf" |
1354 |
|
1355 |
|
1356 |
class alphaBootloaderInfo(bootloaderInfo): |
1357 |
def wholeDevice (self, path): |
1358 |
(device, foo) = getDiskPart(path) |
1359 |
return device |
1360 |
|
1361 |
def partitionNum (self, path): |
1362 |
# getDiskPart returns part numbers 0-based; we need it one based |
1363 |
# *sigh* |
1364 |
(foo, partitionNumber) = getDiskPart(path) |
1365 |
return partitionNumber + 1 |
1366 |
|
1367 |
# See if we would have to use MILO. MILO isn't supported by Red Hat. |
1368 |
def useMilo (self): |
1369 |
try: |
1370 |
f = open ('/proc/cpuinfo', 'ro') |
1371 |
except: |
1372 |
return |
1373 |
lines = f.readlines () |
1374 |
f.close() |
1375 |
serial = "" |
1376 |
for line in lines: |
1377 |
if line.find("system serial number") != -1: |
1378 |
serial = string.strip (string.split (line, ':')[1]) |
1379 |
break |
1380 |
|
1381 |
if serial and len (serial) >= 4 and serial.startswith("MILO"): |
1382 |
return 1 |
1383 |
else: |
1384 |
return 0 |
1385 |
|
1386 |
def writeAboot(self, instRoot, fsset, bl, langs, kernelList, |
1387 |
chainList, defaultDev, justConfig): |
1388 |
# Get bootDevice and rootDevice |
1389 |
rootDevice = fsset.getEntryByMountPoint("/").device.getDevice() |
1390 |
if fsset.getEntryByMountPoint("/boot"): |
1391 |
bootDevice = fsset.getEntryByMountPoint("/boot").device.getDevice() |
1392 |
else: |
1393 |
bootDevice = rootDevice |
1394 |
bootnotroot = bootDevice != rootDevice |
1395 |
|
1396 |
# If /etc/aboot.conf already exists we rename it |
1397 |
# /etc/aboot.conf.rpmsave. |
1398 |
if os.path.isfile(instRoot + self.configfile): |
1399 |
os.rename (instRoot + self.configfile, |
1400 |
instRoot + self.configfile + ".rpmsave") |
1401 |
|
1402 |
# Then we create the necessary files. If the root device isn't |
1403 |
# the boot device, we create /boot/etc/ where the aboot.conf |
1404 |
# will live, and we create /etc/aboot.conf as a symlink to it. |
1405 |
if bootnotroot: |
1406 |
# Do we have /boot/etc ? If not, create one |
1407 |
if not os.path.isdir (instRoot + '/boot/etc'): |
1408 |
os.mkdir(instRoot + '/boot/etc', 0755) |
1409 |
|
1410 |
# We install the symlink (/etc/aboot.conf has already been |
1411 |
# renamed in necessary.) |
1412 |
os.symlink("../boot" + self.configfile, instRoot + self.configfile) |
1413 |
|
1414 |
cfPath = instRoot + "/boot" + self.configfile |
1415 |
# Kernel path is set to / because a boot partition will |
1416 |
# be a root on its own. |
1417 |
kernelPath = '/' |
1418 |
# Otherwise, we just need to create /etc/aboot.conf. |
1419 |
else: |
1420 |
cfPath = instRoot + self.configfile |
1421 |
kernelPath = self.kernelLocation |
1422 |
|
1423 |
# If we already have an aboot.conf, rename it |
1424 |
if os.access (cfPath, os.R_OK): |
1425 |
self.perms = os.stat(cfPath)[0] & 0777 |
1426 |
os.rename(cfPath, cfPath + '.rpmsave') |
1427 |
|
1428 |
# Now we're going to create and populate cfPath. |
1429 |
f = open (cfPath, 'w+') |
1430 |
f.write ("# aboot default configurations\n") |
1431 |
|
1432 |
if bootnotroot: |
1433 |
f.write ("# NOTICE: You have a /boot partition. This means that\n") |
1434 |
f.write ("# all kernel paths are relative to /boot/\n") |
1435 |
|
1436 |
# bpn is the boot partition number. |
1437 |
bpn = self.partitionNum(bootDevice) |
1438 |
lines = 0 |
1439 |
|
1440 |
# We write entries line using the following format: |
1441 |
# <line><bpn><kernel-name> root=<rootdev> [options] |
1442 |
# We get all the kernels we need to know about in kernelList. |
1443 |
|
1444 |
for (kernel, tag, kernelTag) in kernelList: |
1445 |
kernelFile = "%svmlinuz-%s" %(kernelPath, kernelTag) |
1446 |
|
1447 |
f.write("%d:%d%s" %(lines, bpn, kernelFile)) |
1448 |
|
1449 |
# See if we can come up with an initrd argument that exists |
1450 |
initrd = booty.makeInitrd (kernelTag, instRoot) |
1451 |
if os.access(instRoot + initrd, os.R_OK): |
1452 |
f.write(" initrd=%sinitrd-%s.img" %(kernelPath, kernelTag)) |
1453 |
|
1454 |
realroot = getRootDevName(initrd, fsset, rootDevice, instRoot) |
1455 |
f.write(" root=%s" %(realroot,)) |
1456 |
|
1457 |
args = self.args.get() |
1458 |
if args: |
1459 |
f.write(" %s" %(args,)) |
1460 |
|
1461 |
f.write("\n") |
1462 |
lines = lines + 1 |
1463 |
|
1464 |
# We're done writing the file |
1465 |
f.close () |
1466 |
del f |
1467 |
|
1468 |
if not justConfig: |
1469 |
# Now we're ready to write the relevant boot information. wbd |
1470 |
# is the whole boot device, bdpn is the boot device partition |
1471 |
# number. |
1472 |
wbd = self.wholeDevice (bootDevice) |
1473 |
bdpn = self.partitionNum (bootDevice) |
1474 |
|
1475 |
# Calling swriteboot. The first argument is the disk to write |
1476 |
# to and the second argument is a path to the bootstrap loader |
1477 |
# file. |
1478 |
args = ("swriteboot", ("/dev/%s" % wbd), "/boot/bootlx") |
1479 |
log("swriteboot command: %s" %(args,)) |
1480 |
rhpl.executil.execWithRedirect ('/sbin/swriteboot', args, |
1481 |
root = instRoot, |
1482 |
stdout = "/dev/tty5", |
1483 |
stderr = "/dev/tty5") |
1484 |
|
1485 |
# Calling abootconf to configure the installed aboot. The |
1486 |
# first argument is the disk to use, the second argument is |
1487 |
# the number of the partition on which aboot.conf resides. |
1488 |
# It's always the boot partition whether it's / or /boot (with |
1489 |
# the mount point being omitted.) |
1490 |
args = ("abootconf", ("/dev/%s" % wbd), str (bdpn)) |
1491 |
log("abootconf command: %s" %(args,)) |
1492 |
rhpl.executil.execWithRedirect ('/sbin/abootconf', args, |
1493 |
root = instRoot, |
1494 |
stdout = "/dev/tty5", |
1495 |
stderr = "/dev/tty5") |
1496 |
|
1497 |
|
1498 |
def write(self, instRoot, fsset, bl, langs, kernelList, chainList, |
1499 |
defaultDev, justConfig, intf): |
1500 |
if len(kernelList) < 1: |
1501 |
self.noKernelsWarn(intf) |
1502 |
|
1503 |
if self.useMilo(): |
1504 |
intf.messageWindow(_("MILO Not Supported"), |
1505 |
"This system requires the support of MILO to " + |
1506 |
"boot linux (MILO is not included in this " + |
1507 |
"distribution.) The installation of the " + |
1508 |
"bootloader can't be completed on this system.") |
1509 |
# elif not justConfig FIXME. |
1510 |
else: |
1511 |
self.writeAboot(instRoot, fsset, bl, langs, kernelList, |
1512 |
chainList, defaultDev, justConfig) |
1513 |
|
1514 |
def __init__(self): |
1515 |
bootloaderInfo.__init__(self) |
1516 |
self.useGrubVal = 0 |
1517 |
self.configfile = "/etc/aboot.conf" |
1518 |
# self.kernelLocation is already set to what we need. |
1519 |
self.password = None |
1520 |
self.pure = None |
1521 |
|
1522 |
|
1523 |
class ppcBootloaderInfo(bootloaderInfo): |
1524 |
def writeYaboot(self, instRoot, fsset, bl, langs, kernelList, |
1525 |
chainList, defaultDev, justConfigFile): |
1526 |
|
1527 |
from flags import flags |
1528 |
|
1529 |
yabootTarget = '/dev/%s' %(bl.getDevice()) |
1530 |
|
1531 |
bootDev = fsset.getEntryByMountPoint("/boot") |
1532 |
if bootDev: |
1533 |
cf = "/boot/etc/yaboot.conf" |
1534 |
cfPath = "" |
1535 |
if not os.path.isdir(instRoot + "/boot/etc"): |
1536 |
os.mkdir(instRoot + "/boot/etc") |
1537 |
else: |
1538 |
bootDev = fsset.getEntryByMountPoint("/") |
1539 |
cfPath = "/boot" |
1540 |
cf = "/etc/yaboot.conf" |
1541 |
bootDev = bootDev.device.getDevice(asBoot = 1) |
1542 |
|
1543 |
f = open(instRoot + cf, "w+") |
1544 |
|
1545 |
f.write("# yaboot.conf generated by anaconda\n\n") |
1546 |
|
1547 |
f.write("boot=%s\n" %(yabootTarget,)) |
1548 |
f.write("init-message=Welcome to %s\\!\nHit <TAB> for boot options\n\n" |
1549 |
%(butil.getProductName(),)) |
1550 |
|
1551 |
(name, partNum) = getDiskPart(bootDev) |
1552 |
partno = partNum + 1 # 1 based |
1553 |
f.write("partition=%s\n" %(partno,)) |
1554 |
|
1555 |
f.write("timeout=80\n") |
1556 |
f.write("install=/usr/lib/yaboot/yaboot\n") |
1557 |
f.write("delay=5\n") |
1558 |
f.write("enablecdboot\n") |
1559 |
f.write("enableofboot\n") |
1560 |
f.write("enablenetboot\n") |
1561 |
|
1562 |
if butil.getPPCMachine() == "PMac": |
1563 |
# write out the first hfs/hfs+ partition as being macosx |
1564 |
for (label, longlabel, device) in chainList: |
1565 |
if ((not label) or (label == "")): |
1566 |
continue |
1567 |
f.write("macosx=/dev/%s\n" %(device,)) |
1568 |
break |
1569 |
|
1570 |
f.write("magicboot=/usr/lib/yaboot/ofboot\n") |
1571 |
|
1572 |
if butil.getPPCMachine() == "pSeries": |
1573 |
f.write("nonvram\n") |
1574 |
|
1575 |
if self.password: |
1576 |
f.write("password=%s\n" %(self.password,)) |
1577 |
f.write("restricted\n") |
1578 |
|
1579 |
f.write("\n") |
1580 |
|
1581 |
rootDev = fsset.getEntryByMountPoint("/").device.getDevice() |
1582 |
|
1583 |
for (label, longlabel, version) in kernelList: |
1584 |
kernelTag = "-" + version |
1585 |
kernelFile = "%s/vmlinuz%s" %(cfPath, kernelTag) |
1586 |
|
1587 |
f.write("image=%s\n" %(kernelFile,)) |
1588 |
f.write("\tlabel=%s\n" %(label,)) |
1589 |
f.write("\tread-only\n") |
1590 |
|
1591 |
initrd = booty.makeInitrd(kernelTag, instRoot) |
1592 |
if os.access(instRoot + initrd, os.R_OK): |
1593 |
f.write("\tinitrd=%s/initrd%s.img\n" %(cfPath,kernelTag)) |
1594 |
|
1595 |
append = "%s" %(self.args.get(),) |
1596 |
|
1597 |
realroot = getRootDevName(initrd, fsset, rootDev, instRoot) |
1598 |
if not realroot.startswith("LABEL="): |
1599 |
f.write("\troot=%s\n" %(realroot,)) |
1600 |
else: |
1601 |
if len(append) > 0: |
1602 |
append = "%s root=%s" %(append,realroot) |
1603 |
else: |
1604 |
append = "root=%s" %(realroot,) |
1605 |
|
1606 |
if len(append) > 0: |
1607 |
f.write("\tappend=\"%s\"\n" %(append,)) |
1608 |
f.write("\n") |
1609 |
|
1610 |
f.close() |
1611 |
os.chmod(instRoot + cf, 0600) |
1612 |
|
1613 |
# FIXME: hack to make sure things are written to disk |
1614 |
import isys |
1615 |
isys.sync() |
1616 |
isys.sync() |
1617 |
isys.sync() |
1618 |
|
1619 |
ybinargs = [ "/sbin/mkofboot", "-f", "-C", cf ] |
1620 |
if butil.getPPCMachine() == "pSeries": |
1621 |
ybinargs.extend(["--filesystem", "raw"]) |
1622 |
|
1623 |
|
1624 |
log("running: %s" %(ybinargs,)) |
1625 |
if not flags.test: |
1626 |
rhpl.executil.execWithRedirect(ybinargs[0], |
1627 |
ybinargs, |
1628 |
stdout = "/dev/tty5", |
1629 |
stderr = "/dev/tty5", |
1630 |
root = instRoot) |
1631 |
|
1632 |
if (not os.access(instRoot + "/etc/yaboot.conf", os.R_OK) and |
1633 |
os.access(instRoot + "/boot/etc/yaboot.conf", os.R_OK)): |
1634 |
os.symlink("../boot/etc/yaboot.conf", |
1635 |
instRoot + "/etc/yaboot.conf") |
1636 |
|
1637 |
return "" |
1638 |
|
1639 |
def setPassword(self, val, isCrypted = 1): |
1640 |
# yaboot just handles the password and doesn't care if its crypted |
1641 |
# or not |
1642 |
self.password = val |
1643 |
|
1644 |
def write(self, instRoot, fsset, bl, langs, kernelList, chainList, |
1645 |
defaultDev, justConfig, intf): |
1646 |
if len(kernelList) >= 1: |
1647 |
str = self.writeYaboot(instRoot, fsset, bl, langs, kernelList, |
1648 |
chainList, defaultDev, justConfig) |
1649 |
else: |
1650 |
self.noKernelsWarn(intf) |
1651 |
|
1652 |
def __init__(self): |
1653 |
bootloaderInfo.__init__(self) |
1654 |
self.useYabootVal = 1 |
1655 |
self.kernelLocation = "/boot" |
1656 |
self.configfile = "/etc/yaboot.conf" |
1657 |
|
1658 |
|
1659 |
class iseriesBootloaderInfo(bootloaderInfo): |
1660 |
def ddFile(self, inf, of, bs = 4096): |
1661 |
src = os.open(inf, os.O_RDONLY) |
1662 |
dest = os.open(of, os.O_WRONLY | os.O_CREAT) |
1663 |
size = 0 |
1664 |
|
1665 |
buf = os.read(src, bs) |
1666 |
while len(buf) > 0: |
1667 |
size = size + len(buf) |
1668 |
os.write(dest, buf) |
1669 |
buf = os.read(src, bs) |
1670 |
|
1671 |
os.close(src) |
1672 |
os.close(dest) |
1673 |
|
1674 |
return size |
1675 |
|
1676 |
def write(self, instRoot, fsset, bl, langs, kernelList, chainList, |
1677 |
defaultDev, justConfig, intf): |
1678 |
if len(kernelList) < 1: |
1679 |
self.noKernelsWarn(intf) |
1680 |
return |
1681 |
if len(kernelList) > 1: |
1682 |
# FIXME: how can this happen? |
1683 |
log("more than one kernel on iSeries. bailing and just using " |
1684 |
"the first") |
1685 |
|
1686 |
# iseries is Weird (tm) -- here's the basic theory |
1687 |
# a) have /boot/vmlinitrd-$(version) |
1688 |
# b) copy default kernel to PReP partition |
1689 |
# c) dd default kernel to /proc/iSeries/mf/C/vmlinux |
1690 |
# d) set cmdline in /boot/cmdline-$(version) |
1691 |
# e) copy cmdline to /proc/iSeries/mf/C/cmdline |
1692 |
# f) set default side to 'C' i /proc/iSeries/mf/side |
1693 |
# g) put default kernel and cmdline on side B too (#91038) |
1694 |
|
1695 |
rootDevice = fsset.getEntryByMountPoint("/").device.getDevice() |
1696 |
|
1697 |
# write our command line files |
1698 |
for (kernel, tag, kernelTag) in kernelList: |
1699 |
cmdFile = "%scmdline-%s" %(self.kernelLocation, kernelTag) |
1700 |
initrd = "%sinitrd-%s.img" %(self.kernelLocation, kernelTag) |
1701 |
realroot = getRootDevName(initrd, fsset, rootDevice, instRoot) |
1702 |
f = open(instRoot + cmdFile, "w") |
1703 |
f.write("ro root=%s" %(realroot,)) |
1704 |
if bl.args.get(): |
1705 |
f.write(" %s" %(bl.args.get(),)) |
1706 |
f.write("\n") |
1707 |
f.close() |
1708 |
os.chmod(instRoot + cmdFile, 0644) |
1709 |
|
1710 |
kernel, tag, kernelTag = kernelList[0] |
1711 |
kernelFile = "%svmlinitrd-%s" %(self.kernelLocation, kernelTag) |
1712 |
|
1713 |
# write the kernel to the PReP partition since that's what |
1714 |
# OS/400 will load as NWSSTG |
1715 |
bootDev = bl.getDevice() |
1716 |
if bootDev: |
1717 |
log("Writing kernel %s to PReP partition %s" %(kernelFile, |
1718 |
bootDev)) |
1719 |
try: |
1720 |
self.ddFile(instRoot + kernelFile, "%s/dev/%s" %(instRoot, |
1721 |
bootDev)) |
1722 |
except Exception, e: |
1723 |
# FIXME: should this be more fatal |
1724 |
log("Failed to write kernel: %s" %(e,)) |
1725 |
else: |
1726 |
log("No PReP boot partition, not writing kernel for NWSSTG") |
1727 |
|
1728 |
|
1729 |
# now, it's a lot faster to boot if we don't make people go back |
1730 |
# into OS/400, so set up side C (used by default for NWSSTG) with |
1731 |
# our current bits |
1732 |
for side in ("C", "B"): |
1733 |
log("Writing kernel and cmdline to side %s" %(side,)) |
1734 |
wrotekernel = 0 |
1735 |
try: |
1736 |
self.ddFile(instRoot + kernelFile, |
1737 |
"%s/proc/iSeries/mf/%s/vmlinux" %(instRoot, side)) |
1738 |
wrotekernel = 1 |
1739 |
except Exception, e: |
1740 |
# FIXME: should this be more fatal? |
1741 |
log("Failed to write kernel to side %s: %s" %(side, e)) |
1742 |
|
1743 |
if wrotekernel == 1: |
1744 |
try: |
1745 |
# blank it. ugh. |
1746 |
f = open("%s/proc/iSeries/mf/%s/cmdline" %(instRoot, side), |
1747 |
"w+") |
1748 |
f.write(" " * 255) |
1749 |
f.close() |
1750 |
|
1751 |
self.ddFile("%s/%scmdline-%s" %(instRoot, |
1752 |
self.kernelLocation, |
1753 |
kernelTag), |
1754 |
"%s/proc/iSeries/mf/%s/cmdline" %(instRoot, |
1755 |
side)) |
1756 |
except Exception, e: |
1757 |
log("Failed to write kernel command line to side %s: %s" |
1758 |
%(side, e)) |
1759 |
|
1760 |
log("Setting default side to C") |
1761 |
f = open(instRoot + "/proc/iSeries/mf/side", "w") |
1762 |
f.write("C") |
1763 |
f.close() |
1764 |
|
1765 |
def __init__(self): |
1766 |
bootloaderInfo.__init__(self) |
1767 |
self.kernelLocation = "/boot/" |
1768 |
|
1769 |
class sparcBootloaderInfo(bootloaderInfo): |
1770 |
def writeSilo(self, instRoot, fsset, bl, langs, kernelList, |
1771 |
chainList, defaultDev, justConfigFile): |
1772 |
|
1773 |
from flags import flags |
1774 |
|
1775 |
bootDev = fsset.getEntryByMountPoint("/boot") |
1776 |
if bootDev: |
1777 |
cf = "/boot/silo.conf" |
1778 |
mf = "/boot/silo.message" |
1779 |
cfPath = "" |
1780 |
if not os.path.isdir(instRoot + "/boot"): |
1781 |
os.mkdir(instRoot + "/boot") |
1782 |
else: |
1783 |
bootDev = fsset.getEntryByMountPoint("/") |
1784 |
cf = "/etc/silo.conf" |
1785 |
mf = "/etc/silo.message" |
1786 |
cfPath = "/boot" |
1787 |
bootDev = bootDev.device.getDevice(asBoot = 1) |
1788 |
|
1789 |
f = open(instRoot + mf, "w+") |
1790 |
f.write("Welcome to %s!\nHit <TAB> for boot options\n\n" % \ |
1791 |
(butil.getProductName(),)) |
1792 |
f.close() |
1793 |
os.chmod(instRoot + mf, 0600) |
1794 |
|
1795 |
f = open(instRoot + cf, "w+") |
1796 |
f.write("# silo.conf generated by anaconda\n\n") |
1797 |
|
1798 |
f.write("#boot=%s\n" % (bootDev,)) |
1799 |
f.write("message=%s\n" % (mf,)) |
1800 |
f.write("timeout=50\n") |
1801 |
|
1802 |
(name, partNum) = getDiskPart(bootDev) |
1803 |
partno = partNum + 1 |
1804 |
f.write("partition=%s\n" % (partno,)) |
1805 |
|
1806 |
if self.password: |
1807 |
f.write("password=%s\n" % (self.password,)) |
1808 |
f.write("restricted\n") |
1809 |
|
1810 |
f.write("default=%s\n" % (kernelList[0][0],)) |
1811 |
f.write("\n") |
1812 |
|
1813 |
rootDev = fsset.getEntryByMountPoint("/").device.getDevice() |
1814 |
|
1815 |
for (label, longlabel, version) in kernelList: |
1816 |
kernelTag = "-" + version |
1817 |
kernelFile = "%s/vmlinuz%s" % (cfPath, kernelTag) |
1818 |
|
1819 |
f.write("image=%s\n" % (kernelFile,)) |
1820 |
f.write("\tlabel=%s\n" % (label,)) |
1821 |
f.write("\tread-only\n") |
1822 |
|
1823 |
initrd = booty.makeInitrd(kernelTag, instRoot) |
1824 |
if os.access(instRoot + initrd, os.R_OK): |
1825 |
f.write("\tinitrd=%s/initrd%s.img\n" % (cfPath, kernelTag)) |
1826 |
|
1827 |
append = "%s" % (self.args.get(),) |
1828 |
|
1829 |
realroot = getRootDevName(initrd, fsset, rootDev, instRoot) |
1830 |
if not realroot.startswith("LABEL="): |
1831 |
f.write("\troot=%s\n" % (realroot,)) |
1832 |
else: |
1833 |
if len(append) > 0: |
1834 |
append = "%s root=%s" % (append, realroot) |
1835 |
else: |
1836 |
append = "root=%s" % (realroot,) |
1837 |
|
1838 |
if len(append) > 0: |
1839 |
f.write("\tappend=\"%s\"\n" % (append,)) |
1840 |
f.write("\n") |
1841 |
|
1842 |
f.close() |
1843 |
os.chmod(instRoot + cf, 0600) |
1844 |
|
1845 |
# FIXME: hack to make sure things are written to disk |
1846 |
import isys |
1847 |
isys.sync() |
1848 |
isys.sync() |
1849 |
isys.sync() |
1850 |
|
1851 |
backup = "%s/backup.b" % (cfPath,) |
1852 |
sbinargs = ["/sbin/silo", "-f", "-C", cf, "-S", backup] |
1853 |
if butil.getSparcMachine() == "sun4u": |
1854 |
sbinargs += ["-u"] |
1855 |
else: |
1856 |
sbinargs += ["-U"] |
1857 |
|
1858 |
log("running: %s" % (sbinargs,)) |
1859 |
if not flags.test: |
1860 |
rhpl.executil.execWithRedirect(sbinargs[0], |
1861 |
sbinargs, |
1862 |
stdout = "/dev/tty5", |
1863 |
stderr = "/dev/tty5", |
1864 |
root = instRoot) |
1865 |
|
1866 |
if (not os.access(instRoot + "/etc/silo.conf", os.R_OK) and |
1867 |
os.access(instRoot + "/boot/etc/silo.conf", os.R_OK)): |
1868 |
os.symlink("../boot/etc/silo.conf", |
1869 |
instRoot + "/etc/silo.conf") |
1870 |
|
1871 |
return "" |
1872 |
|
1873 |
def setPassword(self, val, isCrypted = 1): |
1874 |
# silo just handles the password unencrypted |
1875 |
self.password = val |
1876 |
|
1877 |
def write(self, instRoot, fsset, bl, langs, kernelList, chainList, |
1878 |
defaultDev, justConfig, intf): |
1879 |
if len(kernelList) >= 1: |
1880 |
self.writeSilo(instRoot, fsset, bl, langs, kernelList, chainList, |
1881 |
defaultDev, justConfig) |
1882 |
else: |
1883 |
self.noKernelsWarn(intf) |
1884 |
|
1885 |
def __init__(self): |
1886 |
bootloaderInfo.__init__(self) |
1887 |
self.useSiloVal = 1 |
1888 |
self.kernelLocation = "/boot" |
1889 |
self.configfile = "/etc/silo.conf" |
1890 |
|
1891 |
############### |
1892 |
# end of boot loader objects... these are just some utility functions used |
1893 |
|
1894 |
# return (disk, partition number) eg ('hda', 1) |
1895 |
def getDiskPart(dev): |
1896 |
cut = len(dev) |
1897 |
if (dev.startswith('rd/') or dev.startswith('ida/') or |
1898 |
dev.startswith('cciss/')): |
1899 |
if dev[-2] == 'p': |
1900 |
cut = -1 |
1901 |
elif dev[-3] == 'p': |
1902 |
cut = -2 |
1903 |
else: |
1904 |
if dev[-2] in string.digits: |
1905 |
cut = -2 |
1906 |
elif dev[-1] in string.digits: |
1907 |
cut = -1 |
1908 |
|
1909 |
name = dev[:cut] |
1910 |
|
1911 |
# hack off the trailing 'p' from /dev/cciss/*, for example |
1912 |
if name[-1] == 'p': |
1913 |
for letter in name: |
1914 |
if letter not in string.letters and letter != "/": |
1915 |
name = name[:-1] |
1916 |
break |
1917 |
|
1918 |
if cut < 0: |
1919 |
partNum = int(dev[cut:]) - 1 |
1920 |
else: |
1921 |
partNum = None |
1922 |
|
1923 |
return (name, partNum) |
1924 |
|
1925 |
# hackery to determine if we should do root=LABEL=/ or whatnot |
1926 |
# as usual, knows too much about anaconda |
1927 |
def getRootDevName(initrd, fsset, rootDev, instRoot): |
1928 |
if not os.access(instRoot + initrd, os.R_OK): |
1929 |
return "/dev/%s" % (rootDev,) |
1930 |
|
1931 |
try: |
1932 |
rootEntry = fsset.getEntryByMountPoint("/") |
1933 |
if rootEntry.getLabel() is not None: |
1934 |
return "LABEL=%s" %(rootEntry.getLabel(),) |
1935 |
return "/dev/%s" %(rootDev,) |
1936 |
except: |
1937 |
return "/dev/%s" %(rootDev,) |
1938 |
|