summaryrefslogtreecommitdiffstats
path: root/libmount/src/context.c
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/context.c
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/context.c')
-rw-r--r--libmount/src/context.c202
1 files changed, 202 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