diff options
-rw-r--r-- | lib/Makefile.am | 5 | ||||
-rw-r--r-- | lib/envop.c | 484 | ||||
-rw-r--r-- | lib/envop.h | 68 | ||||
-rw-r--r-- | lib/wildmatch.c | 140 | ||||
-rw-r--r-- | src/comp.c | 16 | ||||
-rw-r--r-- | src/pies.c | 276 | ||||
-rw-r--r-- | src/pies.h | 5 | ||||
-rw-r--r-- | src/prog.h | 1 | ||||
-rw-r--r-- | src/progman.c | 306 | ||||
-rw-r--r-- | tests/.gitignore | 1 | ||||
-rw-r--r-- | tests/Makefile.am | 11 | ||||
-rw-r--r-- | tests/env.at | 65 | ||||
-rw-r--r-- | tests/envop.at | 101 | ||||
-rw-r--r-- | tests/envtest.c | 209 | ||||
-rw-r--r-- | tests/redirect.at | 2 | ||||
-rw-r--r-- | tests/testsuite.at | 3 |
16 files changed, 1407 insertions, 286 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 4aa9d3e..7b4eb42 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -21,6 +21,8 @@ noinst_HEADERS = libpies.h grecsasrt.h libpies_a_SOURCES=\ addrfmt.c\ arraymember.c\ + envop.c\ + envop.h\ grecsasrt.c\ mkfilename.c\ netrc.c\ @@ -30,7 +32,8 @@ libpies_a_SOURCES=\ safe_strcmp.c\ split3.c\ strtotok.c\ - url.c + url.c\ + wildmatch.c libpies_a_LIBADD=\ $(LIBOBJS)\ diff --git a/lib/envop.c b/lib/envop.c new file mode 100644 index 0000000..79083f7 --- /dev/null +++ b/lib/envop.c @@ -0,0 +1,484 @@ +/* Environment modification functions for GNU Pies. + Copyright (C) 2019 Sergey Poznyakoff + + GNU Pies 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 3, or (at your option) + any later version. + + GNU Pies 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 GNU Pies. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include "envop.h" +#include "wordsplit.h" + +environ_t * +environ_create (char **def) +{ + size_t i; + environ_t *env = malloc (sizeof (*env)); + + if (!env) + return NULL; + + if (!def) + { + static char *nullenv[] = { NULL }; + def = nullenv; + } + + for (i = 0; def[i]; i++) + ; + env->env_count = 0; + env->env_max = i + 1; + env->env_base = calloc (env->env_max, sizeof (env->env_base[0])); + if (!env->env_base) + { + free (env); + return NULL; + } + + for (i = 0; def[i]; i++) + { + if (!(env->env_base[i] = strdup (def[i]))) + { + environ_free (env); + return NULL; + } + env->env_count++; + } + env->env_base[i] = NULL; + return env; +} + +void +environ_free (environ_t *env) +{ + size_t i; + for (i = 0; i < env->env_count; i++) + free (env->env_base[i]); + free (env->env_base); +} + +static ssize_t +getenvind (environ_t *env, char const *name, char **pval) +{ + size_t i; + + for (i = 0; i < env->env_count; i++) + { + char const *p; + char *q; + + for (p = name, q = env->env_base[i]; *p == *q; p++, q++) + if (*p == '=') + break; + if ((*p == 0 || *p == '=') && *q == '=') + { + if (pval) + *pval = q + 1; + return i; + } + } + return -1; +} + +static ssize_t +environ_alloc (environ_t *env) +{ + size_t n; + if (env->env_count + 1 >= env->env_max) + { + char **p; + if (env->env_base == NULL) + { + n = 64; + p = calloc (n, sizeof (p[0])); + if (!p) + return -1; + } + else + { + n = env->env_max; + if ((size_t) -1 / 3 * 2 / sizeof (p[0]) <= n) + { + errno = ENOMEM; + return -1; + } + n += (n + 1) / 2; + p = realloc (env->env_base, n * sizeof (p[0])); + if (!p) + return -1; + } + env->env_base = p; + env->env_max = n; + } + n = env->env_count++; + env->env_base[env->env_count] = NULL; + return n; +} + +static int +environ_add_alloced (environ_t *env, char *def) +{ + ssize_t n; + n = getenvind (env, def, NULL); + if (n == -1) + { + n = environ_alloc (env); + if (n == -1) + return -1; + } + free (env->env_base[n]); + env->env_base[n] = def; + return 0; +} + +int +environ_add (environ_t *env, char const *def) +{ + char *defcp = strdup (def); + if (!defcp) + return -1; + if (environ_add_alloced (env, defcp)) + { + free (defcp); + return -1; + } + return 0; +} + +int +environ_set (environ_t *env, char const *name, char const *value) +{ + size_t len; + char *def; + struct wordsplit ws; + + if (!name) + { + errno = EINVAL; + return -1; + } + if (!value) + return environ_unset (env, name); + + ws.ws_env = (char const **) env->env_base; + if (wordsplit (value, &ws, + WRDSF_NOSPLIT + | WRDSF_QUOTE + | WRDSF_NOCMD /* FIXME */ + | WRDSF_SQUEEZE_DELIMS + | WRDSF_CESCAPES + | WRDSF_ENV + | WRDSF_PATHEXPAND)) + { + int ec = errno; + if (ws.ws_errno != WRDSE_USAGE) /* FIXME */ + wordsplit_free (&ws); + errno = ec; + return -1; + } + + if (strcmp (name, ":") == 0) + { + wordsplit_free (&ws); + return 0; + } + + len = strlen (name) + strlen (ws.ws_wordv[0]) + 2; + def = malloc (len); + if (!def) + { + int ec = errno; + wordsplit_free (&ws); + errno = ec; + return -1; + } + strcat (strcat (strcpy (def, name), "="), ws.ws_wordv[0]); + wordsplit_free (&ws); + if (environ_add_alloced (env, def)) + { + free (def); + return -1; + } + return 0; +} + +int +environ_unset (environ_t *env, char const *name) +{ + ssize_t n; + + if (!env || !name) + { + errno = EINVAL; + return -1; + } + n = getenvind (env, name, NULL); + if (n == -1) + 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; +} + +int +environ_unset_glob (environ_t *env, const char *pattern) +{ + size_t i; + + if (!env || !pattern) + { + errno = EINVAL; + return -1; + } + for (i = 0; i < env->env_count; ) + { + size_t len = strcspn (env->env_base[i], "="); + if (wildmatch (pattern, env->env_base[i], len) == 0) + { + free (env->env_base[i]); + memmove (env->env_base + i, env->env_base + i + 1, + (env->env_count - i) * sizeof (env->env_base[0])); + env->env_count--; + } + else + i++; + } + return 0; +} + +static void +envop_entry_insert (struct envop_entry **phead, struct envop_entry *op) +{ + struct envop_entry *head = *phead; + + if (!head) + { + *phead = op; + return; + } + + switch (op->code) + { + case envop_clear: + if (head->code == envop_clear) + free (op); + else + { + op->next = head; + *phead = op; + } + break; + + case envop_keep: + { + struct envop_entry *prev = NULL; + while (head && head->code <= op->code) + { + prev = head; + head = prev->next; + } + op->next = head; + if (prev) + prev->next = op; + else + *phead = op; + } + break; + + default: + while (head && head->next) + head = head->next; + + head->next = op; + } +} + +static int +valid_envar_name (char const *name) +{ + if (!name) + return 0; + if (!(isalpha (*name) || *name == '_')) + return 0; + while (*++name) + { + if (!(isalnum (*name) || *name == '_')) + return 0; + } + return 1; +} + +int +envop_entry_add (struct envop_entry **head, + enum envop_code code, char const *name, char const *value) +{ + struct envop_entry *op; + size_t s; + + switch (code) + { + case envop_clear: + break; + + case envop_set: + if (!name || !(*name == ':' || valid_envar_name (name))) + { + errno = EINVAL; + return -1; + } + break; + + case envop_keep: + case envop_unset: + break; + + default: + errno = EINVAL; + return -1; + } + + s = sizeof (op[0]); + if (name) + { + s += strlen (name) + 1; + if (value) + s += strlen (value) + 1; + } + op = malloc (s); + if (!op) + return -1; + op->next = NULL; + op->code = code; + op->name = NULL; + op->value = NULL; + if (name) + { + op->name = (char*)(op + 1); + strcpy (op->name, name); + if (value) + { + op->value = op->name + strlen (name) + 1; + strcpy (op->value, value); + } + } + envop_entry_insert (head, op); + return 0; +} + +static int +envopmatch (struct envop_entry *op, char const *var, int len) +{ + if (op->value) + { + if (strncmp (op->name, var, len) == 0) + return strcmp (var + len + 1, op->value); + } + return wildmatch (op->name, var, len); +} + +static int +keep_env (char const *var, struct envop_entry *keep) +{ + int len = strcspn (var, "="); + for (; keep && keep->code == envop_keep; keep = keep->next) + { + if (envopmatch (keep, var, len) == 0) + return 1; + } + return 0; +} + +int +envop_exec (struct envop_entry *op, environ_t *env) +{ + size_t i; + + if (op && op->code == envop_clear) + { + op = op->next; + if (op && op->code == envop_keep) + { + size_t keep_count = 0; + for (i = 0; i < env->env_count; i++) + { + if (keep_env (env->env_base[i], op)) + { + if (i > keep_count) + { + env->env_base[keep_count] = env->env_base[i]; + env->env_base[i] = NULL; + } + keep_count++; + } + else + { + free (env->env_base[i]); + env->env_base[i] = NULL; + } + } + env->env_count = keep_count; + } + else + { + size_t i; + for (i = 0; i < env->env_count; i++) + free (env->env_base[i]); + env->env_base[0] = 0; + env->env_count = 0; + } + } + + /* Process eventual set and unset statements */ + for (; op; op = op->next) + { + switch (op->code) + { + case envop_set: + if (environ_set (env, op->name, op->value)) + return -1; + break; + + case envop_unset: + environ_unset_glob (env, op->name); + break; + + case envop_keep: + break; + + default: + abort (); + } + } + + return 0; +} + +void +envop_free (struct envop_entry *op) +{ + while (op) + { + struct envop_entry *next = op->next; + free (op); + op = next; + } +} + diff --git a/lib/envop.h b/lib/envop.h new file mode 100644 index 0000000..054152e --- /dev/null +++ b/lib/envop.h @@ -0,0 +1,68 @@ +/* Environment and environment operation definitions for GNU Pies. + Copyright (C) 2019 Sergey Poznyakoff + + GNU Pies 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 3, or (at your option) + any later version. + + GNU Pies 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 GNU Pies. If not, see <http://www.gnu.org/licenses/>. */ + +/* Environment structure */ +struct environ +{ + char **env_base; + size_t env_count; + size_t env_max; +}; +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_glob (environ_t *env, const char *pattern); +static inline char ** +environ_ptr (environ_t *env) +{ + return env->env_base; +} + +/* Environment operation codes. + Elements in a oplist are sorted in that order. */ +enum envop_code + { + envop_clear, /* Clear environment */ + envop_keep, /* Keep variable when clearing */ + envop_set, /* Set variable */ + envop_unset /* Unset variable */ + }; + +struct envop_entry /* Environment operation entry */ +{ + struct envop_entry *next; /* Next entry in the list */ + enum envop_code code; /* Operation code */ + char *name; /* Variable name (or globbing pattern) */ + char *value; /* Value of the variable */ +}; + +typedef struct envop_entry envop_t; + +int wildmatch (char const *expr, char const *name, size_t len); + +int envop_entry_add (envop_t **head, + enum envop_code code, + char const *name, char const *value); + +int envop_exec (envop_t *op, environ_t *env); +void envop_free (envop_t *op); + + + diff --git a/lib/wildmatch.c b/lib/wildmatch.c new file mode 100644 index 0000000..2b4d7c8 --- /dev/null +++ b/lib/wildmatch.c @@ -0,0 +1,140 @@ +/* Environment-specific globbing pattern matching for GNU Pies. + Copyright (C) 2019 Sergey Poznyakoff + + GNU Pies 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 3, or (at your option) + any later version. + + GNU Pies 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 GNU Pies. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdlib.h> + +enum + { + WILD_FALSE = 0, + WILD_TRUE, + WILD_ABORT + }; + +static int +match_char_class (char const **pexpr, char c) +{ + int res; + int rc; + char const *expr = *pexpr; + + expr++; + if (*expr == '^') + { + res = 0; + expr++; + } + else + res = 1; + + if (*expr == '-' || *expr == ']') + rc = c == *expr++; + else + rc = !res; + + for (; *expr && *expr != ']'; expr++) + { + if (rc == res) + { + if (*expr == '\\' && expr[1] == ']') + expr++; + } + else if (expr[1] == '-') + { + if (*expr == '\\') + rc = *++expr == c; + else + { + rc = *expr <= c && c <= expr[2]; + expr += 2; + } + } + else if (*expr == '\\' && expr[1] == ']') + rc = *++expr == c; + else + rc = *expr == c; + } + *pexpr = *expr ? expr + 1 : expr; + return rc == res; +} + +#define END_OF_NAME(s,l) ((l) == 0 || *(s) == 0) +#define NEXT_CHAR(s,l) (s++, l--) + +int +wilder_match (char const *expr, char const *name, size_t len) +{ + int c; + + while (expr && *expr) + { + if (END_OF_NAME (name, len) && *expr != '*') + return WILD_ABORT; + switch (*expr) + { + case '*': + while (*++expr == '*') + ; + if (*expr == 0) + return WILD_TRUE; + while (!END_OF_NAME (name, len)) + { + int res = wilder_match (expr, name, len); + if (res != WILD_FALSE) + return res; + NEXT_CHAR (name, len); + } + return WILD_ABORT; + + case '?': + expr++; + NEXT_CHAR (name, len); + break; + + case '[': + if (!match_char_class (&expr, *name)) + return WILD_FALSE; + NEXT_CHAR (name, len); + break; + + case '\\': + if (expr[1]) + { + c = *++expr; expr++; + if (*name != wordsplit_c_unquote_char (c)) + return WILD_FALSE; + NEXT_CHAR (name, len); + break; + } + /* fall through */ + default: + if (*expr != *name) + return WILD_FALSE; + expr++; + NEXT_CHAR (name, len); + } + } + return END_OF_NAME (name, len) ? WILD_TRUE : WILD_FALSE; +} + +/* Return 0 if first LEN bytes of NAME match globbing pattern EXPR. */ +int +wildmatch (char const *expr, char const *name, size_t len) +{ + return wilder_match (expr, name, len) != WILD_TRUE; +} @@ -166,24 +166,12 @@ component_create (const char *name) void component_free (struct component *comp) { - size_t i; - component_unlink (comp); free (comp->tag); free (comp->program); free (comp->command); - if (comp->argv) - { - for (i = 0; i < comp->argc; i++) - free (comp->argv[i]); - free (comp->argv); - } - if (comp->env) - { - for (i = 0; comp->env[i]; i++) - free (comp->env[i]); - free (comp->env); - } + argv_free (comp->argv); + envop_free (comp->envop); free (comp->dir); grecs_list_free (comp->prereq); grecs_list_free (comp->depend); @@ -545,15 +545,126 @@ _cb_umask (enum grecs_callback_command cmd, return 0; } +void +argv_free (char **argv) +{ + if (argv) + { + size_t i; + for (i = 0; argv[i]; i++) + free (argv[i]); + free (argv); + } +} + static int -_cb_env (enum grecs_callback_command cmd, - grecs_locus_t *locus, - void *varptr, grecs_value_t *value, void *cb_data) +parse_legacy_env (char **argv, envop_t **envop) +{ + size_t i = 0; + int rc; + char *name; + + if (strcmp (argv[0], "-") == 0) + { + rc = envop_entry_add (envop, envop_clear, NULL, NULL); + if (rc) + return rc; + i++; + } + for (; (name = argv[i]) != NULL; i++) + { + char *name = argv[i]; + size_t len = strcspn (name, "="); + char *value; + char *mem = NULL; + size_t msize = 0; + enum envop_code code; + + if (name[0] == '-') + { + /* Unset directive */ + name++; + len--; + + if (name[len]) + { + name[len] = 0; + value = name + len + 1; + } + else + value = NULL; + + code = envop_unset; + } + else if (name[len]) + { + size_t vlen; + + if (len == 0) + /* Skip erroneous entry */ + continue; + value = name + len + 1; + vlen = strlen (value); + name[len] = 0; + if (name[len-1] == '+') + { + 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", + name, name, value[0], value + 1); + } + else + { + msize = len + vlen + 6; + snprintf (mem, msize, "${%s:-}%s", name, value); + } + value = mem; + } + else if (value[0] == '+') + { + value++; + vlen--; + + if (vlen > 0 && c_ispunct (value[vlen-1])) + { + 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:-}", + value, name, c, name); + } + else + { + msize = len + vlen + 6; + snprintf (mem, msize, "%s${%s:-}", value, name); + } + value = mem; + } + code = envop_set; + } + else + { + value = NULL; + code = envop_keep; + } + rc = envop_entry_add (envop, code, name, value); + free (mem); + if (rc) + return rc; + } + return 0; +} + +static int +_cb_env (envop_t **envop, grecs_value_t *value, grecs_locus_t *locus) { - size_t argc; char **argv; - char ***penv = varptr; - struct wordsplit ws; + int rc; switch (value->type) { @@ -572,10 +683,146 @@ _cb_env (enum grecs_callback_command cmd, return 1; } - *penv = argv; + rc = parse_legacy_env (argv, envop); + argv_free (argv); + if (rc) + { + grecs_error (locus, errno, _("can't parse legacy env statement")); + return 1; + } return 0; } +static int +cb_env_section_parser (enum grecs_callback_command cmd, + grecs_locus_t *locus, + void *varptr, + grecs_value_t *value, void *cb_data) +{ + struct component *comp = varptr; + + switch (cmd) + { + case grecs_callback_section_begin: + //FIXME + *(struct component **) cb_data = comp; + break; + + case grecs_callback_section_end: + //FIXME + break; + + case grecs_callback_set_value: + return _cb_env (&comp->envop, value, locus); + } + return 0; +} + +static int +_cb_env_clear (enum grecs_callback_command cmd, + grecs_locus_t *locus, + void *varptr, grecs_value_t *value, void *cb_data) +{ + struct component *comp = varptr; + int clear; + + if (assert_scalar_stmt (locus, cmd) + || assert_grecs_value_type (locus, value, GRECS_TYPE_STRING)) + return 1; + if (grecs_string_convert(&clear, grecs_type_bool, value->v.string, locus)) + return 1; + if (clear) + { + if (envop_entry_add (&comp->envop, envop_clear, NULL, NULL)) + grecs_error (locus, errno, "envop_entry_add"); + } + return 0; +} + +static int +_cb_env_keep (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; + p = strchr (value->v.string, '='); + if (p) + *p++ = 0; + if (envop_entry_add (&comp->envop, envop_clear, NULL, NULL)) + grecs_error (locus, errno, "envop_entry_add"); + if (envop_entry_add (&comp->envop, envop_keep, value->v.string, p)) + grecs_error (locus, errno, "envop_entry_add"); + return 0; +} + +static int +_cb_env_set (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; + p = strchr (value->v.string, '='); + if (p) + *p++ = 0; + if (envop_entry_add (&comp->envop, envop_set, value->v.string, p)) + grecs_error (locus, errno, "envop_entry_add"); + return 0; +} + +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; + + 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)) + grecs_error (locus, errno, "envop_entry_add"); + return 0; +} + +struct grecs_keyword cb_env_keywords[] = { + { "clear", + N_("bool"), + N_("Clear environment."), + grecs_type_bool, GRECS_DFLT, + NULL, 0, + _cb_env_clear }, + { "keep", + N_("name[=value]"), + N_("Keep this variable. Unless value is supplied, name can contain wildcards.\n" + "Implies \"clear yes\"."), + grecs_type_string, GRECS_DFLT, + NULL, 0, + _cb_env_keep }, + { "set", + N_("name=value"), + N_("Set environment variable. Note, that argument must be quoted."), + grecs_type_string, GRECS_DFLT, + NULL, 0, + _cb_env_set }, + { "unset", + N_("name"), + N_("Unset environment variable. Name can contain wildcards."), + grecs_type_string, GRECS_DFLT, + NULL, 0, + _cb_env_unset }, + { NULL } +}; + int string_to_syslog_priority (const char *key, int *pres) @@ -1157,12 +1404,19 @@ struct grecs_keyword component_keywords[] = { _cb_limits, }, {"env", + NULL, + N_("Modify program environment."), + grecs_type_section, GRECS_DFLT, + NULL, 0, + cb_env_section_parser, NULL, cb_env_keywords + }, + {"env", N_("arg: list"), - N_("Set program environment. Argument is a list of assignments " - "separated by white space."), + N_("Modify program environment (legacy syntax).\n" + "Argument is a list of quoted assignments separated by white space."), grecs_type_string, GRECS_DFLT, - NULL, offsetof (struct component, env), - _cb_env, + NULL, 0, + cb_env_section_parser, NULL, NULL }, {"chdir", N_("dir"), @@ -56,6 +56,7 @@ #include "identity.h" #include "acl.h" #include "libpies.h" +#include "envop.h" #include "grecs/json.h" #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) @@ -229,7 +230,7 @@ struct component char *command; /* Full command line */ size_t argc; /* Number of command line arguments */ char **argv; /* Program command line */ - char **env; /* Program environment */ + envop_t *envop; /* Environment modification program */ char *dir; /* Working directory */ struct grecs_list *prereq; /* Prerequisites */ struct grecs_list *depend; /* Dependency targets */ @@ -333,6 +334,8 @@ void free_redirector (struct redirector *rp); void pies_schedule_action (int act); void free_action (struct action *act); +void argv_free (char **argv); + #define PIES_CHLD_NONE 0 #define PIES_CHLD_CLEANUP 0x01 #define PIES_CHLD_WAKEUP 0x02 @@ -58,6 +58,7 @@ struct prog time_t timestamp; /* Time of last startup */ size_t failcount; /* Number of failed starts since timestamp */ enum prog_status status; /* Current component status */ + environ_t *env; /* Execution environment (only in child) */ /* If status == status_listener: */ size_t num_instances; /* Number of running instances */ /* If comp->type == pies_comp_inetd && status == status_running */ 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 |