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