3 Generic lens for shell-script config files like the ones found
7 This file is licenced under the LGPL v2+, like the rest of Augeas.
16 (* Delete a blank line, rather than mapping it *)
17 let del_empty = del (Util.empty_generic_re . "\n") "\n"
19 let empty = Util.empty
20 let empty_part_re = Util.empty_generic_re . /\n+/
21 let eol = del (/[ \t]+|[ \t]*[;\n]/ . empty_part_re*) "\n"
22 let semicol_eol = del (/[ \t]*[;\n]/ . empty_part_re*) "\n"
23 let brace_eol = del /[ \t\n]+/ "\n"
25 let key_re = /[A-Za-z0-9_]+(\[[0-9A-Za-z_,]+\])?/ - ("unset" | "export")
26 let matching_re = "${!" . key_re . /[\*@]\}/
27 let eq = Util.del_str "="
29 let eol_for_comment = del /([ \t]*\n)([ \t]*(#[ \t]*)?\n)*/ "\n"
30 let comment = Util.comment_generic_seteol /[ \t]*#[ \t]*/ " # " eol_for_comment
31 (* comment_eol in shell MUST begin with a space *)
32 let comment_eol = Util.comment_generic_seteol /[ \t]+#[ \t]*/ " # " eol_for_comment
33 let comment_or_eol = comment_eol | semicol_eol
35 let xchgs = Build.xchgs
36 let semicol = del /;?/ ""
38 let char = /[^`;()'"&|\n\\# \t]#*|\\\\./
40 let char = /[^"\\]|\\\\./ | Rx.cl
41 in "\"" . char* . "\"" (* " Emacs, relax *)
43 let bquot = /`[^`\n]+`/
44 (* dbquot don't take spaces or semi-colons *)
45 let dbquot = /``[^` \t\n;]+``/
46 let dollar_assign = /\$\([^\(\)#\n]*\)/
47 let dollar_arithm = /\$\(\([^\)#\n]*\)\)/
49 let anyquot = (char|dquot|squot|dollar_assign|dollar_arithm)+ | bquot | dbquot
50 let sto_to_semicol = store (anyquot . (Rx.cl_or_space . anyquot)*)
52 (* Array values of the form '(val1 val2 val3)'. We do not handle empty *)
53 (* arrays here because of typechecking headaches. Instead, they are *)
54 (* treated as a simple value *)
56 let array_value = store anyquot in
57 del /\([ \t]*/ "(" . counter "values" .
58 [ seq "values" . array_value ] .
59 [ del /[ \t\n]+/ " " . seq "values" . array_value ] *
62 (* Treat an empty list () as a value '()'; that's not quite correct *)
63 (* but fairly close. *)
65 let empty_array = /\([ \t]*\)/ in
66 store (anyquot | empty_array)?
68 let export = [ key "export" . Util.del_ws_spc ]
69 let kv = Util.indent . export? . key key_re
70 . eq . (simple_value | array)
72 let var_action (name:string) =
73 Util.indent . del name name . Util.del_ws_spc
74 . label ("@" . name) . counter "var_action"
75 . Build.opt_list [ seq "var_action" . store (key_re | matching_re) ] Util.del_ws_spc
77 let unset = var_action "unset"
78 let bare_export = var_action "export"
82 . del /\.|source/ "." . label ".source"
83 . Util.del_ws_spc . store /[^;=# \t\n]+/
85 let shell_builtin_cmds = "ulimit" | "shift" | "exit"
88 Util.indent . Util.del_str "eval" . Util.del_ws_spc
89 . label "@eval" . store anyquot
92 Util.indent . Util.del_str "alias" . Util.del_ws_spc
93 . label "@alias" . store key_re . eq
94 . [ label "value" . store anyquot ]
97 Util.indent . label "@builtin"
98 . store shell_builtin_cmds
100 . [ label "args" . sto_to_semicol ])?
102 let keyword (kw:string) = Util.indent . Util.del_str kw
103 let keyword_label (kw:string) (lbl:string) = keyword kw . label lbl
106 Util.indent . label "@return"
107 . Util.del_str "return"
108 . ( Util.del_ws_spc . store Rx.integer )?
110 let action (operator:string) (lbl:string) (sto:lens) =
111 let sp = Rx.cl_or_opt_space | /[ \t\n]+/
112 in [ del (sp . operator . sp) (" " . operator . " ")
113 . label ("@".lbl) . sto ]
115 let action_pipe = action "|" "pipe"
116 let action_and = action "&&" "and"
117 let action_or = action "||" "or"
120 let cond (start:string) (end:string) = [ label "type" . store start ]
121 . Util.del_ws_spc . sto_to_semicol
122 . Util.del_ws_spc . Util.del_str end
123 . ( action_and sto_to_semicol | action_or sto_to_semicol )*
124 in Util.indent . label "@condition" . (cond "[" "]" | cond "[[" "]]")
127 let entry_eol_item (item:lens) = [ item . comment_or_eol ]
128 let entry_item (item:lens) = [ item ]
130 let entry_eol_nocommand =
131 entry_eol_item source
133 | entry_eol_item unset
134 | entry_eol_item bare_export
135 | entry_eol_item builtin
136 | entry_eol_item return
137 | entry_eol_item condition
138 | entry_eol_item eval
139 | entry_eol_item alias
141 let entry_noeol_nocommand =
145 | entry_item bare_export
148 | entry_item condition
154 let env = [ key key_re . eq . store anyquot . Sep.cl_or_space ]
155 in let reserved_key = /exit|shift|return|ulimit|unset|export|source|\.|if|for|select|while|until|then|else|fi|done|case|eval|alias/
156 in let word = /[A-Za-z0-9_.-\/]+/
157 in let entry_eol = entry_eol_nocommand | entry_eol_item command
158 in let entry_noeol = entry_noeol_nocommand | entry_item command
159 in let entry = entry_eol | entry_noeol
160 in let pipe = action_pipe (entry_eol_item command | entry_item command)
161 in let and = action_and entry
162 in let or = action_or entry
163 in Util.indent . label "@command" . env* . store (word - reserved_key)
164 . [ Sep.cl_or_space . label "@arg" . sto_to_semicol]?
165 . ( pipe | and | or )?
167 let entry_eol = entry_eol_nocommand
168 | entry_eol_item command
170 let entry_noeol = entry_noeol_nocommand
173 (************************************************************************
174 * Group: CONDITIONALS AND LOOPS
175 *************************************************************************)
177 let generic_cond_start (start_kw:string) (lbl:string)
178 (then_kw:string) (contents:lens) =
179 keyword_label start_kw lbl . Sep.space
180 . sto_to_semicol . semicol_eol
181 . keyword then_kw . eol
184 let generic_cond (start_kw:string) (lbl:string)
185 (then_kw:string) (contents:lens) (end_kw:string) =
186 [ generic_cond_start start_kw lbl then_kw contents
187 . keyword end_kw . comment_or_eol ]
189 let cond_if (entry:lens) =
190 let elif = [ generic_cond_start "elif" "@elif" "then" entry+ ] in
191 let else = [ keyword_label "else" "@else" . eol . entry+ ] in
192 generic_cond "if" "@if" "then" (entry+ . elif* . else?) "fi"
194 let loop_for (entry:lens) =
195 generic_cond "for" "@for" "do" entry+ "done"
197 let loop_while (entry:lens) =
198 generic_cond "while" "@while" "do" entry+ "done"
200 let loop_until (entry:lens) =
201 generic_cond "until" "@until" "do" entry+ "done"
203 let loop_select (entry:lens) =
204 generic_cond "select" "@select" "do" entry+ "done"
206 let case (entry:lens) (entry_noeol:lens) =
207 let pattern = [ label "@pattern" . sto_to_semicol . Sep.opt_space ]
208 in let case_entry = [ label "@case_entry"
209 . Util.indent . pattern
210 . (Util.del_str "|" . Sep.opt_space . pattern)*
211 . Util.del_str ")" . eol
212 . entry* . entry_noeol?
213 . Util.indent . Util.del_str ";;" . eol ] in
214 [ keyword_label "case" "@case" . Sep.space
215 . store (char+ | ("\"" . char+ . "\""))
216 . del /[ \t\n]+/ " " . Util.del_str "in" . eol
217 . (empty* . comment* . case_entry)*
219 . keyword "esac" . comment_or_eol ]
221 let subshell (entry:lens) =
222 [ Util.indent . label "@subshell"
223 . Util.del_str "{" . brace_eol
225 . Util.indent . Util.del_str "}" . eol ]
227 let function (entry:lens) =
228 [ Util.indent . label "@function"
229 . del /(function[ \t]+)?/ ""
230 . store Rx.word . del /[ \t]*\(\)/ "()"
231 . (comment_eol|brace_eol) . Util.del_str "{" . brace_eol
233 . Util.indent . Util.del_str "}" . eol ]
236 let entry = comment | entry_eol | rec_entry in
242 | case entry entry_noeol
246 let lns_norec = del_empty* . (comment | entry_eol) *
248 let lns = del_empty* . (comment | entry_eol | rec_entry) *
250 let sc_incl (n:string) = (incl ("/etc/sysconfig/" . n))
251 let sc_excl (n:string) = (excl ("/etc/sysconfig/" . n))
253 let filter_sysconfig =
255 sc_excl "bootloader" .
258 sc_excl "ip*tables" .
259 sc_excl "ip*tables.save" .
262 sc_excl "sysstat.ioconf" .
263 sc_excl "system-config-firewall" .
264 sc_excl "system-config-securitylevel" .
265 sc_incl "network/config" .
266 sc_incl "network/dhcp" .
267 sc_incl "network/dhcp6r" .
268 sc_incl "network/dhcp6s" .
269 sc_incl "network/ifcfg-*" .
270 sc_incl "network/if-down.d/*" .
271 sc_incl "network/ifroute-*" .
272 sc_incl "network/if-up.d/*" .
273 sc_excl "network/if-up.d/SuSEfirewall2" .
274 sc_incl "network/providers/*" .
275 sc_excl "network-scripts" .
276 sc_incl "network-scripts/ifcfg-*" .
278 sc_incl "rhn/allowed-actions/*" .
279 sc_excl "rhn/allowed-actions/script" .
280 sc_incl "rhn/allowed-actions/script/*" .
281 sc_incl "rhn/rhnsd" .
282 sc_excl "SuSEfirewall2.d" .
283 sc_incl "SuSEfirewall2.d/cobbler" .
284 sc_incl "SuSEfirewall2.d/services/*" .
285 sc_excl "SuSEfirewall2.d/services/TEMPLATE" .
288 let filter_default = incl "/etc/default/*"
289 . excl "/etc/default/grub_installdevice*"
290 . excl "/etc/default/rmt"
291 . excl "/etc/default/star"
292 . excl "/etc/default/whoopsie"
293 . incl "/etc/profile"
294 . incl "/etc/profile.d/*"
295 let filter_misc = incl "/etc/arno-iptables-firewall/debconf.cfg"
296 . incl "/etc/conf.d/*"
297 . incl "/etc/cron-apt/config"
298 . incl "/etc/environment"
299 . incl "/etc/firewalld/firewalld.conf"
300 . incl "/etc/blkid.conf"
301 . incl "/etc/adduser.conf"
302 . incl "/etc/cowpoke.conf"
303 . incl "/etc/cvs-cron.conf"
304 . incl "/etc/cvs-pserver.conf"
305 . incl "/etc/devscripts.conf"
306 . incl "/etc/kamailio/kamctlrc"
307 . incl "/etc/lbu/lbu.conf"
308 . incl "/etc/lintianrc"
309 . incl "/etc/lsb-release"
310 . incl "/etc/os-release"
311 . incl "/etc/periodic.conf"
312 . incl "/etc/popularity-contest.conf"
313 . incl "/etc/rc.conf"
314 . incl "/etc/rc.conf.local"
315 . incl "/etc/selinux/config"
316 . incl "/etc/ucf.conf"
317 . incl "/etc/locale.conf"
318 . incl "/etc/vconsole.conf"
319 . incl "/etc/byobu/*"
321 let filter = filter_sysconfig
326 let xfm = transform lns filter
328 (* Local Variables: *)