]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/lxccontainer.c
added allowrunning command line option for snapshotting alive containers
[mirror_lxc.git] / src / lxc / lxccontainer.c
index c5b515f609916bc0e16afd923514f10469d6adcc..63a66709898897f18910956a613301480e9a73ca 100644 (file)
@@ -18,7 +18,9 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#define _GNU_SOURCE
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
 #include <arpa/inet.h>
 #include <dirent.h>
 #include <errno.h>
@@ -41,7 +43,9 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include "../include/netns_ifaddrs.h"
 #include "af_unix.h"
+#include "api_extensions.h"
 #include "attach.h"
 #include "cgroup.h"
 #include "commands.h"
@@ -61,6 +65,7 @@
 #include "namespace.h"
 #include "network.h"
 #include "parse.h"
+#include "raw_syscalls.h"
 #include "start.h"
 #include "state.h"
 #include "storage.h"
@@ -68,6 +73,7 @@
 #include "storage/overlay.h"
 #include "storage_utils.h"
 #include "sync.h"
+#include "syscall_wrappers.h"
 #include "terminal.h"
 #include "utils.h"
 #include "version.h"
 #include <sys/mkdev.h>
 #endif
 
-#if HAVE_IFADDRS_H
-#include <ifaddrs.h>
-#else
-#include <../include/ifaddrs.h>
-#endif
-
 #if IS_BIONIC
 #include <../include/lxcmntent.h>
 #else
@@ -155,25 +155,33 @@ static int ongoing_create(struct lxc_container *c)
        if (ret < 0 || (size_t)ret >= len)
                return -1;
 
-       if (!file_exists(path))
-               return 0;
+       fd = open(path, O_RDWR | O_CLOEXEC);
+       if (fd < 0) {
+               if (errno != ENOENT)
+                       return -1;
 
-       fd = open(path, O_RDWR);
-       if (fd < 0)
                return 0;
+       }
 
        lk.l_type = F_WRLCK;
        lk.l_whence = SEEK_SET;
-       lk.l_pid = -1;
+       /* F_OFD_GETLK requires that l_pid be set to 0 otherwise the kernel
+        * will EINVAL us.
+        */
+       lk.l_pid = 0;
 
        ret = fcntl(fd, F_OFD_GETLK, &lk);
-       if (ret < 0 && errno == EINVAL)
+       if (ret < 0 && errno == EINVAL) {
                ret = flock(fd, LOCK_EX | LOCK_NB);
+               if (ret < 0 && errno == EWOULDBLOCK)
+                       ret = 0;
+       }
 
        close(fd);
 
-       if (ret == 0 && lk.l_pid != -1)
-               /* create is still ongoing */
+       /* F_OFD_GETLK will not send us back a pid so don't check it. */
+       if (ret == 0)
+               /* Create is still ongoing. */
                return 1;
 
        /* Create completed but partial is still there. */
@@ -194,7 +202,7 @@ static int create_partial(struct lxc_container *c)
        if (ret < 0 || (size_t)ret >= len)
                return -1;
 
-       fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0755);
+       fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
        if (fd < 0)
                return -1;
 
@@ -521,7 +529,7 @@ static bool do_lxcapi_freeze(struct lxc_container *c)
        if (!c)
                return false;
 
-       ret = lxc_freeze(c->name, c->config_path);
+       ret = lxc_freeze(c->lxc_conf, c->name, c->config_path);
        if (ret < 0)
                return false;
 
@@ -537,7 +545,7 @@ static bool do_lxcapi_unfreeze(struct lxc_container *c)
        if (!c)
                return false;
 
-       ret = lxc_unfreeze(c->name, c->config_path);
+       ret = lxc_unfreeze(c->lxc_conf, c->name, c->config_path);
        if (ret < 0)
                return false;
 
@@ -575,6 +583,9 @@ static int do_lxcapi_console_log(struct lxc_container *c, struct lxc_console_log
 {
        int ret;
 
+       if (!c)
+               return -EINVAL;
+
        ret = lxc_cmd_console_log(c->name, do_lxcapi_get_config_path(c), log);
        if (ret < 0) {
                if (ret == -ENODATA)
@@ -962,10 +973,15 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
                /* We don't really care if this doesn't print all the
                 * characters. All that it means is that the proctitle will be
                 * ugly. Similarly, we also don't care if setproctitle() fails.
-                * */
-               (void)snprintf(title, sizeof(title), "[lxc monitor] %s %s", c->config_path, c->name);
-               INFO("Attempting to set proc title to %s", title);
-               (void)setproctitle(title);
+                */
+               ret = snprintf(title, sizeof(title), "[lxc monitor] %s %s", c->config_path, c->name);
+               if (ret > 0) {
+                       ret = setproctitle(title);
+                       if (ret < 0)
+                               INFO("Failed to set process title to %s", title);
+                       else
+                               INFO("Set process title to %s", title);
+               }
 
                /* We fork() a second time to be reparented to init. Like
                 * POSIX's daemon() function we change to "/" and redirect
@@ -1012,24 +1028,22 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
                ret = setsid();
                if (ret < 0)
                        TRACE("Process %d is already process group leader", lxc_raw_getpid());
-       } else {
-               if (!am_single_threaded()) {
-                       ERROR("Cannot start non-daemonized container when threaded");
-                       free_init_cmd(init_cmd);
-                       lxc_free_handler(handler);
-                       return false;
-               }
+       } else if (!am_single_threaded()) {
+               ERROR("Cannot start non-daemonized container when threaded");
+               free_init_cmd(init_cmd);
+               lxc_free_handler(handler);
+               return false;
        }
 
-       /* We need to write PID file after daemonize, so we always
-        * write the right PID.
+       /* We need to write PID file after daemonize, so we always write the
+        * right PID.
         */
        if (c->pidfile) {
                int ret, w;
-               char pidstr[LXC_NUMSTRLEN64];
+               char pidstr[INTTYPE_TO_STRLEN(pid_t)];
 
-               w = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", (int)lxc_raw_getpid());
-               if (w < 0 || (size_t)w >= LXC_NUMSTRLEN64) {
+               w = snprintf(pidstr, sizeof(pidstr), "%d", lxc_raw_getpid());
+               if (w < 0 || (size_t)w >= sizeof(pidstr)) {
                        free_init_cmd(init_cmd);
                        lxc_free_handler(handler);
 
@@ -1046,7 +1060,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
                        free_init_cmd(init_cmd);
                        lxc_free_handler(handler);
 
-                       SYSERROR("Failed to write '%s'", c->pidfile);
+                       SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile);
 
                        if (c->daemonize)
                                _exit(EXIT_FAILURE);
@@ -1061,7 +1075,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
        if (conf->monitor_unshare) {
                ret = unshare(CLONE_NEWNS);
                if (ret < 0) {
-                       SYSERROR("failed to unshare mount namespace");
+                       SYSERROR("Failed to unshare mount namespace");
                        lxc_free_handler(handler);
                        ret = 1;
                        goto on_error;
@@ -2292,21 +2306,19 @@ static bool remove_from_array(char ***names, char *cname, int size)
        return false;
 }
 
-static char ** do_lxcapi_get_interfaces(struct lxc_container *c)
+static char **do_lxcapi_get_interfaces(struct lxc_container *c)
 {
        pid_t pid;
        int i, count = 0, pipefd[2];
        char **interfaces = NULL;
        char interface[IFNAMSIZ];
 
-       if(pipe(pipefd) < 0) {
-               SYSERROR("pipe failed");
+       if (pipe2(pipefd, O_CLOEXEC) < 0)
                return NULL;
-       }
 
        pid = fork();
        if (pid < 0) {
-               SYSERROR("failed to fork task to get interfaces information");
+               SYSERROR("Failed to fork task to get interfaces information");
                close(pipefd[0]);
                close(pipefd[1]);
                return NULL;
@@ -2314,29 +2326,29 @@ static char ** do_lxcapi_get_interfaces(struct lxc_container *c)
 
        if (pid == 0) { /* child */
                int ret = 1, nbytes;
-               struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
+               struct netns_ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
 
                /* close the read-end of the pipe */
                close(pipefd[0]);
 
                if (!enter_net_ns(c)) {
-                       SYSERROR("failed to enter namespace");
+                       SYSERROR("Failed to enter network namespace");
                        goto out;
                }
 
                /* Grab the list of interfaces */
-               if (getifaddrs(&interfaceArray)) {
-                       SYSERROR("failed to get interfaces list");
+               if (netns_getifaddrs(&interfaceArray, -1, &(bool){false})) {
+                       SYSERROR("Failed to get interfaces list");
                        goto out;
                }
 
                /* Iterate through the interfaces */
-               for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = tempIfAddr->ifa_next) {
-                       nbytes = write(pipefd[1], tempIfAddr->ifa_name, IFNAMSIZ);
-                       if (nbytes < 0) {
-                               ERROR("write failed");
+               for (tempIfAddr = interfaceArray; tempIfAddr != NULL;
+                    tempIfAddr = tempIfAddr->ifa_next) {
+                       nbytes = lxc_write_nointr(pipefd[1], tempIfAddr->ifa_name, IFNAMSIZ);
+                       if (nbytes < 0)
                                goto out;
-                       }
+
                        count++;
                }
 
@@ -2344,7 +2356,7 @@ static char ** do_lxcapi_get_interfaces(struct lxc_container *c)
 
        out:
                if (interfaceArray)
-                       freeifaddrs(interfaceArray);
+                       netns_freeifaddrs(interfaceArray);
 
                /* close the write-end of the pipe, thus sending EOF to the reader */
                close(pipefd[1]);
@@ -2354,20 +2366,20 @@ static char ** do_lxcapi_get_interfaces(struct lxc_container *c)
        /* close the write-end of the pipe */
        close(pipefd[1]);
 
-       while (read(pipefd[0], &interface, IFNAMSIZ) == IFNAMSIZ) {
+       while (lxc_read_nointr(pipefd[0], &interface, IFNAMSIZ) == IFNAMSIZ) {
                interface[IFNAMSIZ - 1] = '\0';
 
                if (array_contains(&interfaces, interface, count))
-                               continue;
+                       continue;
 
-               if(!add_to_array(&interfaces, interface, count))
+               if (!add_to_array(&interfaces, interface, count))
                        ERROR("Failed to add \"%s\" to array", interface);
 
                count++;
        }
 
        if (wait_for_pid(pid) != 0) {
-               for(i=0;i<count;i++)
+               for (i = 0; i < count; i++)
                        free(interfaces[i]);
 
                free(interfaces);
@@ -2378,7 +2390,7 @@ static char ** do_lxcapi_get_interfaces(struct lxc_container *c)
        close(pipefd[0]);
 
        /* Append NULL to the array */
-       if(interfaces)
+       if (interfaces)
                interfaces = (char **)lxc_append_null_to_array((void **)interfaces, count);
 
        return interfaces;
@@ -2396,7 +2408,7 @@ static char **do_lxcapi_get_ips(struct lxc_container *c, const char *interface,
        int count = 0;
        char **addresses = NULL;
 
-       ret = pipe(pipefd);
+       ret = pipe2(pipefd, O_CLOEXEC);
        if (ret < 0) {
                SYSERROR("Failed to create pipe");
                return NULL;
@@ -2416,7 +2428,7 @@ static char **do_lxcapi_get_ips(struct lxc_container *c, const char *interface,
                int ret = 1;
                char *address = NULL;
                void *tempAddrPtr = NULL;
-               struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
+               struct netns_ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
 
                /* close the read-end of the pipe */
                close(pipefd[0]);
@@ -2427,7 +2439,7 @@ static char **do_lxcapi_get_ips(struct lxc_container *c, const char *interface,
                }
 
                /* Grab the list of interfaces */
-               if (getifaddrs(&interfaceArray)) {
+               if (netns_getifaddrs(&interfaceArray, -1, &(bool){false})) {
                        SYSERROR("Failed to get interfaces list");
                        goto out;
                }
@@ -2438,6 +2450,9 @@ static char **do_lxcapi_get_ips(struct lxc_container *c, const char *interface,
                        if (tempIfAddr->ifa_addr == NULL)
                                continue;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+
                        if (tempIfAddr->ifa_addr->sa_family == AF_INET) {
                                if (family && strcmp(family, "inet"))
                                        continue;
@@ -2453,6 +2468,8 @@ static char **do_lxcapi_get_ips(struct lxc_container *c, const char *interface,
                                tempAddrPtr = &((struct sockaddr_in6 *)tempIfAddr->ifa_addr)->sin6_addr;
                        }
 
+#pragma GCC diagnostic pop
+
                        if (interface && strcmp(interface, tempIfAddr->ifa_name))
                                continue;
                        else if (!interface && strcmp("lo", tempIfAddr->ifa_name) == 0)
@@ -2478,7 +2495,7 @@ static char **do_lxcapi_get_ips(struct lxc_container *c, const char *interface,
 
        out:
                if (interfaceArray)
-                       freeifaddrs(interfaceArray);
+                       netns_freeifaddrs(interfaceArray);
 
                /* close the write-end of the pipe, thus sending EOF to the reader */
                close(pipefd[1]);
@@ -2627,7 +2644,7 @@ static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file)
                return false;
 
        fd = open(alt_file, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
-                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
        if (fd < 0)
                goto on_error;
 
@@ -2656,8 +2673,8 @@ static bool mod_rdep(struct lxc_container *c0, struct lxc_container *c, bool inc
        struct stat fbuf;
        void *buf = NULL;
        char *del = NULL;
-       char path[MAXPATHLEN];
-       char newpath[MAXPATHLEN];
+       char path[PATH_MAX];
+       char newpath[PATH_MAX];
        int fd, ret, n = 0, v = 0;
        bool bret = false;
        size_t len = 0, bytes = 0;
@@ -2665,12 +2682,12 @@ static bool mod_rdep(struct lxc_container *c0, struct lxc_container *c, bool inc
        if (container_disk_lock(c0))
                return false;
 
-       ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c0->config_path, c0->name);
-       if (ret < 0 || ret > MAXPATHLEN)
+       ret = snprintf(path, PATH_MAX, "%s/%s/lxc_snapshots", c0->config_path, c0->name);
+       if (ret < 0 || ret > PATH_MAX)
                goto out;
 
-       ret = snprintf(newpath, MAXPATHLEN, "%s\n%s\n", c->config_path, c->name);
-       if (ret < 0 || ret > MAXPATHLEN)
+       ret = snprintf(newpath, PATH_MAX, "%s\n%s\n", c->config_path, c->name);
+       if (ret < 0 || ret > PATH_MAX)
                goto out;
 
        /* If we find an lxc-snapshot file using the old format only listing the
@@ -2781,14 +2798,14 @@ out:
 void mod_all_rdeps(struct lxc_container *c, bool inc)
 {
        struct lxc_container *p;
-       char *lxcpath = NULL, *lxcname = NULL, path[MAXPATHLEN];
+       char *lxcpath = NULL, *lxcname = NULL, path[PATH_MAX];
        size_t pathlen = 0, namelen = 0;
        FILE *f;
        int ret;
 
-       ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_rdepends",
+       ret = snprintf(path, PATH_MAX, "%s/%s/lxc_rdepends",
                c->config_path, c->name);
-       if (ret < 0 || ret >= MAXPATHLEN) {
+       if (ret < 0 || ret >= PATH_MAX) {
                ERROR("Path name too long");
                return;
        }
@@ -2828,14 +2845,14 @@ out:
 static bool has_fs_snapshots(struct lxc_container *c)
 {
        FILE *f;
-       char path[MAXPATHLEN];
+       char path[PATH_MAX];
        int ret, v;
        struct stat fbuf;
        bool bret = false;
 
-       ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path,
+       ret = snprintf(path, PATH_MAX, "%s/%s/lxc_snapshots", c->config_path,
                        c->name);
-       if (ret < 0 || ret > MAXPATHLEN)
+       if (ret < 0 || ret > PATH_MAX)
                goto out;
 
        /* If the file doesn't exist there are no snapshots. */
@@ -2863,7 +2880,7 @@ out:
 
 static bool has_snapshots(struct lxc_container *c)
 {
-       char path[MAXPATHLEN];
+       char path[PATH_MAX];
        struct dirent *direntp;
        int count=0;
        DIR *dir;
@@ -2975,6 +2992,10 @@ static bool container_destroy(struct lxc_container *c,
                }
        }
 
+       /* LXC is not managing the storage of the container. */
+       if (conf && !conf->rootfs.managed)
+               goto on_success;
+
        if (conf && conf->rootfs.path && conf->rootfs.mount) {
                if (!do_destroy_container(conf)) {
                        ERROR("Error destroying rootfs for %s", c->name);
@@ -3047,6 +3068,7 @@ static bool container_destroy(struct lxc_container *c,
        }
        INFO("Destroyed directory \"%s\" for \"%s\"", path, c->name);
 
+on_success:
        bret = true;
 
 out:
@@ -3062,14 +3084,16 @@ static bool do_lxcapi_destroy(struct lxc_container *c)
        if (!c || !lxcapi_is_defined(c))
                return false;
 
-       if (has_snapshots(c)) {
-               ERROR("Container %s has snapshots;  not removing", c->name);
-               return false;
-       }
+       if (c->lxc_conf && c->lxc_conf->rootfs.managed) {
+               if (has_snapshots(c)) {
+                       ERROR("Container %s has snapshots;  not removing", c->name);
+                       return false;
+               }
 
-       if (has_fs_snapshots(c)) {
-               ERROR("container %s has snapshots on its rootfs", c->name);
-               return false;
+               if (has_fs_snapshots(c)) {
+                       ERROR("container %s has snapshots on its rootfs", c->name);
+                       return false;
+               }
        }
 
        return container_destroy(c, NULL);
@@ -3254,17 +3278,12 @@ static bool do_lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsy
        if (is_stopped(c))
                return false;
 
-       cgroup_ops = cgroup_init(NULL);
+       cgroup_ops = cgroup_init(c->lxc_conf);
        if (!cgroup_ops)
                return false;
 
-       if (container_disk_lock(c))
-               return false;
-
        ret = cgroup_ops->set(cgroup_ops, subsys, value, c->name, c->config_path);
 
-       container_disk_unlock(c);
-
        cgroup_exit(cgroup_ops);
 
        return ret == 0;
@@ -3283,18 +3302,13 @@ static int do_lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys
        if (is_stopped(c))
                return -1;
 
-       cgroup_ops = cgroup_init(NULL);
+       cgroup_ops = cgroup_init(c->lxc_conf);
        if (!cgroup_ops)
                return -1;
 
-       if (container_disk_lock(c))
-               return -1;
-
        ret = cgroup_ops->get(cgroup_ops, subsys, retv, inlen, c->name,
                              c->config_path);
 
-       container_disk_unlock(c);
-
        cgroup_exit(cgroup_ops);
 
        return ret;
@@ -3344,7 +3358,7 @@ static int copy_file(const char *old, const char *new)
        }
 
        while (1) {
-               len = read(in, buf, 8096);
+               len = lxc_read_nointr(in, buf, 8096);
                if (len < 0) {
                        SYSERROR("Error reading old file %s", old);
                        goto err;
@@ -3353,7 +3367,7 @@ static int copy_file(const char *old, const char *new)
                if (len == 0)
                        break;
 
-               ret = write(out, buf, len);
+               ret = lxc_write_nointr(out, buf, len);
                if (ret < len) { /* should we retry? */
                        SYSERROR("Error: write to new file %s was interrupted", new);
                        goto err;
@@ -3394,7 +3408,7 @@ static int copyhooks(struct lxc_container *oldc, struct lxc_container *c)
                lxc_list_for_each(it, &c->lxc_conf->hooks[i]) {
                        char *hookname = it->elem;
                        char *fname = strrchr(hookname, '/');
-                       char tmppath[MAXPATHLEN];
+                       char tmppath[PATH_MAX];
                        if (!fname) /* relative path - we don't support, but maybe we should */
                                return 0;
 
@@ -3404,9 +3418,9 @@ static int copyhooks(struct lxc_container *oldc, struct lxc_container *c)
                        }
 
                        /* copy the script, and change the entry in confile */
-                       ret = snprintf(tmppath, MAXPATHLEN, "%s/%s/%s",
+                       ret = snprintf(tmppath, PATH_MAX, "%s/%s/%s",
                                        c->config_path, c->name, fname+1);
-                       if (ret < 0 || ret >= MAXPATHLEN)
+                       if (ret < 0 || ret >= PATH_MAX)
                                return -1;
 
                        ret = copy_file(it->elem, tmppath);
@@ -3436,7 +3450,7 @@ static int copyhooks(struct lxc_container *oldc, struct lxc_container *c)
 
 static int copy_fstab(struct lxc_container *oldc, struct lxc_container *c)
 {
-       char newpath[MAXPATHLEN];
+       char newpath[PATH_MAX];
        char *oldpath = oldc->lxc_conf->fstab;
        int ret;
 
@@ -3449,9 +3463,9 @@ static int copy_fstab(struct lxc_container *oldc, struct lxc_container *c)
        if (!p)
                return -1;
 
-       ret = snprintf(newpath, MAXPATHLEN, "%s/%s%s",
+       ret = snprintf(newpath, PATH_MAX, "%s/%s%s",
                        c->config_path, c->name, p);
-       if (ret < 0 || ret >= MAXPATHLEN) {
+       if (ret < 0 || ret >= PATH_MAX) {
                ERROR("error printing new path for %s", oldpath);
                return -1;
        }
@@ -3484,19 +3498,19 @@ static int copy_fstab(struct lxc_container *oldc, struct lxc_container *c)
 
 static void copy_rdepends(struct lxc_container *c, struct lxc_container *c0)
 {
-       char path0[MAXPATHLEN], path1[MAXPATHLEN];
+       char path0[PATH_MAX], path1[PATH_MAX];
        int ret;
 
-       ret = snprintf(path0, MAXPATHLEN, "%s/%s/lxc_rdepends", c0->config_path,
+       ret = snprintf(path0, PATH_MAX, "%s/%s/lxc_rdepends", c0->config_path,
                c0->name);
-       if (ret < 0 || ret >= MAXPATHLEN) {
+       if (ret < 0 || ret >= PATH_MAX) {
                WARN("Error copying reverse dependencies");
                return;
        }
 
-       ret = snprintf(path1, MAXPATHLEN, "%s/%s/lxc_rdepends", c->config_path,
+       ret = snprintf(path1, PATH_MAX, "%s/%s/lxc_rdepends", c->config_path,
                c->name);
-       if (ret < 0 || ret >= MAXPATHLEN) {
+       if (ret < 0 || ret >= PATH_MAX) {
                WARN("Error copying reverse dependencies");
                return;
        }
@@ -3510,13 +3524,13 @@ static void copy_rdepends(struct lxc_container *c, struct lxc_container *c0)
 static bool add_rdepends(struct lxc_container *c, struct lxc_container *c0)
 {
        int ret;
-       char path[MAXPATHLEN];
+       char path[PATH_MAX];
        FILE *f;
        bool bret;
 
-       ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_rdepends", c->config_path,
+       ret = snprintf(path, PATH_MAX, "%s/%s/lxc_rdepends", c->config_path,
                c->name);
-       if (ret < 0 || ret >= MAXPATHLEN)
+       if (ret < 0 || ret >= PATH_MAX)
                return false;
 
        f = fopen(path, "a");
@@ -3630,7 +3644,7 @@ static int clone_update_rootfs(struct clone_update_data *data)
        int flags = data->flags;
        char **hookargs = data->hookargs;
        int ret = -1;
-       char path[MAXPATHLEN];
+       char path[PATH_MAX];
        struct lxc_storage *bdev;
        FILE *fout;
        struct lxc_conf *conf = c->lxc_conf;
@@ -3706,10 +3720,10 @@ static int clone_update_rootfs(struct clone_update_data *data)
        }
 
        if (!(flags & LXC_CLONE_KEEPNAME)) {
-               ret = snprintf(path, MAXPATHLEN, "%s/etc/hostname", bdev->dest);
+               ret = snprintf(path, PATH_MAX, "%s/etc/hostname", bdev->dest);
                storage_put(bdev);
 
-               if (ret < 0 || ret >= MAXPATHLEN)
+               if (ret < 0 || ret >= PATH_MAX)
                        return -1;
 
                if (!file_exists(path))
@@ -3771,7 +3785,7 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                const char *bdevtype, const char *bdevdata, uint64_t newsize,
                char **hookargs)
 {
-       char newpath[MAXPATHLEN];
+       char newpath[PATH_MAX];
        int fd, ret;
        struct clone_update_data data;
        size_t saved_unexp_len;
@@ -3785,9 +3799,8 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
 
        if (container_mem_lock(c))
                return NULL;
-
-       if (!is_stopped(c)) {
-               ERROR("error: Original container (%s) is running", c->name);
+       if (!is_stopped(c) && !(flags & LXC_CLONE_ALLOW_RUNNING)) {
+               ERROR("error: Original container (%s) is running. Use --allowrunning if you want to force a snapshot of the running container.", c->name);
                goto out;
        }
 
@@ -3798,8 +3811,8 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
        if (!lxcpath)
                lxcpath = do_lxcapi_get_config_path(c);
 
-       ret = snprintf(newpath, MAXPATHLEN, "%s/%s/config", lxcpath, newname);
-       if (ret < 0 || ret >= MAXPATHLEN) {
+       ret = snprintf(newpath, PATH_MAX, "%s/%s/config", lxcpath, newname);
+       if (ret < 0 || ret >= PATH_MAX) {
                SYSERROR("clone: failed making config pathname");
                goto out;
        }
@@ -3822,7 +3835,7 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
        }
 
        fd = open(newpath, O_WRONLY | O_CREAT | O_CLOEXEC,
-                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
        if (fd < 0) {
                SYSERROR("Failed to open \"%s\"", newpath);
                goto out;
@@ -3847,8 +3860,8 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
        saved_unexp_conf = NULL;
        c->lxc_conf->unexpanded_len = saved_unexp_len;
 
-       ret = snprintf(newpath, MAXPATHLEN, "%s/%s/rootfs", lxcpath, newname);
-       if (ret < 0 || ret >= MAXPATHLEN) {
+       ret = snprintf(newpath, PATH_MAX, "%s/%s/rootfs", lxcpath, newname);
+       if (ret < 0 || ret >= PATH_MAX) {
                SYSERROR("clone: failed making rootfs pathname");
                goto out;
        }
@@ -4097,13 +4110,13 @@ static bool get_snappath_dir(struct lxc_container *c, char *snappath)
         * If the old style snapshot path exists, use it
         * /var/lib/lxc -> /var/lib/lxcsnaps
         */
-       ret = snprintf(snappath, MAXPATHLEN, "%ssnaps", c->config_path);
-       if (ret < 0 || ret >= MAXPATHLEN)
+       ret = snprintf(snappath, PATH_MAX, "%ssnaps", c->config_path);
+       if (ret < 0 || ret >= PATH_MAX)
                return false;
 
        if (dir_exists(snappath)) {
-               ret = snprintf(snappath, MAXPATHLEN, "%ssnaps/%s", c->config_path, c->name);
-               if (ret < 0 || ret >= MAXPATHLEN)
+               ret = snprintf(snappath, PATH_MAX, "%ssnaps/%s", c->config_path, c->name);
+               if (ret < 0 || ret >= PATH_MAX)
                        return false;
 
                return true;
@@ -4113,8 +4126,8 @@ static bool get_snappath_dir(struct lxc_container *c, char *snappath)
         * Use the new style path
         * /var/lib/lxc -> /var/lib/lxc + c->name + /snaps + \0
         */
-       ret = snprintf(snappath, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
-       if (ret < 0 || ret >= MAXPATHLEN)
+       ret = snprintf(snappath, PATH_MAX, "%s/%s/snaps", c->config_path, c->name);
+       if (ret < 0 || ret >= PATH_MAX)
                return false;
 
        return true;
@@ -4123,15 +4136,19 @@ static bool get_snappath_dir(struct lxc_container *c, char *snappath)
 static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
 {
        int i, flags, ret;
+       time_t timer;
+       struct tm tm_info;
        struct lxc_container *c2;
-       char snappath[MAXPATHLEN], newname[20];
+       char snappath[PATH_MAX], newname[20];
+       char buffer[25];
+       FILE *f;
 
        if (!c || !lxcapi_is_defined(c))
                return -1;
 
        if (!storage_can_backup(c->lxc_conf)) {
-               ERROR("%s's backing store cannot be backed up.", c->name);
-               ERROR("Your container must use another backing store type.");
+               ERROR("%s's backing store cannot be backed up", c->name);
+               ERROR("Your container must use another backing store type");
                return -1;
        }
 
@@ -4156,31 +4173,30 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
        flags = LXC_CLONE_SNAPSHOT | LXC_CLONE_KEEPMACADDR | LXC_CLONE_KEEPNAME |
                LXC_CLONE_KEEPBDEVTYPE | LXC_CLONE_MAYBE_SNAPSHOT;
        if (storage_is_dir(c->lxc_conf)) {
-               ERROR("Snapshot of directory-backed container requested.");
+               ERROR("Snapshot of directory-backed container requested");
                ERROR("Making a copy-clone.  If you do want snapshots, then");
                ERROR("please create overlay clone first, snapshot that");
-               ERROR("and keep the original container pristine.");
+               ERROR("and keep the original container pristine");
                flags &= ~LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT;
        }
 
        c2 = do_lxcapi_clone(c, newname, snappath, flags, NULL, NULL, 0, NULL);
        if (!c2) {
-               ERROR("clone of %s:%s failed", c->config_path, c->name);
+               ERROR("Failed to clone of %s:%s", c->config_path, c->name);
                return -1;
        }
 
        lxc_container_put(c2);
 
        /* Now write down the creation time. */
-       time_t timer;
-       char buffer[25];
-       struct tm* tm_info;
-       FILE *f;
-
        time(&timer);
-       tm_info = localtime(&timer);
 
-       strftime(buffer, 25, "%Y:%m:%d %H:%M:%S", tm_info);
+       if (!localtime_r(&timer, &tm_info)) {
+               ERROR("Failed to get localtime");
+               return -1;
+       }
+
+       strftime(buffer, 25, "%Y:%m:%d %H:%M:%S", &tm_info);
 
        char *dfnam = alloca(strlen(snappath) + strlen(newname) + 5);
        sprintf(dfnam, "%s/%s/ts", snappath, newname);
@@ -4243,12 +4259,12 @@ static char *get_snapcomment_path(char* snappath, char *name)
 
 static char *get_timestamp(char* snappath, char *name)
 {
-       char path[MAXPATHLEN], *s = NULL;
+       char path[PATH_MAX], *s = NULL;
        int ret, len;
        FILE *fin;
 
-       ret = snprintf(path, MAXPATHLEN, "%s/%s/ts", snappath, name);
-       if (ret < 0 || ret >= MAXPATHLEN)
+       ret = snprintf(path, PATH_MAX, "%s/%s/ts", snappath, name);
+       if (ret < 0 || ret >= PATH_MAX)
                return NULL;
 
        fin = fopen(path, "r");
@@ -4276,7 +4292,7 @@ static char *get_timestamp(char* snappath, char *name)
 
 static int do_lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **ret_snaps)
 {
-       char snappath[MAXPATHLEN], path2[MAXPATHLEN];
+       char snappath[PATH_MAX], path2[PATH_MAX];
        int count = 0, ret;
        struct dirent *direntp;
        struct lxc_snapshot *snaps =NULL, *nsnaps;
@@ -4303,8 +4319,8 @@ static int do_lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot
                if (!strcmp(direntp->d_name, ".."))
                        continue;
 
-               ret = snprintf(path2, MAXPATHLEN, "%s/%s/config", snappath, direntp->d_name);
-               if (ret < 0 || ret >= MAXPATHLEN) {
+               ret = snprintf(path2, PATH_MAX, "%s/%s/config", snappath, direntp->d_name);
+               if (ret < 0 || ret >= PATH_MAX) {
                        ERROR("pathname too long");
                        goto out_free;
                }
@@ -4361,7 +4377,7 @@ WRAP_API_1(int, lxcapi_snapshot_list, struct lxc_snapshot **)
 
 static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snapname, const char *newname)
 {
-       char clonelxcpath[MAXPATHLEN];
+       char clonelxcpath[PATH_MAX];
        int flags = 0;
        struct lxc_container *snap, *rest;
        struct lxc_storage *bdev;
@@ -4499,7 +4515,7 @@ static bool remove_all_snapshots(const char *path)
 
 static bool do_lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapname)
 {
-       char clonelxcpath[MAXPATHLEN];
+       char clonelxcpath[PATH_MAX];
 
        if (!c || !c->name || !c->config_path || !snapname)
                return false;
@@ -4514,7 +4530,7 @@ WRAP_API_1(bool, lxcapi_snapshot_destroy, const char *)
 
 static bool do_lxcapi_snapshot_destroy_all(struct lxc_container *c)
 {
-       char clonelxcpath[MAXPATHLEN];
+       char clonelxcpath[PATH_MAX];
 
        if (!c || !c->name || !c->config_path)
                return false;
@@ -4529,6 +4545,9 @@ WRAP_API(bool, lxcapi_snapshot_destroy_all)
 
 static bool do_lxcapi_may_control(struct lxc_container *c)
 {
+       if (!c)
+               return false;
+
        return lxc_try_cmd(c->name, c->config_path) == 0;
 }
 
@@ -4540,7 +4559,7 @@ static bool do_add_remove_node(pid_t init_pid, const char *path, bool add,
        int ret;
        char *tmp;
        pid_t pid;
-       char chrootpath[MAXPATHLEN];
+       char chrootpath[PATH_MAX];
        char *directory_path = NULL;
 
        pid = fork();
@@ -4560,8 +4579,8 @@ static bool do_add_remove_node(pid_t init_pid, const char *path, bool add,
        }
 
        /* prepare the path */
-       ret = snprintf(chrootpath, MAXPATHLEN, "/proc/%d/root", init_pid);
-       if (ret < 0 || ret >= MAXPATHLEN)
+       ret = snprintf(chrootpath, PATH_MAX, "/proc/%d/root", init_pid);
+       if (ret < 0 || ret >= PATH_MAX)
                return false;
 
        ret = chroot(chrootpath);
@@ -4954,7 +4973,7 @@ static int do_lxcapi_mount(struct lxc_container *c, const char *source,
                           struct lxc_mount *mnt)
 {
        char *suff, *sret;
-       char template[MAXPATHLEN], path[MAXPATHLEN];
+       char template[PATH_MAX], path[PATH_MAX];
        pid_t pid, init_pid;
        struct stat sb;
        int ret = -1, fd = -EBADF;
@@ -5656,3 +5675,16 @@ bool lxc_config_item_is_supported(const char *key)
 {
        return !!lxc_get_config(key);
 }
+
+bool lxc_has_api_extension(const char *extension)
+{
+       /* The NULL API extension is always present. :) */
+       if (!extension)
+               return true;
+
+       for (size_t i = 0; i < nr_api_extensions; i++)
+               if (strcmp(api_extensions[i], extension) == 0)
+                       return true;
+
+       return false;
+}