3 * Parses xinetd configuration files
5 * The structure of the lens and allowed attributes are ripped directly
6 * from xinetd's parser in xinetd/parse.c in xinetd's source checkout
7 * The downside of being so precise here is that if attributes are added
8 * they need to be added here, too. Writing a catchall entry, and getting
9 * to typecheck correctly would be a huge pain.
11 * A really enterprising soul could tighten this down even further by
12 * restricting the acceptable values for each attribute.
14 * Author: David Lutterkort
20 let opt_spc = Util.del_opt_ws " "
22 let spc_equal = opt_spc . Sep.equal
24 let op = ([ label "add" . opt_spc . Util.del_str "+=" ]
25 |[ label "del" . opt_spc . Util.del_str "-=" ]
28 let value = store Rx.no_spaces
30 let indent = del Rx.opt_space "\t"
32 let attr_one (n:regexp) =
33 Build.key_value n Sep.space_equal value
35 let attr_lst (n:regexp) (op_eq: lens) =
36 let value_entry = [ label "value" . value ] in
37 Build.key_value n op_eq (opt_spc . Build.opt_list value_entry Sep.space)?
39 let attr_lst_eq (n:regexp) = attr_lst n spc_equal
41 let attr_lst_op (n:regexp) = attr_lst n op
43 (* Variable: service_attr
45 * It is much faster to combine, for example, all the attr_one
46 * attributes into one regexp and pass that to a lens instead of
47 * using lens union (attr_one "a" | attr_one "b"|..) because the latter
48 * causes the type checker to work _very_ hard.
51 attr_one (/socket_type|protocol|wait|user|group|server|instances/i
52 |/rpc_version|rpc_number|id|port|nice|banner|bind|interface/i
53 |/per_source|groups|banner_success|banner_fail|disable|max_load/i
54 |/rlimit_as|rlimit_cpu|rlimit_data|rlimit_rss|rlimit_stack|v6only/i
55 |/deny_time|umask|mdns|libwrap/i)
56 (* redirect and cps aren't really lists, they take exactly two values *)
57 |attr_lst_eq (/server_args|log_type|access_times|type|flags|redirect|cps/i)
58 |attr_lst_op (/log_on_success|log_on_failure|only_from|no_access|env|passenv/i)
61 attr_one (/instances|banner|bind|interface|per_source|groups/i
62 |/banner_success|banner_fail|max_load|v6only|umask|mdns/i)
63 |attr_lst_eq /cps/i (* really only two values, not a whole list *)
64 |attr_lst_op (/log_type|log_on_success|log_on_failure|disabled/i
65 |/no_access|only_from|passenv|enabled/i)
69 * We would really like to say "the body can contain any of a list
70 * of a list of attributes, each of them at most once"; but that
71 * would require that we build a lens that matches the permutation
72 * of all attributes; with around 40 individual attributes, that's
73 * not computationally feasible, even if we didn't have to worry
74 * about how to write that down. The resulting regular expressions
75 * would simply be prohibitively large.
77 let body (attr:lens) = Build.block_newlines_spc
78 (indent . attr . Util.eol)
83 * It would be nice if we could use the directories given in include and
84 * includedir directives to parse additional files instead of hardcoding
85 * all the places where xinetd config files can be found; but that is
86 * currently not possible, and implementing that has a good amount of
87 * hairy corner cases to consider.
90 Build.key_value_line /include(dir)?/ Sep.space (store Rx.no_spaces)
93 let sto_re = /[^# \t\n\/]+/ in
94 Build.key_value_line "service" Sep.space (store sto_re . body service_attr)
96 let defaults = [ key "defaults" . body default_attr . Util.eol ]
98 let lns = ( Util.empty | Util.comment | includes | defaults | service )*
100 let filter = incl "/etc/xinetd.d/*"
101 . incl "/etc/xinetd.conf"
104 let xfm = transform lns filter
106 (* Local Variables: *)