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