Branch data 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 : 12 : static int help(void) {
26 : 12 : _cleanup_free_ char *link = NULL;
27 : : int r;
28 : :
29 : 12 : r = terminal_urlify_man("systemd-escape", "1", &link);
30 [ - + ]: 12 : if (r < 0)
31 : 0 : return log_oom();
32 : :
33 : 12 : 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 : 12 : return 0;
49 : : }
50 : :
51 : 16 : 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 [ - + ]: 16 : assert(argc >= 0);
74 [ - + ]: 16 : assert(argv);
75 : :
76 [ + - ]: 16 : while ((c = getopt_long(argc, argv, "hump", options, NULL)) >= 0)
77 : :
78 [ + - - - : 16 : switch (c) {
- - - - +
- ]
79 : :
80 : 12 : case 'h':
81 : 12 : 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 : 4 : case '?':
121 : 4 : 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 : 16 : static int run(int argc, char *argv[]) {
159 : : char **i;
160 : : int r;
161 : :
162 : 16 : log_show_color(true);
163 : 16 : log_parse_environment();
164 : 16 : log_open();
165 : :
166 : 16 : r = parse_argv(argc, argv);
167 [ + - ]: 16 : if (r <= 0)
168 : 16 : 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 : 16 : DEFINE_MAIN_FUNCTION(run);
|