]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/confile_utils.c
utils: use SYSTRACE() when logging stdio permission fixup failures
[mirror_lxc.git] / src / lxc / confile_utils.c
index a68c6ffd06109850b16adb94ac8880bcf42f2bab..7e2c7a57a9a491e989e59a29468ce9d554f573ca 100644 (file)
@@ -1,37 +1,25 @@
-/* liblxcapi
- *
- * Copyright © 2017 Christian Brauner <christian.brauner@ubuntu.com>.
- * Copyright © 2017 Canonical Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
+/* SPDX-License-Identifier: LGPL-2.1+ */
 
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#include <arpa/inet.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <arpa/inet.h>
 
 #include "conf.h"
+#include "config.h"
 #include "confile.h"
 #include "confile_utils.h"
 #include "error.h"
 #include "list.h"
+#include "lxc.h"
 #include "log.h"
 #include "lxccontainer.h"
+#include "macro.h"
+#include "memory_utils.h"
 #include "network.h"
 #include "parse.h"
 #include "utils.h"
 #include "include/strlcpy.h"
 #endif
 
-lxc_log_define(lxc_confile_utils, lxc);
+lxc_log_define(confile_utils, lxc);
 
 int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
                 unsigned long *hostid, unsigned long *range)
 {
+       __do_free char *dup = NULL;
        int ret = -1;
        unsigned long tmp_hostid, tmp_nsid, tmp_range;
        char tmp_type;
        char *window, *slide;
-       char *dup = NULL;
 
        /* Duplicate string. */
        dup = strdup(idmap);
        if (!dup)
-               goto on_error;
+               return ret_errno(ENOMEM);
 
        /* A prototypical idmap entry would be: "u 1000 1000000 65536" */
 
@@ -63,13 +51,11 @@ int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
        /* skip whitespace */
        slide += strspn(slide, " \t\r");
        if (slide != window && *slide == '\0')
-               goto on_error;
+               return ret_errno(EINVAL);
 
        /* Validate type. */
-       if (*slide != 'u' && *slide != 'g') {
-               ERROR("Invalid id mapping type: %c", *slide);
-               goto on_error;
-       }
+       if (*slide != 'u' && *slide != 'g')
+               return log_error_errno(-EINVAL, EINVAL, "Invalid id mapping type: %c", *slide);
 
        /* Assign type. */
        tmp_type = *slide;
@@ -82,7 +68,7 @@ int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
        slide += strspn(slide, " \t\r");
        /* There must be whitespace. */
        if (slide == window)
-               goto on_error;
+               return ret_errno(EINVAL);
 
        /* Mark beginning of nsid. */
        window = slide;
@@ -90,15 +76,14 @@ int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
        slide += strcspn(slide, " \t\r");
        /* There must be non-whitespace. */
        if (slide == window || *slide == '\0')
-               goto on_error;
+               return ret_errno(EINVAL);
        /* Mark end of nsid. */
        *slide = '\0';
 
        /* Parse nsid. */
-       if (lxc_safe_ulong(window, &tmp_nsid) < 0) {
-               ERROR("Failed to parse nsid: %s", window);
-               goto on_error;
-       }
+       ret = lxc_safe_ulong(window, &tmp_nsid);
+       if (ret < 0)
+               return log_error_errno(ret, errno, "Failed to parse nsid: %s", window);
 
        /* Move beyond \0. */
        slide++;
@@ -108,7 +93,7 @@ int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
         * So only ensure that we're not at the end of the string.
         */
        if (*slide == '\0')
-               goto on_error;
+               return ret_errno(EINVAL);
 
        /* Mark beginning of hostid. */
        window = slide;
@@ -116,15 +101,14 @@ int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
        slide += strcspn(slide, " \t\r");
        /* There must be non-whitespace. */
        if (slide == window || *slide == '\0')
-               goto on_error;
+               return ret_errno(EINVAL);
        /* Mark end of nsid. */
        *slide = '\0';
 
        /* Parse hostid. */
-       if (lxc_safe_ulong(window, &tmp_hostid) < 0) {
-               ERROR("Failed to parse hostid: %s", window);
-               goto on_error;
-       }
+       ret = lxc_safe_ulong(window, &tmp_hostid);
+       if (ret < 0)
+               return log_error_errno(ret, errno, "Failed to parse hostid: %s", window);
 
        /* Move beyond \0. */
        slide++;
@@ -134,7 +118,7 @@ int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
         * So only ensure that we're not at the end of the string.
         */
        if (*slide == '\0')
-               goto on_error;
+               return ret_errno(EINVAL);
 
        /* Mark beginning of range. */
        window = slide;
@@ -142,34 +126,29 @@ int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
        slide += strcspn(slide, " \t\r");
        /* There must be non-whitespace. */
        if (slide == window)
-               goto on_error;
+               return ret_errno(EINVAL);
 
        /* The range is the last valid entry we expect. So make sure that there
         * is no trailing garbage and if there is, error out.
         */
        if (*(slide + strspn(slide, " \t\r\n")) != '\0')
-               goto on_error;
+               return ret_errno(EINVAL);
+
        /* Mark end of range. */
        *slide = '\0';
 
        /* Parse range. */
-       if (lxc_safe_ulong(window, &tmp_range) < 0) {
-               ERROR("Failed to parse id mapping range: %s", window);
-               goto on_error;
-       }
+       ret = lxc_safe_ulong(window, &tmp_range);
+       if (ret < 0)
+               return log_error_errno(ret, errno, "Failed to parse id mapping range: %s", window);
 
-       *type = tmp_type;
-       *nsid = tmp_nsid;
+       *type   = tmp_type;
+       *nsid   = tmp_nsid;
        *hostid = tmp_hostid;
-       *range = tmp_range;
+       *range  = tmp_range;
 
        /* Yay, we survived. */
-       ret = 0;
-
-on_error:
-       free(dup);
-
-       return ret;
+       return 0;
 }
 
 bool lxc_config_value_empty(const char *value)
@@ -182,13 +161,13 @@ bool lxc_config_value_empty(const char *value)
 
 struct lxc_netdev *lxc_network_add(struct lxc_list *networks, int idx, bool tail)
 {
-       struct lxc_list *newlist;
-       struct lxc_netdev *netdev = NULL;
+       __do_free struct lxc_list *newlist = NULL;
+       __do_free struct lxc_netdev *netdev = NULL;
 
        /* network does not exist */
        netdev = malloc(sizeof(*netdev));
        if (!netdev)
-               return NULL;
+               return ret_set_errno(NULL, ENOMEM);
 
        memset(netdev, 0, sizeof(*netdev));
        lxc_list_init(&netdev->ipv4);
@@ -199,10 +178,8 @@ struct lxc_netdev *lxc_network_add(struct lxc_list *networks, int idx, bool tail
 
        /* prepare new list */
        newlist = malloc(sizeof(*newlist));
-       if (!newlist) {
-               free(netdev);
-               return NULL;
-       }
+       if (!newlist)
+               return ret_set_errno(NULL, ENOMEM);
 
        lxc_list_init(newlist);
        newlist->elem = netdev;
@@ -211,7 +188,9 @@ struct lxc_netdev *lxc_network_add(struct lxc_list *networks, int idx, bool tail
                lxc_list_add_tail(networks, newlist);
        else
                lxc_list_add(networks, newlist);
-       return netdev;
+       move_ptr(newlist);
+
+       return move_ptr(netdev);
 }
 
 /* Takes care of finding the correct netdev struct in the networks list or
@@ -236,7 +215,7 @@ struct lxc_netdev *lxc_get_netdev_by_idx(struct lxc_conf *conf,
        }
 
        if (!allocate)
-               return NULL;
+               return ret_set_errno(NULL, EINVAL);
 
        return lxc_network_add(insert, idx, true);
 }
@@ -265,40 +244,66 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
 
                TRACE("index: %zd", netdev->idx);
                TRACE("ifindex: %d", netdev->ifindex);
+
                switch (netdev->type) {
                case LXC_NET_VETH:
                        TRACE("type: veth");
+                       TRACE("veth mode: %d", netdev->priv.veth_attr.mode);
+
                        if (netdev->priv.veth_attr.pair[0] != '\0')
                                TRACE("veth pair: %s",
                                      netdev->priv.veth_attr.pair);
+
                        if (netdev->priv.veth_attr.veth1[0] != '\0')
                                TRACE("veth1 : %s",
                                      netdev->priv.veth_attr.veth1);
+
                        if (netdev->priv.veth_attr.ifindex > 0)
                                TRACE("host side ifindex for veth device: %d",
                                      netdev->priv.veth_attr.ifindex);
+
+                       if (netdev->priv.veth_attr.vlan_id_set)
+                               TRACE("veth vlan id: %d", netdev->priv.veth_attr.vlan_id);
+
+                       lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.vlan_tagged_ids, next) {
+                               unsigned short vlan_tagged_id = PTR_TO_USHORT(cur->elem);
+                               TRACE("veth vlan tagged id: %u", vlan_tagged_id);
+                       }
+
                        break;
                case LXC_NET_MACVLAN:
                        TRACE("type: macvlan");
+
                        if (netdev->priv.macvlan_attr.mode > 0) {
-                               char *macvlan_mode;
-                               macvlan_mode = lxc_macvlan_flag_to_mode(
+                               char *mode;
+
+                               mode = lxc_macvlan_flag_to_mode(
                                    netdev->priv.macvlan_attr.mode);
                                TRACE("macvlan mode: %s",
-                                     macvlan_mode ? macvlan_mode
-                                                  : "(invalid mode)");
+                                     mode ? mode : "(invalid mode)");
                        }
                        break;
+               case LXC_NET_IPVLAN:
+                       TRACE("type: ipvlan");
+
+                       char *mode;
+                       mode = lxc_ipvlan_flag_to_mode(netdev->priv.ipvlan_attr.mode);
+                       TRACE("ipvlan mode: %s", mode ? mode : "(invalid mode)");
+
+                       char *isolation;
+                       isolation = lxc_ipvlan_flag_to_isolation(netdev->priv.ipvlan_attr.isolation);
+                       TRACE("ipvlan isolation: %s", isolation ? isolation : "(invalid isolation)");
+                       break;
                case LXC_NET_VLAN:
                        TRACE("type: vlan");
                        TRACE("vlan id: %d", netdev->priv.vlan_attr.vid);
                        break;
                case LXC_NET_PHYS:
                        TRACE("type: phys");
-                       if (netdev->priv.phys_attr.ifindex > 0) {
+
+                       if (netdev->priv.phys_attr.ifindex > 0)
                                TRACE("host side ifindex for phys device: %d",
                                      netdev->priv.phys_attr.ifindex);
-                       }
                        break;
                case LXC_NET_EMPTY:
                        TRACE("type: empty");
@@ -307,29 +312,42 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
                        TRACE("type: none");
                        break;
                default:
-                       ERROR("invalid network type %d", netdev->type);
+                       ERROR("Invalid network type %d", netdev->type);
                        return;
                }
 
                if (netdev->type != LXC_NET_EMPTY) {
                        TRACE("flags: %s",
                              netdev->flags == IFF_UP ? "up" : "none");
+
                        if (netdev->link[0] != '\0')
                                TRACE("link: %s", netdev->link);
+
+                       /* l2proxy only used when link is specified */
+                       if (netdev->link[0] != '\0')
+                               TRACE("l2proxy: %s", netdev->l2proxy ? "true" : "false");
+
                        if (netdev->name[0] != '\0')
                                TRACE("name: %s", netdev->name);
+
                        if (netdev->hwaddr)
                                TRACE("hwaddr: %s", netdev->hwaddr);
+
                        if (netdev->mtu)
                                TRACE("mtu: %s", netdev->mtu);
+
                        if (netdev->upscript)
                                TRACE("upscript: %s", netdev->upscript);
+
                        if (netdev->downscript)
                                TRACE("downscript: %s", netdev->downscript);
 
                        TRACE("ipv4 gateway auto: %s",
                              netdev->ipv4_gateway_auto ? "true" : "false");
 
+                       TRACE("ipv4 gateway dev: %s",
+                             netdev->ipv4_gateway_dev ? "true" : "false");
+
                        if (netdev->ipv4_gateway) {
                                inet_ntop(AF_INET, netdev->ipv4_gateway,
                                          bufinet4, sizeof(bufinet4));
@@ -345,17 +363,44 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
 
                        TRACE("ipv6 gateway auto: %s",
                              netdev->ipv6_gateway_auto ? "true" : "false");
+
+                       TRACE("ipv6 gateway dev: %s",
+                             netdev->ipv6_gateway_dev ? "true" : "false");
+
                        if (netdev->ipv6_gateway) {
                                inet_ntop(AF_INET6, netdev->ipv6_gateway,
                                          bufinet6, sizeof(bufinet6));
                                TRACE("ipv6 gateway: %s", bufinet6);
                        }
+
                        lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
                                inet6dev = cur->elem;
                                inet_ntop(AF_INET6, &inet6dev->addr, bufinet6,
                                          sizeof(bufinet6));
                                TRACE("ipv6 addr: %s", bufinet6);
                        }
+
+                       if (netdev->type == LXC_NET_VETH) {
+                               lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv4_routes, next) {
+                                       inet4dev = cur->elem;
+                                       if (!inet_ntop(AF_INET, &inet4dev->addr, bufinet4, sizeof(bufinet4))) {
+                                               ERROR("Invalid ipv4 veth route");
+                                               return;
+                                       }
+
+                                       TRACE("ipv4 veth route: %s/%u", bufinet4, inet4dev->prefix);
+                               }
+
+                               lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv6_routes, next) {
+                                       inet6dev = cur->elem;
+                                       if (!inet_ntop(AF_INET6, &inet6dev->addr, bufinet6, sizeof(bufinet6))) {
+                                               ERROR("Invalid ipv6 veth route");
+                                               return;
+                                       }
+
+                                       TRACE("ipv6 veth route: %s/%u", bufinet6, inet6dev->prefix);
+                               }
+                       }
                }
        }
 }
@@ -364,6 +409,9 @@ static void lxc_free_netdev(struct lxc_netdev *netdev)
 {
        struct lxc_list *cur, *next;
 
+       if (!netdev)
+               return;
+
        free(netdev->upscript);
        free(netdev->downscript);
        free(netdev->hwaddr);
@@ -383,14 +431,34 @@ static void lxc_free_netdev(struct lxc_netdev *netdev)
                free(cur);
        }
 
+       if (netdev->type == LXC_NET_VETH) {
+               lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv4_routes, next) {
+                       lxc_list_del(cur);
+                       free(cur->elem);
+                       free(cur);
+               }
+
+               lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv6_routes, next) {
+                       lxc_list_del(cur);
+                       free(cur->elem);
+                       free(cur);
+               }
+
+               lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.vlan_tagged_ids, next) {
+                       lxc_list_del(cur);
+                       free(cur);
+               }
+       }
+
        free(netdev);
 }
 
+define_cleanup_function(struct lxc_netdev *, lxc_free_netdev);
+
 bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx)
 {
+       call_cleaner(lxc_free_netdev) struct lxc_netdev *netdev = NULL;
        struct lxc_list *cur, *next;
-       struct lxc_netdev *netdev;
-       bool found = false;
 
        lxc_list_for_each_safe(cur, &conf->network, next) {
                netdev = cur->elem;
@@ -398,25 +466,19 @@ bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx)
                        continue;
 
                lxc_list_del(cur);
-               found = true;
-               break;
+               free(cur);
+               return true;
        }
 
-       if (!found)
-               return false;
-
-       lxc_free_netdev(netdev);
-       free(cur);
-
-       return true;
+       return false;
 }
 
 void lxc_free_networks(struct lxc_list *networks)
 {
        struct lxc_list *cur, *next;
-       struct lxc_netdev *netdev;
 
-       lxc_list_for_each_safe(cur, networks, next) {
+       lxc_list_for_each_safe (cur, networks, next) {
+               struct lxc_netdev *netdev = cur->elem;
                netdev = cur->elem;
                lxc_free_netdev(netdev);
                free(cur);
@@ -426,21 +488,52 @@ void lxc_free_networks(struct lxc_list *networks)
        lxc_list_init(networks);
 }
 
-static struct macvlan_mode {
+static struct lxc_veth_mode {
+       char *name;
+       int mode;
+} veth_mode[] = {
+       { "bridge", VETH_MODE_BRIDGE },
+       { "router", VETH_MODE_ROUTER },
+};
+
+int lxc_veth_mode_to_flag(int *mode, const char *value)
+{
+       for (size_t i = 0; i < sizeof(veth_mode) / sizeof(veth_mode[0]); i++) {
+               if (strcmp(veth_mode[i].name, value) != 0)
+                       continue;
+
+               *mode = veth_mode[i].mode;
+               return 0;
+       }
+
+       return ret_errno(EINVAL);
+}
+
+char *lxc_veth_flag_to_mode(int mode)
+{
+       for (size_t i = 0; i < sizeof(veth_mode) / sizeof(veth_mode[0]); i++) {
+               if (veth_mode[i].mode != mode)
+                       continue;
+
+               return veth_mode[i].name;
+       }
+
+       return ret_set_errno(NULL, EINVAL);
+}
+
+static struct lxc_macvlan_mode {
        char *name;
        int mode;
 } macvlan_mode[] = {
-    { "private",  MACVLAN_MODE_PRIVATE  },
-    { "vepa",     MACVLAN_MODE_VEPA     },
-    { "bridge",   MACVLAN_MODE_BRIDGE   },
-    { "passthru", MACVLAN_MODE_PASSTHRU },
+       { "private",  MACVLAN_MODE_PRIVATE  },
+       { "vepa",     MACVLAN_MODE_VEPA     },
+       { "bridge",   MACVLAN_MODE_BRIDGE   },
+       { "passthru", MACVLAN_MODE_PASSTHRU },
 };
 
 int lxc_macvlan_mode_to_flag(int *mode, const char *value)
 {
-       size_t i;
-
-       for (i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
+       for (size_t i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
                if (strcmp(macvlan_mode[i].name, value))
                        continue;
 
@@ -448,21 +541,87 @@ int lxc_macvlan_mode_to_flag(int *mode, const char *value)
                return 0;
        }
 
-       return -1;
+       return ret_errno(EINVAL);
 }
 
 char *lxc_macvlan_flag_to_mode(int mode)
 {
-       size_t i;
-
-       for (i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
-               if (macvlan_mode[i].mode == mode)
+       for (size_t i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
+               if (macvlan_mode[i].mode != mode)
                        continue;
 
                return macvlan_mode[i].name;
        }
 
-       return NULL;
+       return ret_set_errno(NULL, EINVAL);
+}
+
+static struct lxc_ipvlan_mode {
+       char *name;
+       int mode;
+} ipvlan_mode[] = {
+       { "l3",  IPVLAN_MODE_L3  },
+       { "l3s", IPVLAN_MODE_L3S },
+       { "l2",  IPVLAN_MODE_L2  },
+};
+
+int lxc_ipvlan_mode_to_flag(int *mode, const char *value)
+{
+       for (size_t i = 0; i < sizeof(ipvlan_mode) / sizeof(ipvlan_mode[0]); i++) {
+               if (strcmp(ipvlan_mode[i].name, value) != 0)
+                       continue;
+
+               *mode = ipvlan_mode[i].mode;
+               return 0;
+       }
+
+       return ret_errno(EINVAL);
+}
+
+char *lxc_ipvlan_flag_to_mode(int mode)
+{
+       for (size_t i = 0; i < sizeof(ipvlan_mode) / sizeof(ipvlan_mode[0]); i++) {
+               if (ipvlan_mode[i].mode != mode)
+                       continue;
+
+               return ipvlan_mode[i].name;
+       }
+
+       return ret_set_errno(NULL, EINVAL);
+}
+
+static struct lxc_ipvlan_isolation {
+       char *name;
+       int flag;
+} ipvlan_isolation[] = {
+       { "bridge",  IPVLAN_ISOLATION_BRIDGE  },
+       { "private", IPVLAN_ISOLATION_PRIVATE },
+       { "vepa",    IPVLAN_ISOLATION_VEPA    },
+};
+
+int lxc_ipvlan_isolation_to_flag(int *flag, const char *value)
+{
+       for (size_t i = 0; i < sizeof(ipvlan_isolation) / sizeof(ipvlan_isolation[0]); i++) {
+               if (strcmp(ipvlan_isolation[i].name, value) != 0)
+                       continue;
+
+               *flag = ipvlan_isolation[i].flag;
+               return 0;
+       }
+
+       return ret_errno(EINVAL);
+}
+
+char *lxc_ipvlan_flag_to_isolation(int flag)
+{
+       for (size_t i = 0; i < sizeof(ipvlan_isolation) / sizeof(ipvlan_isolation[0]); i++) {
+               if (ipvlan_isolation[i].flag != flag)
+                       continue;
+
+               return ipvlan_isolation[i].name;
+       }
+
+       return ret_set_errno(NULL, EINVAL);
 }
 
 int set_config_string_item(char **conf_item, const char *value)
@@ -470,28 +629,22 @@ int set_config_string_item(char **conf_item, const char *value)
        char *new_value;
 
        if (lxc_config_value_empty(value)) {
-               free(*conf_item);
-               *conf_item = NULL;
+               free_disarm(*conf_item);
                return 0;
        }
 
        new_value = strdup(value);
-       if (!new_value) {
-               SYSERROR("failed to duplicate string \"%s\"", value);
-               return -1;
-       }
+       if (!new_value)
+               return log_error_errno(-ENOMEM, ENOMEM, "Failed to duplicate string \"%s\"", value);
 
-       free(*conf_item);
-       *conf_item = new_value;
+       free_move_ptr(*conf_item, new_value);
        return 0;
 }
 
 int set_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;
-       }
+       if (strlen(value) >= max)
+               return log_error_errno(-ENAMETOOLONG, ENAMETOOLONG, "%s is too long (>= %lu)", value, (unsigned long)max);
 
        return set_config_string_item(conf_item, value);
 }
@@ -501,12 +654,40 @@ int set_config_path_item(char **conf_item, const char *value)
        return set_config_string_item_max(conf_item, value, PATH_MAX);
 }
 
+int set_config_bool_item(bool *conf_item, const char *value, bool empty_conf_action)
+{
+       int ret;
+       unsigned int val = 0;
+
+       if (lxc_config_value_empty(value)) {
+               *conf_item = empty_conf_action;
+               return 0;
+       }
+
+       ret = lxc_safe_uint(value, &val);
+       if (ret < 0)
+               return ret;
+
+       switch (val) {
+       case 0:
+               *conf_item = false;
+               return 0;
+       case 1:
+               *conf_item = true;
+               return 0;
+       }
+
+       return ret_errno(EINVAL);
+}
+
 int config_ip_prefix(struct in_addr *addr)
 {
        if (IN_CLASSA(addr->s_addr))
                return 32 - IN_CLASSA_NSHIFT;
+
        if (IN_CLASSB(addr->s_addr))
                return 32 - IN_CLASSB_NSHIFT;
+
        if (IN_CLASSC(addr->s_addr))
                return 32 - IN_CLASSC_NSHIFT;
 
@@ -518,29 +699,49 @@ int network_ifname(char *valuep, const char *value, size_t size)
        size_t retlen;
 
        if (!valuep || !value)
-               return -1;
+               return ret_errno(EINVAL);
 
        retlen = strlcpy(valuep, value, size);
-       if (retlen >= size) {
-               ERROR("Network devie name \"%s\" is too long (>= %zu)", value,
-                     size);
-       }
+       if (retlen >= size)
+               ERROR("Network device name \"%s\" is too long (>= %zu)", value, size);
 
        return 0;
 }
 
-int rand_complete_hwaddr(char *hwaddr)
+bool lxc_config_net_is_hwaddr(const char *line)
+{
+       unsigned index;
+       char tmp[7];
+
+       if (strncmp(line, "lxc.net", 7) != 0)
+               return false;
+
+       if (strncmp(line, "lxc.net.hwaddr", 14) == 0)
+               return true;
+
+       if (strncmp(line, "lxc.network.hwaddr", 18) == 0)
+               return true;
+
+       if (sscanf(line, "lxc.net.%u.%6s", &index, tmp) == 2 ||
+           sscanf(line, "lxc.network.%u.%6s", &index, tmp) == 2)
+               return strncmp(tmp, "hwaddr", 6) == 0;
+
+       return false;
+}
+
+void rand_complete_hwaddr(char *hwaddr)
 {
        const char hex[] = "0123456789abcdef";
        char *curs = hwaddr;
-
-#ifndef HAVE_RAND_R
-       randseed(true);
-#else
+#ifdef HAVE_RAND_R
        unsigned int seed;
 
        seed = randseed(false);
+#else
+
+       (void)randseed(true);
 #endif
+
        while (*curs != '\0' && *curs != '\n') {
                if (*curs == 'x' || *curs == 'X') {
                        if (curs - hwaddr == 1) {
@@ -558,71 +759,27 @@ int rand_complete_hwaddr(char *hwaddr)
                }
                curs++;
        }
-       return 0;
-}
-
-bool lxc_config_net_hwaddr(const char *line)
-{
-       unsigned index;
-       char tmp[7];
-
-       if (strncmp(line, "lxc.net", 7) != 0)
-               return false;
-       if (strncmp(line, "lxc.net.hwaddr", 14) == 0)
-               return true;
-       if (strncmp(line, "lxc.network.hwaddr", 18) == 0)
-               return true;
-       if (sscanf(line, "lxc.net.%u.%6s", &index, tmp) == 2 || sscanf(line, "lxc.network.%u.%6s", &index, tmp) == 2)
-               return strncmp(tmp, "hwaddr", 6) == 0;
-
-       return false;
-}
-
-/*
- * If we find a lxc.net.[i].hwaddr or lxc.network.hwaddr in the original config
- * file, we expand it in the unexpanded_config, so that after a save_config we
- * store the hwaddr for re-use.
- * This is only called when reading the config file, not when executing a
- * lxc.include.
- * 'x' and 'X' are substituted in-place.
- */
-void update_hwaddr(const char *line)
-{
-       char *p;
-
-       line += lxc_char_left_gc(line, strlen(line));
-       if (line[0] == '#')
-               return;
-
-       if (!lxc_config_net_hwaddr(line))
-               return;
-
-       /* Let config_net_hwaddr raise the error. */
-       p = strchr(line, '=');
-       if (!p)
-               return;
-       p++;
-
-       while (isblank(*p))
-               p++;
-
-       if (!*p)
-               return;
-
-       rand_complete_hwaddr(p);
 }
 
 bool new_hwaddr(char *hwaddr)
 {
        int ret;
+#ifdef HAVE_RAND_R
+       unsigned int seed;
+
+       seed = randseed(false);
+
+       ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand_r(&seed) % 255,
+                      rand_r(&seed) % 255, rand_r(&seed) % 255);
+#else
 
        (void)randseed(true);
 
        ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
                       rand() % 255, rand() % 255);
+#endif
        if (ret < 0 || ret >= 18) {
-               SYSERROR("Failed to call snprintf().");
-               return false;
+               return log_error_errno(false, EIO, "Failed to call snprintf()");
        }
 
        return true;
@@ -639,10 +796,10 @@ int lxc_get_conf_str(char *retv, int inlen, const char *value)
        if (retv && inlen >= value_len + 1)
                memcpy(retv, value, value_len + 1);
 
-       return strlen(value);
+       return value_len;
 }
 
-int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
+int lxc_get_conf_bool(struct lxc_conf *c, char *retv, int inlen, bool v)
 {
        int len;
        int fulllen = 0;
@@ -657,7 +814,7 @@ int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
        return fulllen;
 }
 
-int lxc_get_conf_size_t(struct lxc_conf *c, char *retv, int inlen, size_t v)
+int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
 {
        int len;
        int fulllen = 0;
@@ -667,12 +824,12 @@ int lxc_get_conf_size_t(struct lxc_conf *c, char *retv, int inlen, size_t v)
        else
                memset(retv, 0, inlen);
 
-       strprint(retv, inlen, "%zu", v);
+       strprint(retv, inlen, "%d", v);
 
        return fulllen;
 }
 
-int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
+int lxc_get_conf_size_t(struct lxc_conf *c, char *retv, int inlen, size_t v)
 {
        int len;
        int fulllen = 0;
@@ -682,28 +839,24 @@ int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
        else
                memset(retv, 0, inlen);
 
-       strprint(retv, inlen, "%"PRIu64, v);
+       strprint(retv, inlen, "%zu", v);
 
        return fulllen;
 }
 
-bool parse_limit_value(const char **value, rlim_t *res)
+int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
 {
-       char *endptr = NULL;
+       int len;
+       int fulllen = 0;
 
-       if (strncmp(*value, "unlimited", sizeof("unlimited") - 1) == 0) {
-               *res = RLIM_INFINITY;
-               *value += sizeof("unlimited") - 1;
-               return true;
-       }
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
 
-       errno = 0;
-       *res = strtoull(*value, &endptr, 10);
-       if (errno || !endptr)
-               return false;
-       *value = endptr;
+       strprint(retv, inlen, "%"PRIu64, v);
 
-       return true;
+       return fulllen;
 }
 
 static int lxc_container_name_to_pid(const char *lxcname_or_pid,
@@ -715,66 +868,191 @@ static int lxc_container_name_to_pid(const char *lxcname_or_pid,
 
        pid = strtol(lxcname_or_pid, &err, 10);
        if (*err != '\0' || pid < 1) {
-               struct lxc_container *c;
+               __put_lxc_container struct lxc_container *c = NULL;
 
                c = lxc_container_new(lxcname_or_pid, lxcpath);
-               if (!c) {
-                       ERROR("\"%s\" is not a valid pid nor a container name",
-                             lxcname_or_pid);
-                       return -1;
-               }
+               if (!c)
+                       return log_error_errno(-EINVAL, EINVAL, "\"%s\" is not a valid pid nor a container name", lxcname_or_pid);
 
-               if (!c->may_control(c)) {
-                       ERROR("Insufficient privileges to control container "
-                             "\"%s\"", c->name);
-                       lxc_container_put(c);
-                       return -1;
-               }
+               if (!c->may_control(c))
+                       return log_error_errno(-EPERM, EPERM, "Insufficient privileges to control container \"%s\"", c->name);
 
                pid = c->init_pid(c);
-               if (pid < 1) {
-                       ERROR("Container \"%s\" is not running", c->name);
-                       lxc_container_put(c);
-                       return -1;
-               }
+               if (pid < 1)
+                       return log_error_errno(-EINVAL, EINVAL, "Container \"%s\" is not running", c->name);
 
-               lxc_container_put(c);
        }
 
        ret = kill(pid, 0);
-       if (ret < 0) {
-               SYSERROR("Failed to send signal to pid %d", (int)pid);
-               return -EPERM;
-       }
+       if (ret < 0)
+               return log_error_errno(-errno, errno, "Failed to send signal to pid %d", (int)pid);
 
        return pid;
 }
 
-int lxc_inherit_namespace(const char *lxcname_or_pid, const char *lxcpath,
+int lxc_inherit_namespace(const char *nsfd_path, const char *lxcpath,
                          const char *namespace)
 {
+       __do_free char *dup = NULL;
        int fd, pid;
-       char *dup, *lastslash;
+       char *lastslash;
 
-       lastslash = strrchr(lxcname_or_pid, '/');
+       if (nsfd_path[0] == '/') {
+               return open(nsfd_path, O_RDONLY | O_CLOEXEC);
+       }
+
+       lastslash = strrchr(nsfd_path, '/');
        if (lastslash) {
-               dup = strdup(lxcname_or_pid);
+               dup = strdup(nsfd_path);
                if (!dup)
-                       return -ENOMEM;
+                       return ret_errno(ENOMEM);
 
-               dup[lastslash - lxcname_or_pid] = '\0';
-               pid = lxc_container_name_to_pid(lastslash + 1, dup);
-               free(dup);
-       } else {
-               pid = lxc_container_name_to_pid(lxcname_or_pid, lxcpath);
+               dup[lastslash - nsfd_path] = '\0';
+               lxcpath = lastslash + 1;
+               nsfd_path = lastslash + 1;
        }
 
+       pid = lxc_container_name_to_pid(nsfd_path, lxcpath);
        if (pid < 0)
-               return -EINVAL;
+               return pid;
 
        fd = lxc_preserve_ns(pid, namespace);
        if (fd < 0)
-               return -EINVAL;
+               return -errno;
 
        return fd;
 }
+
+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"   },
+#ifdef SIGTRAP
+       { SIGTRAP,   "TRAP"   },
+#endif
+#ifdef SIGIOT
+       { SIGIOT,    "IOT"    },
+#endif
+#ifdef SIGEMT
+       { SIGEMT,    "EMT"    },
+#endif
+#ifdef SIGBUS
+       { SIGBUS,    "BUS"    },
+#endif
+#ifdef SIGSTKFLT
+       { SIGSTKFLT, "STKFLT" },
+#endif
+#ifdef SIGCLD
+       { SIGCLD,    "CLD"    },
+#endif
+#ifdef SIGURG
+       { SIGURG,    "URG"    },
+#endif
+#ifdef SIGXCPU
+       { SIGXCPU,   "XCPU"   },
+#endif
+#ifdef SIGXFSZ
+       { SIGXFSZ,   "XFSZ"   },
+#endif
+#ifdef SIGVTALRM
+       { SIGVTALRM, "VTALRM" },
+#endif
+#ifdef SIGPROF
+       { SIGPROF,   "PROF"   },
+#endif
+#ifdef SIGWINCH
+       { SIGWINCH,  "WINCH"  },
+#endif
+#ifdef SIGIO
+       { SIGIO,     "IO"     },
+#endif
+#ifdef SIGPOLL
+       { SIGPOLL,   "POLL"   },
+#endif
+#ifdef SIGINFO
+       { SIGINFO,   "INFO"   },
+#endif
+#ifdef SIGLOST
+       { SIGLOST,   "LOST"   },
+#endif
+#ifdef SIGPWR
+       { SIGPWR,    "PWR"    },
+#endif
+#ifdef SIGUNUSED
+       { SIGUNUSED, "UNUSED" },
+#endif
+#ifdef SIGSYS
+       { SIGSYS,    "SYS"    },
+#endif
+};
+
+static int sig_num(const char *sig)
+{
+       int ret;
+       unsigned int signum;
+
+       ret = lxc_safe_uint(sig, &signum);
+       if (ret < 0)
+               return ret;
+
+       return signum;
+}
+
+static int rt_sig_num(const char *signame)
+{
+       int rtmax = 0, sig_n = 0;
+
+       if (strncasecmp(signame, "max-", 4) == 0)
+               rtmax = 1;
+
+       signame += 4;
+       if (!isdigit(*signame))
+               return ret_errno(EINVAL);
+
+       sig_n = sig_num(signame);
+       sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
+       if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
+               return ret_errno(EINVAL);
+
+       return sig_n;
+}
+
+int sig_parse(const char *signame)
+{
+       size_t 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 ret_errno(EINVAL);
+}