blob: 68b9bc5b1d27fd8cc082de4bd468dfb25204cd3f [file] [log] [blame]
mblighf4c35322006-03-13 01:01:10 +00001# we regard the grub file as a preamble, plus a sequence of entry stanzas
2# starting in 'title'. Whilst probably not entirely accurate, it works
3# well enough, and is designed not to be lossy
4
5import shutil
6import re
7import os
8import os.path
9import string
10
11class grub:
12 config_locations = ['/boot/grub/grub.conf', '/boot/grub/menu.lst',
13 '/etc/grub.conf']
14
15 def __init__(self, config_file=None):
16 if config_file:
17 self.config = config_file
18 else:
19 self.config = self.detect()
20 self.read()
21
22
23 def read(self):
24 conf_file = file(self.config, 'r')
25 self.lines = conf_file.readlines()
26 conf_file.close()
27
28 self.entries = [] # list of stanzas
29 self.titles = {} # dictionary of titles
30 entry = grub_entry(-1)
31 count = 0
32 for line in self.lines:
33 if re.match(r'\s*title', line):
34 self.entries.append(entry)
35 entry = grub_entry(count)
36 count = count + 1
37 title = line.replace('title ', '')
38 title = title.rstrip('\n')
39 entry.set('title', title)
40 self.titles[title] = entry
41 # if line.startswith('initrd'):
42 if re.match(r'\s*initrd', line):
43 entry.set('initrd',
44 re.sub(r'\s*initrd\s+', '', line))
45 if re.match(r'\s*kernel', line):
46 entry.set('kernel',
47 re.sub(r'\s*kernel\s+', '', line))
48 entry.lines.append(line)
49 self.entries.append(entry)
50 self.preamble = self.entries.pop(0) # separate preamble
51
52
53 def write(self):
54 conf_file = file(self.config, 'w')
55 conf_file.write(self.preamble)
56 for entry in self.entries:
57 conf_file.write(entry.lines)
58 conf_file.close()
59
60
61 def dump(self):
62 for line in self.preamble.lines:
63 print line,
64 for entry in self.entries:
65 for line in entry.lines:
66 print line,
67
68 def backup(self):
69 shutil.copyfile(self.config, self.config+'.bak')
70 restore = file(autodir + '/var/autotest.boot.restore', 'w')
71 restore.write('cp ' + self.config+'.bak ' + self.config + '\n')
72 restore.close()
73
74
75 def bootloader(self):
76 return 'grub'
77
78
79 def detect(self):
80 for config in grub.config_locations:
81 if os.path.isfile(config) and not os.path.islink(config):
82 return config
83
84
85 def list_titles(self):
86 list = []
87 for entry in self.entries:
88 list.append(entry.get('title'))
89 return list
90
91
92 def print_entry(self, index):
93 entry = self.entries[index]
94 entry.print_entry()
95
96
97 def renamed_entry(self, index, newname, args=False):
98 "print a specified entry, renaming it as specified"
99 entry = self.entries[index]
100 entry.set('title', newname)
101 if args:
102 entry.set_autotest_kernel()
103 entry.print_entry()
104
105
106 def omit_markers(self, marker):
107 # print, ommitting entries between specified markers
108 print_state = True
109 for line in lines:
110 if line.count(marker):
111 print_state = not print_state
112 else:
113 if print_state:
114 print line
115
116
117 def select(self, title, boot_options=None):
118 entry = self.titles[title]
119 print "grub: will boot entry %d (0-based)" % entry.index
120 self.set_default(entry.index)
121 self.set_timeout()
122
123
124 def set_default(self, index):
125 lines = (self.preamble).lines
126 for i in range(len(lines)):
127 default = 'default %d' % index
128 lines[i] = re.sub(r'^\s*default.*',
129 default, lines[i])
130
131
132 def set_timeout(self):
133 lines = (self.preamble).lines
134 for i in range(len(lines)):
135 lines[i] = re.sub(r'^timeout.*/',
136 'timeout 60', lines[i])
137 lines[i] = re.sub(r'^(\s*terminal .*--timeout)=\d+',
138 r'\1=30', lines[i])
139
140
141# ----------------------------------------------------------------------
142
143# Note that the lines[] section, whilst fairly foul, is needed to make
144# sure we preserve the original entry intact with comments, formatting,
145# and bits we don't understand.
146
147class grub_entry:
148 def __init__(self, count):
149 self.lines = []
150 self.fields = {} # title, initrd, kernel, etc
151 self.index = count
152
153
154 def set(self, field, value):
155 print "setting '%s' to '%s'" % (field, value)
156 self.fields[field] = value
157 for i in range(len(self.lines)):
158 m = re.match(r'\s*' + field + r'\s+', self.lines[i])
159 if m:
160 self.lines[i] = m.group() + value + '\n'
161
162
163 def get(self, field):
164 return self.fields[field]
165
166
167 def print_entry(self):
168 print self.lines
169
170
171 def set_kernel_options(self, options):
172 kernel = self.get('kernel')
173 re.sub(r'(autotest_args:).*', r'\1'+options, kernel)
174 self.set('kernel', kernel)
175
176 def set_autotest_kernel(self):
177 kernel_words = []
178 found_path = False
179 # Want to copy most of the entry, replacing the 'path'
180 # part of the entry with vmlinux-autotest in the same
181 # dir, and make sure autotest_args: is (uniquely) added
182 for word in (self.get('kernel')).split():
183 if word.startswith('--'):
184 kernel_words.append(word)
185 continue
186 if not found_path:
187 word = os.path.dirname(word)+'vmlinuz-autotest'
188 found_path = True
189 if re.match(r'auto(bench|test)_args:', word):
190 break
191 kernel_words.append(word)
192 kernel_words.append('autotest_args: ')
193 self.set('kernel', string.join(kernel_words))