1# 2# ExtLinuxConf.py - Simple syslinux config parsing 3# 4# Copyright 2010 Citrix Systems Ltd. 5# 6# This software may be freely redistributed under the terms of the GNU 7# general public license. 8# 9# You should have received a copy of the GNU General Public License 10# along with this program; If not, see <http://www.gnu.org/licenses/>. 11# 12 13import sys, re, os 14import logging 15import GrubConf 16 17class ExtLinuxImage(object): 18 def __init__(self, lines, path): 19 self.reset(lines, path) 20 21 def __repr__(self): 22 return ("title: %s\n" 23 " root: %s\n" 24 " kernel: %s\n" 25 " args: %s\n" 26 " initrd: %s\n" %(self.title, self.root, self.kernel, 27 self.args, self.initrd)) 28 def reset(self, lines, path): 29 self._initrd = self._kernel = self._readonly = None 30 self._args = "" 31 self.title = "" 32 self.lines = [] 33 self.path = path 34 self.root = "" 35 map(self.set_from_line, lines) 36 37 def set_from_line(self, line, replace = None): 38 (com, arg) = GrubConf.grub_exact_split(line, 2) 39 com = com.lower() 40 41 # Special handling for mboot.c32 42 if com.lower() == "append" and self.kernel is not None: 43 (_,kernel) = self.kernel 44 if kernel.endswith("mboot.c32"): 45 kernel = None 46 args = None 47 initrd = None 48 modules = arg.split("---") 49 50 if len(modules) == 3: # Assume Xen + Kernel + Initrd 51 (_,kernel,initrd) = modules 52 elif len(modules) == 2: # Assume Kernel + Initrd 53 (kernel,initrd) = modules 54 55 if kernel: 56 setattr(self, "kernel", kernel.strip()) 57 if initrd: 58 setattr(self, "initrd", initrd.strip()) 59 60 # Bypass regular self.commands handling 61 com = None 62 elif "initrd=" in arg: 63 # find initrd image in append line 64 args = arg.strip().split(" ") 65 for a in args: 66 if a.lower().startswith("initrd="): 67 setattr(self, "initrd", a.replace("initrd=", "")) 68 arg = arg.replace(a, "") 69 70 if com is not None and self.commands.has_key(com): 71 if self.commands[com] is not None: 72 setattr(self, self.commands[com], re.sub('^"(.+)"$', r"\1", arg.strip())) 73 else: 74 logging.info("Ignored image directive %s" %(com,)) 75 elif com is not None: 76 logging.warning("Unknown image directive %s" %(com,)) 77 78 # now put the line in the list of lines 79 if replace is None: 80 self.lines.append(line) 81 else: 82 self.lines.pop(replace) 83 self.lines.insert(replace, line) 84 85 def set_kernel(self, val): 86 if val.find(" ") == -1: 87 self._kernel = (None,val) 88 self._args = None 89 return 90 (kernel, args) = val.split(None, 1) 91 self._kernel = (None,kernel) 92 self._args = args 93 def get_kernel(self): 94 return self._kernel 95 def set_args(self, val): 96 self._args = val 97 def get_args(self): 98 return self._args 99 kernel = property(get_kernel, set_kernel) 100 args = property(get_args, set_args) 101 102 def set_initrd(self, val): 103 self._initrd = (None,val) 104 def get_initrd(self): 105 return self._initrd 106 initrd = property(get_initrd, set_initrd) 107 108 def set_readonly(self, val): 109 self._readonly = 1 110 def get_readonly(self): 111 return self._readonly 112 readonly = property(get_readonly, set_readonly) 113 114 # set up command handlers 115 commands = { 116 "label": "title", 117 "kernel": "kernel", 118 "append": "args"} 119 120class ExtLinuxConfigFile(object): 121 def __init__(self, fn = None): 122 self.filename = fn 123 self.images = [] 124 self.timeout = -1 125 self._default = 0 126 127 if fn is not None: 128 self.parse() 129 130 def new_image(self, title, lines): 131 # ExtLinuxImage constructor doesn't have title but since path 132 # is being used by get_{kernel|initrd} functions we pass 133 # empty string rather than None (see lines above) 134 return ExtLinuxImage(lines, "") 135 136 def parse(self, buf = None): 137 if buf is None: 138 if self.filename is None: 139 raise ValueError, "No config file defined to parse!" 140 141 f = open(self.filename, 'r') 142 lines = f.readlines() 143 f.close() 144 else: 145 lines = buf.split("\n") 146 147 path = os.path.dirname(self.filename) 148 img = [] 149 for l in lines: 150 l = l.strip() 151 # skip blank lines 152 if len(l) == 0: 153 continue 154 # skip comments 155 if l.startswith('#'): 156 continue 157 # new image 158 if l.lower().startswith("label"): 159 if len(img) > 0: 160 self.add_image(ExtLinuxImage(img, path)) 161 img = [l] 162 continue 163 164 if len(img) > 0: 165 img.append(l) 166 continue 167 168 (com, arg) = GrubConf.grub_exact_split(l, 2) 169 com = com.lower() 170 if self.commands.has_key(com): 171 if self.commands[com] is not None: 172 setattr(self, self.commands[com], arg.strip()) 173 else: 174 logging.info("Ignored directive %s" %(com,)) 175 else: 176 logging.warning("Unknown directive %s" %(com,)) 177 178 if len(img) > 0: 179 self.add_image(ExtLinuxImage(img, path)) 180 181 def hasPassword(self): 182 return False 183 184 def hasPasswordAccess(self): 185 return True 186 187 def add_image(self, image): 188 self.images.append(image) 189 190 def _get_default(self): 191 for i in range(len(self.images)): 192 if self.images[i].title == self._default: 193 return i 194 return 0 195 def _set_default(self, val): 196 self._default = val 197 default = property(_get_default, _set_default) 198 199 commands = { "default": "default", 200 "timeout": "timeout", 201 "serial": None, 202 "prompt": None, 203 "display": None, 204 "f1": None, 205 "f2": None, 206 } 207 208if __name__ == "__main__": 209 if len(sys.argv) < 2: 210 raise RuntimeError, "Need a configuration file to read" 211 g = ExtLinuxConfigFile(sys.argv[1]) 212 for i in g.images: 213 print i 214 print g.default 215