mbligh | f4c3532 | 2006-03-13 01:01:10 +0000 | [diff] [blame] | 1 | # 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 | |
| 5 | import shutil |
| 6 | import re |
| 7 | import os |
| 8 | import os.path |
| 9 | import string |
| 10 | |
| 11 | class 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 | |
| 147 | class 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)) |