]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
b1a5a998 | 2 | |
3f6fd1ba | 3 | #include <getopt.h> |
b1a5a998 MB |
4 | #include <stdio.h> |
5 | #include <stdlib.h> | |
6 | ||
b5efdb8a | 7 | #include "alloc-util.h" |
b1a5a998 | 8 | #include "log.h" |
5e332028 | 9 | #include "main-func.h" |
99db797b | 10 | #include "path-util.h" |
294bf0c3 | 11 | #include "pretty-print.h" |
07630cea | 12 | #include "string-util.h" |
a1948c7b | 13 | #include "strv.h" |
3f6fd1ba | 14 | #include "unit-name.h" |
b1a5a998 | 15 | |
a1948c7b LP |
16 | static enum { |
17 | ACTION_ESCAPE, | |
18 | ACTION_UNESCAPE, | |
19 | ACTION_MANGLE | |
20 | } arg_action = ACTION_ESCAPE; | |
21 | static const char *arg_suffix = NULL; | |
22 | static const char *arg_template = NULL; | |
23 | static bool arg_path = false; | |
d936cddc | 24 | static bool arg_instance = false; |
a1948c7b | 25 | |
37ec0fdd LP |
26 | static int help(void) { |
27 | _cleanup_free_ char *link = NULL; | |
28 | int r; | |
29 | ||
30 | r = terminal_urlify_man("systemd-escape", "1", &link); | |
31 | if (r < 0) | |
32 | return log_oom(); | |
33 | ||
a1948c7b | 34 | printf("%s [OPTIONS...] [NAME...]\n\n" |
ab7e3ef5 | 35 | "Escape strings for usage in systemd unit names.\n\n" |
a1948c7b LP |
36 | " -h --help Show this help\n" |
37 | " --version Show package version\n" | |
38 | " --suffix=SUFFIX Unit suffix to append to escaped strings\n" | |
39 | " --template=TEMPLATE Insert strings as instance into template\n" | |
d936cddc | 40 | " --instance With --unescape, show just the instance part\n" |
a1948c7b LP |
41 | " -u --unescape Unescape strings\n" |
42 | " -m --mangle Mangle strings\n" | |
601185b4 | 43 | " -p --path When escaping/unescaping assume the string is a path\n" |
bc556335 DDM |
44 | "\nSee the %s for details.\n", |
45 | program_invocation_short_name, | |
46 | link); | |
37ec0fdd LP |
47 | |
48 | return 0; | |
a1948c7b LP |
49 | } |
50 | ||
51 | static int parse_argv(int argc, char *argv[]) { | |
52 | ||
53 | enum { | |
54 | ARG_VERSION = 0x100, | |
55 | ARG_SUFFIX, | |
56 | ARG_TEMPLATE | |
57 | }; | |
58 | ||
59 | static const struct option options[] = { | |
60 | { "help", no_argument, NULL, 'h' }, | |
61 | { "version", no_argument, NULL, ARG_VERSION }, | |
62 | { "suffix", required_argument, NULL, ARG_SUFFIX }, | |
63 | { "template", required_argument, NULL, ARG_TEMPLATE }, | |
64 | { "unescape", no_argument, NULL, 'u' }, | |
65 | { "mangle", no_argument, NULL, 'm' }, | |
66 | { "path", no_argument, NULL, 'p' }, | |
d936cddc | 67 | { "instance", no_argument, NULL, 'i' }, |
a1948c7b LP |
68 | {} |
69 | }; | |
70 | ||
71 | int c; | |
72 | ||
73 | assert(argc >= 0); | |
74 | assert(argv); | |
75 | ||
601185b4 | 76 | while ((c = getopt_long(argc, argv, "hump", options, NULL)) >= 0) |
a1948c7b LP |
77 | |
78 | switch (c) { | |
79 | ||
80 | case 'h': | |
37ec0fdd | 81 | return help(); |
a1948c7b LP |
82 | |
83 | case ARG_VERSION: | |
3f6fd1ba | 84 | return version(); |
a1948c7b | 85 | |
7211c853 ZJS |
86 | case ARG_SUFFIX: { |
87 | UnitType t = unit_type_from_string(optarg); | |
88 | if (t < 0) | |
89 | return log_error_errno(t, "Invalid unit suffix type \"%s\".", optarg); | |
a1948c7b LP |
90 | |
91 | arg_suffix = optarg; | |
92 | break; | |
7211c853 | 93 | } |
a1948c7b LP |
94 | |
95 | case ARG_TEMPLATE: | |
baaa35ad ZJS |
96 | if (!unit_name_is_valid(optarg, UNIT_NAME_TEMPLATE)) |
97 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
98 | "Template name %s is not valid.", optarg); | |
a1948c7b LP |
99 | |
100 | arg_template = optarg; | |
101 | break; | |
102 | ||
103 | case 'u': | |
104 | arg_action = ACTION_UNESCAPE; | |
105 | break; | |
106 | ||
107 | case 'm': | |
108 | arg_action = ACTION_MANGLE; | |
109 | break; | |
110 | ||
111 | case 'p': | |
112 | arg_path = true; | |
113 | break; | |
114 | ||
d936cddc LW |
115 | case 'i': |
116 | arg_instance = true; | |
117 | break; | |
118 | ||
a1948c7b LP |
119 | case '?': |
120 | return -EINVAL; | |
121 | ||
122 | default: | |
04499a70 | 123 | assert_not_reached(); |
a1948c7b | 124 | } |
b1a5a998 | 125 | |
baaa35ad ZJS |
126 | if (optind >= argc) |
127 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
128 | "Not enough arguments."); | |
129 | ||
130 | if (arg_template && arg_suffix) | |
131 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
132 | "--suffix= and --template= may not be combined."); | |
133 | ||
134 | if ((arg_template || arg_suffix) && arg_action == ACTION_MANGLE) | |
135 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
136 | "--suffix= and --template= are not compatible with --mangle."); | |
137 | ||
138 | if (arg_suffix && arg_action == ACTION_UNESCAPE) | |
139 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
140 | "--suffix is not compatible with --unescape."); | |
141 | ||
142 | if (arg_path && !IN_SET(arg_action, ACTION_ESCAPE, ACTION_UNESCAPE)) | |
143 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
144 | "--path may not be combined with --mangle."); | |
145 | ||
146 | if (arg_instance && arg_action != ACTION_UNESCAPE) | |
147 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
148 | "--instance must be used in conjunction with --unescape."); | |
149 | ||
150 | if (arg_instance && arg_template) | |
151 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
152 | "--instance may not be combined with --template."); | |
d936cddc | 153 | |
a1948c7b LP |
154 | return 1; |
155 | } | |
156 | ||
5f200747 | 157 | static int run(int argc, char *argv[]) { |
a1948c7b LP |
158 | int r; |
159 | ||
d2acb93d | 160 | log_setup(); |
a1948c7b LP |
161 | |
162 | r = parse_argv(argc, argv); | |
163 | if (r <= 0) | |
5f200747 | 164 | return r; |
a1948c7b LP |
165 | |
166 | STRV_FOREACH(i, argv + optind) { | |
167 | _cleanup_free_ char *e = NULL; | |
168 | ||
169 | switch (arg_action) { | |
170 | ||
171 | case ACTION_ESCAPE: | |
7410616c LP |
172 | if (arg_path) { |
173 | r = unit_name_path_escape(*i, &e); | |
99db797b LP |
174 | if (r < 0) { |
175 | if (r == -EINVAL) { | |
176 | /* If escaping failed because the string was invalid, let's print a | |
177 | * friendly message about it. Catch these specific error cases | |
178 | * explicitly. */ | |
179 | ||
180 | if (!path_is_valid(*i)) | |
181 | return log_error_errno(r, "Input '%s' is not a valid file system path, failed to escape.", *i); | |
182 | if (!path_is_absolute(*i)) | |
183 | return log_error_errno(r, "Input '%s' is not an absolute file system path, failed to escape.", *i); | |
184 | if (!path_is_normalized(*i)) | |
185 | return log_error_errno(r, "Input '%s' is not a normalized file system path, failed to escape.", *i); | |
186 | } | |
187 | ||
188 | /* All other error cases. */ | |
5f200747 | 189 | return log_error_errno(r, "Failed to escape string: %m"); |
99db797b LP |
190 | } |
191 | ||
192 | /* If the escaping worked, then still warn if the path is not like we'd like | |
193 | * it. Because that means escaping is not necessarily reversible. */ | |
194 | ||
195 | if (!path_is_valid(*i)) | |
196 | log_warning("Input '%s' is not a valid file system path, escaping is likely not going be reversible.", *i); | |
197 | else if (!path_is_absolute(*i)) | |
198 | log_warning("Input '%s' is not an absolute file system path, escaping is likely not going to be reversible.", *i); | |
199 | ||
200 | /* Note that we don't complain about paths not being normalized here, because | |
201 | * some forms of non-normalization is actually OK, such as a series // and | |
202 | * unit_name_path_escape() will clean those up silently, and the reversal is | |
203 | * "close enough" to be OK. */ | |
7410616c | 204 | } else { |
a1948c7b | 205 | e = unit_name_escape(*i); |
5f200747 ZJS |
206 | if (!e) |
207 | return log_oom(); | |
a1948c7b LP |
208 | } |
209 | ||
210 | if (arg_template) { | |
211 | char *x; | |
212 | ||
7410616c | 213 | r = unit_name_replace_instance(arg_template, e, &x); |
5f200747 ZJS |
214 | if (r < 0) |
215 | return log_error_errno(r, "Failed to replace instance: %m"); | |
a1948c7b | 216 | |
c88f45e7 | 217 | free_and_replace(e, x); |
a1948c7b | 218 | } else if (arg_suffix) { |
f8abe13f | 219 | if (!strextend(&e, ".", arg_suffix)) |
5f200747 | 220 | return log_oom(); |
a1948c7b LP |
221 | } |
222 | ||
223 | break; | |
224 | ||
e563e253 LW |
225 | case ACTION_UNESCAPE: { |
226 | _cleanup_free_ char *name = NULL; | |
227 | ||
d936cddc | 228 | if (arg_template || arg_instance) { |
e563e253 LW |
229 | _cleanup_free_ char *template = NULL; |
230 | ||
231 | r = unit_name_to_instance(*i, &name); | |
5f200747 ZJS |
232 | if (r < 0) |
233 | return log_error_errno(r, "Failed to extract instance: %m"); | |
234 | if (isempty(name)) | |
c413bb28 ZJS |
235 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), |
236 | "Unit %s is missing the instance name.", *i); | |
5f200747 | 237 | |
e563e253 | 238 | r = unit_name_template(*i, &template); |
5f200747 ZJS |
239 | if (r < 0) |
240 | return log_error_errno(r, "Failed to extract template: %m"); | |
241 | if (arg_template && !streq(arg_template, template)) | |
c413bb28 ZJS |
242 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), |
243 | "Unit %s template %s does not match specified template %s.", | |
244 | *i, template, arg_template); | |
e563e253 LW |
245 | } else { |
246 | name = strdup(*i); | |
5f200747 ZJS |
247 | if (!name) |
248 | return log_oom(); | |
e563e253 LW |
249 | } |
250 | ||
a1948c7b | 251 | if (arg_path) |
e563e253 | 252 | r = unit_name_path_unescape(name, &e); |
a1948c7b | 253 | else |
e563e253 | 254 | r = unit_name_unescape(name, &e); |
5f200747 ZJS |
255 | if (r < 0) |
256 | return log_error_errno(r, "Failed to unescape string: %m"); | |
a1948c7b | 257 | |
a1948c7b | 258 | break; |
e563e253 | 259 | } |
a1948c7b LP |
260 | |
261 | case ACTION_MANGLE: | |
37cbc1d5 | 262 | r = unit_name_mangle(*i, 0, &e); |
5f200747 ZJS |
263 | if (r < 0) |
264 | return log_error_errno(r, "Failed to mangle name: %m"); | |
265 | ||
a1948c7b LP |
266 | break; |
267 | } | |
268 | ||
c88f45e7 | 269 | if (i != argv + optind) |
a1948c7b | 270 | fputc(' ', stdout); |
b1a5a998 | 271 | |
a1948c7b | 272 | fputs(e, stdout); |
b1a5a998 MB |
273 | } |
274 | ||
a1948c7b | 275 | fputc('\n', stdout); |
b1a5a998 | 276 | |
5f200747 | 277 | return 0; |
b1a5a998 | 278 | } |
5f200747 ZJS |
279 | |
280 | DEFINE_MAIN_FUNCTION(run); |