mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-05 01:47:58 +02:00
platform/tests: add namespace helper functions to nmtstp
This commit is contained in:
parent
d72fe89899
commit
557c495326
2 changed files with 179 additions and 1 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue