summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2010-07-21 02:57:35 +0200
committerLennart Poettering <lennart@poettering.net>2010-07-21 02:57:35 +0200
commitc24eb49e6aecd6de2ad450083e826d4c9d9c75b6 (patch)
tree6833f35a658d6427eb981b320df3c6913e8fc455
parent9d25f5ed7b80df732cf7842985aa9b243bcd2335 (diff)
exec: extend variable substitution to support splitting variable values into seperate arguments
-rw-r--r--Makefile.am12
-rw-r--r--fixme4
-rw-r--r--man/systemd.service.xml12
-rw-r--r--src/test-env-replace.c59
-rw-r--r--src/util.c51
-rw-r--r--units/.gitignore1
-rw-r--r--units/emergency.service2
-rw-r--r--units/fedora/single.service2
8 files changed, 127 insertions, 16 deletions
diff --git a/Makefile.am b/Makefile.am
index 94ae6af352..4dcecc5c7f 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 5737863c00..29a6db425e 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 962388342c..94a21d3fe3 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -274,10 +274,14 @@
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. On
top of that basic environment variable
substitution is supported, where
- <literal>$(FOO)</literal> is replaced
- by the value of the environment
- variable of the same
- name.</para></listitem>
+ <literal>${FOO}</literal> is replaced
+ by the string value of the environment
+ variable of the same name. Also
+ <literal>$FOO</literal> may appear as
+ seperate word on the command line in
+ which case the variable is replaced by
+ its value split at
+ whitespaces.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/src/test-env-replace.c b/src/test-env-replace.c
new file mode 100644
index 0000000000..df101fd135
--- /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 <http://www.gnu.org/licenses/>.
+***/
+
+#include <unistd.h>
+#include <string.h>
+
+#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 45de609c29..da8a6c3336 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 ea85dc081e..5de1b5c7c4 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 dd4a0703e2..7a1f81a468 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 f4af539f85..93a70cf4b0 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}