summaryrefslogtreecommitdiffstats
path: root/libmount/src
diff options
context:
space:
mode:
authorVaclav Dolezal2018-02-19 18:45:55 +0100
committerKarel Zak2018-06-11 15:49:48 +0200
commit4917d842ea6feb1e815f701826dadbef3feb066f (patch)
tree4b88decd9a37c99ac94f190a40ab2fedd273faaf /libmount/src
parentwipefs: postpone BLKRRPART until all is done (diff)
downloadkernel-qcow2-util-linux-4917d842ea6feb1e815f701826dadbef3feb066f.tar.gz
kernel-qcow2-util-linux-4917d842ea6feb1e815f701826dadbef3feb066f.tar.xz
kernel-qcow2-util-linux-4917d842ea6feb1e815f701826dadbef3feb066f.zip
libmount: add support for switching namespaces
[kzak@redhat.com: - cosmetic changes, add some comments] Signed-off-by: Vaclav Dolezal <vdolezal@redhat.com> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libmount/src')
-rw-r--r--libmount/src/context.c202
-rw-r--r--libmount/src/libmount.h.in14
-rw-r--r--libmount/src/libmount.sym9
-rw-r--r--libmount/src/mountP.h9
4 files changed, 234 insertions, 0 deletions
diff --git a/libmount/src/context.c b/libmount/src/context.c
index 7add0e39e..8928a7d96 100644
--- a/libmount/src/context.c
+++ b/libmount/src/context.c
@@ -34,6 +34,7 @@
#include "mountP.h"
#include "fileutils.h"
#include "strutils.h"
+#include "namespace.h"
#include <sys/wait.h>
@@ -60,6 +61,10 @@ struct libmnt_context *mnt_new_context(void)
cxt->loopdev_fd = -1;
+ cxt->ns_orig.fd = -1;
+ cxt->ns_tgt.fd = -1;
+ cxt->ns_cur = &cxt->ns_orig;
+
/* if we're really root and aren't running setuid */
cxt->restricted = (uid_t) 0 == ruid && ruid == euid ? 0 : 1;
@@ -93,6 +98,8 @@ void mnt_free_context(struct libmnt_context *cxt)
mnt_free_lock(cxt->lock);
mnt_free_update(cxt->update);
+ mnt_context_set_target_ns(cxt, NULL);
+
free(cxt->children);
DBG(CXT, ul_debugobj(cxt, "<---- free"));
@@ -2585,6 +2592,201 @@ int mnt_context_wait_for_children(struct libmnt_context *cxt,
return 0;
}
+static void close_ns(struct libmnt_ns *ns)
+{
+ if (ns->fd == -1)
+ return;
+
+ close(ns->fd);
+ ns->fd = -1;
+
+ mnt_unref_cache(ns->cache);
+ ns->cache = NULL;
+}
+
+/**
+ * mnt_context_set_target_ns:
+ * @cxt: mount context
+ * @path: path to target namespace or NULL
+ *
+ * Sets target namespace to namespace represented by @path. If @path is NULL,
+ * target namespace is cleared.
+ *
+ * Returns: 0 on success, negative number in case of error.
+ */
+int mnt_context_set_target_ns(struct libmnt_context *cxt, const char *path)
+{
+ int rc = 0;
+
+ int tmp;
+ if (!cxt)
+ return -EINVAL;
+
+ DBG(CXT, ul_debugobj(cxt, "Setting %s as target namespace", path));
+
+ /* cleanup only */
+ if (!path) {
+ close_ns(&cxt->ns_orig);
+ close_ns(&cxt->ns_tgt);
+ return 0;
+ }
+
+ /* open original namespace */
+ if (cxt->ns_orig.fd == -1) {
+ cxt->ns_orig.fd = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC);
+ if (cxt->ns_orig.fd == -1)
+ return -errno;
+ cxt->ns_orig.cache = NULL;
+ }
+
+ /* open target (wanted) namespace */
+ tmp = open(path, O_RDONLY | O_CLOEXEC);
+ if (tmp == -1)
+ return -errno;
+
+ /* test whether namespace switching works */
+ DBG(CXT, ul_debugobj(cxt, "Trying whether namespace is valid"));
+ if (setns(tmp, CLONE_NEWNS)
+ || setns(cxt->ns_orig.fd, CLONE_NEWNS)) {
+ rc = -errno;
+ DBG(CXT, ul_debugobj(cxt, "setns(2) failed [errno=%d %m]", errno));
+ goto err;
+ }
+
+ close_ns(&cxt->ns_tgt);
+
+ cxt->ns_tgt.fd = tmp;
+ cxt->ns_tgt.cache = NULL;
+
+ return 0;
+err:
+ close(tmp);
+ return rc;
+}
+
+/**
+ * mnt_context_get_target_ns:
+ * @cxt: mount context
+ *
+ * Returns: pointer to target namespace
+ */
+struct libmnt_ns *mnt_context_get_target_ns(struct libmnt_context *cxt)
+{
+ return &cxt->ns_tgt;
+}
+
+/**
+ * mnt_context_get_origin_ns:
+ * @cxt: mount context
+ *
+ * Returns: pointer to original namespace
+ */
+struct libmnt_ns *mnt_context_get_origin_ns(struct libmnt_context *cxt)
+{
+ return &cxt->ns_orig;
+}
+
+
+/**
+ * mnt_context_switch_ns:
+ * @cxt: mount context
+ * @ns: namespace to switch to
+ *
+ * Switch to namespace specified by ns
+ *
+ * Typical usage:
+ * <informalexample>
+ * <programlisting>
+ * struct libmnt_ns *ns_old;
+ * ns_old = mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
+ * ... code ...
+ * mnt_context_switch_ns(cxt, ns_old);
+ * </programlisting>
+ * </informalexample>
+ *
+ * Returns: pointer to previous namespace or NULL on error
+ */
+struct libmnt_ns *mnt_context_switch_ns(struct libmnt_context *cxt, struct libmnt_ns *ns)
+{
+ struct libmnt_ns *old;
+
+ if (!cxt || !ns)
+ return NULL;
+
+ old = cxt->ns_cur;
+ if (ns == old || ns->fd == -1)
+ return old;
+
+ /* remember the curremt cache */
+ if (old->cache != cxt->cache) {
+ mnt_unref_cache(old->cache);
+ old->cache = cxt->cache;
+ mnt_ref_cache(old->cache);
+ }
+
+ /* switch */
+ DBG(CXT, ul_debugobj(cxt, "Switching to %s namespace",
+ ns == mnt_context_get_target_ns(cxt) ? "target" :
+ ns == mnt_context_get_origin_ns(cxt) ? "original" : "other"));
+
+ if (setns(ns->fd, CLONE_NEWNS)) {
+ int errsv = errno;
+
+ DBG(CXT, ul_debugobj(cxt, "setns(2) failed [errno=%d %m]", errno));
+ errno = errsv;
+ return NULL;
+ }
+
+ /* update pointer to the current namespace */
+ cxt->ns_cur = ns;
+
+ /* update pointer to the cache */
+ mnt_unref_cache(cxt->cache);
+ cxt->cache = ns->cache;
+ mnt_ref_cache(cxt->cache);
+
+ return old;
+}
+
+/**
+ * mnt_context_switch_origin_ns:
+ * @cxt: mount context
+ *
+ * Switch to original namespace
+ *
+ * This is shorthand for
+ * <informalexample>
+ * <programlisting>
+ * mnt_context_switch_ns(cxt, mnt_context_get_origin_ns(cxt));
+ * </programlisting>
+ * </informalexample>
+ *
+ * Returns: pointer to previous namespace or NULL on error
+ */
+struct libmnt_ns *mnt_context_switch_origin_ns(struct libmnt_context *cxt)
+{
+ return mnt_context_switch_ns(cxt, mnt_context_get_origin_ns(cxt));
+}
+
+/**
+ * mnt_context_switch_target_ns:
+ * @cxt: mount context
+ *
+ * Switch to target namespace
+ *
+ * This is shorthand for
+ * <informalexample>
+ * <programlisting>
+ * mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
+ * </programlisting>
+ * </informalexample>
+ *
+ * Returns: pointer to previous namespace or NULL on error
+ */
+struct libmnt_ns *mnt_context_switch_target_ns(struct libmnt_context *cxt)
+{
+ return mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
+}
#ifdef TEST_PROGRAM
diff --git a/libmount/src/libmount.h.in b/libmount/src/libmount.h.in
index e12a90f07..885729dfb 100644
--- a/libmount/src/libmount.h.in
+++ b/libmount/src/libmount.h.in
@@ -128,6 +128,13 @@ struct libmnt_monitor;
*/
struct libmnt_tabdiff;
+/**
+ * libmnt_ns:
+ *
+ * Describes mount namespace
+ */
+struct libmnt_ns;
+
/*
* Actions
*/
@@ -815,6 +822,13 @@ extern int mnt_context_strerror(struct libmnt_context *cxt, char *buf,
extern int mnt_context_get_excode(struct libmnt_context *cxt,
int rc, char *buf, size_t bufsz);
+extern int mnt_context_set_target_ns(struct libmnt_context *cxt, const char *path);
+extern struct libmnt_ns *mnt_context_get_target_ns(struct libmnt_context *cxt);
+extern struct libmnt_ns *mnt_context_get_origin_ns(struct libmnt_context *cxt);
+extern struct libmnt_ns *mnt_context_switch_ns(struct libmnt_context *cxt, struct libmnt_ns *ns);
+extern struct libmnt_ns *mnt_context_switch_origin_ns(struct libmnt_context *cxt);
+extern struct libmnt_ns *mnt_context_switch_target_ns(struct libmnt_context *cxt);
+
/* context_mount.c */
extern int mnt_context_mount(struct libmnt_context *cxt);
diff --git a/libmount/src/libmount.sym b/libmount/src/libmount.sym
index ca16cafa1..1db14b2b7 100644
--- a/libmount/src/libmount.sym
+++ b/libmount/src/libmount.sym
@@ -322,3 +322,12 @@ MOUNT_2.30 {
mnt_context_enable_rwonly_mount;
mnt_context_get_excode;
} MOUNT_2.28;
+
+MOUNT_2.33 {
+ mnt_context_get_origin_ns;
+ mnt_context_get_target_ns;
+ mnt_context_set_target_ns;
+ mnt_context_switch_ns;
+ mnt_context_switch_origin_ns;
+ mnt_context_switch_target_ns;
+} MOUNT_2.30;
diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
index 4ce891cda..0c795121a 100644
--- a/libmount/src/mountP.h
+++ b/libmount/src/mountP.h
@@ -268,6 +268,11 @@ struct libmnt_addmount {
struct list_head mounts;
};
+struct libmnt_ns {
+ int fd; /* file descriptor of namespace, -1 when inactive */
+ struct libmnt_cache *cache; /* paths cache associated with NS */
+};
+
/*
* Mount context -- high-level API
*/
@@ -329,6 +334,10 @@ struct libmnt_context
int syscall_status; /* 1: not called yet, 0: success, <0: -errno */
+ struct libmnt_ns ns_orig; /* original namespace */
+ struct libmnt_ns ns_tgt; /* target namespace */
+ struct libmnt_ns *ns_cur; /* pointer to current namespace */
+
unsigned int enabled_textdomain : 1; /* bindtextdomain() called */
};