1(* Intefraces module for Augeas
2   Author: Free Ekanayaka <free@64studio.com>
3
4   Reference: man dhclient.conf
5   The only difference with the reference syntax is that this lens assumes
6   that statements end with a new line, while the reference syntax allows
7   new statements to be started right after the trailing ";" of the
8   previous statement. This should not be a problem in real-life
9   configuration files as statements get usually split across several
10   lines, rather than merged in a single one.
11
12*)
13
14module Dhclient =
15
16   autoload xfm
17
18(************************************************************************
19 *                           USEFUL PRIMITIVES
20 *************************************************************************)
21
22let eol               = Util.eol
23let comment           = Util.comment
24let comment_or_eol    = Util.comment_or_eol
25let empty             = Util.empty
26
27(* Define separators *)
28let sep_spc           = del /[ \t\n]+/ " "
29let sep_scl           = del /[ \t]*;/ ";"
30let sep_obr           = del /[ \t\n]*\{\n]*/ " {\n"
31let sep_cbr           = del /[ \t\n]*\}/ " }"
32let sep_com           = del /[ \t\n]*,[ \t\n]*/ ","
33let sep_slh           = del "\/" "/"
34let sep_col           = del ":" ":"
35let sep_eq            = del /[ \t]*=[ \t]*/ "="
36
37(* Define basic types *)
38let word              = /[A-Za-z0-9_.-]+(\[[0-9]+\])?/
39
40(* Define fields *)
41
42(* TODO: there could be a " " in the middle of a value ... *)
43let sto_to_spc        = store /[^\\#,;{}" \t\n]+|"[^\\#"\n]+"/
44let sto_to_spc_noeval = store /[^=\\#,;{}" \t\n]|[^=\\#,;{}" \t\n][^\\#,;{}" \t\n]*|"[^\\#"\n]+"/
45let sto_to_scl        = store /[^ \t\n][^;\n]+[^ \t]|[^ \t;\n]+/
46let rfc_code          = [ key "code" . sep_spc . store word ]
47                      . sep_eq
48                      . [ label "value" . sto_to_scl ]
49let eval              = [ label "#eval" . Sep.equal . sep_spc . sto_to_scl ]
50let sto_number        = store /[0-9][0-9]*/
51
52(************************************************************************
53 *                         SIMPLE STATEMENTS
54 *************************************************************************)
55
56let stmt_simple_re    = "timeout"
57                      | "retry"
58                      | "select-timeout"
59                      | "reboot"
60                      | "backoff-cutoff"
61                      | "initial-interval"
62                      | "do-forward-updates"
63                      | "reject"
64
65let stmt_simple       = [ key stmt_simple_re
66                        . sep_spc
67                        . sto_to_spc
68                        . sep_scl
69                        . comment_or_eol ]
70
71
72(************************************************************************
73 *                          ARRAY STATEMENTS
74 *************************************************************************)
75
76(* TODO: the array could also be empty, like in the request statement *)
77let stmt_array_re     = "media"
78                      | "request"
79                      | "require"
80
81let stmt_array        = [ key stmt_array_re
82                        . sep_spc
83                        . counter "stmt_array"
84                        . [ seq "stmt_array" . sto_to_spc ]
85                        . [ sep_com . seq "stmt_array" . sto_to_spc ]*
86                        . sep_scl . comment_or_eol ]
87
88(************************************************************************
89 *                          HASH STATEMENTS
90 *************************************************************************)
91
92
93let stmt_hash_re      = "send"
94                      | "option"
95
96let stmt_args         = ( [ key word . sep_spc . sto_to_spc_noeval ]
97                          | [ key word . sep_spc . (rfc_code|eval) ] )
98                        . sep_scl
99                        . comment_or_eol
100
101let stmt_hash         = [ key stmt_hash_re
102                        . sep_spc
103                        . stmt_args ]
104
105let stmt_opt_mod_re   = "append"
106                      | "prepend"
107                      | "default"
108                      | "supersede"
109
110let stmt_opt_mod      = [ key stmt_opt_mod_re
111                        . sep_spc
112                        . stmt_args ]
113
114(************************************************************************
115 *                         BLOCK STATEMENTS
116 *************************************************************************)
117
118let stmt_block_re     = "interface"
119                      | "lease"
120                      | "alias"
121
122let stmt_block_opt_re = "interface"
123                      | "script"
124                      | "bootp"
125                      | "fixed-address"
126                      | "filename"
127                      | "server-name"
128                      | "medium"
129                      | "vendor option space"
130
131(* TODO: some options could take no argument like bootp *)
132let stmt_block_opt    = [ key stmt_block_opt_re
133                         . sep_spc
134                         . sto_to_spc
135                         . sep_scl
136                         . comment_or_eol ]
137
138let stmt_block_date_re
139                      = "renew"
140                      | "rebind"
141                      | "expire"
142
143let stmt_block_date   = [ key stmt_block_date_re
144                        . [ sep_spc . label "weekday" . sto_number ]
145                        . [ sep_spc . label "year"    . sto_number ]
146                        . [ sep_slh . label "month"   . sto_number ]
147                        . [ sep_slh . label "day"     . sto_number ]
148                        . [ sep_spc . label "hour"    . sto_number ]
149                        . [ sep_col . label "minute"  . sto_number ]
150                        . [ sep_col . label "second"  . sto_number ]
151                        . sep_scl
152                        . comment_or_eol ]
153
154let stmt_block_arg    = sep_spc . sto_to_spc
155
156let stmt_block_entry  = sep_spc
157                      . ( stmt_array
158                        | stmt_hash
159                        | stmt_opt_mod
160                        | stmt_block_opt
161                        | stmt_block_date )
162
163let stmt_block        = [ key stmt_block_re
164                        . stmt_block_arg?
165                        . sep_obr
166                        . stmt_block_entry+
167                        . sep_cbr
168                        . comment_or_eol ]
169
170(************************************************************************
171 *                              LENS & FILTER
172 *************************************************************************)
173
174let statement = (stmt_simple|stmt_opt_mod|stmt_array|stmt_hash|stmt_block)
175
176let lns               = ( empty
177                        | comment
178                        | statement )*
179
180let filter            = incl "/etc/dhcp3/dhclient.conf"
181                      . incl "/etc/dhcp/dhclient.conf"
182                      . incl "/etc/dhclient.conf"
183
184let xfm                = transform lns filter
185