File lxc-autodev.patch of Package lxc
From c6883f383e587725552f7c71e96ebe1c34ae7c56 Mon Sep 17 00:00:00 2001
From: Serge Hallyn <serge.hallyn@ubuntu.com>
Date: Thu, 1 Nov 2012 22:27:03 +0100
Subject: [PATCH] Add lxc.autodev
Add a container config option to mount and populate /dev in a container.
We might want to add options to specify a max size for /dev other than
the default 100k, and to specify other devices to create. And maybe
someone can think of a better name than autodev.
Changelog: Don't error out if we couldn't mknod a /dev/ttyN.
Changelog: Describe the option in lxc.conf manpage.
Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
---
doc/lxc.conf.sgml.in | 25 ++++++++++++++++
src/lxc/conf.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/lxc/conf.h | 1 +
src/lxc/confile.c | 12 ++++++++
4 files changed, 115 insertions(+)
Index: lxc-0.8.0/doc/lxc.conf.sgml.in
===================================================================
--- lxc-0.8.0.orig/doc/lxc.conf.sgml.in
+++ lxc-0.8.0/doc/lxc.conf.sgml.in
@@ -482,6 +482,31 @@ Foundation, Inc., 59 Temple Place, Suite
</refsect2>
<refsect2>
+ <title>/dev directory</title>
+ <para>
+ By default, lxc does nothing with the container's
+ <filename>/dev</filename>. This allows the container's
+ <filename>/dev</filename> to be set up as needed in the container
+ rootfs. If lxc.autodev is to 1, then after mounting the container's
+ rootfs LXC will mount a fresh tmpfs under <filename>/dev</filename>
+ (limited to 100k) and fill in a minimal set of initial devices.
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <option>lxc.autodev</option>
+ </term>
+ <listitem>
+ <para>
+ Set this to 1 to have LXC mount and populate a minimal
+ <filename>/dev</filename> when starting the container.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
<title>Mount points</title>
<para>
The mount points section specifies the different places to be
Index: lxc-0.8.0/src/lxc/conf.c
===================================================================
--- lxc-0.8.0.orig/src/lxc/conf.c
+++ lxc-0.8.0/src/lxc/conf.c
@@ -636,6 +636,15 @@ static int setup_tty(const struct lxc_ro
return -1;
}
} else {
+ /* If we populated /dev, then we need to create /dev/ttyN */
+ if (access(path, F_OK)) {
+ ret = creat(path, 0660);
+ if (ret==-1) {
+ SYSERROR("error creating %s\n", path);
+ /* this isn't fatal, continue */
+ } else
+ close(ret);
+ }
if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
WARN("failed to mount '%s'->'%s'",
pty_info->name, path);
@@ -945,6 +954,67 @@ static int chroot_into_slave(struct lxc_
return 0;
}
+struct lxc_devs {
+ char *name;
+ mode_t mode;
+ int maj;
+ int min;
+};
+
+struct lxc_devs lxc_devs[] = {
+ { "null", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 3 },
+ { "zero", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 5 },
+ { "full", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 7 },
+ { "urandom", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 9 },
+ { "random", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 8 },
+ { "tty", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 5, 0 },
+ { "console", S_IFCHR | S_IRUSR | S_IWUSR, 5, 1 },
+};
+
+/*
+ * Do we want to add options for max size of /dev and a file to
+ * specify which devices to create?
+ */
+static int setup_autodev(char *root)
+{
+ int ret;
+ struct lxc_devs *d;
+ char path[MAXPATHLEN];
+ int i;
+
+ INFO("Creating and populating /dev under %s\n", root);
+ ret = snprintf(path, MAXPATHLEN, "%s/dev", root);
+ if (ret < 0 || ret > MAXPATHLEN)
+ return -1;
+ ret = mount("none", path, "tmpfs", 0, "size=100000");
+ if (ret) {
+ SYSERROR("Failed to mount /dev at %s\n", root);
+ return -1;
+ }
+ for (i = 0; i < sizeof(lxc_devs) / sizeof(lxc_devs[0]); i++) {
+ d = &lxc_devs[i];
+ ret = snprintf(path, MAXPATHLEN, "%s/dev/%s", root, d->name);
+ if (ret < 0 || ret >= MAXPATHLEN)
+ return -1;
+ ret = mknod(path, d->mode, makedev(d->maj, d->min));
+ if (ret) {
+ SYSERROR("Error creating %s\n", d->name);
+ return -1;
+ }
+ }
+ ret = snprintf(path, MAXPATHLEN, "%s/dev/pts", root);
+ if (ret < 0 || ret >= MAXPATHLEN)
+ return -1;
+ ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ if (ret) {
+ SYSERROR("Failed to create /dev/pts in container");
+ return -1;
+ }
+
+ INFO("Populated /dev under %s\n", root);
+ return 0;
+}
+
static int setup_rootfs(struct lxc_conf *conf)
{
const struct lxc_rootfs *rootfs = &conf->rootfs;
@@ -2282,6 +2352,13 @@ int lxc_setup(const char *name, struct l
return -1;
}
+ if (lxc_conf->autodev) {
+ if (setup_autodev(lxc_conf->rootfs.mount)) {
+ ERROR("failed to set up /dev in the container");
+ return -1;
+ }
+ }
+
if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab, name)) {
ERROR("failed to setup the mounts for '%s'", name);
return -1;
Index: lxc-0.8.0/src/lxc/conf.h
===================================================================
--- lxc-0.8.0.orig/src/lxc/conf.h
+++ lxc-0.8.0/src/lxc/conf.h
@@ -229,6 +229,7 @@ struct lxc_conf {
#if HAVE_APPARMOR /* || HAVE_SELINUX || HAVE_SMACK */
int lsm_umount_proc;
#endif
+ int autodev; // if 1, mount and fill a /dev at start
};
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
Index: lxc-0.8.0/src/lxc/confile.c
===================================================================
--- lxc-0.8.0.orig/src/lxc/confile.c
+++ lxc-0.8.0/src/lxc/confile.c
@@ -75,6 +75,7 @@ static int config_network_ipv6(const cha
static int config_network_ipv6_gateway(const char *, char *, struct lxc_conf *);
static int config_cap_drop(const char *, char *, struct lxc_conf *);
static int config_console(const char *, char *, struct lxc_conf *);
+static int config_autodev(const char *, char *, struct lxc_conf *);
typedef int (*config_cb)(const char *, char *, struct lxc_conf *);
@@ -118,6 +119,7 @@ static struct config config[] = {
{ "lxc.network.ipv6", config_network_ipv6 },
{ "lxc.cap.drop", config_cap_drop },
{ "lxc.console", config_console },
+ { "lxc.autodev", config_autodev },
};
static const size_t config_size = sizeof(config)/sizeof(struct config);
@@ -699,6 +701,16 @@ static int config_aa_profile(const char
}
#endif
+static int config_autodev(const char *key, char *value,
+ struct lxc_conf *lxc_conf)
+{
+ int v = atoi(value);
+
+ lxc_conf->autodev = v;
+
+ return 0;
+}
+
static int config_cgroup(const char *key, char *value, struct lxc_conf *lxc_conf)
{
char *token = "lxc.cgroup.";