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