diff options
Diffstat (limited to 'src/shared/specifier.c')
-rw-r--r-- | src/shared/specifier.c | 103 |
1 files changed, 90 insertions, 13 deletions
diff --git a/src/shared/specifier.c b/src/shared/specifier.c index 81379041cc..23aaa88c4b 100644 --- a/src/shared/specifier.c +++ b/src/shared/specifier.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -31,6 +32,8 @@ #include "macro.h" #include "specifier.h" #include "string-util.h" +#include "strv.h" +#include "user-util.h" /* * Generic infrastructure for replacing %x style specifiers in @@ -38,11 +41,16 @@ * */ +/* Any ASCII character or digit: our pool of potential specifiers, + * and "%" used for escaping. */ +#define POSSIBLE_SPECIFIERS ALPHANUMERICAL "%" + int specifier_printf(const char *text, const Specifier table[], void *userdata, char **_ret) { - char *ret, *t; + size_t l; + _cleanup_free_ char *ret = NULL; + char *t; const char *f; bool percent = false; - size_t l; int r; assert(text); @@ -73,28 +81,25 @@ int specifier_printf(const char *text, const Specifier table[], void *userdata, size_t k, j; r = i->lookup(i->specifier, i->data, userdata, &w); - if (r < 0) { - free(ret); + if (r < 0) return r; - } j = t - ret; k = strlen(w); n = new(char, j + k + l + 1); - if (!n) { - free(ret); + if (!n) return -ENOMEM; - } memcpy(n, ret, j); memcpy(n + j, w, k); - free(ret); - - ret = n; - t = n + j + k; - } else { + free_and_replace(ret, n); + t = ret + j + k; + } else if (strchr(POSSIBLE_SPECIFIERS, *f)) + /* Oops, an unknown specifier. */ + return -EBADSLT; + else { *(t++) = '%'; *(t++) = *f; } @@ -113,6 +118,7 @@ int specifier_printf(const char *text, const Specifier table[], void *userdata, *t = 0; *_ret = ret; + ret = NULL; return 0; } @@ -190,3 +196,74 @@ int specifier_kernel_release(char specifier, void *data, void *userdata, char ** *ret = n; return 0; } + +int specifier_user_name(char specifier, void *data, void *userdata, char **ret) { + char *t; + + /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want to be able + * to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed. + + * We don't use getusername_malloc() here, because we don't want to look at $USER, to remain consistent with + * specifer_user_id() below. + */ + + t = uid_to_name(getuid()); + if (!t) + return -ENOMEM; + + *ret = t; + return 0; +} + +int specifier_user_id(char specifier, void *data, void *userdata, char **ret) { + + if (asprintf(ret, UID_FMT, getuid()) < 0) + return -ENOMEM; + + return 0; +} + +int specifier_user_home(char specifier, void *data, void *userdata, char **ret) { + + /* On PID 1 (which runs as root) this will not result in NSS, + * which is good. See above */ + + return get_home_dir(ret); +} + +int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) { + + /* On PID 1 (which runs as root) this will not result in NSS, + * which is good. See above */ + + return get_shell(ret); +} + +int specifier_escape_strv(char **l, char ***ret) { + char **z, **p, **q; + + assert(ret); + + if (strv_isempty(l)) { + *ret = NULL; + return 0; + } + + z = new(char*, strv_length(l)+1); + if (!z) + return -ENOMEM; + + for (p = l, q = z; *p; p++, q++) { + + *q = specifier_escape(*p); + if (!*q) { + strv_free(z); + return -ENOMEM; + } + } + + *q = NULL; + *ret = z; + + return 0; +} |