platform/tests: add namespace helper functions to nmtstp

This commit is contained in:
Thomas Haller 2015-11-26 22:08:26 +01:00
parent d72fe89899
commit 557c495326
2 changed files with 179 additions and 1 deletions

View file

@ -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

View file

@ -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);