]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/confile.c
lxc.mount.auto: improve defaults for cgroup and cgroup-full
[mirror_lxc.git] / src / lxc / confile.c
index 09902ba4b8e01ebd6ff5fc21f82eebc5b52f6d60..ac05b7562dbe9f7f15d481ee909222d4707b7b02 100644 (file)
@@ -4,7 +4,7 @@
  * (C) Copyright IBM Corp. 2007, 2008
  *
  * Authors:
- * Daniel Lezcano <dlezcano at fr.ibm.com>
+ * Daniel Lezcano <daniel.lezcano at free.fr>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <pty.h>
+#include <ctype.h>
+#include <signal.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/utsname.h>
-#include <sys/personality.h>
 #include <arpa/inet.h>
 #include <netinet/in.h>
 #include <net/if.h>
 
 #include "parse.h"
+#include "config.h"
 #include "confile.h"
 #include "utils.h"
+#include "log.h"
+#include "conf.h"
+#include "network.h"
+#include "lxcseccomp.h"
 
-#include <lxc/log.h>
-#include <lxc/conf.h>
+#if HAVE_SYS_PERSONALITY_H
+#include <sys/personality.h>
+#endif
 
 lxc_log_define(lxc_confile, lxc);
 
-static int config_personality(const char *, char *, struct lxc_conf *);
-static int config_pts(const char *, char *, struct lxc_conf *);
-static int config_tty(const char *, char *, struct lxc_conf *);
-static int config_ttydir(const char *, char *, struct lxc_conf *);
-#if HAVE_APPARMOR
-static int config_aa_profile(const char *, char *, struct lxc_conf *);
-#endif
-static int config_cgroup(const char *, char *, struct lxc_conf *);
-static int config_mount(const char *, char *, struct lxc_conf *);
-static int config_rootfs(const char *, char *, struct lxc_conf *);
-static int config_rootfs_mount(const char *, char *, struct lxc_conf *);
-static int config_pivotdir(const char *, char *, struct lxc_conf *);
-static int config_utsname(const char *, char *, struct lxc_conf *);
-static int config_network_type(const char *, char *, struct lxc_conf *);
-static int config_network_flags(const char *, char *, struct lxc_conf *);
-static int config_network_link(const char *, char *, struct lxc_conf *);
-static int config_network_name(const char *, char *, struct lxc_conf *);
-static int config_network_veth_pair(const char *, char *, struct lxc_conf *);
-static int config_network_macvlan_mode(const char *, char *, struct lxc_conf *);
-static int config_network_hwaddr(const char *, char *, struct lxc_conf *);
-static int config_network_vlan_id(const char *, char *, struct lxc_conf *);
-static int config_network_mtu(const char *, char *, struct lxc_conf *);
-static int config_network_ipv4(const char *, char *, struct lxc_conf *);
-static int config_network_ipv4_gateway(const char *, char *, struct lxc_conf *);
-static int config_network_script(const char *, char *, struct lxc_conf *);
-static int config_network_ipv6(const char *, char *, struct lxc_conf *);
-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 *);
-
-typedef int (*config_cb)(const char *, char *, struct lxc_conf *);
-
-struct config {
-       char *name;
-       config_cb cb;
-};
-
-static struct config config[] = {
+static int config_personality(const char *, const char *, struct lxc_conf *);
+static int config_pts(const char *, const char *, struct lxc_conf *);
+static int config_tty(const char *, const char *, struct lxc_conf *);
+static int config_ttydir(const char *, const char *, struct lxc_conf *);
+static int config_kmsg(const char *, const char *, struct lxc_conf *);
+static int config_lsm_aa_profile(const char *, const char *, struct lxc_conf *);
+static int config_lsm_se_context(const char *, const char *, struct lxc_conf *);
+static int config_cgroup(const char *, const char *, struct lxc_conf *);
+static int config_idmap(const char *, const char *, struct lxc_conf *);
+static int config_loglevel(const char *, const char *, struct lxc_conf *);
+static int config_logfile(const char *, const char *, struct lxc_conf *);
+static int config_mount(const char *, const char *, struct lxc_conf *);
+static int config_rootfs(const char *, const char *, struct lxc_conf *);
+static int config_rootfs_mount(const char *, const char *, struct lxc_conf *);
+static int config_rootfs_options(const char *, const char *, struct lxc_conf *);
+static int config_pivotdir(const char *, const char *, struct lxc_conf *);
+static int config_utsname(const char *, const char *, struct lxc_conf *);
+static int config_hook(const char *, const char *, struct lxc_conf *lxc_conf);
+static int config_network_type(const char *, const char *, struct lxc_conf *);
+static int config_network_flags(const char *, const char *, struct lxc_conf *);
+static int config_network_link(const char *, const char *, struct lxc_conf *);
+static int config_network_name(const char *, const char *, struct lxc_conf *);
+static int config_network_veth_pair(const char *, const char *, struct lxc_conf *);
+static int config_network_macvlan_mode(const char *, const char *, struct lxc_conf *);
+static int config_network_hwaddr(const char *, const char *, struct lxc_conf *);
+static int config_network_vlan_id(const char *, const char *, struct lxc_conf *);
+static int config_network_mtu(const char *, const char *, struct lxc_conf *);
+static int config_network_ipv4(const char *, const char *, struct lxc_conf *);
+static int config_network_ipv4_gateway(const char *, const char *, struct lxc_conf *);
+static int config_network_script_up(const char *, const char *, struct lxc_conf *);
+static int config_network_script_down(const char *, const char *, struct lxc_conf *);
+static int config_network_ipv6(const char *, const char *, struct lxc_conf *);
+static int config_network_ipv6_gateway(const char *, const char *, struct lxc_conf *);
+static int config_cap_drop(const char *, const char *, struct lxc_conf *);
+static int config_cap_keep(const char *, const char *, struct lxc_conf *);
+static int config_console(const char *, const char *, struct lxc_conf *);
+static int config_seccomp(const char *, const char *, struct lxc_conf *);
+static int config_includefile(const char *, const char *, struct lxc_conf *);
+static int config_network_nic(const char *, const char *, struct lxc_conf *);
+static int config_autodev(const char *, const char *, struct lxc_conf *);
+static int config_haltsignal(const char *, const char *, struct lxc_conf *);
+static int config_stopsignal(const char *, const char *, struct lxc_conf *);
+static int config_start(const char *, const char *, struct lxc_conf *);
+static int config_group(const char *, const char *, struct lxc_conf *);
+
+static struct lxc_config_t config[] = {
 
        { "lxc.arch",                 config_personality          },
        { "lxc.pts",                  config_pts                  },
        { "lxc.tty",                  config_tty                  },
        { "lxc.devttydir",            config_ttydir               },
-#if HAVE_APPARMOR
-       { "lxc.aa_profile",            config_aa_profile          },
-#endif
+       { "lxc.kmsg",                 config_kmsg                 },
+       { "lxc.aa_profile",           config_lsm_aa_profile       },
+       { "lxc.se_context",           config_lsm_se_context       },
        { "lxc.cgroup",               config_cgroup               },
+       { "lxc.id_map",               config_idmap                },
+       { "lxc.loglevel",             config_loglevel             },
+       { "lxc.logfile",              config_logfile              },
        { "lxc.mount",                config_mount                },
        { "lxc.rootfs.mount",         config_rootfs_mount         },
+       { "lxc.rootfs.options",       config_rootfs_options       },
        { "lxc.rootfs",               config_rootfs               },
        { "lxc.pivotdir",             config_pivotdir             },
        { "lxc.utsname",              config_utsname              },
+       { "lxc.hook.pre-start",       config_hook                 },
+       { "lxc.hook.pre-mount",       config_hook                 },
+       { "lxc.hook.mount",           config_hook                 },
+       { "lxc.hook.autodev",         config_hook                 },
+       { "lxc.hook.start",           config_hook                 },
+       { "lxc.hook.post-stop",       config_hook                 },
+       { "lxc.hook.clone",           config_hook                 },
        { "lxc.network.type",         config_network_type         },
        { "lxc.network.flags",        config_network_flags        },
        { "lxc.network.link",         config_network_link         },
        { "lxc.network.name",         config_network_name         },
        { "lxc.network.macvlan.mode", config_network_macvlan_mode },
        { "lxc.network.veth.pair",    config_network_veth_pair    },
-       { "lxc.network.script.up",    config_network_script       },
+       { "lxc.network.script.up",    config_network_script_up    },
+       { "lxc.network.script.down",  config_network_script_down  },
        { "lxc.network.hwaddr",       config_network_hwaddr       },
        { "lxc.network.mtu",          config_network_mtu          },
        { "lxc.network.vlan.id",      config_network_vlan_id      },
@@ -111,13 +138,52 @@ static struct config config[] = {
        { "lxc.network.ipv4",         config_network_ipv4         },
        { "lxc.network.ipv6.gateway", config_network_ipv6_gateway },
        { "lxc.network.ipv6",         config_network_ipv6         },
+       /* config_network_nic must come after all other 'lxc.network.*' entries */
+       { "lxc.network.",             config_network_nic          },
        { "lxc.cap.drop",             config_cap_drop             },
+       { "lxc.cap.keep",             config_cap_keep             },
        { "lxc.console",              config_console              },
+       { "lxc.seccomp",              config_seccomp              },
+       { "lxc.include",              config_includefile          },
+       { "lxc.autodev",              config_autodev              },
+       { "lxc.haltsignal",           config_haltsignal           },
+       { "lxc.stopsignal",           config_stopsignal           },
+       { "lxc.start.auto",           config_start                },
+       { "lxc.start.delay",          config_start                },
+       { "lxc.start.order",          config_start                },
+       { "lxc.group",                config_group                },
+};
+
+struct signame {
+       int num;
+       const char *name;
+};
+
+static const struct signame signames[] = {
+       { SIGHUP,    "HUP" },
+       { SIGINT,    "INT" },
+       { SIGQUIT,   "QUIT" },
+       { SIGILL,    "ILL" },
+       { SIGABRT,   "ABRT" },
+       { SIGFPE,    "FPE" },
+       { SIGKILL,   "KILL" },
+       { SIGSEGV,   "SEGV" },
+       { SIGPIPE,   "PIPE" },
+       { SIGALRM,   "ALRM" },
+       { SIGTERM,   "TERM" },
+       { SIGUSR1,   "USR1" },
+       { SIGUSR2,   "USR2" },
+       { SIGCHLD,   "CHLD" },
+       { SIGCONT,   "CONT" },
+       { SIGSTOP,   "STOP" },
+       { SIGTSTP,   "TSTP" },
+       { SIGTTIN,   "TTIN" },
+       { SIGTTOU,   "TTOU" },
 };
 
-static const size_t config_size = sizeof(config)/sizeof(struct config);
+static const size_t config_size = sizeof(config)/sizeof(struct lxc_config_t);
 
-static struct config *getconfig(const char *key)
+extern struct lxc_config_t *lxc_getconfig(const char *key)
 {
        int i;
 
@@ -128,13 +194,127 @@ static struct config *getconfig(const char *key)
        return NULL;
 }
 
-static int config_network_type(const char *key, char *value,
+#define strprint(str, inlen, ...) \
+       do { \
+               len = snprintf(str, inlen, ##__VA_ARGS__); \
+               if (len < 0) { SYSERROR("snprintf"); return -1; }; \
+               fulllen += len; \
+               if (inlen > 0) { \
+                       if (str) str += len; \
+                       inlen -= len; \
+                       if (inlen < 0) inlen = 0; \
+               } \
+       } while (0);
+
+int lxc_listconfigs(char *retv, int inlen)
+{
+       int i, fulllen = 0, len;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+       for (i = 0; i < config_size; i++) {
+               char *s = config[i].name;
+               if (s[strlen(s)-1] == '.')
+                       continue;
+               strprint(retv, inlen, "%s\n", s);
+       }
+       return fulllen;
+}
+
+static int config_string_item(char **conf_item, const char *value)
+{
+       char *new_value;
+
+       if (!value || strlen(value) == 0) {
+               if (*conf_item)
+                       free(*conf_item);
+               *conf_item = NULL;
+               return 0;
+       }
+
+       new_value = strdup(value);
+       if (!new_value) {
+               SYSERROR("failed to strdup '%s': %m", value);
+               return -1;
+       }
+
+       if (*conf_item)
+               free(*conf_item);
+       *conf_item = new_value;
+       return 0;
+}
+
+static int config_string_item_max(char **conf_item, const char *value,
+                                 size_t max)
+{
+       if (strlen(value) >= max) {
+               ERROR("%s is too long (>= %lu)", value, (unsigned long)max);
+               return -1;
+       }
+
+       return config_string_item(conf_item, value);
+}
+
+static int config_path_item(char **conf_item, const char *value)
+{
+       return config_string_item_max(conf_item, value, PATH_MAX);
+}
+
+/*
+ * config entry is something like "lxc.network.0.ipv4"
+ * the key 'lxc.network.' was found.  So we make sure next
+ * comes an integer, find the right callback (by rewriting
+ * the key), and call it.
+ */
+static int config_network_nic(const char *key, const char *value,
+                              struct lxc_conf *lxc_conf)
+{
+       char *copy = strdup(key), *p;
+       int ret = -1;
+       struct lxc_config_t *config;
+
+       if (!copy) {
+               SYSERROR("failed to allocate memory");
+               return -1;
+       }
+       /*
+        * ok we know that to get here we've got "lxc.network."
+        * and it isn't any of the other network entries.  So
+        * after the second . should come an integer (# of defined
+        * nic) followed by a valid entry.
+        */
+       if (*(key+12) < '0' || *(key+12) > '9')
+               goto out;
+       p = index(key+12, '.');
+       if (!p)
+               goto out;
+       strcpy(copy+12, p+1);
+       config = lxc_getconfig(copy);
+       if (!config) {
+               ERROR("unknown key %s", key);
+               goto out;
+       }
+       ret = config->cb(key, value, lxc_conf);
+
+out:
+       free(copy);
+       return ret;
+}
+
+static int macvlan_mode(int *valuep, const char *value);
+
+static int config_network_type(const char *key, const char *value,
                               struct lxc_conf *lxc_conf)
 {
        struct lxc_list *network = &lxc_conf->network;
        struct lxc_netdev *netdev;
        struct lxc_list *list;
 
+       if (!value || strlen(value) == 0)
+               return lxc_clear_config_network(lxc_conf);
+
        netdev = malloc(sizeof(*netdev));
        if (!netdev) {
                SYSERROR("failed to allocate memory");
@@ -148,6 +328,7 @@ static int config_network_type(const char *key, char *value,
        list = malloc(sizeof(*list));
        if (!list) {
                SYSERROR("failed to allocate memory");
+               free(netdev);
                return -1;
        }
 
@@ -158,14 +339,18 @@ static int config_network_type(const char *key, char *value,
 
        if (!strcmp(value, "veth"))
                netdev->type = LXC_NET_VETH;
-       else if (!strcmp(value, "macvlan"))
+       else if (!strcmp(value, "macvlan")) {
                netdev->type = LXC_NET_MACVLAN;
+               macvlan_mode(&netdev->priv.macvlan_attr.mode, "private");
+       }
        else if (!strcmp(value, "vlan"))
                netdev->type = LXC_NET_VLAN;
        else if (!strcmp(value, "phys"))
                netdev->type = LXC_NET_PHYS;
        else if (!strcmp(value, "empty"))
                netdev->type = LXC_NET_EMPTY;
+       else if (!strcmp(value, "none"))
+               netdev->type = LXC_NET_NONE;
        else {
                ERROR("invalid network type %s", value);
                return -1;
@@ -185,10 +370,91 @@ static int config_ip_prefix(struct in_addr *addr)
        return 0;
 }
 
+/*
+ * if you have p="lxc.network.0.link", pass it p+12
+ * to get back '0' (the index of the nic)
+ */
+static int get_network_netdev_idx(const char *key)
+{
+       int ret, idx;
+
+       if (*key < '0' || *key > '9')
+               return -1;
+       ret = sscanf(key, "%d", &idx);
+       if (ret != 1)
+               return -1;
+       return idx;
+}
+
+/*
+ * if you have p="lxc.network.0", pass this p+12 and it will return
+ * the netdev of the first configured nic
+ */
+static struct lxc_netdev *get_netdev_from_key(const char *key,
+                                             struct lxc_list *network)
+{
+       int i = 0, idx = get_network_netdev_idx(key);
+       struct lxc_netdev *netdev = NULL;
+       struct lxc_list *it;
+       if (idx == -1)
+               return NULL;
+       lxc_list_for_each(it, network) {
+               if (idx == i++) {
+                       netdev = it->elem;
+                       break;
+               }
+       }
+       return netdev;
+}
+
+extern int lxc_list_nicconfigs(struct lxc_conf *c, const char *key,
+                              char *retv, int inlen)
+{
+       struct lxc_netdev *netdev;
+       int fulllen = 0, len;
+
+       netdev = get_netdev_from_key(key+12, &c->network);
+       if (!netdev)
+               return -1;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       strprint(retv, inlen, "script.up\n");
+       strprint(retv, inlen, "script.down\n");
+       if (netdev->type != LXC_NET_EMPTY) {
+               strprint(retv, inlen, "flags\n");
+               strprint(retv, inlen, "link\n");
+               strprint(retv, inlen, "name\n");
+               strprint(retv, inlen, "hwaddr\n");
+               strprint(retv, inlen, "mtu\n");
+               strprint(retv, inlen, "ipv6\n");
+               strprint(retv, inlen, "ipv6_gateway\n");
+               strprint(retv, inlen, "ipv4\n");
+               strprint(retv, inlen, "ipv4_gateway\n");
+       }
+       switch(netdev->type) {
+       case LXC_NET_VETH:
+               strprint(retv, inlen, "veth.pair\n");
+               break;
+       case LXC_NET_MACVLAN:
+               strprint(retv, inlen, "macvlan.mode\n");
+               break;
+       case LXC_NET_VLAN:
+               strprint(retv, inlen, "vlan.id\n");
+               break;
+       case LXC_NET_PHYS:
+               break;
+       }
+       return fulllen;
+}
+
 static struct lxc_netdev *network_netdev(const char *key, const char *value,
                                         struct lxc_list *network)
 {
-       struct lxc_netdev *netdev;
+       struct lxc_netdev *netdev = NULL;
 
        if (lxc_list_empty(network)) {
                ERROR("network is not created for '%s' = '%s' option",
@@ -196,7 +462,11 @@ static struct lxc_netdev *network_netdev(const char *key, const char *value,
                return NULL;
        }
 
-       netdev = lxc_list_last_elem(network);
+       if (get_network_netdev_idx(key+12) == -1)
+               netdev = lxc_list_last_elem(network);
+       else
+               netdev = get_netdev_from_key(key+12, network);
+
        if (!netdev) {
                ERROR("no network device defined for '%s' = '%s' option",
                      key, value);
@@ -206,20 +476,9 @@ static struct lxc_netdev *network_netdev(const char *key, const char *value,
        return netdev;
 }
 
-static int network_ifname(char **valuep, char *value)
+static int network_ifname(char **valuep, const char *value)
 {
-       if (strlen(value) >= IFNAMSIZ) {
-               ERROR("invalid interface name: %s", value);
-               return -1;
-       }
-
-       *valuep = strdup(value);
-       if (!*valuep) {
-               ERROR("failed to dup string '%s'", value);
-               return -1;
-       }
-
-       return 0;
+       return config_string_item_max(valuep, value, IFNAMSIZ);
 }
 
 #ifndef MACVLAN_MODE_PRIVATE
@@ -234,7 +493,7 @@ static int network_ifname(char **valuep, char *value)
 #  define MACVLAN_MODE_BRIDGE 4
 #endif
 
-static int macvlan_mode(int *valuep, char *value)
+static int macvlan_mode(int *valuep, const char *value)
 {
        struct mc_mode {
                char *name;
@@ -258,7 +517,38 @@ static int macvlan_mode(int *valuep, char *value)
        return -1;
 }
 
-static int config_network_flags(const char *key, char *value,
+static int rand_complete_hwaddr(char *hwaddr)
+{
+       const char hex[] = "0123456789abcdef";
+       char *curs = hwaddr;
+
+#ifndef HAVE_RAND_R
+       randseed(true);
+#else
+       unsigned int seed=randseed(false);
+#endif
+       while (*curs != '\0')
+       {
+               if ( *curs == 'x' || *curs == 'X' ) {
+                       if (curs - hwaddr == 1) {
+                               //ensure address is unicast
+#ifdef HAVE_RAND_R
+                               *curs = hex[rand_r(&seed) & 0x0E];
+                       } else {
+                               *curs = hex[rand_r(&seed) & 0x0F];
+#else
+                               *curs = hex[rand() & 0x0E];
+                       } else {
+                               *curs = hex[rand() & 0x0F];
+#endif
+                       }
+               }
+               curs++;
+       }
+       return 0;
+}
+
+static int config_network_flags(const char *key, const char *value,
                                struct lxc_conf *lxc_conf)
 {
        struct lxc_netdev *netdev;
@@ -272,7 +562,7 @@ static int config_network_flags(const char *key, char *value,
        return 0;
 }
 
-static int config_network_link(const char *key, char *value,
+static int config_network_link(const char *key, const char *value,
                               struct lxc_conf *lxc_conf)
 {
        struct lxc_netdev *netdev;
@@ -284,7 +574,7 @@ static int config_network_link(const char *key, char *value,
        return network_ifname(&netdev->link, value);
 }
 
-static int config_network_name(const char *key, char *value,
+static int config_network_name(const char *key, const char *value,
                               struct lxc_conf *lxc_conf)
 {
        struct lxc_netdev *netdev;
@@ -296,7 +586,7 @@ static int config_network_name(const char *key, char *value,
        return network_ifname(&netdev->name, value);
 }
 
-static int config_network_veth_pair(const char *key, char *value,
+static int config_network_veth_pair(const char *key, const char *value,
                                    struct lxc_conf *lxc_conf)
 {
        struct lxc_netdev *netdev;
@@ -308,7 +598,7 @@ static int config_network_veth_pair(const char *key, char *value,
        return network_ifname(&netdev->priv.veth_attr.pair, value);
 }
 
-static int config_network_macvlan_mode(const char *key, char *value,
+static int config_network_macvlan_mode(const char *key, const char *value,
                                       struct lxc_conf *lxc_conf)
 {
        struct lxc_netdev *netdev;
@@ -320,25 +610,35 @@ static int config_network_macvlan_mode(const char *key, char *value,
        return macvlan_mode(&netdev->priv.macvlan_attr.mode, value);
 }
 
-static int config_network_hwaddr(const char *key, char *value,
+static int config_network_hwaddr(const char *key, const char *value,
                                 struct lxc_conf *lxc_conf)
 {
        struct lxc_netdev *netdev;
 
-       netdev = network_netdev(key, value, &lxc_conf->network);
-       if (!netdev)
+       char *new_value = strdup(value);
+       if (!new_value) {
+               SYSERROR("failed to strdup '%s': %m", value);
                return -1;
+       }
+       rand_complete_hwaddr(new_value);
 
-       netdev->hwaddr = strdup(value);
-       if (!netdev->hwaddr) {
-               SYSERROR("failed to dup string '%s'", value);
+       netdev = network_netdev(key, new_value, &lxc_conf->network);
+       if (!netdev) {
+               free(new_value);
                return -1;
+       };
+
+       if (!new_value || strlen(new_value) == 0) {
+               free(new_value);
+               netdev->hwaddr = NULL;
+               return 0;
        }
 
+       netdev->hwaddr = new_value;
        return 0;
 }
 
-static int config_network_vlan_id(const char *key, char *value,
+static int config_network_vlan_id(const char *key, const char *value,
                               struct lxc_conf *lxc_conf)
 {
        struct lxc_netdev *netdev;
@@ -353,7 +653,7 @@ static int config_network_vlan_id(const char *key, char *value,
        return 0;
 }
 
-static int config_network_mtu(const char *key, char *value,
+static int config_network_mtu(const char *key, const char *value,
                              struct lxc_conf *lxc_conf)
 {
        struct lxc_netdev *netdev;
@@ -362,16 +662,10 @@ static int config_network_mtu(const char *key, char *value,
        if (!netdev)
                return -1;
 
-       netdev->mtu = strdup(value);
-       if (!netdev->mtu) {
-               SYSERROR("failed to dup string '%s'", value);
-               return -1;
-       }
-
-       return 0;
+       return config_string_item(&netdev->mtu, value);
 }
 
-static int config_network_ipv4(const char *key, char *value,
+static int config_network_ipv4(const char *key, const char *value,
                               struct lxc_conf *lxc_conf)
 {
        struct lxc_netdev *netdev;
@@ -393,13 +687,20 @@ static int config_network_ipv4(const char *key, char *value,
        list = malloc(sizeof(*list));
        if (!list) {
                SYSERROR("failed to allocate memory");
+               free(inetdev);
                return -1;
        }
 
        lxc_list_init(list);
        list->elem = inetdev;
 
-       addr = value;
+       addr = strdup(value);
+       if (!addr) {
+               ERROR("no address specified");
+               free(inetdev);
+               free(list);
+               return -1;
+       }
 
        cursor = strstr(addr, " ");
        if (cursor) {
@@ -413,18 +714,19 @@ static int config_network_ipv4(const char *key, char *value,
                prefix = slash + 1;
        }
 
-       if (!addr) {
-               ERROR("no address specified");
-               return -1;
-       }
-
        if (!inet_pton(AF_INET, addr, &inetdev->addr)) {
                SYSERROR("invalid ipv4 address: %s", value);
+               free(inetdev);
+               free(addr);
+               free(list);
                return -1;
        }
 
        if (bcast && !inet_pton(AF_INET, bcast, &inetdev->bcast)) {
                SYSERROR("invalid ipv4 broadcast address: %s", value);
+               free(inetdev);
+               free(list);
+               free(addr);
                return -1;
        }
 
@@ -441,12 +743,13 @@ static int config_network_ipv4(const char *key, char *value,
                        htonl(INADDR_BROADCAST >>  inetdev->prefix);
        }
 
-       lxc_list_add(&netdev->ipv4, list);
+       lxc_list_add_tail(&netdev->ipv4, list);
 
+       free(addr);
        return 0;
 }
 
-static int config_network_ipv4_gateway(const char *key, char *value,
+static int config_network_ipv4_gateway(const char *key, const char *value,
                                       struct lxc_conf *lxc_conf)
 {
        struct lxc_netdev *netdev;
@@ -464,15 +767,18 @@ static int config_network_ipv4_gateway(const char *key, char *value,
 
        if (!value) {
                ERROR("no ipv4 gateway address specified");
+               free(gw);
                return -1;
        }
 
        if (!strcmp(value, "auto")) {
+               free(gw);
                netdev->ipv4_gateway = NULL;
                netdev->ipv4_gateway_auto = true;
        } else {
                if (!inet_pton(AF_INET, value, gw)) {
                        SYSERROR("invalid ipv4 gateway address: %s", value);
+                       free(gw);
                        return -1;
                }
 
@@ -483,13 +789,13 @@ static int config_network_ipv4_gateway(const char *key, char *value,
        return 0;
 }
 
-static int config_network_ipv6(const char *key, char *value,
+static int config_network_ipv6(const char *key, const char *value,
                               struct lxc_conf *lxc_conf)
 {
        struct lxc_netdev *netdev;
        struct lxc_inet6dev *inet6dev;
        struct lxc_list *list;
-       char *slash;
+       char *slash,*valdup;
        char *netmask;
 
        netdev = network_netdev(key, value, &lxc_conf->network);
@@ -506,46 +812,52 @@ static int config_network_ipv6(const char *key, char *value,
        list = malloc(sizeof(*list));
        if (!list) {
                SYSERROR("failed to allocate memory");
+               free(inet6dev);
                return -1;
        }
 
        lxc_list_init(list);
        list->elem = inet6dev;
 
+       valdup = strdup(value);
+       if (!valdup) {
+               ERROR("no address specified");
+               free(list);
+               free(inet6dev);
+               return -1;
+       }
+
        inet6dev->prefix = 64;
-       slash = strstr(value, "/");
+       slash = strstr(valdup, "/");
        if (slash) {
                *slash = '\0';
                netmask = slash + 1;
                inet6dev->prefix = atoi(netmask);
        }
 
-       if (!inet_pton(AF_INET6, value, &inet6dev->addr)) {
-               SYSERROR("invalid ipv6 address: %s", value);
+       if (!inet_pton(AF_INET6, valdup, &inet6dev->addr)) {
+               SYSERROR("invalid ipv6 address: %s", valdup);
+               free(list);
+               free(inet6dev);
+               free(valdup);
                return -1;
        }
 
-       lxc_list_add(&netdev->ipv6, list);
+       lxc_list_add_tail(&netdev->ipv6, list);
 
+       free(valdup);
        return 0;
 }
 
-static int config_network_ipv6_gateway(const char *key, char *value,
+static int config_network_ipv6_gateway(const char *key, const char *value,
                                       struct lxc_conf *lxc_conf)
 {
        struct lxc_netdev *netdev;
-       struct in6_addr *gw;
 
        netdev = network_netdev(key, value, &lxc_conf->network);
        if (!netdev)
                return -1;
 
-       gw = malloc(sizeof(*gw));
-       if (!gw) {
-               SYSERROR("failed to allocate ipv6 gateway address");
-               return -1;
-       }
-
        if (!value) {
                ERROR("no ipv6 gateway address specified");
                return -1;
@@ -555,8 +867,17 @@ static int config_network_ipv6_gateway(const char *key, char *value,
                netdev->ipv6_gateway = NULL;
                netdev->ipv6_gateway_auto = true;
        } else {
+               struct in6_addr *gw;
+
+               gw = malloc(sizeof(*gw));
+               if (!gw) {
+                       SYSERROR("failed to allocate ipv6 gateway address");
+                       return -1;
+               }
+
                if (!inet_pton(AF_INET6, value, gw)) {
                        SYSERROR("invalid ipv6 gateway address: %s", value);
+                       free(gw);
                        return -1;
                }
 
@@ -567,30 +888,83 @@ static int config_network_ipv6_gateway(const char *key, char *value,
        return 0;
 }
 
-static int config_network_script(const char *key, char *value,
-                                struct lxc_conf *lxc_conf)
+static int config_network_script_up(const char *key, const char *value,
+                                   struct lxc_conf *lxc_conf)
 {
        struct lxc_netdev *netdev;
 
        netdev = network_netdev(key, value, &lxc_conf->network);
        if (!netdev)
-       return -1;
+               return -1;
+
+       return config_string_item(&netdev->upscript, value);
+}
+
+static int config_network_script_down(const char *key, const char *value,
+                                     struct lxc_conf *lxc_conf)
+{
+       struct lxc_netdev *netdev;
+
+       netdev = network_netdev(key, value, &lxc_conf->network);
+       if (!netdev)
+               return -1;
+
+       return config_string_item(&netdev->downscript, value);
+}
+
+static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook)
+{
+       struct lxc_list *hooklist;
+
+       hooklist = malloc(sizeof(*hooklist));
+       if (!hooklist) {
+               free(hook);
+               return -1;
+       }
+       hooklist->elem = hook;
+       lxc_list_add_tail(&lxc_conf->hooks[which], hooklist);
+       return 0;
+}
+
+static int config_seccomp(const char *key, const char *value,
+                                struct lxc_conf *lxc_conf)
+{
+       return config_path_item(&lxc_conf->seccomp, value);
+}
+
+static int config_hook(const char *key, const char *value,
+                                struct lxc_conf *lxc_conf)
+{
+       char *copy;
+       
+       if (!value || strlen(value) == 0)
+               return lxc_clear_hooks(lxc_conf, key);
 
-       char *copy = strdup(value);
+       copy = strdup(value);
        if (!copy) {
                SYSERROR("failed to dup string '%s'", value);
                return -1;
        }
-       if (strcmp(key, "lxc.network.script.up") == 0) {
-               netdev->upscript = copy;
-               return 0;
-       }
+       if (strcmp(key, "lxc.hook.pre-start") == 0)
+               return add_hook(lxc_conf, LXCHOOK_PRESTART, copy);
+       else if (strcmp(key, "lxc.hook.pre-mount") == 0)
+               return add_hook(lxc_conf, LXCHOOK_PREMOUNT, copy);
+       else if (strcmp(key, "lxc.hook.autodev") == 0)
+               return add_hook(lxc_conf, LXCHOOK_AUTODEV, copy);
+       else if (strcmp(key, "lxc.hook.mount") == 0)
+               return add_hook(lxc_conf, LXCHOOK_MOUNT, copy);
+       else if (strcmp(key, "lxc.hook.start") == 0)
+               return add_hook(lxc_conf, LXCHOOK_START, copy);
+       else if (strcmp(key, "lxc.hook.post-stop") == 0)
+               return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy);
+       else if (strcmp(key, "lxc.hook.clone") == 0)
+               return add_hook(lxc_conf, LXCHOOK_CLONE, copy);
        SYSERROR("Unknown key: %s", key);
        free(copy);
        return -1;
 }
 
-static int config_personality(const char *key, char *value,
+static int config_personality(const char *key, const char *value,
                              struct lxc_conf *lxc_conf)
 {
        signed long personality = lxc_config_parse_arch(value);
@@ -603,7 +977,8 @@ static int config_personality(const char *key, char *value,
        return 0;
 }
 
-static int config_pts(const char *key, char *value, struct lxc_conf *lxc_conf)
+static int config_pts(const char *key, const char *value,
+                     struct lxc_conf *lxc_conf)
 {
        int maxpts = atoi(value);
 
@@ -612,7 +987,73 @@ static int config_pts(const char *key, char *value, struct lxc_conf *lxc_conf)
        return 0;
 }
 
-static int config_tty(const char *key, char *value, struct lxc_conf *lxc_conf)
+static int config_start(const char *key, const char *value,
+                     struct lxc_conf *lxc_conf)
+{
+       if(strcmp(key, "lxc.start.auto") == 0) {
+               lxc_conf->start_auto = atoi(value);
+               return 0;
+       }
+       else if (strcmp(key, "lxc.start.delay") == 0) {
+               lxc_conf->start_delay = atoi(value);
+               return 0;
+       }
+       else if (strcmp(key, "lxc.start.order") == 0) {
+               lxc_conf->start_order = atoi(value);
+               return 0;
+       }
+       SYSERROR("Unknown key: %s", key);
+       return -1;
+}
+
+static int config_group(const char *key, const char *value,
+                     struct lxc_conf *lxc_conf)
+{
+       char *groups, *groupptr, *sptr, *token;
+       struct lxc_list *grouplist;
+       int ret = -1;
+
+       if (!strlen(value))
+               return lxc_clear_groups(lxc_conf);
+
+       groups = strdup(value);
+       if (!groups) {
+               SYSERROR("failed to dup '%s'", value);
+               return -1;
+       }
+
+       /* in case several groups are specified in a single line
+        * split these groups in a single element for the list */
+       for (groupptr = groups;;groupptr = NULL) {
+                token = strtok_r(groupptr, " \t", &sptr);
+                if (!token) {
+                       ret = 0;
+                        break;
+               }
+
+               grouplist = malloc(sizeof(*grouplist));
+               if (!grouplist) {
+                       SYSERROR("failed to allocate groups list");
+                       break;
+               }
+
+               grouplist->elem = strdup(token);
+               if (!grouplist->elem) {
+                       SYSERROR("failed to dup '%s'", token);
+                       free(grouplist);
+                       break;
+               }
+
+               lxc_list_add_tail(&lxc_conf->groups, grouplist);
+        }
+
+       free(groups);
+
+       return ret;
+}
+
+static int config_tty(const char *key, const char *value,
+                     struct lxc_conf *lxc_conf)
 {
        int nbtty = atoi(value);
 
@@ -621,53 +1062,170 @@ static int config_tty(const char *key, char *value, struct lxc_conf *lxc_conf)
        return 0;
 }
 
-static int config_ttydir(const char *key, char *value,
+static int config_ttydir(const char *key, const char *value,
                          struct lxc_conf *lxc_conf)
 {
-       char *path;
+       return config_string_item_max(&lxc_conf->ttydir, value, NAME_MAX+1);
+}
 
-       if (!value || strlen(value) == 0)
-               return 0;
-       path = strdup(value);
-       if (!path) {
-               SYSERROR("failed to strdup '%s': %m", value);
-               return -1;
-       }
+static int config_kmsg(const char *key, const char *value,
+                         struct lxc_conf *lxc_conf)
+{
+       int v = atoi(value);
 
-       lxc_conf->ttydir = path;
+       lxc_conf->kmsg = v;
 
        return 0;
 }
 
-#if HAVE_APPARMOR
-static int config_aa_profile(const char *key, char *value, struct lxc_conf *lxc_conf)
+static int config_lsm_aa_profile(const char *key, const char *value,
+                                struct lxc_conf *lxc_conf)
+{
+       return config_string_item(&lxc_conf->lsm_aa_profile, value);
+}
+
+static int config_lsm_se_context(const char *key, const char *value,
+                                struct lxc_conf *lxc_conf)
+{
+       return config_string_item(&lxc_conf->lsm_se_context, value);
+}
+
+static int config_logfile(const char *key, const char *value,
+                            struct lxc_conf *lxc_conf)
+{
+       int ret;
+
+       // store these values in the lxc_conf, and then try to set for
+       // actual current logging.
+       ret = config_path_item(&lxc_conf->logfile, value);
+       if (ret == 0)
+               ret = lxc_log_set_file(lxc_conf->logfile);
+       return ret;
+}
+
+static int config_loglevel(const char *key, const char *value,
+                            struct lxc_conf *lxc_conf)
 {
-       char *path;
+       int newlevel;
 
        if (!value || strlen(value) == 0)
                return 0;
-       path = strdup(value);
-       if (!path) {
-               SYSERROR("failed to strdup '%s': %m", value);
-               return -1;
-       }
 
-       lxc_conf->aa_profile = path;
+       if (value[0] >= '0' && value[0] <= '9')
+               newlevel = atoi(value);
+       else
+               newlevel = lxc_log_priority_to_int(value);
+       // store these values in the lxc_conf, and then try to set for
+       // actual current logging.
+       lxc_conf->loglevel = newlevel;
+       return lxc_log_set_level(newlevel);
+}
+
+static int config_autodev(const char *key, const char *value,
+                         struct lxc_conf *lxc_conf)
+{
+       int v = atoi(value);
+
+       lxc_conf->autodev = v;
 
        return 0;
 }
-#endif
 
-static int config_cgroup(const char *key, char *value, struct lxc_conf *lxc_conf)
+static int sig_num(const char *sig)
 {
-       char *token = "lxc.cgroup.";
-       char *subkey;
-       struct lxc_list *cglist = NULL;
-       struct lxc_cgroup *cgelem = NULL;
-
-       subkey = strstr(key, token);
+       int n;
+       char *endp = NULL;
 
-       if (!subkey)
+       errno = 0;
+       n = strtol(sig, &endp, 10);
+       if (sig == endp || n < 0 || errno != 0)
+               return -1;
+       return n;
+}
+
+static int rt_sig_num(const char *signame)
+{
+       int sig_n = 0;
+       int rtmax = 0;
+
+       if (strncasecmp(signame, "max-", 4) == 0) {
+               rtmax = 1;
+       }
+       signame += 4;
+       if (!isdigit(*signame))
+               return -1;
+       sig_n = sig_num(signame);
+       sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
+       if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
+               return -1;
+       return sig_n;
+}
+
+static const char *sig_name(int signum) {
+       int n;
+
+       for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++) {
+               if (n == signames[n].num)
+                       return signames[n].name;
+       }
+       return "";
+}
+
+static int sig_parse(const char *signame) {
+       int n;
+
+       if (isdigit(*signame)) {
+               return sig_num(signame);
+       } else if (strncasecmp(signame, "sig", 3) == 0) {
+               signame += 3;
+               if (strncasecmp(signame, "rt", 2) == 0)
+                       return rt_sig_num(signame + 2);
+               for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++) {
+                       if (strcasecmp (signames[n].name, signame) == 0)
+                               return signames[n].num;
+               }
+       }
+       return -1;
+}
+
+static int config_haltsignal(const char *key, const char *value,
+                            struct lxc_conf *lxc_conf)
+{
+       int sig_n = sig_parse(value);
+
+       if (sig_n < 0)
+               return -1;
+       lxc_conf->haltsignal = sig_n;
+
+       return 0;
+}
+
+static int config_stopsignal(const char *key, const char *value,
+                         struct lxc_conf *lxc_conf)
+{
+       int sig_n = sig_parse(value);
+
+       if (sig_n < 0)
+               return -1;
+       lxc_conf->stopsignal = sig_n;
+
+       return 0;
+}
+
+static int config_cgroup(const char *key, const char *value,
+                        struct lxc_conf *lxc_conf)
+{
+       char *token = "lxc.cgroup.";
+       char *subkey;
+       struct lxc_list *cglist = NULL;
+       struct lxc_cgroup *cgelem = NULL;
+
+       if (!value || strlen(value) == 0)
+               return lxc_clear_cgroups(lxc_conf, key);
+
+       subkey = strstr(key, token);
+
+       if (!subkey)
                return -1;
 
        if (!strlen(subkey))
@@ -716,39 +1274,165 @@ out:
        return -1;
 }
 
-static int config_fstab(const char *key, char *value, struct lxc_conf *lxc_conf)
+static int config_idmap(const char *key, const char *value, struct lxc_conf *lxc_conf)
 {
-       if (strlen(value) >= MAXPATHLEN) {
-               ERROR("%s path is too long", value);
+       char *token = "lxc.id_map";
+       char *subkey;
+       struct lxc_list *idmaplist = NULL;
+       struct id_map *idmap = NULL;
+       unsigned long hostid, nsid, range;
+       char type;
+       int ret;
+
+       if (!value || strlen(value) == 0)
+               return lxc_clear_idmaps(lxc_conf);
+
+       subkey = strstr(key, token);
+
+       if (!subkey)
+               return -1;
+
+       if (!strlen(subkey))
                return -1;
+
+       idmaplist = malloc(sizeof(*idmaplist));
+       if (!idmaplist)
+               goto out;
+
+       idmap = malloc(sizeof(*idmap));
+       if (!idmap)
+               goto out;
+       memset(idmap, 0, sizeof(*idmap));
+
+       ret = sscanf(value, "%c %lu %lu %lu", &type, &nsid, &hostid, &range);
+       if (ret != 4)
+               goto out;
+
+       INFO("read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range);
+       if (type == 'u')
+               idmap->idtype = ID_TYPE_UID;
+       else if (type == 'g')
+               idmap->idtype = ID_TYPE_GID;
+       else
+               goto out;
+
+       idmap->hostid = hostid;
+       idmap->nsid = nsid;
+       idmap->range = range;
+
+       idmaplist->elem = idmap;
+       lxc_list_add_tail(&lxc_conf->id_map, idmaplist);
+
+       return 0;
+
+out:
+       if (idmaplist)
+               free(idmaplist);
+
+       if (idmap) {
+               free(idmap);
        }
 
-       lxc_conf->fstab = strdup(value);
-       if (!lxc_conf->fstab) {
-               SYSERROR("failed to duplicate string %s", value);
+       return -1;
+}
+
+static int config_fstab(const char *key, const char *value,
+                       struct lxc_conf *lxc_conf)
+{
+       return config_path_item(&lxc_conf->fstab, value);
+}
+
+static int config_mount_auto(const char *key, const char *value,
+                            struct lxc_conf *lxc_conf)
+{
+       char *autos, *autoptr, *sptr, *token;
+       static struct { const char *token; int mask; int flag; } allowed_auto_mounts[] = {
+               { "proc",               LXC_AUTO_PROC_MASK,      LXC_AUTO_PROC_MIXED         },
+               { "proc:mixed",         LXC_AUTO_PROC_MASK,      LXC_AUTO_PROC_MIXED         },
+               { "proc:rw",            LXC_AUTO_PROC_MASK,      LXC_AUTO_PROC_RW            },
+               { "sys",                LXC_AUTO_SYS_MASK,       LXC_AUTO_SYS_RO             },
+               { "sys:ro",             LXC_AUTO_SYS_MASK,       LXC_AUTO_SYS_RO             },
+               { "sys:rw",             LXC_AUTO_SYS_MASK,       LXC_AUTO_SYS_RW             },
+               { "cgroup",             LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_NOSPEC      },
+               { "cgroup:mixed",       LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_MIXED       },
+               { "cgroup:ro",          LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_RO          },
+               { "cgroup:rw",          LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_RW          },
+               { "cgroup-full",        LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_FULL_NOSPEC },
+               { "cgroup-full:mixed",  LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_FULL_MIXED  },
+               { "cgroup-full:ro",     LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_FULL_RO     },
+               { "cgroup-full:rw",     LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_FULL_RW     },
+               /* NB: For adding anything that ist just a single on/off, but has
+                *     no options: keep mask and flag identical and just define the
+                *     enum value as an unused bit so far
+                */
+               { NULL, 0 }
+       };
+       int i;
+       int ret = -1;
+
+       if (!strlen(value))
+               return -1;
+
+       autos = strdup(value);
+       if (!autos) {
+               SYSERROR("failed to dup '%s'", value);
                return -1;
        }
 
-       return 0;
+       for (autoptr = autos; ; autoptr = NULL) {
+                token = strtok_r(autoptr, " \t", &sptr);
+                if (!token) {
+                       ret = 0;
+                        break;
+               }
+
+               for (i = 0; allowed_auto_mounts[i].token; i++) {
+                       if (!strcmp(allowed_auto_mounts[i].token, token))
+                               break;
+               }
+
+               if (!allowed_auto_mounts[i].token) {
+                       ERROR("Invalid filesystem to automount: %s", token);
+                       break;
+               }
+
+               lxc_conf->auto_mounts &= ~allowed_auto_mounts[i].mask;
+               lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
+        }
+
+       free(autos);
+
+       return ret;
 }
 
-static int config_mount(const char *key, char *value, struct lxc_conf *lxc_conf)
+static int config_mount(const char *key, const char *value,
+                       struct lxc_conf *lxc_conf)
 {
        char *fstab_token = "lxc.mount";
        char *token = "lxc.mount.entry";
+       char *auto_token = "lxc.mount.auto";
        char *subkey;
        char *mntelem;
        struct lxc_list *mntlist;
 
+       if (!value || strlen(value) == 0)
+               return lxc_clear_mount_entries(lxc_conf);
+
        subkey = strstr(key, token);
 
        if (!subkey) {
-               subkey = strstr(key, fstab_token);
+               subkey = strstr(key, auto_token);
 
-               if (!subkey)
-                       return -1;
+               if (!subkey) {
+                       subkey = strstr(key, fstab_token);
+
+                       if (!subkey)
+                               return -1;
 
-               return config_fstab(key, value, lxc_conf);
+                       return config_fstab(key, value, lxc_conf);
+               }
+
+               return config_mount_auto(key, value, lxc_conf);
        }
 
        if (!strlen(subkey))
@@ -759,8 +1443,10 @@ static int config_mount(const char *key, char *value, struct lxc_conf *lxc_conf)
                return -1;
 
        mntelem = strdup(value);
-       if (!mntelem)
+       if (!mntelem) {
+               free(mntlist);
                return -1;
+       }
        mntlist->elem = mntelem;
 
        lxc_list_add_tail(&lxc_conf->mount_list, mntlist);
@@ -768,15 +1454,61 @@ static int config_mount(const char *key, char *value, struct lxc_conf *lxc_conf)
        return 0;
 }
 
-static int config_cap_drop(const char *key, char *value,
+static int config_cap_keep(const char *key, const char *value,
                           struct lxc_conf *lxc_conf)
 {
-       char *dropcaps, *sptr, *token;
-       struct lxc_list *droplist;
+       char *keepcaps, *keepptr, *sptr, *token;
+       struct lxc_list *keeplist;
        int ret = -1;
 
        if (!strlen(value))
+               return lxc_clear_config_keepcaps(lxc_conf);
+
+       keepcaps = strdup(value);
+       if (!keepcaps) {
+               SYSERROR("failed to dup '%s'", value);
                return -1;
+       }
+
+       /* in case several capability keep is specified in a single line
+        * split these caps in a single element for the list */
+       for (keepptr = keepcaps;;keepptr = NULL) {
+                token = strtok_r(keepptr, " \t", &sptr);
+                if (!token) {
+                       ret = 0;
+                        break;
+               }
+
+               keeplist = malloc(sizeof(*keeplist));
+               if (!keeplist) {
+                       SYSERROR("failed to allocate keepcap list");
+                       break;
+               }
+
+               keeplist->elem = strdup(token);
+               if (!keeplist->elem) {
+                       SYSERROR("failed to dup '%s'", token);
+                       free(keeplist);
+                       break;
+               }
+
+               lxc_list_add_tail(&lxc_conf->keepcaps, keeplist);
+        }
+
+       free(keepcaps);
+
+       return ret;
+}
+
+static int config_cap_drop(const char *key, const char *value,
+                          struct lxc_conf *lxc_conf)
+{
+       char *dropcaps, *dropptr, *sptr, *token;
+       struct lxc_list *droplist;
+       int ret = -1;
+
+       if (!strlen(value))
+               return lxc_clear_config_caps(lxc_conf);
 
        dropcaps = strdup(value);
        if (!dropcaps) {
@@ -786,13 +1518,12 @@ static int config_cap_drop(const char *key, char *value,
 
        /* in case several capability drop is specified in a single line
         * split these caps in a single element for the list */
-       for (;;) {
-                token = strtok_r(dropcaps, " \t", &sptr);
+       for (dropptr = dropcaps;;dropptr = NULL) {
+                token = strtok_r(dropptr, " \t", &sptr);
                 if (!token) {
                        ret = 0;
                         break;
                }
-               dropcaps = NULL;
 
                droplist = malloc(sizeof(*droplist));
                if (!droplist) {
@@ -815,71 +1546,44 @@ static int config_cap_drop(const char *key, char *value,
        return ret;
 }
 
-static int config_console(const char *key, char *value,
+static int config_console(const char *key, const char *value,
                          struct lxc_conf *lxc_conf)
 {
-       char *path;
-
-       path = strdup(value);
-       if (!path) {
-               SYSERROR("failed to strdup '%s': %m", value);
-               return -1;
-       }
-
-       lxc_conf->console.path = path;
-
-       return 0;
+       return config_path_item(&lxc_conf->console.path, value);
 }
 
-static int config_rootfs(const char *key, char *value, struct lxc_conf *lxc_conf)
+static int config_includefile(const char *key, const char *value,
+                         struct lxc_conf *lxc_conf)
 {
-       if (strlen(value) >= MAXPATHLEN) {
-               ERROR("%s path is too long", value);
-               return -1;
-       }
-
-       lxc_conf->rootfs.path = strdup(value);
-       if (!lxc_conf->rootfs.path) {
-               SYSERROR("failed to duplicate string %s", value);
-               return -1;
-       }
-
-       return 0;
+       return lxc_config_read(value, lxc_conf);
 }
 
-static int config_rootfs_mount(const char *key, char *value, struct lxc_conf *lxc_conf)
+static int config_rootfs(const char *key, const char *value,
+                        struct lxc_conf *lxc_conf)
 {
-       if (strlen(value) >= MAXPATHLEN) {
-               ERROR("%s path is too long", value);
-               return -1;
-       }
-
-       lxc_conf->rootfs.mount = strdup(value);
-       if (!lxc_conf->rootfs.mount) {
-               SYSERROR("failed to duplicate string '%s'", value);
-               return -1;
-       }
-
-       return 0;
+       return config_path_item(&lxc_conf->rootfs.path, value);
 }
 
-static int config_pivotdir(const char *key, char *value, struct lxc_conf *lxc_conf)
+static int config_rootfs_mount(const char *key, const char *value,
+                              struct lxc_conf *lxc_conf)
 {
-       if (strlen(value) >= MAXPATHLEN) {
-               ERROR("%s path is too long", value);
-               return -1;
-       }
+       return config_path_item(&lxc_conf->rootfs.mount, value);
+}
 
-       lxc_conf->rootfs.pivot = strdup(value);
-       if (!lxc_conf->rootfs.pivot) {
-               SYSERROR("failed to duplicate string %s", value);
-               return -1;
-       }
+static int config_rootfs_options(const char *key, const char *value,
+                              struct lxc_conf *lxc_conf)
+{
+       return config_string_item(&lxc_conf->rootfs.options, value);
+}
 
-       return 0;
+static int config_pivotdir(const char *key, const char *value,
+                          struct lxc_conf *lxc_conf)
+{
+       return config_path_item(&lxc_conf->rootfs.pivot, value);
 }
 
-static int config_utsname(const char *key, char *value, struct lxc_conf *lxc_conf)
+static int config_utsname(const char *key, const char *value,
+                         struct lxc_conf *lxc_conf)
 {
        struct utsname *utsname;
 
@@ -891,11 +1595,14 @@ static int config_utsname(const char *key, char *value, struct lxc_conf *lxc_con
 
        if (strlen(value) >= sizeof(utsname->nodename)) {
                ERROR("node name '%s' is too long",
-                             utsname->nodename);
+                             value);
+               free(utsname);
                return -1;
        }
 
        strcpy(utsname->nodename, value);
+       if (lxc_conf->utsname)
+               free(lxc_conf->utsname);
        lxc_conf->utsname = utsname;
 
        return 0;
@@ -903,7 +1610,7 @@ static int config_utsname(const char *key, char *value, struct lxc_conf *lxc_con
 
 static int parse_line(char *buffer, void *data)
 {
-       struct config *config;
+       struct lxc_config_t *config;
        char *line, *linep;
        char *dot;
        char *key;
@@ -948,9 +1655,9 @@ static int parse_line(char *buffer, void *data)
        value += lxc_char_left_gc(value, strlen(value));
        value[lxc_char_right_gc(value, strlen(value))] = '\0';
 
-       config = getconfig(key);
+       config = lxc_getconfig(key);
        if (!config) {
-               ERROR("unknow key %s", key);
+               ERROR("unknown key %s", key);
                goto out;
        }
 
@@ -961,13 +1668,20 @@ out:
        return ret;
 }
 
-int lxc_config_readline(char *buffer, struct lxc_conf *conf)
+static int lxc_config_readline(char *buffer, struct lxc_conf *conf)
 {
        return parse_line(buffer, conf);
 }
 
 int lxc_config_read(const char *file, struct lxc_conf *conf)
 {
+       if( access(file, R_OK) == -1 ) {
+               return -1;
+       }
+       /* Catch only the top level config file name in the structure */
+       if( ! conf->rcfile ) {
+               conf->rcfile = strdup( file );
+       }
        return lxc_file_for_each_line(file, parse_line, conf);
 }
 
@@ -986,7 +1700,7 @@ int lxc_config_define_add(struct lxc_list *defines, char* arg)
 
 int lxc_config_define_load(struct lxc_list *defines, struct lxc_conf *conf)
 {
-       struct lxc_list *it;
+       struct lxc_list *it,*next;
        int ret = 0;
 
        lxc_list_for_each(it, defines) {
@@ -995,7 +1709,7 @@ int lxc_config_define_load(struct lxc_list *defines, struct lxc_conf *conf)
                        break;
        }
 
-       lxc_list_for_each(it, defines) {
+       lxc_list_for_each_safe(it, defines, next) {
                lxc_list_del(it);
                free(it);
        }
@@ -1005,12 +1719,19 @@ int lxc_config_define_load(struct lxc_list *defines, struct lxc_conf *conf)
 
 signed long lxc_config_parse_arch(const char *arch)
 {
+       #if HAVE_SYS_PERSONALITY_H
        struct per_name {
                char *name;
                unsigned long per;
-       } pername[4] = {
+       } pername[] = {
                { "x86", PER_LINUX32 },
+               { "linux32", PER_LINUX32 },
+               { "i386", PER_LINUX32 },
+               { "i486", PER_LINUX32 },
+               { "i586", PER_LINUX32 },
                { "i686", PER_LINUX32 },
+               { "athlon", PER_LINUX32 },
+               { "linux64", PER_LINUX },
                { "x86_64", PER_LINUX },
                { "amd64", PER_LINUX },
        };
@@ -1022,6 +1743,662 @@ signed long lxc_config_parse_arch(const char *arch)
                if (!strcmp(pername[i].name, arch))
                    return pername[i].per;
        }
+       #endif
 
        return -1;
 }
+
+int lxc_fill_elevated_privileges(char *flaglist, int *flags)
+{
+       char *token, *saveptr = NULL;
+       int i, aflag;
+       struct { const char *token; int flag; } all_privs[] = {
+               { "CGROUP",             LXC_ATTACH_MOVE_TO_CGROUP       },
+               { "CAP",                LXC_ATTACH_DROP_CAPABILITIES    },
+               { "LSM",                LXC_ATTACH_LSM_EXEC             },
+               { NULL, 0 }
+       };
+
+       if (!flaglist) {
+               /* for the sake of backward compatibility, drop all privileges
+                  if none is specified */
+               for (i = 0; all_privs[i].token; i++) {
+                       *flags |= all_privs[i].flag;
+               }
+               return 0;
+       }
+
+       token = strtok_r(flaglist, "|", &saveptr);
+       while (token) {
+               aflag = -1;
+               for (i = 0; all_privs[i].token; i++) {
+                       if (!strcmp(all_privs[i].token, token))
+                               aflag = all_privs[i].flag;
+               }
+               if (aflag < 0)
+                       return -1;
+
+               *flags |= aflag;
+
+               token = strtok_r(NULL, "|", &saveptr);
+       }
+       return 0;
+}
+
+static int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
+{
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+       return snprintf(retv, inlen, "%d", v);
+}
+
+static int lxc_get_arch_entry(struct lxc_conf *c, char *retv, int inlen)
+{
+       int fulllen = 0;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       #if HAVE_SYS_PERSONALITY_H
+       int len = 0;
+
+       switch(c->personality) {
+       case PER_LINUX32: strprint(retv, inlen, "i686"); break;
+       case PER_LINUX: strprint(retv, inlen, "x86_64"); break;
+       default: break;
+       }
+       #endif
+
+       return fulllen;
+}
+
+/*
+ * If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list,
+ * then just the value(s) will be printed.  Since there still could be
+ * more than one, it is newline-separated.
+ * (Maybe that's ambigous, since some values, i.e. devices.list, will
+ * already have newlines?)
+ * If you ask for 'lxc.cgroup", then all cgroup entries will be printed,
+ * in 'lxc.cgroup.subsystem.key = value' format.
+ */
+static int lxc_get_cgroup_entry(struct lxc_conf *c, char *retv, int inlen,
+                               const char *key)
+{
+       int fulllen = 0, len;
+       int all = 0;
+       struct lxc_list *it;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       if (strcmp(key, "all") == 0)
+               all = 1;
+
+       lxc_list_for_each(it, &c->cgroup) {
+               struct lxc_cgroup *cg = it->elem;
+               if (all) {
+                       strprint(retv, inlen, "lxc.cgroup.%s = %s\n", cg->subsystem, cg->value);
+               } else if (strcmp(cg->subsystem, key) == 0) {
+                       strprint(retv, inlen, "%s\n", cg->value);
+               }
+       }
+       return fulllen;
+}
+
+static int lxc_get_item_hooks(struct lxc_conf *c, char *retv, int inlen,
+                             const char *key)
+{
+       char *subkey;
+       int len, fulllen = 0, found = -1;
+       struct lxc_list *it;
+       int i;
+
+       /* "lxc.hook.mount" */
+       subkey = index(key, '.');
+       if (subkey) subkey = index(subkey+1, '.');
+       if (!subkey)
+               return -1;
+       subkey++;
+       if (!*subkey)
+               return -1;
+       for (i=0; i<NUM_LXC_HOOKS; i++) {
+               if (strcmp(lxchook_names[i], subkey) == 0) {
+                       found=i;
+                       break;
+               }
+       }
+       if (found == -1)
+               return -1;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       lxc_list_for_each(it, &c->hooks[found]) {
+               strprint(retv, inlen, "%s\n", (char *)it->elem);
+       }
+       return fulllen;
+}
+
+static int lxc_get_item_groups(struct lxc_conf *c, char *retv, int inlen)
+{
+       int len, fulllen = 0;
+       struct lxc_list *it;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       lxc_list_for_each(it, &c->groups) {
+               strprint(retv, inlen, "%s\n", (char *)it->elem);
+       }
+       return fulllen;
+}
+
+static int lxc_get_item_cap_drop(struct lxc_conf *c, char *retv, int inlen)
+{
+       int len, fulllen = 0;
+       struct lxc_list *it;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       lxc_list_for_each(it, &c->caps) {
+               strprint(retv, inlen, "%s\n", (char *)it->elem);
+       }
+       return fulllen;
+}
+
+static int lxc_get_item_cap_keep(struct lxc_conf *c, char *retv, int inlen)
+{
+       int len, fulllen = 0;
+       struct lxc_list *it;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       lxc_list_for_each(it, &c->keepcaps) {
+               strprint(retv, inlen, "%s\n", (char *)it->elem);
+       }
+       return fulllen;
+}
+
+static int lxc_get_mount_entries(struct lxc_conf *c, char *retv, int inlen)
+{
+       int len, fulllen = 0;
+       struct lxc_list *it;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       lxc_list_for_each(it, &c->mount_list) {
+               strprint(retv, inlen, "%s\n", (char *)it->elem);
+       }
+       return fulllen;
+}
+
+static int lxc_get_auto_mounts(struct lxc_conf *c, char *retv, int inlen)
+{
+       int len, fulllen = 0;
+       const char *sep = "";
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       if (!(c->auto_mounts & LXC_AUTO_ALL_MASK))
+               return 0;
+
+       switch (c->auto_mounts & LXC_AUTO_PROC_MASK) {
+               case LXC_AUTO_PROC_MIXED:         strprint(retv, inlen, "%sproc:mixed", sep);        sep = " "; break;
+               case LXC_AUTO_PROC_RW:            strprint(retv, inlen, "%sproc:rw", sep);           sep = " "; break;
+               default: break;
+       }
+       switch (c->auto_mounts & LXC_AUTO_SYS_MASK) {
+               case LXC_AUTO_SYS_RO:             strprint(retv, inlen, "%ssys:ro", sep);            sep = " "; break;
+               case LXC_AUTO_SYS_RW:             strprint(retv, inlen, "%ssys:rw", sep);            sep = " "; break;
+               default: break;
+       }
+       switch (c->auto_mounts & LXC_AUTO_CGROUP_MASK) {
+               case LXC_AUTO_CGROUP_NOSPEC:      strprint(retv, inlen, "%scgroup", sep);            sep = " "; break;
+               case LXC_AUTO_CGROUP_MIXED:       strprint(retv, inlen, "%scgroup:mixed", sep);      sep = " "; break;
+               case LXC_AUTO_CGROUP_RO:          strprint(retv, inlen, "%scgroup:ro", sep);         sep = " "; break;
+               case LXC_AUTO_CGROUP_RW:          strprint(retv, inlen, "%scgroup:rw", sep);         sep = " "; break;
+               case LXC_AUTO_CGROUP_FULL_NOSPEC: strprint(retv, inlen, "%scgroup-full", sep);       sep = " "; break;
+               case LXC_AUTO_CGROUP_FULL_MIXED:  strprint(retv, inlen, "%scgroup-full:mixed", sep); sep = " "; break;
+               case LXC_AUTO_CGROUP_FULL_RO:     strprint(retv, inlen, "%scgroup-full:ro", sep);    sep = " "; break;
+               case LXC_AUTO_CGROUP_FULL_RW:     strprint(retv, inlen, "%scgroup-full:rw", sep);    sep = " "; break;
+               default: break;
+       }
+
+       return fulllen;
+}
+
+/*
+ * lxc.network.0.XXX, where XXX can be: name, type, link, flags, type,
+ * macvlan.mode, veth.pair, vlan, ipv4, ipv6, script.up, hwaddr, mtu,
+ * ipv4_gateway, ipv6_gateway.  ipvX_gateway can return 'auto' instead
+ * of an address.  ipv4 and ipv6 return lists (newline-separated).
+ * things like veth.pair return '' if invalid (i.e. if called for vlan
+ * type).
+ */
+static int lxc_get_item_nic(struct lxc_conf *c, char *retv, int inlen,
+                           const char *key)
+{
+       char *p1;
+       int len, fulllen = 0;
+       struct lxc_netdev *netdev;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       p1 = index(key, '.');
+       if (!p1 || *(p1+1) == '\0') return -1;
+       p1++;
+
+       netdev = get_netdev_from_key(key, &c->network);
+       if (!netdev)
+               return -1;
+       if (strcmp(p1, "name") == 0) {
+               if (netdev->name)
+                       strprint(retv, inlen, "%s", netdev->name);
+       } else if (strcmp(p1, "type") == 0) {
+               strprint(retv, inlen, "%s", lxc_net_type_to_str(netdev->type));
+       } else if (strcmp(p1, "link") == 0) {
+               if (netdev->link)
+                       strprint(retv, inlen, "%s", netdev->link);
+       } else if (strcmp(p1, "flags") == 0) {
+               if (netdev->flags & IFF_UP)
+                       strprint(retv, inlen, "up");
+       } else if (strcmp(p1, "script.up") == 0) {
+               if (netdev->upscript)
+                       strprint(retv, inlen, "%s", netdev->upscript);
+       } else if (strcmp(p1, "script.down") == 0) {
+               if (netdev->downscript)
+                       strprint(retv, inlen, "%s", netdev->downscript);
+       } else if (strcmp(p1, "hwaddr") == 0) {
+               if (netdev->hwaddr)
+                       strprint(retv, inlen, "%s", netdev->hwaddr);
+       } else if (strcmp(p1, "mtu") == 0) {
+               if (netdev->mtu)
+                       strprint(retv, inlen, "%s", netdev->mtu);
+       } else if (strcmp(p1, "macvlan.mode") == 0) {
+               if (netdev->type == LXC_NET_MACVLAN) {
+                       const char *mode;
+                       switch (netdev->priv.macvlan_attr.mode) {
+                       case MACVLAN_MODE_PRIVATE: mode = "private"; break;
+                       case MACVLAN_MODE_VEPA: mode = "vepa"; break;
+                       case MACVLAN_MODE_BRIDGE: mode = "bridge"; break;
+                       default: mode = "(invalid)"; break;
+                       }
+                       strprint(retv, inlen, "%s", mode);
+               }
+       } else if (strcmp(p1, "veth.pair") == 0) {
+               if (netdev->type == LXC_NET_VETH) {
+                       strprint(retv, inlen, "%s",
+                                netdev->priv.veth_attr.pair ?
+                                 netdev->priv.veth_attr.pair :
+                                 netdev->priv.veth_attr.veth1);
+               }
+       } else if (strcmp(p1, "vlan") == 0) {
+               if (netdev->type == LXC_NET_VLAN) {
+                       strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
+               }
+       } else if (strcmp(p1, "ipv4_gateway") == 0) {
+               if (netdev->ipv4_gateway_auto) {
+                       strprint(retv, inlen, "auto");
+               } else if (netdev->ipv4_gateway) {
+                       char buf[INET_ADDRSTRLEN];
+                       inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
+                       strprint(retv, inlen, "%s", buf);
+               }
+       } else if (strcmp(p1, "ipv4") == 0) {
+               struct lxc_list *it2;
+               lxc_list_for_each(it2, &netdev->ipv4) {
+                       struct lxc_inetdev *i = it2->elem;
+                       char buf[INET_ADDRSTRLEN];
+                       inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
+                       strprint(retv, inlen, "%s\n", buf);
+               }
+       } else if (strcmp(p1, "ipv6_gateway") == 0) {
+               if (netdev->ipv6_gateway_auto) {
+                       strprint(retv, inlen, "auto");
+               } else if (netdev->ipv6_gateway) {
+                       char buf[INET_ADDRSTRLEN];
+                       inet_ntop(AF_INET, netdev->ipv6_gateway, buf, sizeof(buf));
+                       strprint(retv, inlen, "%s", buf);
+               }
+       } else if (strcmp(p1, "ipv6") == 0) {
+               struct lxc_list *it2;
+               lxc_list_for_each(it2, &netdev->ipv6) {
+                       struct lxc_inetdev *i = it2->elem;
+                       char buf[INET_ADDRSTRLEN];
+                       inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
+                       strprint(retv, inlen, "%s\n", buf);
+               }
+       }
+       return fulllen;
+}
+
+static int lxc_get_item_network(struct lxc_conf *c, char *retv, int inlen)
+{
+       int len, fulllen = 0;
+       struct lxc_list *it;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       lxc_list_for_each(it, &c->network) {
+               struct lxc_netdev *n = it->elem;
+               const char *t = lxc_net_type_to_str(n->type);
+               strprint(retv, inlen, "%s\n", t ? t : "(invalid)");
+       }
+       return fulllen;
+}
+
+int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
+                       int inlen)
+{
+       const char *v = NULL;
+
+       if (strcmp(key, "lxc.mount.entry") == 0)
+               return lxc_get_mount_entries(c, retv, inlen);
+       else if (strcmp(key, "lxc.mount.auto") == 0)
+               return lxc_get_auto_mounts(c, retv, inlen);
+       else if (strcmp(key, "lxc.mount") == 0)
+               v = c->fstab;
+       else if (strcmp(key, "lxc.tty") == 0)
+               return lxc_get_conf_int(c, retv, inlen, c->tty);
+       else if (strcmp(key, "lxc.pts") == 0)
+               return lxc_get_conf_int(c, retv, inlen, c->pts);
+       else if (strcmp(key, "lxc.devttydir") == 0)
+               v = c->ttydir;
+       else if (strcmp(key, "lxc.arch") == 0)
+               return lxc_get_arch_entry(c, retv, inlen);
+       else if (strcmp(key, "lxc.aa_profile") == 0)
+               v = c->lsm_aa_profile;
+       else if (strcmp(key, "lxc.se_context") == 0)
+               v = c->lsm_se_context;
+       else if (strcmp(key, "lxc.logfile") == 0)
+               v = lxc_log_get_file();
+       else if (strcmp(key, "lxc.loglevel") == 0)
+               v = lxc_log_priority_to_string(lxc_log_get_level());
+       else if (strcmp(key, "lxc.cgroup") == 0) // all cgroup info
+               return lxc_get_cgroup_entry(c, retv, inlen, "all");
+       else if (strncmp(key, "lxc.cgroup.", 11) == 0) // specific cgroup info
+               return lxc_get_cgroup_entry(c, retv, inlen, key + 11);
+       else if (strcmp(key, "lxc.utsname") == 0)
+               v = c->utsname ? c->utsname->nodename : NULL;
+       else if (strcmp(key, "lxc.console") == 0)
+               v = c->console.path;
+       else if (strcmp(key, "lxc.rootfs.mount") == 0)
+               v = c->rootfs.mount;
+       else if (strcmp(key, "lxc.rootfs.options") == 0)
+               v = c->rootfs.options;
+       else if (strcmp(key, "lxc.rootfs") == 0)
+               v = c->rootfs.path;
+       else if (strcmp(key, "lxc.pivotdir") == 0)
+               v = c->rootfs.pivot;
+       else if (strcmp(key, "lxc.cap.drop") == 0)
+               return lxc_get_item_cap_drop(c, retv, inlen);
+       else if (strcmp(key, "lxc.cap.keep") == 0)
+               return lxc_get_item_cap_keep(c, retv, inlen);
+       else if (strncmp(key, "lxc.hook", 8) == 0)
+               return lxc_get_item_hooks(c, retv, inlen, key);
+       else if (strcmp(key, "lxc.network") == 0)
+               return lxc_get_item_network(c, retv, inlen);
+       else if (strncmp(key, "lxc.network.", 12) == 0)
+               return lxc_get_item_nic(c, retv, inlen, key + 12);
+       else if (strcmp(key, "lxc.start.auto") == 0)
+               return lxc_get_conf_int(c, retv, inlen, c->start_auto);
+       else if (strcmp(key, "lxc.start.delay") == 0)
+               return lxc_get_conf_int(c, retv, inlen, c->start_delay);
+       else if (strcmp(key, "lxc.start.order") == 0)
+               return lxc_get_conf_int(c, retv, inlen, c->start_order);
+       else if (strcmp(key, "lxc.group") == 0)
+               return lxc_get_item_groups(c, retv, inlen);
+       else if (strcmp(key, "lxc.seccomp") == 0)
+               v = c->seccomp;
+       else return -1;
+
+       if (!v)
+               return 0;
+       if (retv && inlen >= strlen(v) + 1)
+               strncpy(retv, v, strlen(v)+1);
+       return strlen(v);
+}
+
+int lxc_clear_config_item(struct lxc_conf *c, const char *key)
+{
+       if (strcmp(key, "lxc.network") == 0)
+               return lxc_clear_config_network(c);
+       else if (strncmp(key, "lxc.network.", 12) == 0)
+               return lxc_clear_nic(c, key + 12);
+       else if (strcmp(key, "lxc.cap.drop") == 0)
+               return lxc_clear_config_caps(c);
+       else if (strcmp(key, "lxc.cap.keep") == 0)
+               return lxc_clear_config_keepcaps(c);
+       else if (strncmp(key, "lxc.cgroup", 10) == 0)
+               return lxc_clear_cgroups(c, key);
+       else if (strcmp(key, "lxc.mount.entries") == 0)
+               return lxc_clear_mount_entries(c);
+       else if (strcmp(key, "lxc.mount.auto") == 0)
+               return lxc_clear_automounts(c);
+       else if (strncmp(key, "lxc.hook", 8) == 0)
+               return lxc_clear_hooks(c, key);
+       else if (strncmp(key, "lxc.group", 9) == 0)
+               return lxc_clear_groups(c);
+       else if (strncmp(key, "lxc.seccomp", 11) == 0) {
+               lxc_seccomp_free(c);
+               return 0;
+       }
+
+       return -1;
+}
+
+/*
+ * writing out a confile.
+ */
+void write_config(FILE *fout, struct lxc_conf *c)
+{
+       struct lxc_list *it;
+       int i;
+
+       if (c->fstab)
+               fprintf(fout, "lxc.mount = %s\n", c->fstab);
+       lxc_list_for_each(it, &c->mount_list) {
+               fprintf(fout, "lxc.mount.entry = %s\n", (char *)it->elem);
+       }
+       if (c->auto_mounts & LXC_AUTO_ALL_MASK) {
+               fprintf(fout, "lxc.mount.auto =");
+               switch (c->auto_mounts & LXC_AUTO_PROC_MASK) {
+                       case LXC_AUTO_PROC_MIXED:         fprintf(fout, " proc:mixed");        break;
+                       case LXC_AUTO_PROC_RW:            fprintf(fout, " proc:rw");           break;
+                       default: break;
+               }
+               switch (c->auto_mounts & LXC_AUTO_SYS_MASK) {
+                       case LXC_AUTO_SYS_RO:             fprintf(fout, " sys:ro");            break;
+                       case LXC_AUTO_SYS_RW:             fprintf(fout, " sys:rw");            break;
+                       default: break;
+               }
+               switch (c->auto_mounts & LXC_AUTO_CGROUP_MASK) {
+                       case LXC_AUTO_CGROUP_NOSPEC:      fprintf(fout, " cgroup");            break;
+                       case LXC_AUTO_CGROUP_MIXED:       fprintf(fout, " cgroup:mixed");      break;
+                       case LXC_AUTO_CGROUP_RO:          fprintf(fout, " cgroup:ro");         break;
+                       case LXC_AUTO_CGROUP_RW:          fprintf(fout, " cgroup:rw");         break;
+                       case LXC_AUTO_CGROUP_FULL_NOSPEC: fprintf(fout, " cgroup-full");       break;
+                       case LXC_AUTO_CGROUP_FULL_MIXED:  fprintf(fout, " cgroup-full:mixed"); break;
+                       case LXC_AUTO_CGROUP_FULL_RO:     fprintf(fout, " cgroup-full:ro");    break;
+                       case LXC_AUTO_CGROUP_FULL_RW:     fprintf(fout, " cgroup-full:rw");    break;
+                       default: break;
+               }
+               fprintf(fout, "\n");
+       }
+       if (c->tty)
+               fprintf(fout, "lxc.tty = %d\n", c->tty);
+       if (c->pts)
+               fprintf(fout, "lxc.pts = %d\n", c->pts);
+       if (c->ttydir)
+               fprintf(fout, "lxc.devttydir = %s\n", c->ttydir);
+       if (c->haltsignal)
+               fprintf(fout, "lxc.haltsignal = SIG%s\n", sig_name(c->haltsignal));
+       if (c->stopsignal)
+               fprintf(fout, "lxc.stopsignal = SIG%s\n", sig_name(c->stopsignal));
+       #if HAVE_SYS_PERSONALITY_H
+       switch(c->personality) {
+       case PER_LINUX32: fprintf(fout, "lxc.arch = i686\n"); break;
+       case PER_LINUX: fprintf(fout, "lxc.arch = x86_64\n"); break;
+       default: break;
+       }
+       #endif
+       if (c->lsm_aa_profile)
+               fprintf(fout, "lxc.aa_profile = %s\n", c->lsm_aa_profile);
+       if (c->lsm_se_context)
+               fprintf(fout, "lxc.se_context = %s\n", c->lsm_se_context);
+       if (c->seccomp)
+               fprintf(fout, "lxc.seccomp = %s\n", c->seccomp);
+       if (c->kmsg == 0)
+               fprintf(fout, "lxc.kmsg = 0\n");
+       if (c->autodev > 0)
+               fprintf(fout, "lxc.autodev = 1\n");
+       if (c->loglevel != LXC_LOG_PRIORITY_NOTSET)
+               fprintf(fout, "lxc.loglevel = %s\n", lxc_log_priority_to_string(c->loglevel));
+       if (c->logfile)
+               fprintf(fout, "lxc.logfile = %s\n", c->logfile);
+       lxc_list_for_each(it, &c->cgroup) {
+               struct lxc_cgroup *cg = it->elem;
+               fprintf(fout, "lxc.cgroup.%s = %s\n", cg->subsystem, cg->value);
+       }
+       if (c->utsname)
+               fprintf(fout, "lxc.utsname = %s\n", c->utsname->nodename);
+       lxc_list_for_each(it, &c->network) {
+               struct lxc_netdev *n = it->elem;
+               const char *t = lxc_net_type_to_str(n->type);
+               struct lxc_list *it2;
+               fprintf(fout, "lxc.network.type = %s\n", t ? t : "(invalid)");
+               if (n->flags & IFF_UP)
+                       fprintf(fout, "lxc.network.flags = up\n");
+               if (n->link)
+                       fprintf(fout, "lxc.network.link = %s\n", n->link);
+               if (n->name)
+                       fprintf(fout, "lxc.network.name = %s\n", n->name);
+               if (n->type == LXC_NET_MACVLAN) {
+                       const char *mode;
+                       switch (n->priv.macvlan_attr.mode) {
+                       case MACVLAN_MODE_PRIVATE: mode = "private"; break;
+                       case MACVLAN_MODE_VEPA: mode = "vepa"; break;
+                       case MACVLAN_MODE_BRIDGE: mode = "bridge"; break;
+                       default: mode = "(invalid)"; break;
+                       }
+                       fprintf(fout, "lxc.network.macvlan.mode = %s\n", mode);
+               } else if (n->type == LXC_NET_VETH) {
+                       if (n->priv.veth_attr.pair)
+                               fprintf(fout, "lxc.network.veth.pair = %s\n",
+                                       n->priv.veth_attr.pair);
+               } else if (n->type == LXC_NET_VLAN) {
+                       fprintf(fout, "lxc.network.vlan.id = %d\n", n->priv.vlan_attr.vid);
+               }
+               if (n->upscript)
+                       fprintf(fout, "lxc.network.script.up = %s\n", n->upscript);
+               if (n->downscript)
+                       fprintf(fout, "lxc.network.script.down = %s\n", n->downscript);
+               if (n->hwaddr)
+                       fprintf(fout, "lxc.network.hwaddr = %s\n", n->hwaddr);
+               if (n->mtu)
+                       fprintf(fout, "lxc.network.mtu = %s\n", n->mtu);
+               if (n->ipv4_gateway_auto)
+                       fprintf(fout, "lxc.network.ipv4.gateway = auto\n");
+               else if (n->ipv4_gateway) {
+                       char buf[INET_ADDRSTRLEN];
+                       inet_ntop(AF_INET, n->ipv4_gateway, buf, sizeof(buf));
+                       fprintf(fout, "lxc.network.ipv4.gateway = %s\n", buf);
+               }
+               lxc_list_for_each(it2, &n->ipv4) {
+                       struct lxc_inetdev *i = it2->elem;
+                       char buf[INET_ADDRSTRLEN];
+                       inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
+                       fprintf(fout, "lxc.network.ipv4 = %s", buf);
+
+                       if (i->prefix)
+                               fprintf(fout, "/%d", i->prefix);
+
+                       if (i->bcast.s_addr != (i->addr.s_addr |
+                           htonl(INADDR_BROADCAST >>  i->prefix))) {
+
+                               inet_ntop(AF_INET, &i->bcast, buf, sizeof(buf));
+                               fprintf(fout, " %s\n", buf);
+                       }
+                       else
+                               fprintf(fout, "\n");
+               }
+               if (n->ipv6_gateway_auto)
+                       fprintf(fout, "lxc.network.ipv6.gateway = auto\n");
+               else if (n->ipv6_gateway) {
+                       char buf[INET6_ADDRSTRLEN];
+                       inet_ntop(AF_INET6, n->ipv6_gateway, buf, sizeof(buf));
+                       fprintf(fout, "lxc.network.ipv6.gateway = %s\n", buf);
+               }
+               lxc_list_for_each(it2, &n->ipv6) {
+                       struct lxc_inet6dev *i = it2->elem;
+                       char buf[INET6_ADDRSTRLEN];
+                       inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
+                       if (i->prefix)
+                               fprintf(fout, "lxc.network.ipv6 = %s/%d\n",
+                                       buf, i->prefix);
+                       else
+                               fprintf(fout, "lxc.network.ipv6 = %s\n", buf);
+               }
+       }
+       lxc_list_for_each(it, &c->caps)
+               fprintf(fout, "lxc.cap.drop = %s\n", (char *)it->elem);
+       lxc_list_for_each(it, &c->keepcaps)
+               fprintf(fout, "lxc.cap.keep = %s\n", (char *)it->elem);
+       lxc_list_for_each(it, &c->id_map) {
+               struct id_map *idmap = it->elem;
+               fprintf(fout, "lxc.id_map = %c %lu %lu %lu\n",
+                       idmap->idtype == ID_TYPE_UID ? 'u' : 'g', idmap->nsid,
+                       idmap->hostid, idmap->range);
+       }
+       for (i=0; i<NUM_LXC_HOOKS; i++) {
+               lxc_list_for_each(it, &c->hooks[i])
+                       fprintf(fout, "lxc.hook.%s = %s\n",
+                               lxchook_names[i], (char *)it->elem);
+       }
+       if (c->console.path)
+               fprintf(fout, "lxc.console = %s\n", c->console.path);
+       if (c->rootfs.path)
+               fprintf(fout, "lxc.rootfs = %s\n", c->rootfs.path);
+       if (c->rootfs.mount && strcmp(c->rootfs.mount, LXCROOTFSMOUNT) != 0)
+               fprintf(fout, "lxc.rootfs.mount = %s\n", c->rootfs.mount);
+       if (c->rootfs.options)
+               fprintf(fout, "lxc.rootfs.options = %s\n", c->rootfs.options);
+       if (c->rootfs.pivot)
+               fprintf(fout, "lxc.pivotdir = %s\n", c->rootfs.pivot);
+       if (c->start_auto)
+               fprintf(fout, "lxc.start.auto = %d\n", c->start_auto);
+       if (c->start_delay)
+               fprintf(fout, "lxc.start.delay = %d\n", c->start_delay);
+       if (c->start_order)
+               fprintf(fout, "lxc.start.order = %d\n", c->start_order);
+       lxc_list_for_each(it, &c->groups)
+               fprintf(fout, "lxc.group = %s\n", (char *)it->elem);
+}