summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2019-12-16 23:14:45 +0100
committerHarald Welte <laforge@osmocom.org>2019-12-17 13:49:28 +0100
commitc6a8697800376a02b868cdea8fc1bf55f12798f1 (patch)
treee42f7a62ae2a17efd8f10810dfc63d3e776c0809 /tests
parent22c7ec3b60d6544d3042a115d519b9311b6bee45 (diff)
Introduce helper functions for safe fork+exec of processes
In some situations, we want to execute an external shell command in a non-blocking way. Similar to 'system', but without waiting for the child to complete. We also want to close all file descriptors ahead of the exec() and filter + modify the environment. Change-Id: Ib24ac8a083db32e55402ce496a5eabd8749cc888 Related: OS#4332
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.am10
-rw-r--r--tests/exec/exec_test.c155
-rw-r--r--tests/exec/exec_test.err1
-rw-r--r--tests/exec/exec_test.ok46
-rw-r--r--tests/testsuite.at7
5 files changed, 217 insertions, 2 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3a3ea376..bf7017b1 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -60,8 +60,10 @@ check_PROGRAMS += \
$(NULL)
endif
-if ENABLE_STATS_TEST
-check_PROGRAMS += stats/stats_test
+if !EMBEDDED
+check_PROGRAMS += \
+ stats/stats_test \
+ exec/exec_test
endif
if ENABLE_GB
@@ -259,6 +261,9 @@ use_count_use_count_test_LDADD = $(LDADD)
context_context_test_SOURCES = context/context_test.c
context_context_test_LDADD = $(LDADD)
+exec_exec_test_SOURCES = exec/exec_test.c
+exec_exec_test_LDADD = $(LDADD)
+
# The `:;' works around a Bash 3.2 bug when the output is not writeable.
$(srcdir)/package.m4: $(top_srcdir)/configure.ac
:;{ \
@@ -334,6 +339,7 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \
use_count/use_count_test.ok use_count/use_count_test.err \
context/context_test.ok \
gsm0502/gsm0502_test.ok \
+ exec/exec_test.ok exec/exec_test.err \
$(NULL)
DISTCLEANFILES = atconfig atlocal conv/gsm0503_test_vectors.c
diff --git a/tests/exec/exec_test.c b/tests/exec/exec_test.c
new file mode 100644
index 00000000..5f4b460c
--- /dev/null
+++ b/tests/exec/exec_test.c
@@ -0,0 +1,155 @@
+#include <osmocom/core/utils.h>
+#include <osmocom/core/exec.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+
+static void env_dump(char **env)
+{
+ char **ent;
+
+ for (ent = env; *ent; ent++)
+ printf("\t%s\n", *ent);
+}
+
+static void test_env_filter(void)
+{
+ char *out[256];
+ char *env_in[] = {
+ "FOO=1",
+ "BAR=2",
+ "USER=mahlzeit",
+ "BAZ=3",
+ "SHELL=/bin/sh",
+ NULL
+ };
+ const char *filter[] = {
+ "SHELL",
+ "USER",
+ NULL
+ };
+ int rc;
+
+ printf("\n==== osmo_environment_filter ====\n");
+
+ printf("Input Environment:\n");
+ env_dump(env_in);
+ printf("Input Whitelist:\n");
+ env_dump((char **) filter);
+ rc = osmo_environment_filter(out, ARRAY_SIZE(out), env_in, filter);
+ printf("Output Environment (%d):\n", rc);
+ env_dump(out);
+ OSMO_ASSERT(rc == 3);
+
+ printf("Testing for NULL out\n");
+ rc = osmo_environment_filter(NULL, 123, env_in, filter);
+ OSMO_ASSERT(rc < 0);
+
+ printf("Testing for zero-length out\n");
+ rc = osmo_environment_filter(out, 0, env_in, filter);
+ OSMO_ASSERT(rc < 0);
+
+ printf("Testing for one-length out\n");
+ rc = osmo_environment_filter(out, 1, env_in, filter);
+ OSMO_ASSERT(rc == 1 && out[0] == NULL);
+
+ printf("Testing for no filter\n");
+ rc = osmo_environment_filter(out, ARRAY_SIZE(out), env_in, NULL);
+ OSMO_ASSERT(rc < 0);
+
+ printf("Testing for no input\n");
+ rc = osmo_environment_filter(out, ARRAY_SIZE(out), NULL, filter);
+ OSMO_ASSERT(rc == 1 && out[0] == NULL);
+ printf("Success!\n");
+}
+
+static void test_env_append(void)
+{
+ char *out[256] = {
+ "FOO=a",
+ "BAR=b",
+ "BAZ=c",
+ NULL,
+ };
+ char *add[] = {
+ "MAHL=zeit",
+ "GSM=global",
+ "UMTS=universal",
+ "LTE=evolved",
+ NULL,
+ };
+ int rc;
+
+ printf("\n==== osmo_environment_append ====\n");
+
+ printf("Input Environment:\n");
+ env_dump(out);
+ printf("Input Addition:\n");
+ env_dump(add);
+ rc = osmo_environment_append(out, ARRAY_SIZE(out), add);
+ printf("Output Environment (%d)\n", rc);
+ env_dump(out);
+ OSMO_ASSERT(rc == 8);
+ printf("Success!\n");
+}
+
+static void test_close_fd(void)
+{
+ struct stat st;
+ int fds[2];
+ int rc;
+
+ printf("\n==== osmo_close_all_fds_above ====\n");
+
+ /* create some extra fds */
+ rc = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+ OSMO_ASSERT(rc == 0);
+
+ rc = fstat(fds[0], &st);
+ OSMO_ASSERT(rc == 0);
+
+ osmo_close_all_fds_above(2);
+
+ rc = fstat(fds[0], &st);
+ OSMO_ASSERT(rc == -1 && errno == EBADF);
+ rc = fstat(fds[1], &st);
+ OSMO_ASSERT(rc == -1 && errno == EBADF);
+ printf("Success!\n");
+}
+
+static void test_system_nowait(void)
+{
+ char *addl_env[] = {
+ "MAHLZEIT=spaet",
+ NULL
+ };
+ int rc, pid, i;
+
+ printf("\n==== osmo_system_nowait ====\n");
+
+ pid = osmo_system_nowait("env | grep MAHLZEIT 1>&2", osmo_environment_whitelist, addl_env);
+ OSMO_ASSERT(pid > 0);
+ for (i = 0; i < 10; i++) {
+ sleep(1);
+ rc = waitpid(pid, NULL, WNOHANG);
+ if (rc == pid) {
+ printf("Success!\n");
+ return;
+ }
+ }
+ printf("ERROR: child didn't terminate within 10s\n");
+}
+
+int main(int argc, char **argv)
+{
+ test_env_filter();
+ test_env_append();
+ test_close_fd();
+ test_system_nowait();
+
+ exit(0);
+}
diff --git a/tests/exec/exec_test.err b/tests/exec/exec_test.err
new file mode 100644
index 00000000..4edc61d6
--- /dev/null
+++ b/tests/exec/exec_test.err
@@ -0,0 +1 @@
+MAHLZEIT=spaet
diff --git a/tests/exec/exec_test.ok b/tests/exec/exec_test.ok
new file mode 100644
index 00000000..45a20f07
--- /dev/null
+++ b/tests/exec/exec_test.ok
@@ -0,0 +1,46 @@
+
+==== osmo_environment_filter ====
+Input Environment:
+ FOO=1
+ BAR=2
+ USER=mahlzeit
+ BAZ=3
+ SHELL=/bin/sh
+Input Whitelist:
+ SHELL
+ USER
+Output Environment (3):
+ USER=mahlzeit
+ SHELL=/bin/sh
+Testing for NULL out
+Testing for zero-length out
+Testing for one-length out
+Testing for no filter
+Testing for no input
+Success!
+
+==== osmo_environment_append ====
+Input Environment:
+ FOO=a
+ BAR=b
+ BAZ=c
+Input Addition:
+ MAHL=zeit
+ GSM=global
+ UMTS=universal
+ LTE=evolved
+Output Environment (8)
+ FOO=a
+ BAR=b
+ BAZ=c
+ MAHL=zeit
+ GSM=global
+ UMTS=universal
+ LTE=evolved
+Success!
+
+==== osmo_close_all_fds_above ====
+Success!
+
+==== osmo_system_nowait ====
+Success!
diff --git a/tests/testsuite.at b/tests/testsuite.at
index c231b964..cb83ab91 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -362,3 +362,10 @@ AT_KEYWORDS([context])
cat $abs_srcdir/context/context_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/context/context_test], [0], [expout], [ignore])
AT_CLEANUP
+
+AT_SETUP([exec])
+AT_KEYWORDS([exec])
+cat $abs_srcdir/exec/exec_test.ok > expout
+cat $abs_srcdir/exec/exec_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/exec/exec_test], [0], [expout], [experr])
+AT_CLEANUP