1 (* Apache HTTPD lens for Augeas
4 David Lutterkort <lutter@redhat.com>
5 Francis Giraldeau <francis.giraldeau@usherbrooke.ca>
6 Raphael Pinson <raphink@gmail.com>
9 Online Apache configuration manual: http://httpd.apache.org/docs/trunk/
12 This file is licensed under the LGPL v2+.
15 Sample usage of this lens in augtool
17 Apache configuration is represented by two main structures, nested sections
18 and directives. Sections are used as labels, while directives are kept as a
19 value. Sections and directives can have positional arguments inside values
20 of "arg" nodes. Arguments of sections must be the firsts child of the
23 This lens doesn't support automatic string quoting. Hence, the string must
24 be quoted when containing a space.
26 Create a new VirtualHost section with one directive:
27 > clear /files/etc/apache2/sites-available/foo/VirtualHost
28 > set /files/etc/apache2/sites-available/foo/VirtualHost/arg "172.16.0.1:80"
29 > set /files/etc/apache2/sites-available/foo/VirtualHost/directive "ServerAdmin"
30 > set /files/etc/apache2/sites-available/foo/VirtualHost/*[self::directive="ServerAdmin"]/arg "admin@example.com"
32 About: Configuration files
33 This lens applies to files in /etc/httpd and /etc/apache2. See <filter>.
42 (******************************************************************
44 *****************************************************************)
45 let dels (s:string) = del s s
47 (* The continuation sequence that indicates that we should consider the
48 * next line part of the current line *)
49 let cont = /\\\\\r?\n/
51 (* Whitespace within a line: space, tab, and the continuation sequence *)
52 let ws = /[ \t]/ | cont
54 (* Any possible character - '.' does not match \n *)
57 (* Any character preceded by a backslash *)
58 let esc_any = /\\\\(.|\n)/
60 (* Newline sequence - both for Unix and DOS newlines *)
63 (* Whitespace at the end of a line *)
64 let eol = del (ws* . nl) "\n"
66 (* deal with continuation lines *)
67 let sep_spc = del ws+ " "
68 let sep_osp = del ws* ""
69 let sep_eq = del (ws* . "=" . ws*) "="
71 let nmtoken = /[a-zA-Z:_][a-zA-Z0-9:_.-]*/
72 let word = /[a-z][a-z0-9._-]*/i
74 (* A complete line that is either just whitespace or a comment that only
75 * contains whitespace *)
76 let empty = [ del (ws* . /#?/ . ws* . nl) "\n" ]
78 let indent = Util.indent
80 (* A comment that is not just whitespace. We define it in terms of the
81 * things that are not allowed as part of such a comment:
82 * 1) Starts with whitespace
83 * 2) Ends with whitespace, a backslash or \r
84 * 3) Unescaped newlines
87 let comment_start = del (ws* . "#" . ws* ) "# " in
88 let unesc_eol = /[^\]?/ . nl in
89 let w = /[^\t\n\r \\]/ in
95 * let t = /[\t\n\r ]/ in
96 * let x = b . (t? . (s|w)* ) in
97 * but the definition of b depends on commit 244c0edd in 1.9.0 and
98 * would make the lens unusable with versions before 1.9.0. So we write
99 * x out which works in older versions, too
101 let x = /\\\\[\t\n\r ]?[^\n\\]*/ in
102 let line = ((r . s* . w|w|r) . (s|w)* . x*|(r.s* )?).w.(s*.w)* in
103 [ label "#comment" . comment_start . store line . eol ]
105 (* borrowed from shellvars.aug *)
106 let char_arg_sec = /([^\\ '"\t\r\n>]|[^ '"\t\r\n>]+[^\\ \t\r\n>])|\\\\"|\\\\'|\\\\ /
107 let char_arg_wl = /([^\\ '"},\t\r\n]|[^ '"},\t\r\n]+[^\\ '"},\t\r\n])/
110 let no_dquot = /[^"\\\r\n]/
111 in /"/ . (no_dquot|esc_any)* . /"/
113 let no_dquot = /([^ \t"\\\r\n]|[^"\\\r\n]+[^ \t"\\\r\n])/
114 in /"/ . (no_dquot|esc_any)* . no_dquot
117 let no_squot = /[^'\\\r\n]/
118 in /'/ . (no_squot|esc_any)* . /'/
121 (******************************************************************
123 *****************************************************************)
125 (* The arguments for a directive come in two flavors: quoted with single or
126 * double quotes, or bare. Bare arguments may not start with a single or
127 * double quote; since we also treat "word lists" special, i.e. lists
128 * enclosed in curly braces, bare arguments may not start with those,
131 * Bare arguments may not contain unescaped spaces, but we allow escaping
132 * with '\\'. Quoted arguments can contain anything, though the quote must
133 * be escaped with '\\'.
135 let bare = /([^{"' \t\n\r]|\\\\.)([^ \t\n\r]|\\\\.)*[^ \t\n\r\\]|[^{"' \t\n\r\\]/
137 let arg_quoted = [ label "arg" . store (dquot|squot) ]
138 let arg_bare = [ label "arg" . store bare ]
140 (* message argument starts with " but ends at EOL *)
141 let arg_dir_msg = [ label "arg" . store dquot_msg ]
142 let arg_wl = [ label "arg" . store (char_arg_wl+|dquot|squot) ]
144 (* comma-separated wordlist as permitted in the SSLRequire directive *)
146 let wl_start = dels "{" in
147 let wl_end = dels "}" in
148 let wl_sep = del /[ \t]*,[ \t]*/ ", "
149 in [ label "wordlist" . wl_start . arg_wl . (wl_sep . arg_wl)* . wl_end ]
151 let argv (l:lens) = l . (sep_spc . l)*
153 (* the arguments of a directive. We use this once we have parsed the name
154 * of the directive, and the space right after it. When dir_args is used,
155 * we also know that we have at least one argument. We need to be careful
156 * with the spacing between arguments: quoted arguments and word lists do
157 * not need to have space between them, but bare arguments do.
159 * Apache apparently is also happy if the last argument starts with a double
160 * quote, but has no corresponding closing duoble quote, which is what
161 * arg_dir_msg handles
164 let arg_nospc = arg_quoted|arg_wordlist in
165 (arg_bare . sep_spc | arg_nospc . sep_osp)* . (arg_bare|arg_nospc|arg_dir_msg)
168 [ indent . label "directive" . store word . (sep_spc . dir_args)? . eol ]
170 let arg_sec = [ label "arg" . store (char_arg_sec+|comp|dquot|squot) ]
172 let section (body:lens) =
173 (* opt_eol includes empty lines *)
174 let opt_eol = del /([ \t]*#?[ \t]*\r?\n)*/ "\n" in
175 let inner = (sep_spc . argv arg_sec)? . sep_osp .
176 dels ">" . opt_eol . ((body|comment) . (body|empty|comment)*)? .
177 indent . dels "</" in
178 let kword = key (word - /perl/i) in
179 let dword = del (word - /perl/i) "a" in
180 [ indent . dels "<" . square kword inner dword . del />[ \t\n\r]*/ ">\n" ]
182 let perl_section = [ indent . label "Perl" . del /<perl>/i "<Perl>"
184 . del /<\/perl>/i "</Perl>" . eol ]
187 let rec content = section (content|directive)
190 let lns = (content|directive|comment|empty)*
192 let filter = (incl "/etc/apache2/apache2.conf") .
193 (incl "/etc/apache2/httpd.conf") .
194 (incl "/etc/apache2/ports.conf") .
195 (incl "/etc/apache2/conf.d/*") .
196 (incl "/etc/apache2/conf-available/*.conf") .
197 (incl "/etc/apache2/mods-available/*") .
198 (incl "/etc/apache2/sites-available/*") .
199 (incl "/etc/apache2/vhosts.d/*.conf") .
200 (incl "/etc/httpd/conf.d/*.conf") .
201 (incl "/etc/httpd/httpd.conf") .
202 (incl "/etc/httpd/conf/httpd.conf") .
203 (incl "/etc/httpd/conf.modules.d/*.conf") .
206 let xfm = transform lns filter