1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "path-util.h"
28 #include "unit-name.h"
32 "abcdefghijklmnopqrstuvwxyz" \
33 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
36 bool unit_name_is_valid_no_type(const char *n, bool template_ok) {
37 const char *e, *i, *at;
41 * string@instance.suffix
47 if (strlen(n) >= UNIT_NAME_MAX)
54 for (i = n, at = NULL; i < e; i++) {
59 if (!strchr("@" VALID_CHARS, *i))
67 if (!template_ok && at+1 == e)
74 bool unit_instance_is_valid(const char *i) {
77 /* The max length depends on the length of the string, so we
78 * don't really check this here. */
83 /* We allow additional @ in the instance string, we do not
84 * allow them in the prefix! */
87 if (!strchr("@" VALID_CHARS, *i))
93 bool unit_prefix_is_valid(const char *p) {
95 /* We don't allow additional @ in the instance string */
101 if (!strchr(VALID_CHARS, *p))
107 int unit_name_to_instance(const char *n, char **instance) {
114 /* Everything past the first @ and before the last . is the instance */
115 if (!(p = strchr(n, '@'))) {
120 assert_se(d = strrchr(n, '.'));
123 if (!(i = strndup(p+1, d-p-1)))
130 char *unit_name_to_prefix_and_instance(const char *n) {
135 assert_se(d = strrchr(n, '.'));
137 return strndup(n, d - n);
140 char *unit_name_to_prefix(const char *n) {
143 if ((p = strchr(n, '@')))
144 return strndup(n, p - n);
146 return unit_name_to_prefix_and_instance(n);
149 char *unit_name_change_suffix(const char *n, const char *suffix) {
154 assert(unit_name_is_valid_no_type(n, true));
157 assert_se(e = strrchr(n, '.'));
161 if (!(r = new(char, a + b + 1)))
165 memcpy(r+a, suffix, b+1);
170 char *unit_name_build(const char *prefix, const char *instance, const char *suffix) {
172 assert(unit_prefix_is_valid(prefix));
173 assert(!instance || unit_instance_is_valid(instance));
177 return strappend(prefix, suffix);
179 return join(prefix, "@", instance, suffix, NULL);
182 static char* do_escape(const char *f, char *t) {
189 else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f)) {
192 *(t++) = hexchar(*f >> 4);
193 *(t++) = hexchar(*f);
201 char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix) {
208 /* Takes a arbitrary string for prefix and instance plus a
209 * suffix and makes a nice string suitable as unit name of it,
210 * escaping all weird chars on the way.
212 * / becomes ., and all chars not allowed in a unit name get
213 * escaped as \xFF, including \ and ., of course. This
214 * escaping is hence reversible.
216 * This is primarily useful to make nice unit names from
217 * strings, but is actually useful for any kind of string.
224 b = strlen(instance);
226 if (!(r = new(char, a*4 + 1 + b*4 + c + 1)))
229 t = do_escape(prefix, r);
231 t = do_escape(instance, t);
234 if (!(r = new(char, a*4 + c + 1)))
237 t = do_escape(prefix, r);
244 char *unit_name_escape(const char *f) {
247 if (!(r = new(char, strlen(f)*4+1)))
257 char *unit_name_unescape(const char *f) {
262 if (!(r = strdup(f)))
265 for (t = r; *f; f++) {
268 else if (*f == '\\') {
272 (a = unhexchar(f[2])) < 0 ||
273 (b = unhexchar(f[3])) < 0) {
274 /* Invalid escape code, let's take it literal then */
277 *(t++) = (char) ((a << 4) | b);
289 bool unit_name_is_template(const char *n) {
294 if (!(p = strchr(n, '@')))
300 char *unit_name_replace_instance(const char *f, const char *i) {
308 assert_se(e = strrchr(f, '.'));
317 if (!(r = new(char, a + 1 + b + strlen(e) + 1)))
320 k = mempcpy(r, f, a + 1);
321 k = mempcpy(k, i, b);
324 if (!(r = new(char, a + strlen(e) + 1)))
327 k = mempcpy(r, f, a);
334 char *unit_name_template(const char *f) {
339 if (!(p = strchr(f, '@')))
342 assert_se(e = strrchr(f, '.'));
345 if (!(r = new(char, a + strlen(e) + 1)))
348 strcpy(mempcpy(r, f, a), e);
353 char *unit_name_from_path(const char *path, const char *suffix) {
359 if (!(p = strdup(path)))
362 path_kill_slashes(p);
364 path = p[0] == '/' ? p + 1 : p;
368 return strappend("-", suffix);
371 r = unit_name_build_escape(path, NULL, suffix);
377 char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix) {
383 if (!(p = strdup(path)))
386 path_kill_slashes(p);
388 path = p[0] == '/' ? p + 1 : p;
392 return unit_name_build_escape(prefix, "-", suffix);
395 r = unit_name_build_escape(prefix, path, suffix);
401 char *unit_name_to_path(const char *name) {
406 if (!(w = unit_name_to_prefix(name)))
409 e = unit_name_unescape(w);
416 w = strappend("/", e);
428 char *unit_name_path_unescape(const char *f) {
433 if (!(e = unit_name_unescape(f)))
439 w = strappend("/", e);