3 Parses grub configuration
5 Author: David Lutterkort <lutter@redhat.com>
8 This file is licenced under the LGPL v2+, like the rest of Augeas.
17 (* This only covers the most basic grub directives. Needs to be *)
18 (* expanded to cover more (and more esoteric) directives *)
19 (* It is good enough to handle the grub.conf on my Fedora 8 box *)
22 (************************************************************************
23 * Group: USEFUL PRIMITIVES
24 *************************************************************************)
26 (* View: value_to_eol *)
27 let value_to_eol = store /[^= \t\n][^\n]*[^= \t\n]|[^= \t\n]/
33 let spc = Util.del_ws_spc
36 let opt_ws = Util.del_opt_ws ""
39 let dels (s:string) = Util.del_str s
45 let switch (n:regexp) = dels "--" . key n
47 (* View: switch_arg *)
48 let switch_arg (n:regexp) = switch n . eq . store Rx.no_spaces
51 let value_sep (dflt:string) = del /[ \t]*[ \t=][ \t]*/ dflt
53 (* View: comment_re *)
54 let comment_re = /([^ \t\n].*[^ \t\n]|[^ \t\n])/
55 - /# ## (Start|End) Default Options ##/
59 [ Util.indent . label "#comment" . del /#[ \t]*/ "# "
60 . store comment_re . eol ]
63 let empty = Util.empty
65 (************************************************************************
66 * Group: USEFUL FUNCTIONS
67 *************************************************************************)
70 let command (kw:regexp) (indent:string) =
71 Util.del_opt_ws indent . key kw
74 let kw_arg (kw:regexp) (indent:string) (dflt_sep:string) =
75 [ command kw indent . value_sep dflt_sep . value_to_eol . eol ]
77 (* View: kw_boot_arg *)
78 let kw_boot_arg (kw:regexp) = kw_arg kw "\t" " "
80 (* View: kw_menu_arg *)
81 let kw_menu_arg (kw:regexp) = kw_arg kw "" " "
83 (* View: password_arg *)
84 let password_arg = [ command "password" "" .
85 (spc . [ switch "md5" ])? .
86 (spc . [ switch "encrypted" ])? .
87 spc . store (/[^ \t\n]+/ - /--[^ \t\n]+/) .
88 (spc . [ label "file" . store /[^ \t\n]+/ ])? .
92 let kw_pres (kw:string) = [ opt_ws . key kw . eol ]
95 * Parse a line that looks almost like a valid setting, but isn't,
96 * into an '#error' node. Any line that starts with letters, but not
97 * anything matching kw, is considered an error line.
100 * kw:regexp - the valid keywords that are _not_ considered an
103 let error (kw:regexp) =
104 let not_kw = /[a-zA-Z]+/ - kw in
105 [ label "#error" . Util.del_opt_ws "\t"
106 . store (not_kw . /([^a-zA-Z\n].*[^ \t\n])?/) . eol ]
109 (************************************************************************
110 * Group: BOOT ENTRIES
111 *************************************************************************)
114 * This is a shell-only directive in upstream grub; the grub versions
115 * in at least Fedora/RHEL use this to find devices for UEFI boot *)
117 [ command "device" "" . Sep.space . store /\([A-Za-z0-9_.-]+\)/ . spc .
118 [ label "file" . value_to_eol ] . Util.eol ]
122 (* Should we nail it down to exactly the color names that *)
123 (* grub supports ? *)
124 let color_name = store /[A-Za-z-]+/ in
126 [ label "foreground" . color_name] .
128 [ label "background" . color_name ] in
129 [ opt_ws . key "color" .
130 spc . [ label "normal" . color_spec ] .
131 (spc . [ label "highlight" . color_spec ])? .
136 [ command "serial" "" .
137 [ spc . switch_arg /unit|port|speed|word|parity|stop|device/ ]* .
142 [ command "terminal" "" .
143 ([ spc . switch /dumb|no-echo|no-edit|silent/ ]
144 |[ spc . switch_arg /timeout|lines/ ])* .
145 [ spc . key /console|serial|hercules/ ]* . eol ]
148 let setkey = [ command "setkey" "" .
149 ( spc . [ label "to" . store Rx.no_spaces ] .
150 spc . [ label "from" . store Rx.no_spaces ] )? .
153 (* View: menu_entry *)
154 let menu_entry = kw_menu_arg "default"
155 | kw_menu_arg "fallback"
156 | kw_pres "hiddenmenu"
157 | kw_menu_arg "timeout"
158 | kw_menu_arg "splashimage"
159 | kw_menu_arg "gfxmenu"
160 | kw_menu_arg "foreground"
161 | kw_menu_arg "background"
162 | kw_menu_arg "verbose"
163 | kw_menu_arg "boot" (* only for CLI, ignored in conf *)
172 * Accept lines not matching menu_entry and stuff them into
176 let kw = /default|fallback|hiddenmenu|timeout|splashimage|gfxmenu/
177 |/foreground|background|verbose|boot|password|title/
178 |/serial|setkey|terminal|color|device/ in
181 (* View: menu_setting
182 * a valid menu setting or a line that looks like one but is an #error
184 let menu_setting = menu_entry | menu_error
187 let title = del /title[ \t=]+/ "title " . value_to_eol . eol
189 (* View: multiboot_arg
190 * Permits a second form for Solaris multiboot kernels that
191 * take a path (with a slash) as their first arg, e.g.
192 * /boot/multiboot kernel/unix another=arg *)
193 let multiboot_arg = [ label "@path" .
194 store (Rx.word . "/" . Rx.no_spaces) ]
197 Parse the file name and args on a kernel or module line. *)
199 let arg = /[A-Za-z0-9_.$\+-]+/ - /type|no-mem-option/ in
200 store /(\([a-z0-9,]+\))?\/[^ \t\n]*/ .
201 (spc . multiboot_arg)? .
202 (spc . [ key arg . (eq. store /([^ \t\n])*/)?])* . eol
205 Solaris extension adds module$ and kernel$ for variable interpolation *)
207 [ command /module\$?/ "\t" . spc . kernel_args ]
211 [ command "map" "\t" . spc .
212 [ label "from" . store /[()A-za-z0-9]+/ ] . spc .
213 [ label "to" . store /[()A-za-z0-9]+/ ] . eol ]
217 [ command /kernel\$?/ "\t" .
219 ([switch "type" . eq . store /[a-z]+/]
220 |[switch "no-mem-option"]))* .
223 (* View: chainloader *)
225 [ command "chainloader" "\t" .
226 [ spc . switch "force" ]? . spc . store Rx.no_spaces . eol ]
228 (* View: savedefault *)
230 [ command "savedefault" "\t" . (spc . store Rx.integer)? . eol ]
232 (* View: configfile *)
234 [ command "configfile" "\t" . spc . store Rx.no_spaces . eol ]
239 let boot_arg_re = "root" | "initrd" | "rootnoverify" | "uuid"
240 | "findroot" | "bootfs" (* Solaris extensions *)
241 in kw_boot_arg boot_arg_re
244 | kw_pres "quiet" (* Seems to be a Ubuntu extension *)
250 | kw_pres "makeactive"
254 * Accept lines not matching boot_entry and stuff them into
258 let kw = /lock|uuid|password|root|initrd|rootnoverify|findroot|bootfs/
259 |/configfile|chainloader|title|boot|quiet|kernel|module/
260 |/makeactive|savedefault|map/ in
263 (* View: boot_setting
264 * a valid boot setting or a line that looks like one but is an #error
266 let boot_setting = boot_entry | boot_error
270 let line = ((boot_setting|comment)* . boot_setting)? in
271 [ label "title" . title . line ]
273 (************************************************************************
274 * Group: DEBIAN-SPECIFIC SECTIONS
275 *************************************************************************)
277 (* View: debian_header
278 Header for a <debian>-specific section *)
279 let debian_header = "## ## Start Default Options ##\n"
281 (* View: debian_footer
282 Footer for a <debian>-specific section *)
283 let debian_footer = "## ## End Default Options ##\n"
285 (* View: debian_comment_re *)
286 let debian_comment_re = /([^ \t\n].*[^ \t\n]|[^ \t\n])/
287 - "## End Default Options ##"
289 (* View: debian_comment
290 A comment entry inside a <debian>-specific section *)
292 [ Util.indent . label "#comment" . del /##[ \t]*/ "## "
293 . store debian_comment_re . eol ]
295 (* View: debian_setting_re *)
296 let debian_setting_re = "kopt"
307 | "updatedefaultentry"
311 (* View: debian_entry *)
312 let debian_entry = [ Util.del_str "#" . Util.indent
313 . key debian_setting_re . del /[ \t]*=/ "="
314 . value_to_eol? . eol ]
317 A debian-specific section, made of <debian_entry> lines *)
318 let debian = [ label "debian"
319 . del debian_header debian_header
320 . (debian_comment|empty|debian_entry)*
321 . del debian_footer debian_footer ]
323 (************************************************************************
324 * Group: LENS AND FILTER
325 *************************************************************************)
328 let lns = (comment | empty | menu_setting | debian)*
329 . (boot . (comment | empty | boot)*)?
332 let filter = incl "/boot/grub/grub.conf"
333 . incl "/boot/grub/menu.lst"
334 . incl "/etc/grub.conf"
335 . incl "/boot/efi/EFI/*/grub.conf"
337 let xfm = transform lns filter