Line data Source code
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 "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 3 : static int help(void) {
26 3 : _cleanup_free_ char *link = NULL;
27 : int r;
28 :
29 3 : r = terminal_urlify_man("systemd-escape", "1", &link);
30 3 : if (r < 0)
31 0 : return log_oom();
32 :
33 3 : 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 3 : return 0;
49 : }
50 :
51 4 : 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 4 : assert(argc >= 0);
74 4 : assert(argv);
75 :
76 4 : while ((c = getopt_long(argc, argv, "hump", options, NULL)) >= 0)
77 :
78 4 : switch (c) {
79 :
80 3 : case 'h':
81 3 : return help();
82 :
83 0 : case ARG_VERSION:
84 0 : return version();
85 :
86 0 : case ARG_SUFFIX:
87 :
88 0 : if (unit_type_from_string(optarg) < 0)
89 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
90 : "Invalid unit suffix type %s.", optarg);
91 :
92 0 : arg_suffix = optarg;
93 0 : break;
94 :
95 0 : case ARG_TEMPLATE:
96 :
97 0 : if (!unit_name_is_valid(optarg, UNIT_NAME_TEMPLATE))
98 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
99 : "Template name %s is not valid.", optarg);
100 :
101 0 : arg_template = optarg;
102 0 : break;
103 :
104 0 : case 'u':
105 0 : arg_action = ACTION_UNESCAPE;
106 0 : break;
107 :
108 0 : case 'm':
109 0 : arg_action = ACTION_MANGLE;
110 0 : break;
111 :
112 0 : case 'p':
113 0 : arg_path = true;
114 0 : break;
115 :
116 0 : case 'i':
117 0 : arg_instance = true;
118 0 : break;
119 :
120 1 : case '?':
121 1 : return -EINVAL;
122 :
123 0 : default:
124 0 : assert_not_reached("Unhandled option");
125 : }
126 :
127 0 : if (optind >= argc)
128 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
129 : "Not enough arguments.");
130 :
131 0 : if (arg_template && arg_suffix)
132 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
133 : "--suffix= and --template= may not be combined.");
134 :
135 0 : if ((arg_template || arg_suffix) && arg_action == ACTION_MANGLE)
136 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
137 : "--suffix= and --template= are not compatible with --mangle.");
138 :
139 0 : if (arg_suffix && arg_action == ACTION_UNESCAPE)
140 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
141 : "--suffix is not compatible with --unescape.");
142 :
143 0 : if (arg_path && !IN_SET(arg_action, ACTION_ESCAPE, ACTION_UNESCAPE))
144 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
145 : "--path may not be combined with --mangle.");
146 :
147 0 : if (arg_instance && arg_action != ACTION_UNESCAPE)
148 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
149 : "--instance must be used in conjunction with --unescape.");
150 :
151 0 : if (arg_instance && arg_template)
152 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
153 : "--instance may not be combined with --template.");
154 :
155 0 : return 1;
156 : }
157 :
158 4 : static int run(int argc, char *argv[]) {
159 : char **i;
160 : int r;
161 :
162 4 : log_show_color(true);
163 4 : log_parse_environment();
164 4 : log_open();
165 :
166 4 : r = parse_argv(argc, argv);
167 4 : if (r <= 0)
168 4 : return r;
169 :
170 0 : STRV_FOREACH(i, argv + optind) {
171 0 : _cleanup_free_ char *e = NULL;
172 :
173 0 : switch (arg_action) {
174 :
175 0 : case ACTION_ESCAPE:
176 0 : if (arg_path) {
177 0 : r = unit_name_path_escape(*i, &e);
178 0 : if (r < 0)
179 0 : return log_error_errno(r, "Failed to escape string: %m");
180 : } else {
181 0 : e = unit_name_escape(*i);
182 0 : if (!e)
183 0 : return log_oom();
184 : }
185 :
186 0 : if (arg_template) {
187 : char *x;
188 :
189 0 : r = unit_name_replace_instance(arg_template, e, &x);
190 0 : if (r < 0)
191 0 : return log_error_errno(r, "Failed to replace instance: %m");
192 :
193 0 : free_and_replace(e, x);
194 0 : } else if (arg_suffix) {
195 : char *x;
196 :
197 0 : x = strjoin(e, ".", arg_suffix);
198 0 : if (!x)
199 0 : return log_oom();
200 :
201 0 : free_and_replace(e, x);
202 : }
203 :
204 0 : break;
205 :
206 0 : case ACTION_UNESCAPE: {
207 0 : _cleanup_free_ char *name = NULL;
208 :
209 0 : if (arg_template || arg_instance) {
210 0 : _cleanup_free_ char *template = NULL;
211 :
212 0 : r = unit_name_to_instance(*i, &name);
213 0 : if (r < 0)
214 0 : return log_error_errno(r, "Failed to extract instance: %m");
215 0 : if (isempty(name))
216 0 : return log_error("Unit %s is missing the instance name.", *i);
217 :
218 0 : r = unit_name_template(*i, &template);
219 0 : if (r < 0)
220 0 : return log_error_errno(r, "Failed to extract template: %m");
221 0 : if (arg_template && !streq(arg_template, template))
222 0 : return log_error("Unit %s template %s does not match specified template %s.",
223 : *i, template, arg_template);
224 : } else {
225 0 : name = strdup(*i);
226 0 : if (!name)
227 0 : return log_oom();
228 : }
229 :
230 0 : if (arg_path)
231 0 : r = unit_name_path_unescape(name, &e);
232 : else
233 0 : r = unit_name_unescape(name, &e);
234 0 : if (r < 0)
235 0 : return log_error_errno(r, "Failed to unescape string: %m");
236 :
237 0 : break;
238 : }
239 :
240 0 : case ACTION_MANGLE:
241 0 : r = unit_name_mangle(*i, 0, &e);
242 0 : if (r < 0)
243 0 : return log_error_errno(r, "Failed to mangle name: %m");
244 :
245 0 : break;
246 : }
247 :
248 0 : if (i != argv + optind)
249 0 : fputc(' ', stdout);
250 :
251 0 : fputs(e, stdout);
252 : }
253 :
254 0 : fputc('\n', stdout);
255 :
256 0 : return 0;
257 : }
258 :
259 4 : DEFINE_MAIN_FUNCTION(run);
|