From c24eb49e6aecd6de2ad450083e826d4c9d9c75b6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Jul 2010 02:57:35 +0200 Subject: [PATCH] exec: extend variable substitution to support splitting variable values into seperate arguments --- Makefile.am | 12 +++++++- fixme | 4 +-- man/systemd.service.xml | 12 +++++--- src/test-env-replace.c | 59 +++++++++++++++++++++++++++++++++++++ src/util.c | 51 +++++++++++++++++++++++++++----- units/.gitignore | 1 + units/emergency.service | 2 +- units/fedora/single.service | 2 +- 8 files changed, 127 insertions(+), 16 deletions(-) create mode 100644 src/test-env-replace.c diff --git a/Makefile.am b/Makefile.am index 94ae6af3..4dcecc5c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -77,7 +77,8 @@ noinst_PROGRAMS = \ test-ns \ test-loopback \ test-daemon \ - test-cgroup + test-cgroup \ + test-env-replace if HAVE_PAM pamlib_LTLIBRARIES = \ @@ -446,6 +447,15 @@ test_cgroup_CFLAGS = \ test_cgroup_LDADD = \ libsystemd-basic.la +test_env_replace_SOURCES = \ + src/test-env-replace.c + +test_env_replace_CFLAGS = \ + $(AM_CFLAGS) + +test_env_replace_LDADD = \ + libsystemd-basic.la + systemd_logger_SOURCES = \ src/logger.c \ src/sd-daemon.c \ diff --git a/fixme b/fixme index 5737863c..29a6db42 100644 --- a/fixme +++ b/fixme @@ -35,9 +35,9 @@ * systemctl status $PID, systemctl stop $PID! -* place /etc/inittab with explaining blurb. +/dev/null symlinks supporten -* In command lines, support both "$FOO" and $FOO +* place /etc/inittab with explaining blurb. * /etc must always take precedence even if we follow symlinks! diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 96238834..94a21d3f 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -274,10 +274,14 @@ systemd.unit5. On top of that basic environment variable substitution is supported, where - $(FOO) is replaced - by the value of the environment - variable of the same - name. + ${FOO} is replaced + by the string value of the environment + variable of the same name. Also + $FOO may appear as + seperate word on the command line in + which case the variable is replaced by + its value split at + whitespaces. diff --git a/src/test-env-replace.c b/src/test-env-replace.c new file mode 100644 index 00000000..df101fd1 --- /dev/null +++ b/src/test-env-replace.c @@ -0,0 +1,59 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" +#include "log.h" +#include "strv.h" + +int main(int argc, char *argv[]) { + + const char *env[] = { + "FOO=BAR BAR", + "BAR=waldo", + NULL + }; + + const char *line[] = { + "FOO$FOO", + "FOO$FOOFOO", + "FOO${FOO}$FOO", + "FOO${FOO}", + "${FOO}", + "$FOO", + "$FOO$FOO", + "${FOO}${BAR}", + "${FOO", + NULL + }; + + char **i, **r; + + r = replace_env_argv((char**) line, (char**) env); + + STRV_FOREACH(i, r) + printf("%s\n", *i); + + strv_free(r); + +} diff --git a/src/util.c b/src/util.c index 45de609c..da8a6c33 100644 --- a/src/util.c +++ b/src/util.c @@ -2778,7 +2778,7 @@ void status_welcome(void) { char *replace_env(const char *format, char **env) { enum { WORD, - DOLLAR, + CURLY, VARIABLE } state = WORD; @@ -2793,11 +2793,11 @@ char *replace_env(const char *format, char **env) { case WORD: if (*e == '$') - state = DOLLAR; + state = CURLY; break; - case DOLLAR: - if (*e == '(') { + case CURLY: + if (*e == '{') { if (!(k = strnappend(r, word, e-word-1))) goto fail; @@ -2821,7 +2821,7 @@ char *replace_env(const char *format, char **env) { break; case VARIABLE: - if (*e == ')') { + if (*e == '}') { char *t; if ((t = strv_env_get_with_length(env, word+2, e-word-2))) { @@ -2853,12 +2853,49 @@ fail: char **replace_env_argv(char **argv, char **env) { char **r, **i; - unsigned k = 0; + unsigned k = 0, l = 0; + + l = strv_length(argv); - if (!(r = new(char*, strv_length(argv)+1))) + if (!(r = new(char*, l+1))) return NULL; STRV_FOREACH(i, argv) { + + /* If $FOO appears as single word, replace it by the split up variable */ + if ((*i)[0] == '$') { + char *e = strv_env_get(env, *i+1); + + if (e) { + char **w, **m; + unsigned q; + + if (!(m = strv_split_quoted(e))) { + r[k] = NULL; + strv_free(r); + return NULL; + } + + q = strv_length(m); + l = l + q - 1; + + if (!(w = realloc(r, sizeof(char*) * (l+1)))) { + r[k] = NULL; + strv_free(r); + strv_free(m); + return NULL; + } + + r = w; + memcpy(r + k, m, q * sizeof(char*)); + free(m); + + k += q; + continue; + } + } + + /* If ${FOO} appears as part of a word, replace it by the variable as-is */ if (!(r[k++] = replace_env(*i, env))) { strv_free(r); return NULL; diff --git a/units/.gitignore b/units/.gitignore index ea85dc08..5de1b5c7 100644 --- a/units/.gitignore +++ b/units/.gitignore @@ -6,3 +6,4 @@ graphical.target multi-user.target getty@.service remote-fs.target +test-env-replace diff --git a/units/emergency.service b/units/emergency.service index dd4a0703..7a1f81a4 100644 --- a/units/emergency.service +++ b/units/emergency.service @@ -22,4 +22,4 @@ KillMode=process-group # Bash ignores SIGTERM, so we send SIGHUP first, to ensure that bash # terminates cleanly. -ExecStop=-/bin/kill -HUP $(MAINPID) +ExecStop=-/bin/kill -HUP ${MAINPID} diff --git a/units/fedora/single.service b/units/fedora/single.service index f4af539f..93a70cf4 100644 --- a/units/fedora/single.service +++ b/units/fedora/single.service @@ -25,4 +25,4 @@ KillMode=process-group # Bash ignores SIGTERM, so we send SIGHUP first, to ensure that bash # terminates cleanly. -ExecStop=-/bin/kill -HUP $(MAINPID) +ExecStop=-/bin/kill -HUP ${MAINPID} -- 2.39.5