diff options
author | Thomas Haller <thaller@redhat.com> | 2015-11-26 22:08:26 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-11-27 14:22:06 +0100 |
commit | 557c495326069a870a1b785878b48244d777c981 (patch) | |
tree | 1885ad44802cf5b52a5f9db35b97faf43cd934f8 /src/platform | |
parent | d72fe89899f9b0d116b10c12c3814be75fe37857 (diff) | |
download | NetworkManager-557c495326069a870a1b785878b48244d777c981.tar.gz |
platform/tests: add namespace helper functions to nmtstp
Diffstat (limited to 'src/platform')
-rw-r--r-- | src/platform/tests/test-common.c | 165 | ||||
-rw-r--r-- | src/platform/tests/test-common.h | 15 |
2 files changed, 179 insertions, 1 deletions
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 5e2e819988..298ac8686d 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -2,6 +2,8 @@ #include <sys/mount.h> #include <sched.h> +#include <sys/wait.h> +#include <fcntl.h> #include "test-common.h" @@ -879,6 +881,169 @@ nmtstp_link_set_updown (gboolean external_command, /*****************************************************************************/ +struct _NMTstpNamespaceHandle { + pid_t pid; + int pipe_fd; +}; + +NMTstpNamespaceHandle * +nmtstp_namespace_create (int unshare_flags, GError **error) +{ + NMTstpNamespaceHandle *ns_handle; + int e; + int errsv; + pid_t pid, pid2; + int pipefd_c2p[2]; + int pipefd_p2c[2]; + ssize_t r; + + e = pipe (pipefd_c2p); + if (e != 0) { + errsv = errno; + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "pipe() failed with %d (%s)", errsv, strerror (errsv)); + return FALSE; + } + + e = pipe (pipefd_p2c); + if (e != 0) { + errsv = errno; + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "pipe() failed with %d (%s)", errsv, strerror (errsv)); + close (pipefd_c2p[0]); + close (pipefd_c2p[1]); + return FALSE; + } + + pid = fork (); + if (pid < 0) { + errsv = errno; + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "fork() failed with %d (%s)", errsv, strerror (errsv)); + close (pipefd_c2p[0]); + close (pipefd_c2p[1]); + close (pipefd_p2c[0]); + close (pipefd_p2c[1]); + return FALSE; + } + + if (pid == 0) { + char read_buf[1]; + + close (pipefd_c2p[0]); /* close read-end */ + close (pipefd_p2c[1]); /* close write-end */ + + if (unshare (unshare_flags) != 0) { + errsv = errno; + if (errsv == 0) + errsv = -1; + } else + errsv = 0; + + /* sync with parent process and send result. */ + do { + r = write (pipefd_c2p[1], &errsv, sizeof (errsv)); + } while (r < 0 && errno == EINTR); + if (r != sizeof (errsv)) { + errsv = errno; + if (errsv == 0) + errsv = -2; + } + close (pipefd_c2p[1]); + + /* wait until parent process terminates (or kills us). */ + if (errsv == 0) { + do { + r = read (pipefd_p2c[0], read_buf, sizeof (read_buf)); + } while (r < 0 && errno == EINTR); + } + close (pipefd_p2c[0]); + _exit (0); + } + + close (pipefd_c2p[1]); /* close write-end */ + close (pipefd_p2c[0]); /* close read-end */ + + /* sync with child process. */ + do { + r = read (pipefd_c2p[0], &errsv, sizeof (errsv)); + } while (r < 0 && errno == EINTR); + + close (pipefd_c2p[0]); + + if ( r != sizeof (errsv) + || errsv != 0) { + int status; + + if (r != sizeof (errsv)) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "child process failed for unknown reason"); + } else { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "child process signaled failure %d (%s)", errsv, strerror (errsv)); + } + close (pipefd_p2c[1]); + kill (pid, SIGKILL); + do { + pid2 = waitpid (pid, &status, 0); + } while (pid2 == -1 && errno == EINTR); + return FALSE; + } + + ns_handle = g_new0 (NMTstpNamespaceHandle, 1); + ns_handle->pid = pid; + ns_handle->pipe_fd = pipefd_p2c[1]; + return ns_handle; +} + +pid_t +nmtstp_namespace_handle_get_pid (NMTstpNamespaceHandle *ns_handle) +{ + g_return_val_if_fail (ns_handle, 0); + g_return_val_if_fail (ns_handle->pid > 0, 0); + + return ns_handle->pid; +} + +void +nmtstp_namespace_handle_release (NMTstpNamespaceHandle *ns_handle) +{ + pid_t pid; + int status; + + if (!ns_handle) + return; + + g_return_if_fail (ns_handle->pid > 0); + + close (ns_handle->pipe_fd); + ns_handle->pipe_fd = 0; + + kill (ns_handle->pid, SIGKILL); + + do { + pid = waitpid (ns_handle->pid, &status, 0); + } while (pid == -1 && errno == EINTR); + ns_handle->pid = 0; + + g_free (ns_handle); +} + +int +nmtstp_namespace_get_fd_for_process (pid_t pid, const char *ns_name) +{ + char p[1000]; + + g_return_val_if_fail (pid > 0, 0); + g_return_val_if_fail (ns_name && ns_name[0] && strlen (ns_name) < 50, 0); + + nm_sprintf_buf (p, "/proc/%lu/ns/%s", (long unsigned) pid, ns_name); + + return open(p, O_RDONLY); +} + +/*****************************************************************************/ + NMTST_DEFINE(); static gboolean diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index fbcb7bea2d..edb00b879a 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -46,6 +46,19 @@ typedef struct { gboolean nmtstp_is_root_test (void); gboolean nmtstp_is_sysfs_writable (void); +/******************************************************************************/ + +typedef struct _NMTstpNamespaceHandle NMTstpNamespaceHandle; + +NMTstpNamespaceHandle *nmtstp_namespace_create (int flags, GError **error); + +void nmtstp_namespace_handle_release (NMTstpNamespaceHandle *handle); +pid_t nmtstp_namespace_handle_get_pid (NMTstpNamespaceHandle *handle); + +int nmtstp_namespace_get_fd_for_process (pid_t pid, const char *ns_name); + +/******************************************************************************/ + SignalData *add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCallback callback, int ifindex, const char *ifname); #define add_signal(name, change_type, callback) add_signal_full (name, change_type, (GCallback) callback, 0, NULL) #define add_signal_ifindex(name, change_type, callback, ifindex) add_signal_full (name, change_type, (GCallback) callback, ifindex, NULL) @@ -71,7 +84,7 @@ void _assert_ip4_route_exists (const char *file, guint line, const char *func, g void link_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformLink *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data); int nmtstp_run_command (const char *format, ...) __attribute__((__format__ (__printf__, 1, 2))); -#define nmtstp_run_command_check(format, ...) do { g_assert_cmpint (nmtstp_run_command (format, __VA_ARGS__), ==, 0); } while (0) +#define nmtstp_run_command_check(...) do { g_assert_cmpint (nmtstp_run_command (__VA_ARGS__), ==, 0); } while (0) gboolean nmtstp_wait_for_signal (guint timeout_ms); gboolean nmtstp_wait_for_signal_until (gint64 until_ms); |