1 |
slords |
1.1 |
#!/usr/bin/python |
2 |
|
|
# |
3 |
|
|
# Check to see whether it looks like GRUB or LILO is the boot loader |
4 |
|
|
# being used on the system. |
5 |
|
|
# |
6 |
|
|
# Jeremy Katz <katzj@redhat.com> |
7 |
|
|
# |
8 |
|
|
# Copyright 2001 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 |
|
|
import os,sys |
18 |
|
|
import string |
19 |
|
|
|
20 |
|
|
grubConfigFile = "/boot/grub/grub.conf" |
21 |
|
|
liloConfigFile = "/etc/lilo.conf" |
22 |
|
|
yabootConfigFile = "/etc/yaboot.conf" |
23 |
|
|
|
24 |
|
|
|
25 |
|
|
# XXX: this is cut and pasted directly from booty/bootloaderInfo.py |
26 |
|
|
# should eventually just go from there |
27 |
|
|
def getDiskPart(dev): |
28 |
|
|
"""Return (disk, partition number) tuple for dev""" |
29 |
|
|
cut = len(dev) |
30 |
|
|
if (dev[:3] == "rd/" or dev[:4] == "ida/" or |
31 |
|
|
dev[:6] == "cciss/"): |
32 |
|
|
if dev[-2] == 'p': |
33 |
|
|
cut = -1 |
34 |
|
|
elif dev[-3] == 'p': |
35 |
|
|
cut = -2 |
36 |
|
|
else: |
37 |
|
|
if dev[-2] in string.digits: |
38 |
|
|
cut = -2 |
39 |
|
|
elif dev[-1] in string.digits: |
40 |
|
|
cut = -1 |
41 |
|
|
|
42 |
|
|
name = dev[:cut] |
43 |
|
|
|
44 |
|
|
# hack off the trailing 'p' from /dev/cciss/*, for example |
45 |
|
|
if name[-1] == 'p': |
46 |
|
|
for letter in name: |
47 |
|
|
if letter not in string.letters and letter != "/": |
48 |
|
|
name = name[:-1] |
49 |
|
|
break |
50 |
|
|
|
51 |
|
|
if cut < 0: |
52 |
|
|
partNum = int(dev[cut:]) - 1 |
53 |
|
|
else: |
54 |
|
|
partNum = None |
55 |
|
|
|
56 |
|
|
return (name, partNum) |
57 |
|
|
|
58 |
|
|
|
59 |
|
|
def getRaidDisks(raidDevice, raidLevel=None, stripPart=1): |
60 |
|
|
rc = [] |
61 |
|
|
if raidLevel is not None: |
62 |
|
|
try: |
63 |
|
|
raidLevel = "raid%d" % (int(raidLevel),) |
64 |
|
|
except ValueError: |
65 |
|
|
pass |
66 |
|
|
|
67 |
|
|
try: |
68 |
|
|
f = open("/proc/mdstat", "r") |
69 |
|
|
lines = f.readlines() |
70 |
|
|
f.close() |
71 |
|
|
except: |
72 |
|
|
return rc |
73 |
|
|
|
74 |
|
|
for line in lines: |
75 |
|
|
fields = string.split(line, ' ') |
76 |
|
|
if fields[0] == raidDevice: |
77 |
|
|
if raidLevel is not None and fields[3] != raidLevel: |
78 |
|
|
continue |
79 |
|
|
for field in fields[4:]: |
80 |
|
|
if string.find(field, "[") == -1: |
81 |
|
|
continue |
82 |
|
|
dev = string.split(field, '[')[0] |
83 |
|
|
if len(dev) == 0: |
84 |
|
|
continue |
85 |
|
|
if stripPart: |
86 |
|
|
disk = getDiskPart(dev)[0] |
87 |
|
|
rc.append(disk) |
88 |
|
|
else: |
89 |
|
|
rc.append(dev) |
90 |
|
|
|
91 |
|
|
return rc |
92 |
|
|
|
93 |
|
|
|
94 |
|
|
def getBootBlock(bootDev, instRoot, seekBlocks=0): |
95 |
|
|
"""Get the boot block from bootDev. Return a 512 byte string.""" |
96 |
|
|
block = " " * 512 |
97 |
|
|
if bootDev is None: |
98 |
|
|
return block |
99 |
|
|
|
100 |
|
|
# get the devices in the raid device |
101 |
|
|
if bootDev[5:7] == "md": |
102 |
|
|
bootDevs = getRaidDisks(bootDev[5:]) |
103 |
|
|
bootDevs.sort() |
104 |
|
|
else: |
105 |
|
|
bootDevs = [ bootDev[5:] ] |
106 |
|
|
|
107 |
|
|
# FIXME: this is kind of a hack |
108 |
|
|
# look at all of the devs in the raid device until we can read the |
109 |
|
|
# boot block for one of them. should do this better at some point |
110 |
|
|
# by looking at all of the drives properly |
111 |
|
|
for dev in bootDevs: |
112 |
|
|
try: |
113 |
|
|
fd = os.open("%s/dev/%s" % (instRoot, dev), os.O_RDONLY) |
114 |
|
|
if seekBlocks > 0: |
115 |
|
|
os.lseek(fd, seekBlocks * 512, 0) |
116 |
|
|
block = os.read(fd, 512) |
117 |
|
|
os.close(fd) |
118 |
|
|
return block |
119 |
|
|
except: |
120 |
|
|
pass |
121 |
|
|
return block |
122 |
|
|
|
123 |
|
|
# takes a line like #boot=/dev/hda and returns /dev/hda |
124 |
|
|
# also handles cases like quoted versions and other nonsense |
125 |
|
|
def getBootDevString(line): |
126 |
|
|
dev = string.split(line, '=')[1] |
127 |
|
|
dev = string.strip(dev) |
128 |
|
|
dev = string.replace(dev, '"', '') |
129 |
|
|
dev = string.replace(dev, "'", "") |
130 |
|
|
return dev |
131 |
|
|
|
132 |
|
|
def getBootloaderTypeAndBoot(instRoot = "/"): |
133 |
|
|
haveGrubConf = 1 |
134 |
|
|
haveLiloConf = 1 |
135 |
|
|
haveYabootConf = 1 |
136 |
|
|
|
137 |
|
|
bootDev = None |
138 |
|
|
|
139 |
|
|
# make sure they have the config file, otherwise we definitely can't |
140 |
|
|
# use that bootloader |
141 |
|
|
if not os.access(instRoot + grubConfigFile, os.R_OK): |
142 |
|
|
haveGrubConf = 0 |
143 |
|
|
if not os.access(instRoot + liloConfigFile, os.R_OK): |
144 |
|
|
haveLiloConf = 0 |
145 |
|
|
if not os.access(instRoot + yabootConfigFile, os.R_OK): |
146 |
|
|
haveYabootConf = 0 |
147 |
|
|
|
148 |
|
|
if haveGrubConf: |
149 |
|
|
bootDev = None |
150 |
|
|
for (fn, stanza) in [ ("/etc/sysconfig/grub", "boot="), |
151 |
|
|
(grubConfigFile, "#boot=") ]: |
152 |
|
|
try: |
153 |
|
|
f = open(instRoot + fn, "r") |
154 |
|
|
except: |
155 |
|
|
continue |
156 |
|
|
|
157 |
|
|
# the following bits of code are straight from checkbootloader.py |
158 |
|
|
lines = f.readlines() |
159 |
|
|
f.close() |
160 |
|
|
for line in lines: |
161 |
|
|
if line.startswith(stanza): |
162 |
|
|
import checkbootloader |
163 |
|
|
bootDev = getBootDevString(line) |
164 |
|
|
break |
165 |
|
|
if bootDev is not None: |
166 |
|
|
break |
167 |
|
|
|
168 |
|
|
if bootDev is not None: |
169 |
|
|
block = getBootBlock(bootDev, instRoot) |
170 |
|
|
# XXX I don't like this, but it's what the maintainer suggested :( |
171 |
|
|
if string.find(block, "GRUB") >= 0: |
172 |
|
|
return ("GRUB", bootDev) |
173 |
|
|
|
174 |
|
|
if haveLiloConf: |
175 |
|
|
f = open(instRoot + liloConfigFile, "r") |
176 |
|
|
lines = f.readlines() |
177 |
|
|
for line in lines: |
178 |
|
|
if line[0:5] == "boot=": |
179 |
|
|
bootDev = getBootDevString(line) |
180 |
|
|
break |
181 |
|
|
|
182 |
|
|
block = getBootBlock(bootDev, instRoot) |
183 |
|
|
# this at least is well-defined |
184 |
|
|
if block[6:10] == "LILO": |
185 |
|
|
return ("LILO", bootDev) |
186 |
|
|
|
187 |
|
|
if haveYabootConf: |
188 |
|
|
f = open(instRoot + yabootConfigFile, "r") |
189 |
|
|
lines = f.readlines() |
190 |
|
|
for line in lines: |
191 |
|
|
if line[0:5] == "boot=": |
192 |
|
|
bootDev = getBootDevString(line) |
193 |
|
|
|
194 |
|
|
if bootDev: |
195 |
|
|
return ("YABOOT", bootDev) |
196 |
|
|
|
197 |
|
|
return (None, None) |
198 |
|
|
|
199 |
|
|
def whichBootLoader(instRoot = "/"): |
200 |
|
|
ret = getBootloaderTypeAndBoot(instRoot) |
201 |
|
|
if not ret: |
202 |
|
|
return None |
203 |
|
|
else: |
204 |
|
|
return ret[0] |
205 |
|
|
|
206 |
|
|
if __name__ == "__main__": |
207 |
|
|
bootloader = whichBootLoader() |
208 |
|
|
if bootloader: |
209 |
|
|
print "Found %s." % (bootloader) |
210 |
|
|
else: |
211 |
|
|
print "Unable to determine boot loader." |