summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWaLyong Cho <walyong.cho@samsung.com>2016-11-08 09:22:55 (GMT)
committerWaLyong Cho <walyong.cho@samsung.com>2016-11-08 09:23:08 (GMT)
commite25a89806d181e40028ac3e82abec22032b9bce5 (patch)
tree2581435c0925f0846a5f8fa8846fdd253abc6d29
parentb3d97ce44cd29478fdfe13068eaf08ef57583755 (diff)
parent4809efe44e7ecee13a1c2b19fb3114621f1e3c12 (diff)
downloadlibsystem-e25a89806d181e40028ac3e82abec22032b9bce5.zip
libsystem-e25a89806d181e40028ac3e82abec22032b9bce5.tar.gz
libsystem-e25a89806d181e40028ac3e82abec22032b9bce5.tar.bz2
release: 4.0-2
[Model] Common [BinType] AP [Customer] N/A [Issue] N/A [Request] N/A [Occurrence Version] N/A [Problem] release: 4.0-2 [Cause & Measure] N/A [Checking Method] N/A [Team] SystemFW [Developer] WaLyong Cho [Solution company] Samsung [Change Type] N/A * devel/systemfw/master: release: 4.0-2 build: run make check with build libsystem: glib-util: wipe out _cleanup_g_xxx_ libsystem-sd: use g_auto(), g_autoptr() or g_autofree libsystem: test: add test for exec libsystem: exec: kill child on timeout and add kill signal selectable api libsystem: exec: add do_fork_exec_redirect() gitignore: add test-driver spec: resolve rpmlint warnings and use rpmmacros Change-Id: I2443c80bb4ca398b3d733eb57200b9241ad72e8c Signed-off-by: WaLyong Cho <walyong.cho@samsung.com>
-rw-r--r--.gitignore3
-rw-r--r--packaging/libsystem.spec43
-rw-r--r--src/Makefile.am9
-rw-r--r--src/libsystem-sd/systemd.c34
-rw-r--r--src/libsystem/exec.c97
-rw-r--r--src/libsystem/glib-util.h85
-rw-r--r--src/libsystem/libsystem.h110
-rw-r--r--src/test/test-exec.c97
8 files changed, 326 insertions, 152 deletions
diff --git a/.gitignore b/.gitignore
index 8c45dde..75d3a83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,4 +41,5 @@ stamp-*
/debugfiles.list
/debuglinks.list
/debugsources.list
-/documentation.list \ No newline at end of file
+/documentation.list
+/test-driver \ No newline at end of file
diff --git a/packaging/libsystem.spec b/packaging/libsystem.spec
index 109f442..a15de97 100644
--- a/packaging/libsystem.spec
+++ b/packaging/libsystem.spec
@@ -1,7 +1,7 @@
Name: libsystem
Summary: System Libraries
Version: 4.0
-Release: 1
+Release: 2%{?release_flags}
License: Apache-2.0
Group: System/Libraries
Source: %{name}-%{version}.tar.gz
@@ -11,8 +11,8 @@ BuildRequires: autoconf
BuildRequires: automake
BuildRequires: libtool
BuildRequires: pkgconfig(dbus-1)
-BuildRequires: pkgconfig(glib-2.0)
-BuildRequires: pkgconfig(gio-2.0)
+BuildRequires: pkgconfig(glib-2.0) >= 2.44
+BuildRequires: pkgconfig(gio-2.0) >= 2.44
Requires: /bin/cp
@@ -20,29 +20,32 @@ Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
%description
-System libraries.
+System utility libraries.
%package devel
-Summary: Development header files for System Libraries
+Summary: Header files for System Libraries
License: Apache-2.0
+Requires: %{name} = %{version}
Requires: pkgconfig(glib-2.0)
%description devel
-Development headers and auxiliary files.
+Development header files for System Libraries.
%package -n libsystem-sd
Summary: Utility libraries for systemd
License: Apache-2.0
+Requires: libsystem = %{version}
%description -n libsystem-sd
-systemd utility libraries.
+A helper utility libraries for systemd.
%package -n libsystem-sd-devel
-Summary: Development header files for systemd util
+Summary: Header files for systemd util
License: Apache-2.0
+Requires: libsystem-sd = %{version}
+Requires: pkgconfig(libsystem) = %{version}
Requires: pkgconfig(gio-2.0)
Requires: pkgconfig(dbus-1)
-Requires: pkgconfig(libsystem)
%description -n libsystem-sd-devel
Development header files for systemd util.
@@ -60,19 +63,20 @@ export CFLAGS=$(echo $CFLAGS | sed -e 's/-Wp,-D_FORTIFY_SOURCE=2 / /g')
export CFLAGS="-O0 -g $CFLAGS"
%endif
-./autogen.sh
-%configure \
- --disable-static \
- --prefix=%{_prefix} \
+%autogen
+%reconfigure
make %{?_smp_mflags}
%install
%make_install
-# Remove local archives
-rm -f %{buildroot}%{_libdir}/*.la
+# make sure debugsources.list exist, it used by rpm macro in %file
+# section.
+touch debugsources.list
+%check
+make check
%post
/sbin/ldconfig
@@ -82,15 +86,17 @@ rm -f %{buildroot}%{_libdir}/*.la
%post -n libsystem-sd
/sbin/ldconfig
-%postun -n libsystem-sd -p /sbin/ldconfig
+%postun -n libsystem-sd
+/sbin/ldconfig
%files
%defattr(-,root,root,-)
-%{_libdir}/libsystem.so.*
%manifest %{name}.manifest
+%{_libdir}/libsystem.so.*
%files devel
%defattr(-,root,root,-)
+%manifest %{name}.manifest
%{_libdir}/libsystem.so
%{_includedir}/libsystem/config-parser.h
%{_includedir}/libsystem/dbus-util.h
@@ -100,11 +106,12 @@ rm -f %{buildroot}%{_libdir}/*.la
%files -n libsystem-sd
%defattr(-,root,root,-)
-%{_libdir}/libsystem-sd.so.*
%manifest %{name}.manifest
+%{_libdir}/libsystem-sd.so.*
%files -n libsystem-sd-devel
%defattr(-,root,root,-)
+%manifest %{name}.manifest
%{_libdir}/libsystem-sd.so
%{_includedir}/libsystem-sd/systemd.h
%{_libdir}/pkgconfig/libsystem-sd.pc
diff --git a/src/Makefile.am b/src/Makefile.am
index 61fee7c..e7df956 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -84,6 +84,15 @@ test_truncate_nl_LDADD = \
tests += test-truncate_nl
# ------------------------------------------------------------------------------
+test_exec_SOURCES = \
+ test/test-exec.c
+
+test_exec_LDADD = \
+ libsystem.la
+
+tests += test-exec
+
+# ------------------------------------------------------------------------------
pkgconfiglib_DATA += \
libsystem-sd/libsystem-sd.pc
diff --git a/src/libsystem-sd/systemd.c b/src/libsystem-sd/systemd.c
index ec53b90..cfcd5d6 100644
--- a/src/libsystem-sd/systemd.c
+++ b/src/libsystem-sd/systemd.c
@@ -87,7 +87,7 @@ static int systemd_call_sync(GDBusConnection *connection,
NULL,
&err);
else {
- _cleanup_g_object_unref_ GDBusProxy *proxy = NULL;
+ g_autofree GDBusProxy *proxy = NULL;
proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
@@ -125,8 +125,8 @@ static int systemd_call_sync(GDBusConnection *connection,
}
int systemd_subscribe(GDBusConnection *connection, char **err_msg) {
- _cleanup_g_variant_unref_ GVariant *reply = NULL;
- _cleanup_g_error_free_ GError *error = NULL;
+ g_autofree GVariant *reply = NULL;
+ g_autofree GError *error = NULL;
int r;
r = systemd_call_sync(connection,
@@ -148,8 +148,8 @@ int systemd_subscribe(GDBusConnection *connection, char **err_msg) {
}
int systemd_unsubscribe(GDBusConnection *connection, char **err_msg) {
- _cleanup_g_variant_unref_ GVariant *reply = NULL;
- _cleanup_g_error_free_ GError *error = NULL;
+ g_autofree GVariant *reply = NULL;
+ g_autofree GError *error = NULL;
int r;
r = systemd_call_sync(connection,
@@ -175,8 +175,8 @@ int systemd_get_unit(GDBusConnection *connection,
char **unit,
char **err_msg) {
- _cleanup_g_variant_unref_ GVariant *reply = NULL;
- _cleanup_g_error_free_ GError *error = NULL;
+ g_autofree GVariant *reply = NULL;
+ g_autofree GError *error = NULL;
char *obj = NULL;
int r;
@@ -219,8 +219,8 @@ int systemd_control_unit(GDBusConnection *connection,
char **job,
char **err_msg) {
- _cleanup_g_variant_unref_ GVariant *reply = NULL;
- _cleanup_g_error_free_ GError *error = NULL;
+ g_autofree GVariant *reply = NULL;
+ g_autofree GError *error = NULL;
char *obj = NULL;
int r;
@@ -347,7 +347,7 @@ static int systemd_get_property(GDBusConnection *connection,
GVariant **variant,
char **err_msg) {
- _cleanup_g_error_free_ GError *error = NULL;
+ g_autofree GError *error = NULL;
int r;
assert(name);
@@ -471,7 +471,7 @@ static int systemd_get_service_property(GDBusConnection *connection,
value* result, \
char** err_msg) { \
\
- _cleanup_g_variant_unref_ GVariant *var = NULL, *inner = NULL; \
+ g_autofree GVariant *var = NULL, *inner = NULL; \
int r; \
\
assert(target); \
@@ -606,7 +606,7 @@ void systemd_unit_status_list_free_full(GList *status_list) {
static int systemd_parse_list_units_result(GVariant *result, GList **unit_list) {
char *name, *description, *load_state, *active_state, *sub_state;
char *followed, *obj_path, *job_type, *job_obj_path;
- _cleanup_g_variant_iter_free_ GVariantIter *iter;
+ g_autofree GVariantIter *iter;
unsigned int job_id;
GList *list = NULL;
int r;
@@ -728,8 +728,8 @@ on_error:
}
int systemd_get_units_list(GDBusConnection *conn, GList **unit_list, char **err_msg) {
- _cleanup_g_variant_unref_ GVariant *reply = NULL;
- _cleanup_g_error_free_ GError *error = NULL;
+ g_autofree GVariant *reply = NULL;
+ g_autofree GError *error = NULL;
int r;
assert(unit_list);
@@ -786,7 +786,7 @@ void systemd_unit_file_status_list_free_full(GList *status_list) {
}
static int systemd_parse_list_unit_files_result(GVariant *result, GList **unit_files_list) {
- _cleanup_g_variant_iter_free_ GVariantIter *iter;
+ g_autofree GVariantIter *iter;
GList *list = NULL;
char *name, *status;
int r;
@@ -843,8 +843,8 @@ on_error:
}
int systemd_get_unit_files_list(GDBusConnection *conn, GList **unit_files_list, char **err_msg) {
- _cleanup_g_variant_unref_ GVariant *reply = NULL;
- _cleanup_g_error_free_ GError *error = NULL;
+ g_autofree GVariant *reply = NULL;
+ g_autofree GError *error = NULL;
int r;
assert(conn);
diff --git a/src/libsystem/exec.c b/src/libsystem/exec.c
index 05dc89c..5fb49f4 100644
--- a/src/libsystem/exec.c
+++ b/src/libsystem/exec.c
@@ -29,10 +29,52 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <signal.h>
#include "libsystem.h"
-int do_fork_exec(char *const argv[], char * const envp[], int64_t timeout_msec) {
+static int wait_child(pid_t pid, int64_t timeout_msec, int sig) {
+ struct timeval start, timeout;
+ int status;
+
+ if (timeout_msec < 0)
+ return 0;
+
+ if (timeout_msec > 0) {
+ msec_to_timeval((uint64_t) timeout_msec, &timeout);
+
+ if (gettimeofday(&start, NULL) < 0)
+ return -errno;
+ }
+
+ for (;;) {
+ struct timeval current, delta;
+ pid_t p;
+
+ p = waitpid(pid, &status, WNOHANG);
+ if (p == pid)
+ break;
+
+ if (timeout_msec == 0)
+ continue;
+
+ if (gettimeofday(&current, NULL) < 0)
+ return -errno;
+
+ timersub(&current, &start, &delta);
+
+ if (timercmp(&timeout, &delta, <)) {
+ (void) kill(pid, sig);
+ return -ETIME;
+ }
+
+ usleep(100000);
+ }
+
+ return WEXITSTATUS(status);
+}
+
+int do_fork_exec_kill_redirect(char *const argv[], char * const envp[], int64_t timeout_msec, int sig, int fd, int flags) {
pid_t pid;
assert(argv);
@@ -41,50 +83,43 @@ int do_fork_exec(char *const argv[], char * const envp[], int64_t timeout_msec)
if (pid < 0)
return -errno;
else if (pid == 0) {
+
+ if (fd >= 0) {
+ if (flags & EXEC_REDIRECT_OUTPUT)
+ dup2(fd, STDOUT_FILENO);
+
+ if (flags & EXEC_REDIRECT_ERROR)
+ dup2(fd, STDERR_FILENO);
+ }
+
if (!envp)
execv(*argv, argv);
else
execvpe(*argv, argv, envp);
_exit(EXIT_FAILURE);
- } else {
- struct timeval start, timeout;
- int status;
-
- if (timeout_msec < 0)
- return 0;
-
- if (timeout_msec > 0) {
- msec_to_timeval((uint64_t) timeout_msec, &timeout);
+ }
- if (gettimeofday(&start, NULL) < 0)
- return -errno;
- }
+ return wait_child(pid, timeout_msec, sig);
+}
- for (;;) {
- struct timeval current, delta;
- pid_t p;
+int do_fork_exec_redirect(char *const argv[], char * const envp[], int64_t timeout_msec, int fd, int flags) {
- p = waitpid(pid, &status, WNOHANG);
- if (p == pid)
- break;
+ assert(argv);
- if (timeout_msec == 0)
- continue;
+ return do_fork_exec_kill_redirect(argv, envp, timeout_msec, SIGTERM, fd, flags);
+}
- if (gettimeofday(&current, NULL) < 0)
- return -errno;
+int do_fork_exec_kill(char *const argv[], char * const envp[], int64_t timeout_msec, int sig) {
- timersub(&current, &start, &delta);
+ assert(argv);
- if (timercmp(&timeout, &delta, <))
- return -ETIME;
+ return do_fork_exec_kill_redirect(argv, envp, timeout_msec, sig, -1, EXEC_REDIRECT_NONE);
+}
- usleep(100000);
- }
+int do_fork_exec(char *const argv[], char * const envp[], int64_t timeout_msec) {
- return WEXITSTATUS(status);
- }
+ assert(argv);
- return 0;
+ return do_fork_exec_kill(argv, envp, timeout_msec, SIGTERM);
}
diff --git a/src/libsystem/glib-util.h b/src/libsystem/glib-util.h
index b87ebdf..7d3c7ad 100644
--- a/src/libsystem/glib-util.h
+++ b/src/libsystem/glib-util.h
@@ -38,91 +38,6 @@
extern "C" {
#endif
-
-/**
- * gchar free function. This function has to not be called
- * directly. If a gchar value is declared with #_cleanup_g_free_, this
- * function is called when the value goes out of scope.
- */
-static inline void __g_free(gchar **p) {
- if (*p)
- g_free(*p);
-}
-
-/**
- * GError free function. This function has to not be called
- * directly. If a GError value is declared with
- * #_cleanup_g_error_free_, this function is called when the value
- * goes out of scope.
- */
-static inline void __g_error_free(GError **e) {
- if (*e)
- g_error_free(*e);
-}
-
-/**
- * GObject free function. This function has to not be called
- * directly. If a GObject value is declared with
- * #_cleanup_g_object_unref_, this function is called when the value
- * goes out of scope.
- */
-static inline void __g_object_unref(gpointer p) {
- if (p)
- g_object_unref(*(gpointer *) p);
-}
-
-/**
- * GVariant free function. This function has to not be called
- * directly. If a GVariant value is declared with
- * #_cleanup_g_variant_unref_, this function is called when the value
- * goes out of scope.
- */
-static inline void __g_variant_unref(GVariant **v) {
- if (*v)
- g_variant_unref(*v);
-}
-
-/**
- * GVariantIter free function. This function has to not be called
- * directly. If a GVariantIter value is declared with
- * #_cleanup_g_variant_iter_free_, this function is called when the
- * value goes out of scope.
- */
-static inline void __g_variant_iter_free(GVariantIter **i) {
- if (*i)
- g_variant_iter_free(*i);
-}
-
-/**
- * cleanup attribute for gchar to run #__g_free() when the value is
- * going out of scope.
- */
-#define _cleanup_g_free_ _cleanup_(__g_free)
-
-/**
- * cleanup attribute for GError to run #__g_error_free() when the
- * value is going out of scope.
- */
-#define _cleanup_g_error_free_ _cleanup_(__g_error_free)
-
-/**
- * cleanup attribute for GObject to run #__g_object_unref() when the
- * value is going out of scope.
- */
-#define _cleanup_g_object_unref_ _cleanup_(__g_object_unref)
-
-/**
- * cleanup attribute for GVariant to run #__g_variant_unref() when the
- * value is going out of scope.
- */
-#define _cleanup_g_variant_unref_ _cleanup_(__g_variant_unref)
-
-/**
- * cleanup attribute for GVariantIter to run #__g_variant_iter_free()
- * when the value is going out of scope.
- */
-#define _cleanup_g_variant_iter_free_ _cleanup_(__g_variant_iter_free)
-
/**
* @brief Iterate for each list nodes.
*
diff --git a/src/libsystem/libsystem.h b/src/libsystem/libsystem.h
index 7819aa7..096b849 100644
--- a/src/libsystem/libsystem.h
+++ b/src/libsystem/libsystem.h
@@ -809,6 +809,116 @@ bool mnt_is_mounted(const char *fsname, const char *dir, const char *type, const
*/
/**
+ * standard output/error redirect flags
+ */
+enum {
+ /**
+ * Do not redirect standard output/error
+ */
+ EXEC_REDIRECT_NONE = 0x01 << 0,
+ /**
+ * Redirect standard output only
+ */
+ EXEC_REDIRECT_OUTPUT = 0x01 << 1,
+ /**
+ * Redirect standard error only
+ */
+ EXEC_REDIRECT_ERROR = 0x01 << 2,
+ /**
+ * Redirect standard output and error all
+ */
+ EXEC_REDIRECT_ALL = (EXEC_REDIRECT_OUTPUT | EXEC_REDIRECT_ERROR),
+};
+
+/**
+ * @brief Traditional fork() and exec() helper. If child is not
+ * deactivated within given \p timeout_msec then kill it with given
+ * signal. And additionally redirect child process standard output or
+ * standard error to given fd.
+ *
+ * @param argv array of pointers to null-terminated strings that
+ * represent the argument list available to the new program. The first
+ * argument should point to the filename associated with the file
+ * being executed. The array of pointers must be terminated by a NULL
+ * pointer.
+ * @param envp specify the environment of the executed program via the
+ * argument envp. The envp argument is an array of pointers to
+ * null-terminated strings and must be terminated by a NULL pointer.
+ * @param timeout_msec timeout millisecond to prevent infinite
+ * waiting. If negative is given, the parent will not wait the
+ * child. In other word, the parent will return immediately. If 0 is
+ * given, parent will wait the child infinitly. And if positive value
+ * is given parent will wait given milliseconds and expired return
+ * -1. If the child is exit within the tiemout millisecond return with
+ * child exit code.
+ * @param sig signal to kill the child on timeout.
+ * @param fd file descriptor to redirect child standard output or
+ * error.
+ * @param flags redirect flag. This flags is able to include
+ * EXEC_REDIRECT_OUTPUT or EXEC_REDIRECT_ERROR.
+ *
+ * @return exit code of child. It is fully depend on the child
+ * process. If the child exit with 1 then this function also return 1.
+ * Negative errno on error. -ETIME on timer expired.
+ */
+int do_fork_exec_kill_redirect(char *const argv[], char * const envp[], int64_t timeout_msec, int sig, int fd, int flags);
+
+/**
+ * @brief Traditional fork() and exec() helper. And additionally
+ * redirect child process standard output or standard error to given fd.
+ *
+ * @param argv array of pointers to null-terminated strings that
+ * represent the argument list available to the new program. The first
+ * argument should point to the filename associated with the file
+ * being executed. The array of pointers must be terminated by a NULL pointer.
+ * @param envp specify the environment of the executed program via the
+ * argument envp. The envp argument is an array of pointers to
+ * null-terminated strings and must be terminated by a NULL pointer.
+ * @param timeout_msec timeout millisecond to prevent infinite
+ * waiting. If negative is given, the parent will not wait the
+ * child. In other word, the parent will return immediately. If 0 is
+ * given, parent will wait the child infinitly. And if positive value
+ * is given parent will wait given milliseconds and expired return
+ * -1. If the child is exit within the tiemout millisecond return with
+ * child exit code.
+ * @param fd file descriptor to redirect child standard output or error.
+ * @param flags redirect flag. This flags is able to include
+ * EXEC_REDIRECT_OUTPUT or EXEC_REDIRECT_ERROR.
+ *
+ * @return exit code of child. It is fully depend on the child
+ * process. If the child exit with 1 then this function also return 1.
+ * Negative errno on error. -ETIME on timer expired.
+ */
+int do_fork_exec_redirect(char *const argv[], char * const envp[], int64_t timeout_msec, int fd, int flags);
+
+/**
+ * @brief Traditional fork() and exec() helper. If child is not
+ * deactivated within given \p timeout_msec then kill it with given
+ * signal.
+ *
+ * @param argv array of pointers to null-terminated strings that
+ * represent the argument list available to the new program. The first
+ * argument should point to the filename associated with the file
+ * being executed. The array of pointers must be terminated by a NULL pointer.
+ * @param envp specify the environment of the executed program via the
+ * argument envp. The envp argument is an array of pointers to
+ * null-terminated strings and must be terminated by a NULL pointer.
+ * @param timeout_msec timeout millisecond to prevent infinite
+ * waiting. If negative is given, the parent will not wait the
+ * child. In other word, the parent will return immediately. If 0 is
+ * given, parent will wait the child infinitly. And if positive value
+ * is given parent will wait given milliseconds and expired return
+ * -1. If the child is exit within the tiemout millisecond return with
+ * child exit code.
+ * @param sig signal to kill the child on timeout.
+ *
+ * @return exit code of child. It is fully depend on the child
+ * process. If the child exit with 1 then this function also return 1.
+ * Negative errno on error. -ETIME on timer expired.
+ */
+int do_fork_exec_kill(char *const argv[], char * const envp[], int64_t timeout_msec, int sig);
+
+/**
* @brief Traditional fork() and exec() helper.
*
* @param argv array of pointers to null-terminated strings that
diff --git a/src/test/test-exec.c b/src/test/test-exec.c
new file mode 100644
index 0000000..c5513cc
--- /dev/null
+++ b/src/test/test-exec.c
@@ -0,0 +1,97 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "libsystem/libsystem.h"
+
+#define TEST_EXEC_FILE "/tmp/test-exec"
+
+static void test_do_sleep(int argc, char *argv[]) {
+
+ assert(argc == 2);
+
+ sleep(atoi(argv[1]));
+
+ exit(EXIT_SUCCESS);
+}
+
+static void test_do_fork_exec(int argc, char *argv[]) {
+ char *test_argv[3] = { NULL, NULL, NULL };
+
+ test_argv[0] = argv[0];
+ test_argv[1] = "1";
+
+ assert(do_fork_exec(test_argv, NULL, 500) == -ETIME);
+ assert(do_fork_exec(test_argv, NULL, 1500) == 0);
+}
+
+static void test_do_write_file(int argc, char *argv[]) {
+ char *test1, *test2;
+
+ assert(argc == 3);
+
+ test1 = getenv("TEST1");
+ test2 = getenv("TEST2");
+
+ fprintf(stdout, "%s", argv[1]);
+ fprintf(stdout, "%s", argv[2]);
+ fprintf(stdout, "%s", test1);
+ fprintf(stdout, "%s", test2);
+
+ exit(EXIT_SUCCESS);
+}
+
+static void test_do_fork_exec_redirect(int argc, char *argv[]) {
+ char *test_argv[4] = { NULL, "foo", "bar", NULL };
+ char *test_envp[] = { "TEST1=7", "TEST2=hello", NULL };
+ _cleanup_close_ int fd = -1;
+ _cleanup_free_ char *buf = NULL;
+
+ fd = creat(TEST_EXEC_FILE, 0644);
+ /* Skip if file is not able to be opened. */
+ if (fd < 0) {
+ fprintf(stderr, "Failed to open '" TEST_EXEC_FILE "': %m, skipping\n");
+ return;
+ }
+
+ test_argv[0] = argv[0];
+
+ assert(do_fork_exec_redirect(test_argv, test_envp, 0, fd, EXEC_REDIRECT_ALL) == 0);
+ assert(read_one_line_from_path(TEST_EXEC_FILE, &buf) == 0);
+ assert(strneq(buf, "foobar7hello", 12));
+}
+
+int main(int argc, char *argv[]) {
+ if (argc == 2)
+ test_do_sleep(argc, argv);
+ else if (argc == 3)
+ test_do_write_file(argc, argv);
+
+ test_do_fork_exec(argc, argv);
+ test_do_fork_exec_redirect(argc, argv);
+
+ return 0;
+}