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/>.
27 #include "unit-name.h"
31 "abcdefghijklmnopqrstuvwxyz" \
32 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
35 bool unit_name_is_valid_no_type(const char *n, bool template_ok) {
36 const char *e, *i, *at;
40 * string@instance.suffix
46 if (strlen(n) >= UNIT_NAME_MAX)
53 for (i = n, at = NULL; i < e; i++) {
58 if (!strchr("@" VALID_CHARS, *i))
66 if (!template_ok && at+1 == e)
73 bool unit_instance_is_valid(const char *i) {
76 /* The max length depends on the length of the string, so we
77 * don't really check this here. */
82 /* We allow additional @ in the instance string, we do not
83 * allow them in the prefix! */
86 if (!strchr("@" VALID_CHARS, *i))
92 bool unit_prefix_is_valid(const char *p) {
94 /* We don't allow additional @ in the instance string */
100 if (!strchr(VALID_CHARS, *p))
106 int unit_name_to_instance(const char *n, char **instance) {
113 /* Everything past the first @ and before the last . is the instance */
114 if (!(p = strchr(n, '@'))) {
119 assert_se(d = strrchr(n, '.'));
122 if (!(i = strndup(p+1, d-p-1)))
129 char *unit_name_to_prefix_and_instance(const char *n) {
134 assert_se(d = strrchr(n, '.'));
136 return strndup(n, d - n);
139 char *unit_name_to_prefix(const char *n) {
142 if ((p = strchr(n, '@')))
143 return strndup(n, p - n);
145 return unit_name_to_prefix_and_instance(n);
148 char *unit_name_change_suffix(const char *n, const char *suffix) {
153 assert(unit_name_is_valid_no_type(n, true));
156 assert_se(e = strrchr(n, '.'));
160 if (!(r = new(char, a + b + 1)))
164 memcpy(r+a, suffix, b+1);
169 char *unit_name_build(const char *prefix, const char *instance, const char *suffix) {
171 assert(unit_prefix_is_valid(prefix));
172 assert(!instance || unit_instance_is_valid(instance));
176 return strappend(prefix, suffix);
178 return join(prefix, "@", instance, suffix, NULL);
181 static char* do_escape(const char *f, char *t) {
188 else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f)) {
191 *(t++) = hexchar(*f >> 4);
192 *(t++) = hexchar(*f);
200 char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix) {
207 /* Takes a arbitrary string for prefix and instance plus a
208 * suffix and makes a nice string suitable as unit name of it,
209 * escaping all weird chars on the way.
211 * / becomes ., and all chars not allowed in a unit name get
212 * escaped as \xFF, including \ and ., of course. This
213 * escaping is hence reversible.
215 * This is primarily useful to make nice unit names from
216 * strings, but is actually useful for any kind of string.
223 b = strlen(instance);
225 if (!(r = new(char, a*4 + 1 + b*4 + c + 1)))
228 t = do_escape(prefix, r);
230 t = do_escape(instance, t);
233 if (!(r = new(char, a*4 + c + 1)))
236 t = do_escape(prefix, r);
243 char *unit_name_escape(const char *f) {
246 if (!(r = new(char, strlen(f)*4+1)))
256 char *unit_name_unescape(const char *f) {
261 if (!(r = strdup(f)))
264 for (t = r; *f; f++) {
267 else if (*f == '\\') {
271 (a = unhexchar(f[2])) < 0 ||
272 (b = unhexchar(f[3])) < 0) {
273 /* Invalid escape code, let's take it literal then */
276 *(t++) = (char) ((a << 4) | b);
288 bool unit_name_is_template(const char *n) {
293 if (!(p = strchr(n, '@')))
299 char *unit_name_replace_instance(const char *f, const char *i) {
307 assert_se(e = strrchr(f, '.'));
316 if (!(r = new(char, a + 1 + b + strlen(e) + 1)))
319 k = mempcpy(r, f, a + 1);
320 k = mempcpy(k, i, b);
323 if (!(r = new(char, a + strlen(e) + 1)))
326 k = mempcpy(r, f, a);
333 char *unit_name_template(const char *f) {
338 if (!(p = strchr(f, '@')))
341 assert_se(e = strrchr(f, '.'));
344 if (!(r = new(char, a + strlen(e) + 1)))
347 strcpy(mempcpy(r, f, a), e);
352 char *unit_name_from_path(const char *path, const char *suffix) {
358 if (!(p = strdup(path)))
361 path_kill_slashes(p);
363 path = p[0] == '/' ? p + 1 : p;
367 return strappend("-", suffix);
370 r = unit_name_build_escape(path, NULL, suffix);
376 char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix) {
382 if (!(p = strdup(path)))
385 path_kill_slashes(p);
387 path = p[0] == '/' ? p + 1 : p;
391 return unit_name_build_escape(prefix, "-", suffix);
394 r = unit_name_build_escape(prefix, path, suffix);
400 char *unit_name_to_path(const char *name) {
405 if (!(w = unit_name_to_prefix(name)))
408 e = unit_name_unescape(w);
415 w = strappend("/", e);
427 char *unit_name_path_unescape(const char *f) {
432 if (!(e = unit_name_unescape(f)))
438 w = strappend("/", e);