aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2024-03-14 17:35:09 +0200
committerSergey Poznyakoff <gray@gnu.org>2024-03-14 17:59:52 +0200
commite879cd3085ff09f2ff7aff88b9a725d69f209a24 (patch)
treef16d044f42aa19faa5f1f0d0e7c5ec12d89f5fe2
parent33ab56c03ef99f1d9f508090d3452a78496cfe93 (diff)
downloadruncap-master.tar.gz
runcap-master.tar.bz2
Allow to set execution environmentHEADv1.4master
* runcap.3: Document changes. * runcap.c (runcap_start): Set environ if rc->rc_env is not NULL. (runcap_init): Initialize rc->rc_env with NULL if RCF_ENV is not set. * runcap.h (struct runcap): New field: rc_env. (RCF_ENV): New flag. * t/env.at: New test. * t/Makefile.am: Add new test. * t/testsuite.at: Likewise. * t/rt.c: New option: -e (modify environment).
-rw-r--r--runcap.325
-rw-r--r--runcap.c7
-rw-r--r--runcap.h2
-rw-r--r--t/Makefile.am3
-rw-r--r--t/env.at28
-rw-r--r--t/rt.c142
-rw-r--r--t/testsuite.at2
7 files changed, 188 insertions, 21 deletions
diff --git a/runcap.3 b/runcap.3
index 76dc6cc..2bd3648 100644
--- a/runcap.3
+++ b/runcap.3
@@ -15,3 +15,3 @@
.\" along with runcap. If not, see <http://www.gnu.org/licenses/>.
-.TH RUNCAP 2 "January 30, 2020" "RUNCAP" "User Commands"
+.TH RUNCAP 2 "March 14, 2024" "RUNCAP" "User Commands"
.SH NAME
@@ -69,9 +69,10 @@ struct runcap
{
- char *rc_program; /* [\fIIN\fR] (Path)name of the program to run */
- char **rc_argv; /* [\fIIN\fR] Argument vector */
- unsigned rc_timeout; /* [\fIIN\fR] Execution timeout */
+ char *rc_program; /* [\fIIN\fR] (Path)name of the program to run. */
+ char **rc_argv; /* [\fIIN\fR] Argument vector. */
+ char **rc_env; /* [\fIIN\fR] Environment variables. */
+ unsigned rc_timeout; /* [\fIIN\fR] Execution timeout. */
struct stream_capture rc_cap[3];
- pid_t rc_pid; /* [\fIOUT\fR] PID of the process */
- int rc_status; /* [\fIOUT\fR] Termination status */
- int rc_errno; /* [\fIOUT\fR] System error code */
+ pid_t rc_pid; /* [\fIOUT\fR] PID of the process. */
+ int rc_status; /* [\fIOUT\fR] Termination status. */
+ int rc_errno; /* [\fIOUT\fR] System error code. */
};
@@ -98,2 +99,10 @@ the \fBRCF_TIMEOUT\fR bit must be set in \fIflags\fR. If not set,
will wait indefinitely.
+.TP
+.B rc_env
+A
+.BR NULL -terminated
+array of environment variables. Each element (except the last
+.BR NULL )
+has the form "\fIname\fR=\fIvalue\fR". If initialized, the
+\fBRCF_ENV\fR bit must be set in \fIflags\fR.
.PP
@@ -478,3 +487,3 @@ Sergey Poznyakoff
.SH COPYRIGHT
-Copyright \(co 2017--2020 Sergey Poznyakoff
+Copyright \(co 2017--2024 Sergey Poznyakoff
.br
diff --git a/runcap.c b/runcap.c
index de64f70..56f6974 100644
--- a/runcap.c
+++ b/runcap.c
@@ -262,2 +262,4 @@ timeval_diff(struct timeval const *a, struct timeval const *b)
+extern char **environ;
+
static int
@@ -308,2 +310,4 @@ runcap_start(struct runcap *rc)
+ if (rc->rc_env)
+ environ = rc->rc_env;
execvp(rc->rc_program ? rc->rc_program : rc->rc_argv[0],
@@ -481,3 +485,4 @@ runcap_init(struct runcap *rc, int flags)
rc->rc_timeout = 0;
-
+ if (!(flags & RCF_ENV))
+ rc->rc_env = NULL;
if (flags & RCF_STDIN) {
diff --git a/runcap.h b/runcap.h
index 1fbb8f7..011cb06 100644
--- a/runcap.h
+++ b/runcap.h
@@ -49,2 +49,3 @@ struct runcap
char **rc_argv; /* [IN] Argument vector */
+ char **rc_env; /* [IN] Environment variables */
unsigned rc_timeout; /* [IN] Execution timeout */
@@ -60,2 +61,3 @@ struct runcap
#define RCF_STDIN 0x0004 /* rc_cap[RUNCAP_STDIN] is set */
+#define RCF_ENV 0x0008 /* rc_env is set */
diff --git a/t/Makefile.am b/t/Makefile.am
index 9e958ad..1905212 100644
--- a/t/Makefile.am
+++ b/t/Makefile.am
@@ -57,3 +57,4 @@ TESTSUITE_AT = \
seek00.at\
- seek01.at
+ seek01.at\
+ env.at
# Add more files here
diff --git a/t/env.at b/t/env.at
new file mode 100644
index 0000000..42883a1
--- /dev/null
+++ b/t/env.at
@@ -0,0 +1,28 @@
+# Testsuite for runcap - run program and capture its output -*- autotest -*-
+# Copyright (C) 2024 Sergey Poznyakoff
+#
+# Runcap 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 of the License, or (at your
+# option) any later version.
+#
+# Runcap 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 Runcap. If not, see <http://www.gnu.org/licenses/>.
+AT_SETUP([environment modifications])
+AT_KEYWORDS([env environ])
+AT_CHECK([rt -n stdout -e FOO=bar -- /bin/sh -c 'echo $FOO'],
+[0],
+[res=0
+exit code: 0
+stdout: 1 lines, 4 bytes
+stderr: 0 lines, 0 bytes
+stdout listing:
+ 1: bar
+stdout listing ends
+])
+AT_CLEANUP
diff --git a/t/rt.c b/t/rt.c
index 1ecdc3a..bcb49a4 100644
--- a/t/rt.c
+++ b/t/rt.c
@@ -27,2 +27,3 @@
#include <inttypes.h>
+#include <assert.h>
#include "runcap.h"
@@ -51,2 +52,6 @@ usage(int code)
fprintf(fp, " -S all|stderr|stdout selects capture for the next -m, -N, or -s option\n");
+ fprintf(fp, " -e VAR=NAME set environment variable\n");
+ fprintf(fp, " -e -VAR unset environment variable\n");
+ fprintf(fp, " -e - clear environment (except for PATH,\n");
+ fprintf(fp, " HOME, and LOGNAME)\n");
fprintf(fp, " -f FILE reads stdin from FILE\n");
@@ -236,7 +241,5 @@ readreq_do(struct runcap *rc, struct readreq *req)
ssize_t n;
-
- if (!buf) {
- perror("malloc");
- abort();
- }
+
+ assert(buf != NULL);
+
n = runcap_read(rc, req->what, buf, req->count);
@@ -281,2 +284,119 @@ open_outfile(char *file, int stream, struct runcap *rc, int *flags)
+static int
+getenvind(char **env, char const *name)
+{
+ size_t i;
+ for (i = 0; env[i]; i++) {
+ char const *p;
+ char *q;
+
+ for (p = name, q = env[i]; *p == *q; p++, q++)
+ ;
+ if (*p == 0 && *q == '=') {
+ return i;
+ }
+ }
+ return -1;
+}
+
+char **
+envdup(char **env)
+{
+ int i;
+ char **new_env;
+
+ for (i = 0; env[i]; i++)
+ ;
+
+ new_env = calloc(i+1, sizeof(env[0]));
+ assert(new_env != NULL);
+
+ for (i = 0; env[i]; i++) {
+ new_env[i] = strdup(env[i]);
+ assert(new_env[i] != NULL);
+ }
+ new_env[i] = NULL;
+
+ return new_env;
+}
+
+char **envupdate(char **, char *);
+
+char **
+envclear(char **env)
+{
+ int i, j;
+ static char *keep[] = {
+ "PATH",
+ "HOME",
+ "LOGNAME",
+ NULL
+ };
+ char **new_env = calloc(1, sizeof(new_env[0]));
+ assert(new_env != NULL);
+ for (i = 0; keep[i]; i++) {
+ j = getenvind(env, keep[i]);
+ if (j != -1)
+ new_env = envupdate(new_env, env[j]);
+ }
+ for (i = 0; env[i]; i++)
+ free(env[i]);
+ free(env);
+ return new_env;
+}
+
+char **
+envappend(char **env, char *arg)
+{
+ int i;
+
+ for (i = 0; env[i]; i++)
+ ;
+ env = realloc(env, (i+2) * sizeof(env[0]));
+ assert(env != NULL);
+ env[i] = strdup(arg);
+ assert(env[i] != NULL);
+ env[i+1] = NULL;
+ return env;
+}
+
+char **
+envdelete(char **env, char *arg)
+{
+ int i = getenvind(env, arg);
+ if (i != -1) {
+ int n;
+ for (n = 0; env[n]; n++)
+ ;
+ free(env[i]);
+ memmove(env + i, env + i + 1, (n - i) * sizeof(env[0]));
+ }
+ return env;
+}
+
+extern char **environ;
+
+char **
+envupdate(char **env, char *arg)
+{
+ if (env == NULL)
+ env = envdup(environ);
+ if (*arg == '-') {
+ if (arg[1] == 0)
+ env = envclear(env);
+ else
+ env = envdelete(env, arg+1);
+ } else {
+ int i = getenvind(env, arg);
+ if (i == -1)
+ env = envappend(env, arg);
+ else {
+ free(env[i]);
+ env[i] = strdup(arg);
+ assert(env[i] != NULL);
+ }
+ }
+ return env;
+}
+
int
@@ -308,4 +428,9 @@ main(int argc, char **argv)
progname = argv[0];
- while ((c = getopt(argc, argv, "?f:iNn:mo:p:r:S:s:t:")) != EOF) {
+ memset(&rc, 0, sizeof(rc));
+ while ((c = getopt(argc, argv, "?e:f:iNn:mo:p:r:S:s:t:")) != EOF) {
switch (c) {
+ case 'e':
+ rc.rc_env = envupdate(rc.rc_env, optarg);
+ rcf |= RCF_ENV;
+ break;
case 'f':
@@ -327,6 +452,3 @@ main(int argc, char **argv)
buffer = malloc(size + 1);
- if (!buffer) {
- error("not enough memory");
- exit(1);
- }
+ assert(buffer != NULL);
diff --git a/t/testsuite.at b/t/testsuite.at
index a3dd7c9..bbce1ff 100644
--- a/t/testsuite.at
+++ b/t/testsuite.at
@@ -34,2 +34,2 @@ m4_include([read.at])
m4_include([redirect.at])
-
+m4_include([env.at])

Return to:

Send suggestions and report system problems to the System administrator.