aboutsummaryrefslogtreecommitdiff
path: root/src/progman.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-06-02 07:40:11 +0300
committerSergey Poznyakoff <gray@gnu.org>2019-06-02 08:03:16 +0300
commitcc298a11a131b162f291d6ee27ba1d7598a1b6c4 (patch)
tree4d82a9a5da05fbfdce0c9bf03e605ecf00baa07a /src/progman.c
parent1f28935841a69aa8be7eb2e88f580df9c95206d2 (diff)
downloadpies-cc298a11a131b162f291d6ee27ba1d7598a1b6c4.tar.gz
pies-cc298a11a131b162f291d6ee27ba1d7598a1b6c4.tar.bz2
New configuration statement for manipulating the environment.
The "env" statement is now a compound statement. It can contain four substatements: "clear" to clear the environment, "keep" to retain certain variable while clearing it, "set" to set a variable, and "unset" to unset a variable or variables. Both "keep" and "unset" can take globbing pattern as their argument, in which case they affect all variable matching that pattern. The value part in the "set" statement is subject to variable expansion, e.g. set "MANPATH=$MANPATH${MANPATH:+:}/usr/local/man" The support for the old one-line syntax of "env" is retained for backward compatibility. This commit also fixes redirection to a file: new data are appended to the file, instead of overwriting it. * lib/Makefile.am: Add new files. * lib/envop.c: New file. * lib/envop.h: New file. * lib/wildmatch.c: New file. * src/comp.c (component_free): Update. * src/pies.c (argv_free): New function. (parse_legacy_env): New function. (_cb_env): Remove. (cb_env_section_parser): New function. (cb_env_keywords): New keywords for the "env" block statement: clear, keep, set, unset. (component_keywords): New compount statement: env. Old usage retained for backward compatibility. * src/pies.h: Include "envop.h" (component)<env>: Remove. <envop>: New field. * src/prog.h (prog)<env>: New field. * src/progman.c (redirect_to_file): Position to the end of file. (DEBUG_ENVIRON): Remove macro. (debug_environ): New function. (environ_setup): Remove. (prog_sockenv): Use environ_set to modify local copy of environment. (prog_start_prologue): Use environ_create + envop_exec to create and modify the environment. (prog_execute): Set environment to prog-local copy. * tests/.gitignore: Build envtest * tests/Makefile.am: Add new tests. * tests/testsuite.at: Add environment tests. * tests/envop.at: New file. * tests/envtest.c: New file. * tests/env.at: New file. * tests/redirect.at: Check first two lines of the output file.
Diffstat (limited to 'src/progman.c')
-rw-r--r--src/progman.c310
1 files changed, 50 insertions, 260 deletions
diff --git a/src/progman.c b/src/progman.c
index 85670f2..b75a2db 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -390,6 +390,14 @@ redirect_to_file (struct prog *master, int stream)
master->v.p.comp->redir[stream].v.file,
strerror (errno));
}
+ /* Position to the end of file */
+ if (lseek (fd, 0, SEEK_END) == -1)
+ {
+ if (errno != ESPIPE)
+ logmsg (LOG_ERR, "lseek(%s): %s",
+ master->v.p.comp->redir[stream].v.file,
+ strerror (errno));
+ }
return fd;
}
@@ -604,10 +612,6 @@ conn_class_remove (struct conn_class *pcclass)
}
-extern char **environ; /* Environment */
-static size_t envsize; /* Size of environ. If it is not 0, then we
- have allocated space for the environ. */
-
#define ENV_PROTO "PROTO"
#define ENV_SOCKTYPE "SOCKTYPE"
#define ENV_LOCALIP "LOCALIP"
@@ -616,254 +620,30 @@ static size_t envsize; /* Size of environ. If it is not 0, then we
#define ENV_REMOTEIP "REMOTEIP"
#define ENV_REMOTEPORT "REMOTEPORT"
#define ENV_REMOTEHOST "REMOTEHOST"
-static char *sockenv_hint[] = {
- "-" ENV_PROTO,
- "-" ENV_SOCKTYPE,
- "-" ENV_LOCALIP,
- "-" ENV_LOCALPORT,
- "-" ENV_LOCALHOST,
- "-" ENV_REMOTEIP,
- "-" ENV_REMOTEPORT,
- "-" ENV_REMOTEHOST,
+static char *sockenv_var[] = {
+ ENV_PROTO,
+ ENV_SOCKTYPE,
+ ENV_LOCALIP,
+ ENV_LOCALPORT,
+ ENV_LOCALHOST,
+ ENV_REMOTEIP,
+ ENV_REMOTEPORT,
+ ENV_REMOTEHOST,
NULL
};
-#define DEBUG_ENVIRON(l) \
- do \
- if (debug_level >= (l)) \
- { \
- int i; \
- logmsg_printf (LOG_DEBUG, "environment: "); \
- for (i = 0; environ[i]; i++) \
- logmsg_printf (LOG_DEBUG, "%s ", environ[i]); \
- logmsg_printf (LOG_DEBUG, "\n"); \
- } \
- while (0)
-
-static void
-add_env (const char *name, const char *value)
-{
- size_t i;
- size_t namelen = strlen (name);
- char *p;
-
- for (i = 0; environ[i]; i++)
- {
- if (!strncmp (environ[i], name, namelen) && environ[i][namelen] == '=')
- break;
- }
-
- if (environ[i] == NULL)
- {
- if (envsize == 0)
- {
- char **new_env;
-
- envsize = i + 4;
- new_env = grecs_calloc (envsize, sizeof new_env[0]);
- for (i = 0; (new_env[i] = environ[i]); i++)
- ;
- environ = new_env;
- }
- else if (i == envsize)
- {
- envsize += 4;
- environ = grecs_realloc (environ,
- envsize * sizeof environ[0]);
- }
- environ[i+1] = NULL;
- }
-
- if (!value)
- value = "";
- p = grecs_malloc (namelen + 1 + strlen (value) + 1);
- strcpy (p, name);
- p[namelen] = '=';
- strcpy (p + namelen + 1, value);
- environ[i] = p;
-}
-
-/* Find variable NAME in environment ENV.
- On success, store the index of the ENV slot in *IDX,
- the offset of the value (position right past '=') in *VALOFF, and
- return 0 (IDX and/or VALOFF can be NULL, if that info is not needed).
- Return -1 if NAME was not found. */
-static int
-find_env_pos (char **env, char *name, size_t *idx, size_t *valoff)
+static inline void
+debug_environ (struct prog *prog, int l)
{
- size_t nlen = strcspn (name, "+=");
- size_t i;
-
- for (i = 0; env[i]; i++)
+ if (debug_level >= l)
{
- size_t elen = strcspn (env[i], "=");
- if (elen == nlen && memcmp (name, env[i], nlen) == 0)
- {
- if (idx)
- *idx = i;
- if (valoff)
- *valoff = elen + 1;
- return 0;
- }
- }
- return -1;
-}
-
-/* Find variable NAME in environment ENV.
- On success, return pointer to the variable assignment (if VAL is 0),
- or to the value (if VAL is 1).
- Return NULL if NAME is not present in ENV. */
-static char *
-find_env_ptr (char **env, char *name, int val)
-{
- size_t i, j;
- if (find_env_pos (env, name, &i, &j))
- return NULL;
- return val ? env[i] + j : env[i];
-}
-
-/* Return 1 if ENV contains a matching unset statement for variable NAME. */
-static int
-var_is_unset (char **env, const char *name)
-{
- int i;
- int nlen = strcspn (name, "=");
-
- for (i = 0; env[i]; i++)
- {
- if (env[i][0] == '-')
- {
- size_t elen = strcspn (env[i] + 1, "=");
- if (elen == nlen && memcmp (name, env[i] + 1, nlen) == 0)
- {
- if (env[i][nlen + 1])
- return strcmp (name + nlen, env[i] + 1 + nlen) == 0;
- else
- return 1;
- }
- }
- }
- return 0;
-}
-
-static char *
-env_concat (const char *name, size_t namelen, const char *a, const char *b)
-{
- char *res;
- size_t len;
-
- if (a && b)
- {
- res = grecs_malloc (namelen + 1 + strlen (a) + strlen (b) + 1);
- strcpy (res + namelen + 1, a);
- strcat (res + namelen + 1, b);
- }
- else if (a)
- {
- len = strlen (a);
- if (c_ispunct (a[len-1]))
- len--;
- res = grecs_malloc (namelen + 1 + len + 1);
- memcpy (res + namelen + 1, a, len);
- res[namelen + 1 + len] = 0;
- }
- else /* if (a == NULL) */
- {
- if (c_ispunct (b[0]))
- b++;
- len = strlen (b);
- res = grecs_malloc (namelen + 1 + len + 1);
- strcpy (res + namelen + 1, b);
- }
- memcpy (res, name, namelen);
- res[namelen] = '=';
- return res;
-}
-
-static void
-environ_setup (char **hint)
-{
- char **old_env = environ;
- char **new_env;
- size_t count, i, j, n;
-
- if (!hint)
- return;
-
- if (strcmp (hint[0], "-") == 0)
- {
- old_env = NULL;
- hint++;
- }
-
- /* Count new environment size */
- count = 0;
- if (old_env)
- for (i = 0; old_env[i]; i++)
- count++;
-
- for (i = 0; hint[i]; i++)
- count++;
-
- /* Allocate new environment. */
- new_env = grecs_calloc (count + 1, sizeof new_env[0]);
-
- /* Populate the environment. */
- n = 0;
-
- if (old_env)
- for (i = 0; old_env[i]; i++)
- {
- if (!var_is_unset (hint, old_env[i]))
- new_env[n++] = old_env[i];
- }
-
- for (i = 0; hint[i]; i++)
- {
- char *p;
-
- if (hint[i][0] == '-')
- {
- /* Skip unset directives. */
- continue;
- }
-
- /* Find the slot for the variable. Use next available
- slot if there's no such variable in new_env */
- if (find_env_pos (new_env, hint[i], &j, NULL))
- j = n;
-
- if ((p = strchr (hint[i], '=')))
- {
- if (p == hint[i])
- continue; /* Ignore erroneous entry */
- if (p[-1] == '+')
- new_env[j] = env_concat (hint[i], p - hint[i] - 1,
- find_env_ptr (environ, hint[i], 1),
- p + 1);
- else if (p[1] == '+')
- new_env[j] = env_concat (hint[i], p - hint[i],
- p + 2,
- find_env_ptr (environ, hint[i], 1));
- else
- new_env[j] = hint[i];
- }
- else if ((p = find_env_ptr (environ, hint[i], 0)))
- new_env[j] = p;
- else
- continue;
-
- /* Adjust environment size */
- if (j == n)
- ++n;
+ int i;
+ char **env = environ_ptr (prog->v.p.env);
+ logmsg_printf (LOG_DEBUG, "environment: ");
+ for (i = 0; env[i]; i++)
+ logmsg_printf (LOG_DEBUG, "%s ", env[i]);
+ logmsg_printf (LOG_DEBUG, "\n");
}
- new_env[n] = NULL;
-
- if (envsize)
- free (environ);
-
- environ = new_env;
- envsize = count + 1;
}
/* Pass socket information in environment variables. */
@@ -884,7 +664,7 @@ prog_sockenv (struct prog *prog)
if (socket_type_to_str (prog->v.p.comp->socket_type, &proto))
proto = umaxtostr (prog->v.p.comp->socket_type, buf);
- add_env (ENV_SOCKTYPE, proto);
+ environ_set (prog->v.p.env, ENV_SOCKTYPE, proto);
if (prog->v.p.comp->socket_url)
proto = prog->v.p.comp->socket_url->proto_s;
@@ -893,7 +673,7 @@ prog_sockenv (struct prog *prog)
else if (ISCF_TCPMUX (prog->v.p.comp->flags))
proto = "TCP";
- add_env (ENV_PROTO, proto);
+ environ_set (prog->v.p.env, ENV_PROTO, proto);
if (getsockname (prog->v.p.socket,
(struct sockaddr *) &sa_server, &len) < 0)
@@ -902,10 +682,10 @@ prog_sockenv (struct prog *prog)
{
p = inet_ntoa (sa_server.s_in.sin_addr);
if (p)
- add_env (ENV_LOCALIP, p);
+ environ_set (prog->v.p.env, ENV_LOCALIP, p);
p = umaxtostr (ntohs (sa_server.s_in.sin_port), buf);
- add_env (ENV_LOCALPORT, p);
+ environ_set (prog->v.p.env, ENV_LOCALPORT, p);
if (prog->v.p.comp->flags & CF_RESOLVE)
{
@@ -914,7 +694,7 @@ prog_sockenv (struct prog *prog)
AF_INET)) == NULL)
logmsg (LOG_WARNING, "gethostbyaddr: %s", strerror (errno));
else
- add_env (ENV_LOCALHOST, host->h_name);
+ environ_set (prog->v.p.env, ENV_LOCALHOST, host->h_name);
}
}
@@ -922,10 +702,10 @@ prog_sockenv (struct prog *prog)
{
p = inet_ntoa (sa_client->s_in.sin_addr);
if (p)
- add_env (ENV_REMOTEIP, p);
+ environ_set (prog->v.p.env, ENV_REMOTEIP, p);
p = umaxtostr (ntohs (sa_client->s_in.sin_port), buf);
- add_env (ENV_REMOTEPORT, p);
+ environ_set (prog->v.p.env, ENV_REMOTEPORT, p);
if (prog->v.p.comp->flags & CF_RESOLVE)
{
@@ -935,11 +715,11 @@ prog_sockenv (struct prog *prog)
logmsg (LOG_WARNING, "gethostbyaddr: %s",
strerror (errno));
else
- add_env (ENV_REMOTEHOST, host->h_name);
+ environ_set (prog->v.p.env, ENV_REMOTEHOST, host->h_name);
}
}
/* FIXME: $REMOTEINFO ? */
- DEBUG_ENVIRON (4);
+ debug_environ (prog, 4);
}
static int
@@ -1036,12 +816,21 @@ prog_start_prologue (struct prog *prog)
prog_tag (prog), prog->v.p.comp->dir, strerror (errno));
}
- environ_setup (prog->v.p.comp->env ?
- prog->v.p.comp->env :
- ((prog->v.p.comp->flags & CF_SOCKENV) ? sockenv_hint : NULL));
+ 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]);
+ }
+ envop_exec (prog->v.p.comp->envop, prog->v.p.env);
if (init_process)
- environ_setup (sysvinit_environ_hint);
- DEBUG_ENVIRON (4);
+ {
+ size_t i;
+ for (i = 0; sysvinit_environ_hint[i]; i++)
+ environ_add (prog->v.p.env, sysvinit_environ_hint[i]);
+ }
+ debug_environ (prog, 4);
pies_priv_setup (&prog->v.p.comp->privs);
if (prog->v.p.comp->umask)
@@ -1066,6 +855,7 @@ prog_start_prologue (struct prog *prog)
static void
prog_execute (struct prog *prog)
{
+ environ = environ_ptr (prog->v.p.env);
if (prog->v.p.comp->builtin)
{
mf_proctitle_format ("inetd %s",

Return to:

Send suggestions and report system problems to the System administrator.