3 Parses systemd unit files.
5 Author: Dominic Cleal <dcleal@redhat.com>
8 This lens tries to keep as close as possible to systemd.unit(5) and
9 systemd.service(5) etc where possible.
12 This file is licenced under the LGPL v2+, like the rest of Augeas.
17 About: Configuration files
18 This lens applies to /lib/systemd/system/* and /etc/systemd/system/*.
25 (************************************************************************
26 * Group: USEFUL PRIMITIVES
27 *************************************************************************)
33 An <IniFile.comment> entry for standalone comment lines (; or #) *)
34 let comment = IniFile.comment IniFile.comment_re "#"
37 An <IniFile.comment> entry for end of line comments (# only) *)
38 let eol_comment = IniFile.comment "#" "#"
41 An <IniFile.sep> entry *)
42 let sep = IniFile.sep "=" "="
44 (* Variable: entry_single_kw *)
45 let entry_single_kw = "Description"
47 (* Variable: entry_command_kw *)
48 let entry_command_kw = /Exec[A-Za-z][A-Za-z0-9._-]+/
50 (* Variable: entry_env_kw *)
51 let entry_env_kw = "Environment"
53 (* Variable: entry_multi_kw *)
55 let forbidden = entry_single_kw | entry_command_kw | entry_env_kw
56 in /[A-Za-z][A-Za-z0-9._-]+/ - forbidden
58 (* Variable: value_single_re *)
59 let value_single_re = /[^# \t\n\\][^#\n\\]*[^# \t\n\\]|[^# \t\n\\]/
61 (* View: sto_value_single
62 Support multiline values with a backslash *)
63 let sto_value_single = Util.del_opt_ws ""
64 . store (value_single_re
65 . (/\\\\\n/ . value_single_re)*)
68 let sto_value = store /[^# \t\n]*[^# \t\n\\]/
70 (* Variable: value_sep
71 Multi-value entries separated by whitespace or backslash and newline *)
72 let value_sep = del /[ \t]+|[ \t]*\\\\[ \t]*\n[ \t]*/ " "
74 (* Variable: value_cmd_re
75 Don't parse @ and - prefix flags *)
76 let value_cmd_re = /[^#@ \t\n\\-][^#@ \t\n\\-][^# \t\n\\]*/
78 (* Variable: env_key *)
79 let env_key = /[A-Za-z0-9_]+(\[[0-9]+\])?/
81 (************************************************************************
83 *************************************************************************)
86 Supported entry features, selected by key names:
87 * multi-value space separated attrs (the default)
88 * single-value attrs (Description)
89 * systemd.service: Exec* attrs with flags, command and arguments
90 * systemd.service: Environment NAME=arg
94 Prototype for our various key=value lines, with optional comment *)
95 let entry_fn (kw:regexp) (val:lens) =
96 [ key kw . sep . val . (eol_comment|eol) ]
99 Store a value that doesn't contain spaces *)
100 let entry_value = [ label "value" . sto_value ]
102 (* View: entry_single
103 Entry that takes a single value containing spaces *)
104 let entry_single = entry_fn entry_single_kw
105 [ label "value" . sto_value_single ]?
107 (* View: entry_command
108 Entry that takes a space separated set of values (the default) *)
109 let entry_multi = entry_fn entry_multi_kw
111 . Build.opt_list entry_value value_sep )?
113 (* View: entry_command_flags
114 Exec* flags "@" and "-". Order is important, see systemd.service(8) *)
115 let entry_command_flags =
116 let exit = [ label "ignoreexit" . Util.del_str "-" ]
117 in let arg0 = [ label "arg0" . Util.del_str "@" ]
120 (* View: entry_command
121 Entry that takes a command, arguments and the optional prefix flags *)
123 let cmd = [ label "command" . store value_cmd_re ]
124 in let arg = [ seq "args" . sto_value ]
125 in let args = [ counter "args" . label "arguments"
126 . (value_sep . arg)+ ]
127 in entry_fn entry_command_kw ( entry_command_flags . Util.del_opt_ws "" . cmd . args? )?
130 Entry that takes a space separated set of ENV=value key/value pairs *)
132 let envkv (env_val:lens) = key env_key . Util.del_str "=" . env_val
133 (* bare has no spaces, and is optionally quoted *)
134 in let bare = Quote.do_quote_opt (envkv (store /[^#'" \t\n]*[^#'" \t\n\\]/)?)
135 in let bare_dqval = envkv (store /"[^#"\t\n]*"/)
136 in let bare_sqval = envkv (store /'[^#'\t\n]*'/)
137 (* quoted may be empty *)
138 in let quoted = Quote.do_quote (envkv (store /[^#"'\n]*[ \t]+[^#"'\n]*/))
139 in let envkv_quoted = [ bare ] | [ bare_dqval ] | [ bare_sqval ] | [ quoted ]
140 in entry_fn entry_env_kw ( Util.del_opt_ws "" . ( Build.opt_list envkv_quoted value_sep ))
143 (************************************************************************
145 *************************************************************************)
148 An <IniFile.entry> *)
149 let entry = entry_single | entry_multi | entry_command | entry_env | comment
152 Includes another file at this position *)
153 let include = [ key ".include" . Util.del_ws_spc . sto_value
154 . (eol_comment|eol) ]
157 An <IniFile.title> *)
158 let title = IniFile.title IniFile.record_re
161 An <IniFile.record> *)
162 let record = IniFile.record title (entry|include)
166 let lns = IniFile.lns record (comment|include)
169 let filter = incl "/lib/systemd/system/*"
170 . incl "/lib/systemd/system/*/*"
171 . incl "/etc/systemd/system/*"
172 . incl "/etc/systemd/system/*/*"
173 . incl "/etc/systemd/logind.conf"
174 . incl "/etc/sysconfig/*.systemd"
175 . incl "/lib/systemd/network/*"
176 . incl "/usr/local/lib/systemd/network/*"
177 . incl "/etc/systemd/network/*"
178 . excl "/lib/systemd/system/*.d"
179 . excl "/etc/systemd/system/*.d"
180 . excl "/lib/systemd/system/*.wants"
181 . excl "/etc/systemd/system/*.wants"
184 let xfm = transform lns filter