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