summaryrefslogtreecommitdiff
path: root/src/shared/specifier.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/specifier.c')
-rw-r--r--src/shared/specifier.c103
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;
+}