aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-06-03 13:17:13 +0300
committerSergey Poznyakoff <gray@gnu.org>2019-06-03 13:41:34 +0300
commitf50a208f9df348cede2ba50b4f435351d8d3f19e (patch)
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.
-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,13 +1,13 @@
-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
The --no-init option instructs pies not to switch to init mode if its
PID is 1. Use this option if you run pies as a process manager in a
docker container.
@@ -35,21 +35,61 @@ contains redirections, pipes, etc. E.g.
flags shell;
command "if [ -n "$X" ]; then foo; else bar; fi"
}
* 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
statement is processed correctly and defines a single variable
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
* SysV-style Init
GNU Pies can now be used as init process daemon - the first process
diff --git a/configure.ac b/configure.ac
index a3c0b34..ccfd9fc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,13 +12,13 @@
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# 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])
AM_INIT_AUTOMAKE([1.11 gnits tar-ustar dist-bzip2 std-options silent-rules])
# Enable silent rules by default:
diff --git a/doc/pies.texi b/doc/pies.texi
index b77a40c..ccb9f0e 100644
--- a/doc/pies.texi
+++ b/doc/pies.texi
@@ -119,12 +119,13 @@ Configuration File Syntax
Component Statement
* Prerequisites::
* Component Privileges::
* Resources::
+* Environment::
* Actions Before Startup::
* Exit Actions::
* Output Redirectors::
* Inetd-Style Components::
* Meta1-Style Components::
* Visibility::
@@ -709,13 +710,13 @@ If the latter is absent, the remembered file name does not change.
@item # @var{num} "@var{file}"
This is a special form of @code{#line} statement, understood for
compatibility with the @sc{c} preprocessor.
@end table
@node Component Statement
-@section Component Statement
+@section The @code{component} Statement
@kwindex component
@deffn {Config} component
The @code{component} statement defines a new component:
@end deffn
@@ -934,12 +935,13 @@ The following subsections describe the rest of @samp{component}
substatements.
@menu
* Prerequisites::
* Component Privileges::
* Resources::
+* Environment::
* Actions Before Startup::
* Exit Actions::
* Output Redirectors::
* Inetd-Style Components::
* Meta1-Style Components::
* Visibility::
@@ -1035,34 +1037,195 @@ in version @value{VERSION}.
@deffn {Config: component} umask @var{number}
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
following specifiers are understood:
@table @asis
@item - (a dash)
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
value. If no such variable is present in the environment, it is
created and @var{value} is assigned to it. However, if @var{value}
begins with a punctuation character, this character is removed from it
@@ -1074,24 +1237,48 @@ PATH+=:/sbin
@end example
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
@subsection Actions Before Startup
The statements described in this subsection specify actions to perform
@@ -1183,12 +1370,15 @@ environment from the main @command{pies} process with the following
additional variables:
@table @env
@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}).
@item PIES_PID
PID of the terminated component.
diff --git a/lib/envop.c b/lib/envop.c
index 79083f7..80a8b6c 100644
--- a/lib/envop.c
+++ b/lib/envop.c
@@ -170,13 +170,13 @@ environ_set (environ_t *env, char const *name, char const *value)
if (!name)
{
errno = EINVAL;
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,
WRDSF_NOSPLIT
| WRDSF_QUOTE
| WRDSF_NOCMD /* FIXME */
@@ -215,24 +215,27 @@ environ_set (environ_t *env, char const *name, char const *value)
return -1;
}
return 0;
}
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,
(env->env_count - n) * sizeof (env->env_base[0]));
env->env_count--;
return 0;
@@ -454,13 +457,16 @@ envop_exec (struct envop_entry *op, environ_t *env)
case envop_set:
if (environ_set (env, op->name, op->value))
return -1;
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:
break;
default:
diff --git a/lib/envop.h b/lib/envop.h
index 054152e..82be3a5 100644
--- a/lib/envop.h
+++ b/lib/envop.h
@@ -24,13 +24,13 @@ struct environ
typedef struct environ environ_t;
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)
{
return env->env_base;
}
diff --git a/src/pies.c b/src/pies.c
index 2387cef..fe8d9b4 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -610,13 +610,13 @@ parse_legacy_env (char **argv, envop_t **envop)
{
name[--len] = 0;
if (c_ispunct (value[0]))
{
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
{
msize = len + vlen + 6;
snprintf (mem, msize, "${%s:-}%s", name, value);
@@ -632,13 +632,13 @@ parse_legacy_env (char **argv, envop_t **envop)
{
int c = value[vlen-1];
value[--vlen] = 0;
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
{
msize = len + vlen + 6;
snprintf (mem, msize, "%s${%s:-}", value, name);
@@ -782,17 +782,21 @@ _cb_env_set (enum grecs_callback_command cmd,
static int
_cb_env_unset (enum grecs_callback_command cmd,
grecs_locus_t *locus,
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;
}
struct grecs_keyword cb_env_keywords[] = {
{ "clear",
diff --git a/src/progman.c b/src/progman.c
index b75a2db..a6dc418 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -818,13 +818,13 @@ prog_start_prologue (struct prog *prog)
prog->v.p.env = environ_create (environ);
if (prog->v.p.comp->flags & CF_SOCKENV)
{
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)
{
size_t i;
for (i = 0; sysvinit_environ_hint[i]; i++)
@@ -1975,16 +1975,18 @@ status_matches_p (struct action *act, unsigned status)
}
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 ();
if (pid == (pid_t) -1)
{
logmsg (LOG_ERR, "fork: %s", strerror (errno));
@@ -1995,12 +1997,13 @@ run_command (struct action *act, struct prog *prog, unsigned retcode,
{
debug (1, (_("executing %s"), act->command));
/* Child */
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);
else
setenv ("PIES_STATUS", 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
@@ -12,21 +12,21 @@ component envtest {
}
command "$abs_builddir/envtest -clone";
chdir $PWD;
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
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],
[$4])
AT_CLEANUP])
@@ -65,6 +65,74 @@ LOGIN="user"
PATH="/usr/local/bin:/usr/bin:/bin"
PIES_INSTANCE="pies"
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
@@ -94,8 +94,31 @@ ENVTEST([unset wildcard],[unset],[-unset 'LC_*'],
LOGIN="user"
PATH="/usr/local/bin:/usr/bin:/bin"
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.