summaryrefslogtreecommitdiff
path: root/src/platform
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2015-11-26 22:08:26 +0100
committerThomas Haller <thaller@redhat.com>2015-11-27 14:22:06 +0100
commit557c495326069a870a1b785878b48244d777c981 (patch)
tree1885ad44802cf5b52a5f9db35b97faf43cd934f8 /src/platform
parentd72fe89899f9b0d116b10c12c3814be75fe37857 (diff)
downloadNetworkManager-557c495326069a870a1b785878b48244d777c981.tar.gz
platform/tests: add namespace helper functions to nmtstp
Diffstat (limited to 'src/platform')
-rw-r--r--src/platform/tests/test-common.c165
-rw-r--r--src/platform/tests/test-common.h15
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);