From c6a8697800376a02b868cdea8fc1bf55f12798f1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 16 Dec 2019 23:14:45 +0100 Subject: 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 --- tests/exec/exec_test.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++ tests/exec/exec_test.err | 1 + tests/exec/exec_test.ok | 46 ++++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 tests/exec/exec_test.c create mode 100644 tests/exec/exec_test.err create mode 100644 tests/exec/exec_test.ok (limited to 'tests/exec') 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 +#include + +#include +#include +#include +#include +#include +#include + +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! -- cgit v1.2.3