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