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