]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/escape/escape.c
Merge pull request #9832 from yuwata/fix-9831
[thirdparty/systemd.git] / src / escape / escape.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <getopt.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6
7 #include "alloc-util.h"
8 #include "log.h"
9 #include "string-util.h"
10 #include "strv.h"
11 #include "terminal-util.h"
12 #include "unit-name.h"
13
14 static enum {
15 ACTION_ESCAPE,
16 ACTION_UNESCAPE,
17 ACTION_MANGLE
18 } arg_action = ACTION_ESCAPE;
19 static const char *arg_suffix = NULL;
20 static const char *arg_template = NULL;
21 static bool arg_path = false;
22 static bool arg_instance = false;
23
24 static int help(void) {
25 _cleanup_free_ char *link = NULL;
26 int r;
27
28 r = terminal_urlify_man("systemd-escape", "1", &link);
29 if (r < 0)
30 return log_oom();
31
32 printf("%s [OPTIONS...] [NAME...]\n\n"
33 "Escape strings for usage in systemd unit names.\n\n"
34 " -h --help Show this help\n"
35 " --version Show package version\n"
36 " --suffix=SUFFIX Unit suffix to append to escaped strings\n"
37 " --template=TEMPLATE Insert strings as instance into template\n"
38 " --instance With --unescape, show just the instance part\n"
39 " -u --unescape Unescape strings\n"
40 " -m --mangle Mangle strings\n"
41 " -p --path When escaping/unescaping assume the string is a path\n"
42 "\nSee the %s for details.\n"
43 , program_invocation_short_name
44 , link
45 );
46
47 return 0;
48 }
49
50 static int parse_argv(int argc, char *argv[]) {
51
52 enum {
53 ARG_VERSION = 0x100,
54 ARG_SUFFIX,
55 ARG_TEMPLATE
56 };
57
58 static const struct option options[] = {
59 { "help", no_argument, NULL, 'h' },
60 { "version", no_argument, NULL, ARG_VERSION },
61 { "suffix", required_argument, NULL, ARG_SUFFIX },
62 { "template", required_argument, NULL, ARG_TEMPLATE },
63 { "unescape", no_argument, NULL, 'u' },
64 { "mangle", no_argument, NULL, 'm' },
65 { "path", no_argument, NULL, 'p' },
66 { "instance", no_argument, NULL, 'i' },
67 {}
68 };
69
70 int c;
71
72 assert(argc >= 0);
73 assert(argv);
74
75 while ((c = getopt_long(argc, argv, "hump", options, NULL)) >= 0)
76
77 switch (c) {
78
79 case 'h':
80 return help();
81
82 case ARG_VERSION:
83 return version();
84
85 case ARG_SUFFIX:
86
87 if (unit_type_from_string(optarg) < 0) {
88 log_error("Invalid unit suffix type %s.", optarg);
89 return -EINVAL;
90 }
91
92 arg_suffix = optarg;
93 break;
94
95 case ARG_TEMPLATE:
96
97 if (!unit_name_is_valid(optarg, UNIT_NAME_TEMPLATE)) {
98 log_error("Template name %s is not valid.", optarg);
99 return -EINVAL;
100 }
101
102 arg_template = optarg;
103 break;
104
105 case 'u':
106 arg_action = ACTION_UNESCAPE;
107 break;
108
109 case 'm':
110 arg_action = ACTION_MANGLE;
111 break;
112
113 case 'p':
114 arg_path = true;
115 break;
116
117 case 'i':
118 arg_instance = true;
119 break;
120
121 case '?':
122 return -EINVAL;
123
124 default:
125 assert_not_reached("Unhandled option");
126 }
127
128 if (optind >= argc) {
129 log_error("Not enough arguments.");
130 return -EINVAL;
131 }
132
133 if (arg_template && arg_suffix) {
134 log_error("--suffix= and --template= may not be combined.");
135 return -EINVAL;
136 }
137
138 if ((arg_template || arg_suffix) && arg_action == ACTION_MANGLE) {
139 log_error("--suffix= and --template= are not compatible with --mangle.");
140 return -EINVAL;
141 }
142
143 if (arg_suffix && arg_action == ACTION_UNESCAPE) {
144 log_error("--suffix is not compatible with --unescape.");
145 return -EINVAL;
146 }
147
148 if (arg_path && !IN_SET(arg_action, ACTION_ESCAPE, ACTION_UNESCAPE)) {
149 log_error("--path may not be combined with --mangle.");
150 return -EINVAL;
151 }
152
153 if (arg_instance && arg_action != ACTION_UNESCAPE) {
154 log_error("--instance must be used in conjunction with --unescape.");
155 return -EINVAL;
156 }
157
158 if (arg_instance && arg_template) {
159 log_error("--instance may not be combined with --template.");
160 return -EINVAL;
161 }
162
163 return 1;
164 }
165
166 int main(int argc, char *argv[]) {
167 char **i;
168 int r;
169
170 log_parse_environment();
171 log_open();
172
173 r = parse_argv(argc, argv);
174 if (r <= 0)
175 goto finish;
176
177 STRV_FOREACH(i, argv + optind) {
178 _cleanup_free_ char *e = NULL;
179
180 switch (arg_action) {
181
182 case ACTION_ESCAPE:
183 if (arg_path) {
184 r = unit_name_path_escape(*i, &e);
185 if (r < 0) {
186 log_error_errno(r, "Failed to escape string: %m");
187 goto finish;
188 }
189 } else {
190 e = unit_name_escape(*i);
191 if (!e) {
192 r = log_oom();
193 goto finish;
194 }
195 }
196
197 if (arg_template) {
198 char *x;
199
200 r = unit_name_replace_instance(arg_template, e, &x);
201 if (r < 0) {
202 log_error_errno(r, "Failed to replace instance: %m");
203 goto finish;
204 }
205
206 free(e);
207 e = x;
208 } else if (arg_suffix) {
209 char *x;
210
211 x = strjoin(e, ".", arg_suffix);
212 if (!x) {
213 r = log_oom();
214 goto finish;
215 }
216
217 free(e);
218 e = x;
219 }
220
221 break;
222
223 case ACTION_UNESCAPE: {
224 _cleanup_free_ char *name = NULL;
225
226 if (arg_template || arg_instance) {
227 _cleanup_free_ char *template = NULL;
228
229 r = unit_name_to_instance(*i, &name);
230 if (r < 0) {
231 log_error_errno(r, "Failed to extract instance: %m");
232 goto finish;
233 }
234 if (isempty(name)) {
235 log_error("Unit %s is missing the instance name.", *i);
236 r = -EINVAL;
237 goto finish;
238 }
239 r = unit_name_template(*i, &template);
240 if (r < 0) {
241 log_error_errno(r, "Failed to extract template: %m");
242 goto finish;
243 }
244 if (arg_template && !streq(arg_template, template)) {
245 log_error("Unit %s template %s does not match specified template %s.", *i, template, arg_template);
246 r = -EINVAL;
247 goto finish;
248 }
249 } else {
250 name = strdup(*i);
251 if (!name) {
252 r = log_oom();
253 goto finish;
254 }
255 }
256
257 if (arg_path)
258 r = unit_name_path_unescape(name, &e);
259 else
260 r = unit_name_unescape(name, &e);
261
262 if (r < 0) {
263 log_error_errno(r, "Failed to unescape string: %m");
264 goto finish;
265 }
266 break;
267 }
268
269 case ACTION_MANGLE:
270 r = unit_name_mangle(*i, 0, &e);
271 if (r < 0) {
272 log_error_errno(r, "Failed to mangle name: %m");
273 goto finish;
274 }
275 break;
276 }
277
278 if (i != argv+optind)
279 fputc(' ', stdout);
280
281 fputs(e, stdout);
282 }
283
284 fputc('\n', stdout);
285
286 finish:
287 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
288 }