summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-06-03 10:17:13 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-06-03 10:41:34 (GMT)
commitf50a208f9df348cede2ba50b4f435351d8d3f19e (patch) (side-by-side diff)
treec596fdf237b17713ab56c0269cdb1d339e306941
parent8004bbaa1b31b14dd4c4d3886b5f57b103bf7405 (diff)
downloadpies-f50a208f9df348cede2ba50b4f435351d8d3f19e.tar.gz
pies-f50a208f9df348cede2ba50b4f435351d8d3f19e.tar.bz2
Finish the env re-implementation
* NEWS: Document the "env" statement and the PIES_MASTER_PID environment variable. Version 1.3.91 * configure.ac: Version 1.3.91 * doc/pies.texi: Document the new "env" statement syntax. Provide instructions on how to convert legacy "env" statement to the new form. * lib/envop.c (environ_unset): Take reference value as argument. If supplied, unset the variable only if its value matches the reference one. * lib/envop.h (environ_unset): Change proto. * src/pies.c (parse_legacy_env): Minor changes. (_cb_env_unset): Allow to specify value. * src/progman.c (run_command): Define PIES_MASTER_PID. * tests/env.at: Check the legacy env syntax. * tests/envop.at: Additional checks.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--NEWS46
-rw-r--r--configure.ac2
-rw-r--r--doc/pies.texi212
-rw-r--r--lib/envop.c14
-rw-r--r--lib/envop.h2
-rw-r--r--src/pies.c10
-rw-r--r--src/progman.c7
-rw-r--r--tests/env.at72
-rw-r--r--tests/envop.at23
9 files changed, 361 insertions, 27 deletions
diff --git a/NEWS b/NEWS
index f34a6f0..db79097 100644
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,10 @@
-GNU Pies NEWS -- history of user-visible changes. 2019-05-31
+GNU Pies NEWS -- history of user-visible changes. 2019-06-03
See the end of file for copying conditions.
Please send Pies bug reports to <bug-pies@gnu.org> or
<bug-pies@gnu.org.ua>
-Version 1.3.90 (git)
+Version 1.3.91 (git)
* New option --no-init
@@ -38,7 +38,41 @@ contains redirections, pipes, etc. E.g.
* Improved cyclic dependency diagnostics
-* Fix a bug in 'env' statement
+* New 'env' statement
+
+The 'env' statement has been re-implemented as a compound statement.
+It can contain the following sub-statements:
+
+** clear yes
+Clears the environment
+
+** keep NAME
+Keeps the variable NAME when clearing the environment. Implies
+"clear yes". NAME can be a globbing pattern, in which case all
+variables matching the pattern are retained.
+
+** set "NAME=VALUE"
+Sets the environment variable for the component. VALUE is subject
+to variable expansion.
+
+** unset NAME
+Unsets the variable. NAME can be a globbing pattern, in which case all
+variables matching the pattern are unset.
+
+Example:
+
+ env {
+ clear yes
+ keep PATH
+ keep MANPATH
+ keep "LC_*"
+ set "MANPATH=$MANPATH${MANPATH:+:}/usr/local/man"
+ }
+
+* Legacy 'env' statement.
+
+Support for the old one-line syntax of "env" is retained for
+backward compatibility.
Previous versions applied unnecessary word splitting if given a
single argument. This is now fixed, so that e.g. the following
@@ -47,6 +81,12 @@ X to have the value "foo bar":
env "X=foo bar"
+* New environment variable available in commands started from return-code
+
+Programs started via "exec" statement in the "return-code" block
+obtain the PID of the master pies process in environment variable
+PIES_MASTER_PID.
+
Version 1.3, 2016-10-01
diff --git a/configure.ac b/configure.ac
index a3c0b34..ccfd9fc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,7 +15,7 @@
# along with GNU Pies. If not, see <http://www.gnu.org/licenses/>.
AC_PREREQ([2.63])
-AC_INIT([GNU Pies], [1.3.90], [bug-pies@gnu.org.ua])
+AC_INIT([GNU Pies], [1.3.91], [bug-pies@gnu.org.ua])
AC_CONFIG_SRCDIR([src/pies.h])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
diff --git a/doc/pies.texi b/doc/pies.texi
index b77a40c..ccb9f0e 100644
--- a/doc/pies.texi
+++ b/doc/pies.texi
@@ -122,6 +122,7 @@ Component Statement
* Prerequisites::
* Component Privileges::
* Resources::
+* Environment::
* Actions Before Startup::
* Exit Actions::
* Output Redirectors::
@@ -712,7 +713,7 @@ compatibility with the @sc{c} preprocessor.
@end table
@node Component Statement
-@section Component Statement
+@section The @code{component} Statement
@kwindex component
@deffn {Config} component
@@ -937,6 +938,7 @@ substatements.
* Prerequisites::
* Component Privileges::
* Resources::
+* Environment::
* Actions Before Startup::
* Exit Actions::
* Output Redirectors::
@@ -1038,7 +1040,122 @@ Set the umask. The @var{number} must be an octal value not greater
than @samp{777}. The default umask is inherited at startup.
@end deffn
-@deffn {Config: component} env @var{args}
+@deffn {Config: component} max-instances @var{n}
+Sets the maximum number of simultaneously running instances of this
+component.
+@end deffn
+
+@node Environment
+@subsection Environment
+Normally all components inherit the environment of the master
+@command{pies} process. You can modify this environment using
+the @code{env} statement. It has two variants: @dfn{compound} and @dfn{legacy}.
+The legacy one-line statement was used in @command{pies} versions
+up to 1.3 and is still retained for backward compatibility. It is
+described in @ref{env legacy syntax}. This subsection describes the
+modern compount syntax.
+
+@deffn {Config: component} env @{ ... @}
+The compound @code{env} statement has the following syntax:
+
+@example
+@group
+env @{
+ clear @var{bool};
+ keep @var{pattern};
+ set "@var{name}=@var{value}";
+ unset @var{pattern};
+@}
+@end group
+@end example
+@end deffn
+
+Statements inside the @code{env} block define operations that
+modify the environment. The @code{clear} and @code{keep} statements
+are executed first. Then, the @code{set} and @code{unset} statements
+are applied in the order of their appearance in the configuration.
+
+@deffn {env} clear @var{bool}
+If @var{bool} is @samp{yes}, all environment variables will be cleared
+(unset). The resulting environment will be empty, unless one or more
+@code{keep} statements are also given (see below). The @code{clear}
+statement is always executed first.
+@end deffn
+
+@deffn {env} keep @var{pattern}
+Declares variables matching @var{pattern} (a globbing pattern) as
+exempt from clearing. This statement implies @code{clear}.
+
+For example, the following configuration fragment removes from the
+environment all variables except @samp{HOME}, @samp{USER},
+@samp{PATH}, and variables beginning with @samp{LC_}:
+
+@example
+@group
+env @{
+ clear yes;
+ keep HOME;
+ keep USER;
+ keep PATH;
+ keep "LC_*";
+@}
+@end group
+@end example
+@end deffn
+
+@deffn {env} keep "@var{name}=@var{value}"
+Retains the variable @var{name}, if it has the given value. Note, that
+the argument must be quoted.
+@end deffn
+
+@deffn {env} set "@var{name}=@var{value}"
+Assigns @var{value} to environment variable @var{name}. The value is
+subject to @dfn{variable expansion} using the same syntax as in shell.
+The @code{set} and @code{unset} (see below) statements are executed in
+order of their appearance. For example
+
+@example
+@group
+env @{
+ set "MYLIB=$HOME/lib";
+ set "LD_LIBRARY_PATH=$LD_LIBRARY_PATH$@{LD_LIBRARY_PATH:+:@}$MYLIB";
+@}
+@end group
+@end example
+@end deffn
+
+@deffn {env} unset @var{pattern}
+Unset environment variables matching @var{pattern}. The following
+will unset the @env{LOGIN} variable:
+
+@example
+unset LOGIN;
+@end example
+
+@noindent
+The following will unset all variables starting with @samp{LD_}:
+
+@example
+unset "LD_*";
+@end example
+
+@noindent
+Notice, that patterns containing wildcard characters must be quoted.
+@end deffn
+
+@menu
+* env legacy syntax::
+@end menu
+
+@node env legacy syntax
+@subsubsection @code{env}: legacy syntax.
+Up to version 1.3 @command{pies} implemented the one-line variant of
+the @code{env} statement. The use of this legacy syntax is
+discouraged. It is supported for backward compatibility only and will
+be removed in future versions. This subsection describes the legacy
+syntax.
+
+@deffn {legacy syntax} env @var{args}
Set program environment.
Arguments are a whitespace-delimited list of specifiers. The
@@ -1049,17 +1166,63 @@ following specifiers are understood:
Clear the environment. This is understood only when used as a first
word in @var{args}.
+The modern syntax equivalent is:
+
+@example
+@group
+env @{
+ clear yes;
+@}
+@end group
+@end example
+
@item -@var{name}
-Unset the environment variable @var{name}.
+Unset the environment variable @var{name}. The modern syntax
+equivalent is
+
+@example
+@group
+env @{
+ unset @var{name};
+@}
+@end group
+@end example
@item -@var{name}=@var{val}
Unset the environment variable @var{name} only if its value is @var{val}.
+The modern syntax equivalent is:
+
+@example
+@group
+env @{
+ unset "@var{name}=@var{val}";
+@}
+@end group
+@end example
@item @var{name}
-Retain the environment variable @var{name}.
+Retain the environment variable @var{name}. The modern syntax
+equivalent is
+
+@example
+@group
+env @{
+ keep @var{name};
+@}
+@end group
+@end example
@item @var{name}=@var{value}
-Define environment variable @var{name} to have given @var{value}.
+Define environment variable @var{name} to have given @var{value}. The
+modern syntax equivalent is:
+
+@example
+@group
+env @{
+ keep "@var{name}=@var{value}";
+@}
+@end group
+@end example
@item @var{name}+=@var{value}
Retain variable @var{name} and append @var{value} to its existing
@@ -1077,18 +1240,42 @@ In this example, if @env{PATH} exists, @samp{:/sbin} will be appended
to it. Otherwise, it will be created and @samp{/sbin} will be
assigned to it.
+In modern syntax, use shell variable references, e.g.:
+
+@example
+@group
+env @{
+ set "PATH=$@{PATH@}$@{PATH:+:@}/sbin";
+@}
+@end group
+@end example
+
@item @var{name}=+@var{value}
Retain variable @var{name} and prepend @var{value} to its existing
value. If no such variable is present in the environment, it is
created and @var{value} is assigned to it. However, if @var{value}
ends with a punctuation character, this character is removed from it
-before assignment.
-@end table
-@end deffn
+before assignment.
-@deffn {Config: component} max-instances @var{n}
-Sets the maximum number of simultaneously running instances of this
-component.
+In modern syntax, use shell variable references, e.g. instead of
+doing
+
+@example
+env PATH=+/sbin:
+@end example
+
+@noindent
+use
+
+@example
+@group
+env @{
+ set "PATH=/sbin$@{PATH:+:@}$PATH";
+@}
+@end group
+@end example
+
+@end table
@end deffn
@node Actions Before Startup
@@ -1186,6 +1373,9 @@ additional variables:
@item PIES_VERSION
The @command{pies} version number (@value{VERSION}).
+@item PIES_MASTER_PID
+PID of the master @command{pies} process.
+
@item PIES_COMPONENT
Tag of the terminated component (@pxref{Component Statement, tag}).
diff --git a/lib/envop.c b/lib/envop.c
index 79083f7..80a8b6c 100644
--- a/lib/envop.c
+++ b/lib/envop.c
@@ -173,7 +173,7 @@ environ_set (environ_t *env, char const *name, char const *value)
return -1;
}
if (!value)
- return environ_unset (env, name);
+ return environ_unset (env, name, value);
ws.ws_env = (char const **) env->env_base;
if (wordsplit (value, &ws,
@@ -218,18 +218,21 @@ environ_set (environ_t *env, char const *name, char const *value)
}
int
-environ_unset (environ_t *env, char const *name)
+environ_unset (environ_t *env, char const *name, char const *refval)
{
ssize_t n;
+ char *val;
if (!env || !name)
{
errno = EINVAL;
return -1;
}
- n = getenvind (env, name, NULL);
+ n = getenvind (env, name, &val);
if (n == -1)
return ENOENT;
+ if (refval && strcmp (val, refval))
+ return ENOENT;
free (env->env_base[n]);
memmove (env->env_base + n, env->env_base + n + 1,
@@ -457,7 +460,10 @@ envop_exec (struct envop_entry *op, environ_t *env)
break;
case envop_unset:
- environ_unset_glob (env, op->name);
+ if (op->value)
+ environ_unset (env, op->name, op->value);
+ else
+ environ_unset_glob (env, op->name);
break;
case envop_keep:
diff --git a/lib/envop.h b/lib/envop.h
index 054152e..82be3a5 100644
--- a/lib/envop.h
+++ b/lib/envop.h
@@ -27,7 +27,7 @@ environ_t *environ_create (char **);
void environ_free (environ_t *env);
int environ_add (environ_t *env, char const *def);
int environ_set (environ_t *env, char const *name, char const *val);
-int environ_unset (environ_t *env, char const *name);
+int environ_unset (environ_t *env, char const *name, char const *val);
int environ_unset_glob (environ_t *env, const char *pattern);
static inline char **
environ_ptr (environ_t *env)
diff --git a/src/pies.c b/src/pies.c
index 2387cef..fe8d9b4 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -613,7 +613,7 @@ parse_legacy_env (char **argv, envop_t **envop)
{
msize = 2*len + 9 + vlen + 1;
mem = grecs_malloc (msize);
- snprintf (mem, msize, "${%s:-}${%s+%c}%s",
+ snprintf (mem, msize, "${%s:-}${%s:+%c}%s",
name, name, value[0], value + 1);
}
else
@@ -635,7 +635,7 @@ parse_legacy_env (char **argv, envop_t **envop)
msize = 2*len + 10 + vlen + 1;
mem = grecs_malloc (msize);
- snprintf (mem, msize, "%s${%s+%c}${%s:-}",
+ snprintf (mem, msize, "%s${%s:+%c}${%s:-}",
value, name, c, name);
}
else
@@ -785,11 +785,15 @@ _cb_env_unset (enum grecs_callback_command cmd,
void *varptr, grecs_value_t *value, void *cb_data)
{
struct component *comp = varptr;
+ char *p;
if (assert_scalar_stmt (locus, cmd)
|| assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
return 1;
- if (envop_entry_add (&comp->envop, envop_unset, value->v.string, NULL))
+ p = strchr (value->v.string, '=');
+ if (p)
+ *p++ = 0;
+ if (envop_entry_add (&comp->envop, envop_unset, value->v.string, p))
grecs_error (locus, errno, "envop_entry_add");
return 0;
}
diff --git a/src/progman.c b/src/progman.c
index b75a2db..a6dc418 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -821,7 +821,7 @@ prog_start_prologue (struct prog *prog)
{
size_t i;
for (i = 0; sockenv_var[i]; i++)
- environ_unset (prog->v.p.env, sockenv_var[i]);
+ environ_unset (prog->v.p.env, sockenv_var[i], NULL);
}
envop_exec (prog->v.p.comp->envop, prog->v.p.env);
if (init_process)
@@ -1978,10 +1978,12 @@ static void
run_command (struct action *act, struct prog *prog, unsigned retcode,
pid_t child_pid)
{
- pid_t pid;
+ pid_t pid, master_pid;
char *argv[4];
char buf[INT_BUFSIZE_BOUND (uintmax_t)];
+ master_pid = getpid ();
+
/* FIXME: optionally set output redirectors for this command? */
pid = fork ();
@@ -1998,6 +2000,7 @@ run_command (struct action *act, struct prog *prog, unsigned retcode,
setsid ();
setenv ("PIES_VERSION", PACKAGE_VERSION, 1);
setenv ("PIES_COMPONENT", prog_tag (prog), 1);
+ setenv ("PIES_MASTER_PID", umaxtostr (master_pid, buf), 1);
setenv ("PIES_PID", umaxtostr (child_pid, buf), 1);
if (retcode & STATUS_SIG_BIT)
setenv ("PIES_SIGNAL", umaxtostr (STATUS_CODE (retcode), buf), 1);
diff --git a/tests/env.at b/tests/env.at
index 18b0e52..430bf10 100644
--- a/tests/env.at
+++ b/tests/env.at
@@ -15,7 +15,7 @@ component envtest {
stdout file "$PWD/log";
return-code 0 {
action disable;
- exec "piesctl --url unix:///$PWD/pies.ctl --no-netrc shutdown";
+ exec "$abs_top_builddir/src/piesctl --url unix:///$PWD/pies.ctl --no-netrc shutdown";
}
}
_EOT
@@ -23,7 +23,7 @@ _EOT
to 5 \
envtest -exec \
$abs_top_builddir/src/pies --foreground --stderr \
- --config-file control.conf --config-file envtest.conf 2>errlog
+ --config-file control.conf --config-file envtest.conf --debug 1 2>errlog
cat log
],
[0],
@@ -68,3 +68,71 @@ USER="user"
])
m4_popdef([ENVTEST])
+
+# ##############################
+# Legacy syntax
+# ##############################
+
+AT_BANNER([env: legacy syntax])
+
+m4_pushdef([ENVTEST],
+[AT_SETUP([$1])
+AT_KEYWORDS([env $2])
+AT_CHECK([
+PIES_XFAIL_CHECK
+PIES_CONTROL_INIT
+cat > envtest.conf <<_EOT
+component envtest {
+ env $3;
+ command "$abs_builddir/envtest -clone";
+ chdir $PWD;
+ stdout file "$PWD/log";
+ return-code 0 {
+ action disable;
+ exec "$abs_top_builddir/src/piesctl --url unix:///$PWD/pies.ctl --no-netrc shutdown";
+ }
+}
+_EOT
+
+to 5 \
+ envtest -exec \
+ $abs_top_builddir/src/pies --foreground --stderr \
+ --config-file control.conf --config-file envtest.conf --debug 1 2>errlog
+cat log
+],
+[0],
+[$4])
+AT_CLEANUP])
+
+ENVTEST([clear],[clear],[-],[])
+ENVTEST([keep],[keep],[- USER LOGIN],
+[LOGIN="user"
+USER="user"
+])
+
+ENVTEST([set],[set],["FOO=bar" "BAR=bar"],
+[BAR="bar"
+FOO="bar"
+HOME="/home/user"
+LC_ALL="C"
+LC_CTYPE="C"
+LC_MESSAGES="C"
+LC_NUMERIC="C"
+LOGIN="user"
+PATH="/usr/local/bin:/usr/bin:/bin"
+PIES_INSTANCE="pies"
+PWD="/home"
+USER="user"
+])
+
+ENVTEST([unset],[unset],["-LC_NUMERIC" "-LC_CTYPE" "-LC_MESSAGES"],
+[HOME="/home/user"
+LC_ALL="C"
+LOGIN="user"
+PATH="/usr/local/bin:/usr/bin:/bin"
+PIES_INSTANCE="pies"
+PWD="/home"
+USER="user"
+])
+
+
diff --git a/tests/envop.at b/tests/envop.at
index 6f634fb..2b857f5 100644
--- a/tests/envop.at
+++ b/tests/envop.at
@@ -97,5 +97,28 @@ PWD="/home"
USER="user"
])
+ENVTEST([unset with value],[unset],[-unset 'LOGIN=user'],
+[HOME="/home/user"
+LC_ALL="C"
+LC_CTYPE="C"
+LC_MESSAGES="C"
+LC_NUMERIC="C"
+PATH="/usr/local/bin:/usr/bin:/bin"
+PWD="/home"
+USER="user"
+])
+
+ENVTEST([unset with value (mismatch)],[unset],[-unset 'LOGIN=another'],
+[HOME="/home/user"
+LC_ALL="C"
+LC_CTYPE="C"
+LC_MESSAGES="C"
+LC_NUMERIC="C"
+LOGIN="user"
+PATH="/usr/local/bin:/usr/bin:/bin"
+PWD="/home"
+USER="user"
+])
+
m4_popdef([ENVTEST])

Return to:

Send suggestions and report system problems to the System administrator.