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 |
slords |
1.2 |
# Peter Jones <pjones@redhat.com> |
8 |
slords |
1.1 |
# |
9 |
slords |
1.2 |
# Copyright 2001,2005 Red Hat, Inc. |
10 |
slords |
1.1 |
# |
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 |
slords |
1.2 |
import os |
19 |
slords |
1.1 |
import string |
20 |
|
|
|
21 |
|
|
grubConfigFile = "/boot/grub/grub.conf" |
22 |
|
|
liloConfigFile = "/etc/lilo.conf" |
23 |
|
|
yabootConfigFile = "/etc/yaboot.conf" |
24 |
slords |
1.2 |
siloConfigFile = "/etc/silo.conf" |
25 |
slords |
1.1 |
|
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 |
slords |
1.2 |
haveSiloConf = 1 |
139 |
slords |
1.1 |
|
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 |
slords |
1.2 |
if not os.access(instRoot + siloConfigFile, os.R_OK): |
151 |
|
|
haveSiloConf = 0 |
152 |
slords |
1.1 |
|
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 |
slords |
1.2 |
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 |
slords |
1.1 |
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." |