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