377f00ace2cdf93753b7fbd495cc335776e6108f
[platform/upstream/augeas.git] / lenses / shellvars.aug
1 (*
2 Module: Shellvars
3  Generic lens for shell-script config files like the ones found
4  in /etc/sysconfig
5
6 About: License
7    This file is licenced under the LGPL v2+, like the rest of Augeas.
8
9 About: Lens Usage
10    To be documented
11 *)
12
13 module Shellvars =
14   autoload xfm
15
16   (* Delete a blank line, rather than mapping it *)
17   let del_empty = del (Util.empty_generic_re . "\n") "\n"
18
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"
24
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 "="
28
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
34
35   let xchgs   = Build.xchgs
36   let semicol = del /;?/ ""
37
38   let char  = /[^`;()'"&|\n\\# \t]#*|\\\\./
39   let dquot =
40        let char = /[^"\\]|\\\\./ | Rx.cl
41     in "\"" . char* . "\""                    (* " Emacs, relax *)
42   let squot = /'[^']*'/
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]*\)\)/
48
49   let anyquot = (char|dquot|squot|dollar_assign|dollar_arithm)+ | bquot | dbquot
50   let sto_to_semicol = store (anyquot . (Rx.cl_or_space . anyquot)*)
51
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                                           *)
55   let array =
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 ] *
60       . del /[ \t]*\)/ ")"
61
62   (* Treat an empty list () as a value '()'; that's not quite correct *)
63   (* but fairly close.                                                *)
64   let simple_value =
65     let empty_array = /\([ \t]*\)/ in
66       store (anyquot | empty_array)?
67
68   let export = [ key "export" . Util.del_ws_spc ]
69   let kv = Util.indent . export? . key key_re
70            . eq . (simple_value | array)
71
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
76
77   let unset = var_action "unset"
78   let bare_export = var_action "export"
79
80   let source =
81     Util.indent
82     . del /\.|source/ "." . label ".source"
83     . Util.del_ws_spc . store /[^;=# \t\n]+/
84
85   let shell_builtin_cmds = "ulimit" | "shift" | "exit"
86
87   let eval =
88     Util.indent . Util.del_str "eval" . Util.del_ws_spc
89     . label "@eval" . store anyquot
90
91   let alias =
92     Util.indent . Util.del_str "alias" . Util.del_ws_spc
93     . label "@alias" . store key_re . eq
94     . [ label "value" . store anyquot ]
95
96   let builtin =
97     Util.indent . label "@builtin"
98     . store shell_builtin_cmds
99     . (Sep.cl_or_space
100     . [ label "args" . sto_to_semicol ])?
101
102   let keyword (kw:string) = Util.indent . Util.del_str kw
103   let keyword_label (kw:string) (lbl:string) = keyword kw . label lbl
104
105   let return =
106     Util.indent . label "@return"
107     . Util.del_str "return"
108     . ( Util.del_ws_spc . store Rx.integer )?
109
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 ]
114
115   let action_pipe = action "|" "pipe"
116   let action_and = action "&&" "and"
117   let action_or = action "||" "or"
118
119   let condition =
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 "[[" "]]")
125
126   (* Entry types *)
127   let entry_eol_item (item:lens) = [ item . comment_or_eol ]
128   let entry_item (item:lens) = [ item ]
129
130   let entry_eol_nocommand =
131       entry_eol_item source
132         | entry_eol_item kv
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
140
141   let entry_noeol_nocommand =
142       entry_item source
143         | entry_item kv
144         | entry_item unset
145         | entry_item bare_export
146         | entry_item builtin
147         | entry_item return
148         | entry_item condition
149         | entry_item eval
150         | entry_item alias
151
152   (* Command *)
153   let rec command =
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 )?
166
167   let entry_eol = entry_eol_nocommand
168                 | entry_eol_item command
169
170   let entry_noeol = entry_noeol_nocommand
171                   | entry_item command
172
173 (************************************************************************
174  * Group:                 CONDITIONALS AND LOOPS
175  *************************************************************************)
176
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
182       . contents
183
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 ]
188
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"
193
194   let loop_for (entry:lens) =
195     generic_cond "for" "@for" "do" entry+ "done"
196
197   let loop_while (entry:lens) =
198     generic_cond "while" "@while" "do" entry+ "done"
199
200   let loop_until (entry:lens) =
201     generic_cond "until" "@until" "do" entry+ "done"
202
203   let loop_select (entry:lens) =
204     generic_cond "select" "@select" "do" entry+ "done"
205
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)*
218         . empty* . comment*
219         . keyword "esac" . comment_or_eol ]
220
221   let subshell (entry:lens) =
222     [ Util.indent . label "@subshell"
223     . Util.del_str "{" . brace_eol
224     . entry+
225     . Util.indent . Util.del_str "}" . eol ]
226
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
232     . entry+
233     . Util.indent . Util.del_str "}" . eol ]
234
235   let rec rec_entry =
236     let entry = comment | entry_eol | rec_entry in
237         cond_if entry
238       | loop_for entry
239       | loop_select entry
240       | loop_while entry
241       | loop_until entry
242       | case entry entry_noeol
243       | function entry
244       | subshell entry
245
246   let lns_norec = del_empty* . (comment | entry_eol) *
247
248   let lns = del_empty* . (comment | entry_eol | rec_entry) *
249
250   let sc_incl (n:string) = (incl ("/etc/sysconfig/" . n))
251   let sc_excl (n:string) = (excl ("/etc/sysconfig/" . n))
252
253   let filter_sysconfig =
254       sc_incl "*" .
255       sc_excl "bootloader" .
256       sc_excl "hw-uuid" .
257       sc_excl "hwconf" .
258       sc_excl "ip*tables" .
259       sc_excl "ip*tables.save" .
260       sc_excl "kernel" .
261       sc_excl "*.pub" .
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-*" .
277       sc_excl "rhn" .
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" .
286       sc_excl "*.systemd"
287
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/*"
320
321   let filter = filter_sysconfig
322              . filter_default
323              . filter_misc
324              . Util.stdexcl
325
326   let xfm = transform lns filter
327
328 (* Local Variables: *)
329 (* mode: caml       *)
330 (* End:             *)