The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxc/pull/2162

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com>

We'll remove the atfork handlers for now and let our LXD testsuite bang against LXC for a while to make sure that it is safe. But I've been reasoning about this for a while and I'm in the process of convincing myself that they are not needed anymore. In any case if we figure out they are needed we can simply revert before the release.
From e3f0e4368fa0ef0c8b7d334c876bc1b029385ec8 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brau...@ubuntu.com>
Date: Sat, 10 Feb 2018 23:25:18 +0100
Subject: [PATCH 1/2] lxclock: remove pthread_atfork_handlers

They shouldn't be needed anymore.

Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com>
---
 src/lxc/attach.c  |  9 +++------
 src/lxc/lxclock.c | 17 -----------------
 2 files changed, 3 insertions(+), 23 deletions(-)

diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index c3bb8bfb0..28c2cadfd 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -1242,13 +1242,10 @@ int lxc_attach(const char *name, const char *lxcpath,
                return -1;
        }
 
-       /* Create intermediate subprocess, three reasons:
-        *       1. Runs all pthread_atfork handlers and the child will no
-        *          longer be threaded (we can't properly setns() in a threaded
-        *          process).
-        *       2. We can't setns() in the child itself, since we want to make
+       /* Create intermediate subprocess, two reasons:
+        *       1. We can't setns() in the child itself, since we want to make
         *          sure we are properly attached to the pidns.
-        *       3. Also, the initial thread has to put the attached process
+        *       2. Also, the initial thread has to put the attached process
         *          into the cgroup, which we can only do if we didn't already
         *          setns() (otherwise, user namespaces will hate us).
         */
diff --git a/src/lxc/lxclock.c b/src/lxc/lxclock.c
index dee5aa5f0..87496f681 100644
--- a/src/lxc/lxclock.c
+++ b/src/lxc/lxclock.c
@@ -317,23 +317,6 @@ void process_unlock(void)
        unlock_mutex(&thread_mutex);
 }
 
-/* One thread can do fork() while another one is holding a mutex.
- * There is only one thread in child just after the fork(), so no one will 
ever release that mutex.
- * We setup a "child" fork handler to unlock the mutex just after the fork().
- * For several mutex types, unlocking an unlocked mutex can lead to undefined 
behavior.
- * One way to deal with it is to setup "prepare" fork handler
- * to lock the mutex before fork() and both "parent" and "child" fork handlers
- * to unlock the mutex.
- * This forbids doing fork() while explicitly holding the lock.
- */
-#ifdef HAVE_PTHREAD_ATFORK
-__attribute__((constructor))
-static void process_lock_setup_atfork(void)
-{
-       pthread_atfork(process_lock, process_unlock, process_unlock);
-}
-#endif
-
 int container_mem_lock(struct lxc_container *c)
 {
        return lxclock(c->privlock, 0);

From 0e7ff52c929ca8a93e1d090c20b5d78336a53f43 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brau...@ubuntu.com>
Date: Tue, 13 Feb 2018 05:37:48 +0100
Subject: [PATCH 2/2] tree-wide: remove cgmanager

Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com>
---
 .travis.yml                 |    2 +-
 configure.ac                |   51 --
 src/lxc/Makefile.am         |   13 -
 src/lxc/cgroups/cgfs.c      |    1 -
 src/lxc/cgroups/cgfsng.c    |    3 +-
 src/lxc/cgroups/cgmanager.c | 1683 -------------------------------------------
 6 files changed, 2 insertions(+), 1751 deletions(-)
 delete mode 100644 src/lxc/cgroups/cgmanager.c

diff --git a/.travis.yml b/.travis.yml
index 9595ae510..d078b0222 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,7 +18,7 @@ before_install:
  - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne 
'/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
  - sudo add-apt-repository ppa:ubuntu-lxc/daily -y
  - sudo apt-get update -qq
- - sudo apt-get install -qq libapparmor-dev libcap-dev libseccomp-dev 
python3-dev python3-setuptools docbook2x libgnutls-dev liblua5.2-dev 
libselinux1-dev libcgmanager-dev
+ - sudo apt-get install -qq libapparmor-dev libcap-dev libseccomp-dev 
python3-dev python3-setuptools docbook2x libgnutls-dev liblua5.2-dev 
libselinux1-dev
 script:
  - ./autogen.sh
  - rm -Rf build
diff --git a/configure.ac b/configure.ac
index b56b35b1a..224e1f15e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -305,45 +305,6 @@ AM_COND_IF([ENABLE_SECCOMP],
                ])
        ])
 
-# cgmanager
-AC_ARG_ENABLE([cgmanager],
-       [AC_HELP_STRING([--enable-cgmanager], [enable cgmanager support 
[default=auto]])],
-       [], [enable_cgmanager=auto])
-
-if test "x$enable_cgmanager" = "xauto" ; then
-       
AC_CHECK_LIB([cgmanager],[cgmanager_create],[enable_cgmanager=yes],[enable_cgmanager=no],[-lnih
 -lnih-dbus -ldbus-1])
-fi
-AM_CONDITIONAL([ENABLE_CGMANAGER], [test "x$enable_cgmanager" = "xyes"])
-
-AM_COND_IF([ENABLE_CGMANAGER],
-       [PKG_CHECK_MODULES([CGMANAGER], [libcgmanager])
-       PKG_CHECK_MODULES([NIH], [libnih >= 1.0.2])
-       PKG_CHECK_MODULES([NIH_DBUS], [libnih-dbus >= 1.0.0])
-       PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.2.16])
-       ])
-
-AC_MSG_CHECKING(for get_pid_cgroup_abs_sync)
-save_LIBS=$LIBS
-AC_SEARCH_LIBS([cgmanager_get_pid_cgroup_abs_sync], [cgmanager], 
[have_abs_cgroups=yes], [have_abs_cgroups=no], [-lnih -lnih-dbus -ldbus-1])
-LIBS=$save_LIBS
-if test "x$have_abs_cgroups" = "xyes"; then
-       AC_DEFINE([HAVE_CGMANAGER_GET_PID_CGROUP_ABS_SYNC], 1, [Have 
cgmanager_get_pid_cgroup_abs_sync])
-       AC_MSG_RESULT([yes])
-else
-       AC_MSG_RESULT([no])
-fi
-
-AC_MSG_CHECKING(for cgmanager_list_controllers)
-save_LIBS=$LIBS
-AC_SEARCH_LIBS([cgmanager_list_controllers_sync], [cgmanager], 
[have_list_controllers=yes], [have_list_controllers=no], [-lnih -lnih-dbus 
-ldbus-1])
-LIBS=$save_LIBS
-if test "x$have_list_controllers" = "xyes"; then
-       AC_DEFINE([HAVE_CGMANAGER_LIST_CONTROLLERS], 1, [Have 
cgmanager_list_controllers])
-       AC_MSG_RESULT([yes])
-else
-       AC_MSG_RESULT([no])
-fi
-
 AC_MSG_CHECKING(for static libcap)
 # Check for static libcap, make sure the function checked for differs from the
 # the one checked below so the cache doesn't give a wrong answer
@@ -664,7 +625,6 @@ AC_CHECK_FUNCS([setns pivot_root sethostname unshare rand_r 
confstr faccessat ge
 
 # Check for some functions
 AC_CHECK_LIB(pthread, main)
-AC_CHECK_FUNCS(pthread_atfork)
 AC_CHECK_FUNCS(statvfs)
 AC_CHECK_LIB(util, openpty)
 AC_CHECK_FUNCS([openpty hasmntopt setmntent endmntent utmpxname])
@@ -965,7 +925,6 @@ Security features:
  - Linux capabilities: $enable_capabilities
  - seccomp: $enable_seccomp
  - SELinux: $enable_selinux
- - cgmanager: $enable_cgmanager
 
 Bindings:
  - lua: $enable_lua
@@ -983,13 +942,3 @@ Debugging:
 Paths:
  - Logs in configpath: $enable_configpath_log
 EOF
-
-if test "x$ac_cv_func_pthread_atfork" = "xno" ; then
-cat << EOF
-
-WARNING: Threading not supported on your platform
-
-       You are compiling LXC for bionic target which lacks certain threading 
related functionality used by LXC API (like pthread_atfork).
-       Please note that, because of the missing functionality, multithreaded 
usage of LXC API cause some problems.
-EOF
-fi
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index f56436bbc..1cc986275 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -136,10 +136,6 @@ liblxc_la_SOURCES = \
        \
        $(LSM_SOURCES)
 
-if ENABLE_CGMANAGER
-liblxc_la_SOURCES += cgroups/cgmanager.c
-endif
-
 if IS_BIONIC
 liblxc_la_SOURCES += \
        ../include/ifaddrs.c ../include/ifaddrs.h \
@@ -182,10 +178,6 @@ if ENABLE_APPARMOR
 AM_CFLAGS += -DHAVE_APPARMOR
 endif
 
-if ENABLE_CGMANAGER
-AM_CFLAGS += -DHAVE_CGMANAGER
-endif
-
 if ENABLE_SELINUX
 AM_CFLAGS += -DHAVE_SELINUX
 endif
@@ -209,11 +201,6 @@ liblxc_la_LDFLAGS = \
 
 liblxc_la_LIBADD = $(CAP_LIBS) $(SELINUX_LIBS) $(SECCOMP_LIBS)
 
-if ENABLE_CGMANAGER
-liblxc_la_LIBADD += $(CGMANAGER_LIBS) $(DBUS_LIBS) $(NIH_LIBS) $(NIH_DBUS_LIBS)
-liblxc_la_CFLAGS += $(CGMANAGER_CFLAGS) $(DBUS_CFLAGS) $(NIH_CFLAGS) 
$(NIH_DBUS_CFLAGS)
-endif
-
 bin_SCRIPTS = cmd/lxc-checkconfig \
              cmd/lxc-update-config
 
diff --git a/src/lxc/cgroups/cgfs.c b/src/lxc/cgroups/cgfs.c
index a2630efa4..338097f4d 100644
--- a/src/lxc/cgroups/cgfs.c
+++ b/src/lxc/cgroups/cgfs.c
@@ -103,7 +103,6 @@ struct cgroup_mount_point {
  *                      hierarchies
  *
  * Note this is the per-process info tracked by the cgfs_ops.
- * This is not used with cgmanager.
  */
 struct cgroup_process_info {
        struct cgroup_process_info *next;
diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index 4c4dda61c..050b397df 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -26,8 +26,7 @@
  * cgroup backend.  The original cgfs.c was designed to be as flexible
  * as possible.  It would try to find cgroup filesystems no matter where
  * or how you had them mounted, and deduce the most usable mount for
- * each controller.  It also was not designed for unprivileged use, as
- * that was reserved for cgmanager.
+ * each controller.
  *
  * This new implementation assumes that cgroup filesystems are mounted
  * under /sys/fs/cgroup/clist where clist is either the controller, or
diff --git a/src/lxc/cgroups/cgmanager.c b/src/lxc/cgroups/cgmanager.c
deleted file mode 100644
index c23443c9f..000000000
--- a/src/lxc/cgroups/cgmanager.c
+++ /dev/null
@@ -1,1683 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * 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
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <pthread.h>
-#include <grp.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <sys/inotify.h>
-#include <sys/mount.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#include <poll.h>
-
-#include "error.h"
-#include "commands.h"
-#include "list.h"
-#include "namespace.h"
-#include "conf.h"
-#include "utils.h"
-#include "log.h"
-#include "cgroup.h"
-#include "start.h"
-#include "state.h"
-#include "storage.h"
-
-#define CGM_SUPPORTS_GET_ABS 3
-#define CGM_SUPPORTS_NAMED 4
-#define CGM_SUPPORTS_MULT_CONTROLLERS 10
-
-#ifdef HAVE_CGMANAGER
-lxc_log_define(lxc_cgmanager, lxc);
-
-#include <nih-dbus/dbus_connection.h>
-#include <cgmanager/cgmanager-client.h>
-#include <nih/alloc.h>
-#include <nih/error.h>
-#include <nih/string.h>
-
-struct cgm_data {
-       char *name;
-       char *cgroup_path;
-       const char *cgroup_pattern;
-};
-
-static pthread_mutex_t cgm_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void lock_mutex(pthread_mutex_t *l)
-{
-       int ret;
-
-       if ((ret = pthread_mutex_lock(l)) != 0) {
-               fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, 
strerror(ret));
-               exit(1);
-       }
-}
-
-static void unlock_mutex(pthread_mutex_t *l)
-{
-       int ret;
-
-       if ((ret = pthread_mutex_unlock(l)) != 0) {
-               fprintf(stderr, "%s: pthread_mutex_unlock returned:%d %s\n",
-                               __FILE__, ret, strerror(ret));
-               exit(1);
-       }
-}
-
-void cgm_lock(void)
-{
-       lock_mutex(&cgm_mutex);
-}
-
-void cgm_unlock(void)
-{
-       unlock_mutex(&cgm_mutex);
-}
-
-#ifdef HAVE_PTHREAD_ATFORK
-__attribute__((constructor))
-static void process_lock_setup_atfork(void)
-{
-       pthread_atfork(cgm_lock, cgm_unlock, cgm_unlock);
-}
-#endif
-
-static NihDBusProxy *cgroup_manager = NULL;
-static int32_t api_version;
-
-static struct cgroup_ops cgmanager_ops;
-static int nr_subsystems;
-static char **subsystems, **subsystems_inone;
-static bool dbus_threads_initialized = false;
-static void cull_user_controllers(void);
-
-static void cgm_dbus_disconnect(void)
-{
-       if (cgroup_manager) {
-               dbus_connection_flush(cgroup_manager->connection);
-               dbus_connection_close(cgroup_manager->connection);
-               nih_free(cgroup_manager);
-       }
-       cgroup_manager = NULL;
-       cgm_unlock();
-}
-
-#define CGMANAGER_DBUS_SOCK "unix:path=/sys/fs/cgroup/cgmanager/sock"
-static bool cgm_dbus_connect(void)
-{
-       DBusError dbus_error;
-       static DBusConnection *connection;
-
-       cgm_lock();
-       if (!dbus_threads_initialized) {
-               /* tell dbus to do struct locking for thread safety */
-               dbus_threads_init_default();
-               dbus_threads_initialized = true;
-       }
-
-       dbus_error_init(&dbus_error);
-
-       connection = dbus_connection_open_private(CGMANAGER_DBUS_SOCK, 
&dbus_error);
-       if (!connection) {
-               DEBUG("Failed opening dbus connection: %s: %s",
-                               dbus_error.name, dbus_error.message);
-               dbus_error_free(&dbus_error);
-               cgm_unlock();
-               return false;
-       }
-       dbus_connection_set_exit_on_disconnect(connection, FALSE);
-       dbus_error_free(&dbus_error);
-       cgroup_manager = nih_dbus_proxy_new(NULL, connection,
-                               NULL /* p2p */,
-                               "/org/linuxcontainers/cgmanager", NULL, NULL);
-       dbus_connection_unref(connection);
-       if (!cgroup_manager) {
-               NihError *nerr;
-               nerr = nih_error_get();
-               ERROR("Error opening cgmanager proxy: %s", nerr->message);
-               nih_free(nerr);
-               cgm_dbus_disconnect();
-               return false;
-       }
-
-       /* get the api version */
-       if (cgmanager_get_api_version_sync(NULL, cgroup_manager, &api_version) 
!= 0) {
-               NihError *nerr;
-               nerr = nih_error_get();
-               ERROR("Error cgroup manager api version: %s", nerr->message);
-               nih_free(nerr);
-               cgm_dbus_disconnect();
-               return false;
-       }
-       if (api_version < CGM_SUPPORTS_NAMED)
-               cull_user_controllers();
-       return true;
-}
-
-static bool cgm_all_controllers_same;
-
-/*
- * Check whether we can use "all" when talking to cgmanager.
- * We check two things:
- * 1. whether cgmanager is new enough to support this.
- * 2. whether the task we are interested in is in the same
- *    cgroup for all controllers.
- * In cgm_init (before an lxc-start) we care about our own
- * cgroup.  In cgm_attach, we care about the target task's
- * cgroup.
- */
-static void check_supports_multiple_controllers(pid_t pid)
-{
-       FILE *f;
-       char *line = NULL, *prevpath = NULL;
-       size_t sz = 0;
-       char path[100];
-
-       cgm_all_controllers_same = false;
-
-       if (pid == -1)
-               sprintf(path, "/proc/self/cgroup");
-       else
-               sprintf(path, "/proc/%d/cgroup", pid);
-       f = fopen(path, "r");
-       if (!f)
-               return;
-
-       cgm_all_controllers_same = true;
-
-       while (getline(&line, &sz, f) != -1) {
-               /* file format: hierarchy:subsystems:group */
-               char *colon;
-               if (!line[0])
-                       continue;
-
-               colon = strchr(line, ':');
-               if (!colon)
-                       continue;
-               colon = strchr(colon+1, ':');
-               if (!colon)
-                       continue;
-               colon++;
-               if (!prevpath) {
-                       prevpath = alloca(strlen(colon)+1);
-                       strcpy(prevpath, colon);
-                       continue;
-               }
-               if (strcmp(prevpath, colon) != 0) {
-                       cgm_all_controllers_same = false;
-                       break;
-               }
-       }
-
-       fclose(f);
-       free(line);
-}
-
-static int send_creds(int sock, int rpid, int ruid, int rgid)
-{
-       struct msghdr msg = { 0 };
-       struct iovec iov;
-       struct cmsghdr *cmsg;
-       struct ucred cred = {
-               .pid = rpid,
-               .uid = ruid,
-               .gid = rgid,
-       };
-       char cmsgbuf[CMSG_SPACE(sizeof(cred))];
-       char buf[1];
-       buf[0] = 'p';
-
-       msg.msg_control = cmsgbuf;
-       msg.msg_controllen = sizeof(cmsgbuf);
-
-       cmsg = CMSG_FIRSTHDR(&msg);
-       cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
-       cmsg->cmsg_level = SOL_SOCKET;
-       cmsg->cmsg_type = SCM_CREDENTIALS;
-       memcpy(CMSG_DATA(cmsg), &cred, sizeof(cred));
-
-       msg.msg_name = NULL;
-       msg.msg_namelen = 0;
-
-       iov.iov_base = buf;
-       iov.iov_len = sizeof(buf);
-       msg.msg_iov = &iov;
-       msg.msg_iovlen = 1;
-
-       if (sendmsg(sock, &msg, 0) < 0)
-               return -1;
-       return 0;
-}
-
-static bool lxc_cgmanager_create(const char *controller, const char 
*cgroup_path, int32_t *existed)
-{
-       bool ret = true;
-       if ( cgmanager_create_sync(NULL, cgroup_manager, controller,
-                                      cgroup_path, existed) != 0) {
-               NihError *nerr;
-               nerr = nih_error_get();
-               ERROR("call to cgmanager_create_sync failed: %s", 
nerr->message);
-               nih_free(nerr);
-               ERROR("Failed to create %s:%s", controller, cgroup_path);
-               ret = false;
-       }
-
-       return ret;
-}
-
-/*
- * Escape to the root cgroup if we are root, so that the container will
- * be in "/lxc/c1" rather than "/user/..../c1"
- * called internally with connection already open
- */
-static bool cgm_escape(void *hdata)
-{
-       bool ret = true, cgm_needs_disconnect = false;
-       pid_t me = lxc_raw_getpid();
-       char **slist = subsystems;
-       int i;
-
-       if (!cgroup_manager) {
-               if (!cgm_dbus_connect()) {
-                       ERROR("Error connecting to cgroup manager");
-                       return false;
-               }
-               cgm_needs_disconnect = true;
-       }
-
-
-       if (cgm_all_controllers_same)
-               slist = subsystems_inone;
-
-       for (i = 0; slist[i]; i++) {
-               if (cgmanager_move_pid_abs_sync(NULL, cgroup_manager,
-                                       slist[i], "/", me) != 0) {
-                       NihError *nerr;
-                       nerr = nih_error_get();
-                       ERROR("call to cgmanager_move_pid_abs_sync(%s) failed: 
%s",
-                                       slist[i], nerr->message);
-                       nih_free(nerr);
-                       ret = false;
-                       break;
-               }
-       }
-
-       if (cgm_needs_disconnect)
-               cgm_dbus_disconnect();
-
-       return ret;
-}
-
-static int cgm_num_hierarchies(void)
-{
-       /* not implemented */
-       return -1;
-}
-
-static bool cgm_get_hierarchies(int i, char ***out)
-{
-       /* not implemented */
-       return false;
-}
-
-struct chown_data {
-       const char *cgroup_path;
-       uid_t origuid;
-};
-
-static int do_chown_cgroup(const char *controller, const char *cgroup_path,
-               uid_t newuid)
-{
-       int sv[2] = {-1, -1}, optval = 1, ret = -1;
-       pid_t pid_self;
-       char buf[1];
-       struct pollfd fds;
-
-       if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) {
-               SYSERROR("Error creating socketpair");
-               goto out;
-       }
-       if (setsockopt(sv[1], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) 
== -1) {
-               SYSERROR("setsockopt failed");
-               goto out;
-       }
-       if (setsockopt(sv[0], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) 
== -1) {
-               SYSERROR("setsockopt failed");
-               goto out;
-       }
-       if ( cgmanager_chown_scm_sync(NULL, cgroup_manager, controller,
-                                      cgroup_path, sv[1]) != 0) {
-               NihError *nerr;
-               nerr = nih_error_get();
-               ERROR("call to cgmanager_chown_scm_sync failed: %s", 
nerr->message);
-               nih_free(nerr);
-               goto out;
-       }
-       /* now send credentials */
-
-       fds.fd = sv[0];
-       fds.events = POLLIN;
-       fds.revents = 0;
-       if (poll(&fds, 1, -1) <= 0) {
-               ERROR("Error getting go-ahead from server: %s", 
strerror(errno));
-               goto out;
-       }
-       if (read(sv[0], &buf, 1) != 1) {
-               ERROR("Error getting reply from server over socketpair");
-               goto out;
-       }
-
-       pid_self = lxc_raw_getpid();
-       if (send_creds(sv[0], pid_self, getuid(), getgid())) {
-               SYSERROR("Error sending pid over SCM_CREDENTIAL");
-               goto out;
-       }
-       fds.fd = sv[0];
-       fds.events = POLLIN;
-       fds.revents = 0;
-       if (poll(&fds, 1, -1) <= 0) {
-               ERROR("Error getting go-ahead from server: %s", 
strerror(errno));
-               goto out;
-       }
-       if (read(sv[0], &buf, 1) != 1) {
-               ERROR("Error getting reply from server over socketpair");
-               goto out;
-       }
-       if (send_creds(sv[0], pid_self, newuid, 0)) {
-               SYSERROR("Error sending pid over SCM_CREDENTIAL");
-               goto out;
-       }
-       fds.fd = sv[0];
-       fds.events = POLLIN;
-       fds.revents = 0;
-       if (poll(&fds, 1, -1) <= 0) {
-               ERROR("Error getting go-ahead from server: %s", 
strerror(errno));
-               goto out;
-       }
-       ret = read(sv[0], buf, 1);
-out:
-       close(sv[0]);
-       close(sv[1]);
-       if (ret == 1 && *buf == '1')
-               return 0;
-       return -1;
-}
-
-static int chown_cgroup_wrapper(void *data)
-{
-       struct chown_data *arg = data;
-       char **slist = subsystems;
-       int i, ret = -1;
-       uid_t destuid;
-
-       if (setresgid(0,0,0) < 0)
-               SYSERROR("Failed to setgid to 0");
-       if (setresuid(0,0,0) < 0)
-               SYSERROR("Failed to setuid to 0");
-       if (setgroups(0, NULL) < 0)
-               SYSERROR("Failed to clear groups");
-       cgm_dbus_disconnect();
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               return -1;
-       }
-       destuid = get_ns_uid(arg->origuid);
-
-       if (cgm_all_controllers_same)
-               slist = subsystems_inone;
-
-       for (i = 0; slist[i]; i++) {
-               if (do_chown_cgroup(slist[i], arg->cgroup_path, destuid) < 0) {
-                       ERROR("Failed to chown %s:%s to container root",
-                               slist[i], arg->cgroup_path);
-                       goto fail;
-               }
-       }
-       ret = 0;
-fail:
-       cgm_dbus_disconnect();
-       return ret;
-}
-
-/* Internal helper.  Must be called with the cgmanager dbus socket open */
-static bool lxc_cgmanager_chmod(const char *controller,
-               const char *cgroup_path, const char *file, int mode)
-{
-       if (cgmanager_chmod_sync(NULL, cgroup_manager, controller,
-                       cgroup_path, file, mode) != 0) {
-               NihError *nerr;
-               nerr = nih_error_get();
-               ERROR("call to cgmanager_chmod_sync failed: %s", nerr->message);
-               nih_free(nerr);
-               return false;
-       }
-       return true;
-}
-
-/* Internal helper.  Must be called with the cgmanager dbus socket open */
-static bool chown_cgroup(const char *cgroup_path, struct lxc_conf *conf)
-{
-       struct chown_data data;
-       char **slist = subsystems;
-       int i;
-
-       if (lxc_list_empty(&conf->id_map))
-               /* If there's no mapping then we don't need to chown */
-               return true;
-
-       data.cgroup_path = cgroup_path;
-       data.origuid = geteuid();
-
-       /* Unpriv users can't chown it themselves, so chown from
-        * a child namespace mapping both our own and the target uid
-        */
-       if (userns_exec_1(conf, chown_cgroup_wrapper, &data,
-                         "chown_cgroup_wrapper") < 0) {
-               ERROR("Error requesting cgroup chown in new namespace");
-               return false;
-       }
-
-       /*
-        * Now chmod 775 the directory else the container cannot create cgroups.
-        * This can't be done in the child namespace because it only group-owns
-        * the cgroup
-        */
-       if (cgm_all_controllers_same)
-               slist = subsystems_inone;
-
-       for (i = 0; slist[i]; i++) {
-               if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "", 0775))
-                       return false;
-               if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "tasks", 0664))
-                       return false;
-               if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "cgroup.procs", 
0664))
-                       return false;
-       }
-
-       return true;
-}
-
-#define CG_REMOVE_RECURSIVE 1
-/* Internal helper.  Must be called with the cgmanager dbus socket open */
-static void cgm_remove_cgroup(const char *controller, const char *path)
-{
-       int existed;
-       if ( cgmanager_remove_sync(NULL, cgroup_manager, controller,
-                                  path, CG_REMOVE_RECURSIVE, &existed) != 0) {
-               NihError *nerr;
-               nerr = nih_error_get();
-               ERROR("call to cgmanager_remove_sync failed: %s", 
nerr->message);
-               nih_free(nerr);
-               ERROR("Error removing %s:%s", controller, path);
-       }
-       if (existed == -1)
-               INFO("cgroup removal attempt: %s:%s did not exist", controller, 
path);
-}
-
-static void *cgm_init(struct lxc_handler *handler)
-{
-       struct cgm_data *d;
-
-       d = malloc(sizeof(*d));
-       if (!d)
-               return NULL;
-
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               goto err1;
-       }
-
-       memset(d, 0, sizeof(*d));
-       d->name = strdup(handler->name);
-       if (!d->name) {
-               cgm_dbus_disconnect();
-               goto err1;
-       }
-
-       d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
-
-       /* cgm_create immediately gets called so keep the connection open */
-       return d;
-
-err1:
-       free(d);
-       return NULL;
-}
-
-/* Called after a failed container startup */
-static void cgm_destroy(void *hdata, struct lxc_conf *conf)
-{
-       struct cgm_data *d = hdata;
-       char **slist = subsystems;
-       int i;
-
-       if (!d || !d->cgroup_path)
-               return;
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               return;
-       }
-
-       if (cgm_all_controllers_same)
-               slist = subsystems_inone;
-       for (i = 0; slist[i]; i++)
-               cgm_remove_cgroup(slist[i], d->cgroup_path);
-
-       free(d->name);
-       free(d->cgroup_path);
-       free(d);
-       cgm_dbus_disconnect();
-}
-
-/*
- * remove all the cgroups created
- * called internally with dbus connection open
- */
-static inline void cleanup_cgroups(char *path)
-{
-       int i;
-       char **slist = subsystems;
-
-       if (cgm_all_controllers_same)
-               slist = subsystems_inone;
-       for (i = 0; slist[i]; i++)
-               cgm_remove_cgroup(slist[i], path);
-}
-
-static inline bool cgm_create(void *hdata)
-{
-       struct cgm_data *d = hdata;
-       char **slist = subsystems;
-       int i, index=0, baselen, ret;
-       int32_t existed;
-       char result[MAXPATHLEN], *tmp, *cgroup_path;
-
-       if (!d)
-               return false;
-
-       /* XXX we should send a hint to the cgmanager that when these cgroups
-        * become empty they should be deleted. Requires a cgmanager extension.
-        */
-       memset(result, 0, MAXPATHLEN);
-       tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
-       if (!tmp)
-               goto bad;
-       if (strlen(tmp) >= MAXPATHLEN) {
-               free(tmp);
-               goto bad;
-       }
-       strcpy(result, tmp);
-       baselen = strlen(result);
-       free(tmp);
-       tmp = result;
-       while (*tmp == '/')
-               tmp++;
-again:
-       if (index == 100) { /* turn this into a warn later */
-               ERROR("cgroup error?  100 cgroups with this name already 
running");
-               goto bad;
-       }
-       if (index) {
-               ret = snprintf(result+baselen, MAXPATHLEN-baselen, "-%d", 
index);
-               if (ret < 0 || ret >= MAXPATHLEN-baselen)
-                       goto bad;
-       }
-       existed = 0;
-
-       if (cgm_all_controllers_same)
-               slist = subsystems_inone;
-
-       for (i = 0; slist[i]; i++) {
-               if (!lxc_cgmanager_create(slist[i], tmp, &existed)) {
-                       ERROR("Error creating cgroup %s:%s", slist[i], result);
-                       cleanup_cgroups(tmp);
-                       goto bad;
-               }
-               if (existed == 1)
-                       goto next;
-       }
-       /* success */
-       cgroup_path = strdup(tmp);
-       if (!cgroup_path) {
-               cleanup_cgroups(tmp);
-               goto bad;
-       }
-       d->cgroup_path = cgroup_path;
-       cgm_dbus_disconnect();
-       return true;
-
-next:
-       index++;
-       goto again;
-bad:
-       cgm_dbus_disconnect();
-       return false;
-}
-
-/*
- * Use the cgmanager to move a task into a cgroup for a particular
- * hierarchy.
- * All the subsystems in this hierarchy are co-mounted, so we only
- * need to transition the task into one of the cgroups
- *
- * Internal helper, must be called with cgmanager dbus socket open
- */
-static bool lxc_cgmanager_enter(pid_t pid, const char *controller,
-               const char *cgroup_path, bool abs)
-{
-       int ret;
-
-       if (abs)
-               ret = cgmanager_move_pid_abs_sync(NULL, cgroup_manager,
-                       controller, cgroup_path, pid);
-       else
-               ret = cgmanager_move_pid_sync(NULL, cgroup_manager,
-                       controller, cgroup_path, pid);
-       if (ret != 0) {
-               NihError *nerr;
-               nerr = nih_error_get();
-               WARN("call to cgmanager_move_pid_%ssync failed: %s",
-                       abs ? "abs_" : "", nerr->message);
-               nih_free(nerr);
-               return false;
-       }
-       return true;
-}
-
-static inline bool cgm_enter(void *hdata, pid_t pid)
-{
-       struct cgm_data *d = hdata;
-       char **slist = subsystems;
-       bool ret = false;
-       int i;
-
-       if (!d || !d->cgroup_path)
-               return false;
-
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               return false;
-       }
-
-       if (cgm_all_controllers_same)
-               slist = subsystems_inone;
-
-       for (i = 0; slist[i]; i++) {
-               if (!lxc_cgmanager_enter(pid, slist[i], d->cgroup_path, false))
-                       goto out;
-       }
-       ret = true;
-out:
-       cgm_dbus_disconnect();
-       return ret;
-}
-
-static const char *cgm_get_cgroup(void *hdata, const char *subsystem)
-{
-       struct cgm_data *d = hdata;
-
-       if (!d || !d->cgroup_path)
-               return NULL;
-       return d->cgroup_path;
-}
-
-#if HAVE_CGMANAGER_GET_PID_CGROUP_ABS_SYNC
-static inline bool abs_cgroup_supported(void) {
-       return api_version >= CGM_SUPPORTS_GET_ABS;
-}
-#else
-static inline bool abs_cgroup_supported(void) {
-       return false;
-}
-#define cgmanager_get_pid_cgroup_abs_sync(...) -1
-#endif
-
-static char *try_get_abs_cgroup(const char *name, const char *lxcpath,
-               const char *controller)
-{
-       char *cgroup = NULL;
-
-       if (abs_cgroup_supported()) {
-               /* get the container init pid and ask for its abs cgroup */
-               pid_t pid = lxc_cmd_get_init_pid(name, lxcpath);
-               if (pid < 0)
-                       return NULL;
-               if (cgmanager_get_pid_cgroup_abs_sync(NULL, cgroup_manager,
-                               controller, pid, &cgroup) != 0) {
-                       cgroup = NULL;
-                       NihError *nerr;
-                       nerr = nih_error_get();
-                       nih_free(nerr);
-               } else
-                       prune_init_scope(cgroup);
-               return cgroup;
-       }
-
-       /* use the command interface to look for the cgroup */
-       return lxc_cmd_get_cgroup_path(name, lxcpath, controller);
-}
-
-/*
- * nrtasks is called by the utmp helper by the container monitor.
- * cgmanager socket was closed after cgroup setup was complete, so we need
- * to reopen here.
- *
- * Return -1 on error.
- */
-static int cgm_get_nrtasks(void *hdata)
-{
-       struct cgm_data *d = hdata;
-       int32_t *pids;
-       size_t pids_len;
-
-       if (!d || !d->cgroup_path)
-               return -1;
-
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               return -1;
-       }
-       if (cgmanager_get_tasks_sync(NULL, cgroup_manager, subsystems[0],
-                                    d->cgroup_path, &pids, &pids_len) != 0) {
-               NihError *nerr;
-               nerr = nih_error_get();
-               ERROR("call to cgmanager_get_tasks_sync failed: %s", 
nerr->message);
-               nih_free(nerr);
-               pids_len = -1;
-               goto out;
-       }
-       nih_free(pids);
-out:
-       cgm_dbus_disconnect();
-       return pids_len;
-}
-
-#if HAVE_CGMANAGER_LIST_CONTROLLERS
-static bool lxc_list_controllers(char ***list)
-{
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               return false;
-       }
-       if (cgmanager_list_controllers_sync(NULL, cgroup_manager, list) != 0) {
-               NihError *nerr;
-               nerr = nih_error_get();
-               ERROR("call to cgmanager_list_controllers_sync failed: %s", 
nerr->message);
-               nih_free(nerr);
-               cgm_dbus_disconnect();
-               return false;
-       }
-
-       cgm_dbus_disconnect();
-       return true;
-}
-#else
-static bool lxc_list_controllers(char ***list)
-{
-       return false;
-}
-#endif
-
-static inline void free_abs_cgroup(char *cgroup)
-{
-       if (!cgroup)
-               return;
-       if (abs_cgroup_supported())
-               nih_free(cgroup);
-       else
-               free(cgroup);
-}
-
-static void do_cgm_get(const char *name, const char *lxcpath, const char 
*filename, int outp, bool sendvalue)
-{
-       char *controller, *key, *cgroup = NULL, *cglast;
-       int len = -1;
-       int ret;
-       nih_local char *result = NULL;
-
-       controller = alloca(strlen(filename)+1);
-       strcpy(controller, filename);
-       key = strchr(controller, '.');
-       if (!key) {
-               ret = write(outp, &len, sizeof(len));
-               if (ret != sizeof(len))
-                       WARN("Failed to warn cgm_get of error; parent may 
hang");
-               exit(1);
-       }
-       *key = '\0';
-
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               ret = write(outp, &len, sizeof(len));
-               if (ret != sizeof(len))
-                       WARN("Failed to warn cgm_get of error; parent may 
hang");
-               exit(1);
-       }
-       cgroup = try_get_abs_cgroup(name, lxcpath, controller);
-       if (!cgroup) {
-               cgm_dbus_disconnect();
-               ret = write(outp, &len, sizeof(len));
-               if (ret != sizeof(len))
-                       WARN("Failed to warn cgm_get of error; parent may 
hang");
-               exit(1);
-       }
-       cglast = strrchr(cgroup, '/');
-       if (!cglast) {
-               cgm_dbus_disconnect();
-               free_abs_cgroup(cgroup);
-               ret = write(outp, &len, sizeof(len));
-               if (ret != sizeof(len))
-                       WARN("Failed to warn cgm_get of error; parent may 
hang");
-               exit(1);
-       }
-       *cglast = '\0';
-       if (!lxc_cgmanager_enter(lxc_raw_getpid(), controller, cgroup, 
abs_cgroup_supported())) {
-               WARN("Failed to enter container cgroup %s:%s", controller, 
cgroup);
-               ret = write(outp, &len, sizeof(len));
-               if (ret != sizeof(len))
-                       WARN("Failed to warn cgm_get of error; parent may 
hang");
-               cgm_dbus_disconnect();
-               free_abs_cgroup(cgroup);
-               exit(1);
-       }
-       if (cgmanager_get_value_sync(NULL, cgroup_manager, controller, 
cglast+1, filename, &result) != 0) {
-               NihError *nerr;
-               nerr = nih_error_get();
-               nih_free(nerr);
-               free_abs_cgroup(cgroup);
-               cgm_dbus_disconnect();
-               ret = write(outp, &len, sizeof(len));
-               if (ret != sizeof(len))
-                       WARN("Failed to warn cgm_get of error; parent may 
hang");
-               exit(1);
-       }
-       free_abs_cgroup(cgroup);
-       cgm_dbus_disconnect();
-       len = strlen(result);
-       ret = write(outp, &len, sizeof(len));
-       if (ret != sizeof(len)) {
-               WARN("Failed to send length to parent");
-               exit(1);
-       }
-       if (!len || !sendvalue) {
-               exit(0);
-       }
-       ret = write(outp, result, len);
-       if (ret < 0)
-               exit(1);
-       exit(0);
-}
-
-/* cgm_get is called to get container cgroup settings, not during startup */
-static int cgm_get(const char *filename, char *value, size_t len, const char 
*name, const char *lxcpath)
-{
-       pid_t pid;
-       int p[2], ret, newlen, readlen;
-
-       if (pipe(p) < 0)
-               return -1;
-       if ((pid = fork()) < 0) {
-               close(p[0]);
-               close(p[1]);
-               return -1;
-       }
-       if (!pid) /* do_cgm_get exits */
-               do_cgm_get(name, lxcpath, filename, p[1], len && value);
-       close(p[1]);
-       ret = read(p[0], &newlen, sizeof(newlen));
-       if (ret != sizeof(newlen)) {
-               close(p[0]);
-               ret = -1;
-               goto out;
-       }
-       if (!len || !value) {
-               close(p[0]);
-               ret = newlen;
-               goto out;
-       }
-       memset(value, 0, len);
-       if (newlen < 0) { /* child is reporting an error */
-               close(p[0]);
-               ret = -1;
-               goto out;
-       }
-       if (newlen == 0) { /* empty read */
-               close(p[0]);
-               ret = 0;
-               goto out;
-       }
-       readlen = newlen > len ? len : newlen;
-       ret = read(p[0], value, readlen);
-       close(p[0]);
-       if (ret != readlen) {
-               ret = -1;
-               goto out;
-       }
-       if (newlen >= len) {
-               value[len-1] = '\0';
-               newlen = len-1;
-       } else if (newlen+1 < len) {
-               /* cgmanager doesn't add eol to last entry */
-               value[newlen++] = '\n';
-               value[newlen] = '\0';
-       }
-       ret = newlen;
-out:
-       if (wait_for_pid(pid))
-               WARN("do_cgm_get exited with error");
-       return ret;
-}
-
-static void do_cgm_set(const char *name, const char *lxcpath, const char 
*filename, const char *value, int outp)
-{
-       char *controller, *key, *cgroup = NULL;
-       int retval = 0;  /* value we are sending to the parent over outp */
-       int ret;
-       char *cglast;
-
-       controller = alloca(strlen(filename)+1);
-       strcpy(controller, filename);
-       key = strchr(controller, '.');
-       if (!key) {
-               ret = write(outp, &retval, sizeof(retval));
-               if (ret != sizeof(retval))
-                       WARN("Failed to warn cgm_set of error; parent may 
hang");
-               exit(1);
-       }
-       *key = '\0';
-
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               ret = write(outp, &retval, sizeof(retval));
-               if (ret != sizeof(retval))
-                       WARN("Failed to warn cgm_set of error; parent may 
hang");
-               exit(1);
-       }
-       cgroup = try_get_abs_cgroup(name, lxcpath, controller);
-       if (!cgroup) {
-               cgm_dbus_disconnect();
-               ret = write(outp, &retval, sizeof(retval));
-               if (ret != sizeof(retval))
-                       WARN("Failed to warn cgm_set of error; parent may 
hang");
-               exit(1);
-       }
-       cglast = strrchr(cgroup, '/');
-       if (!cglast) {
-               cgm_dbus_disconnect();
-               free_abs_cgroup(cgroup);
-               ret = write(outp, &retval, sizeof(retval));
-               if (ret != sizeof(retval))
-                       WARN("Failed to warn cgm_set of error; parent may 
hang");
-               exit(1);
-       }
-       *cglast = '\0';
-       if (!lxc_cgmanager_enter(lxc_raw_getpid(), controller, cgroup, 
abs_cgroup_supported())) {
-               ERROR("Failed to enter container cgroup %s:%s", controller, 
cgroup);
-               ret = write(outp, &retval, sizeof(retval));
-               if (ret != sizeof(retval))
-                       WARN("Failed to warn cgm_set of error; parent may 
hang");
-               cgm_dbus_disconnect();
-               free_abs_cgroup(cgroup);
-               exit(1);
-       }
-       if (cgmanager_set_value_sync(NULL, cgroup_manager, controller, 
cglast+1, filename, value) != 0) {
-               NihError *nerr;
-               nerr = nih_error_get();
-               ERROR("Error setting cgroup value %s for %s:%s", filename, 
controller, cgroup);
-               ERROR("call to cgmanager_set_value_sync failed: %s", 
nerr->message);
-               nih_free(nerr);
-               free_abs_cgroup(cgroup);
-               cgm_dbus_disconnect();
-               ret = write(outp, &retval, sizeof(retval));
-               if (ret != sizeof(retval))
-                       WARN("Failed to warn cgm_set of error; parent may 
hang");
-               exit(1);
-       }
-       free_abs_cgroup(cgroup);
-       cgm_dbus_disconnect();
-       /* tell parent that we are done */
-       retval = 1;
-       ret = write(outp, &retval, sizeof(retval));
-       if (ret != sizeof(retval)) {
-               exit(1);
-       }
-       exit(0);
-}
-
-/* cgm_set is called to change cgroup settings, not during startup */
-static int cgm_set(const char *filename, const char *value, const char *name, 
const char *lxcpath)
-{
-       pid_t pid;
-       int p[2], ret, v;
-
-       if (pipe(p) < 0)
-               return -1;
-       if ((pid = fork()) < 0) {
-               close(p[1]);
-               close(p[0]);
-               return -1;
-       }
-       if (!pid) /* do_cgm_set exits */
-               do_cgm_set(name, lxcpath, filename, value, p[1]);
-       close(p[1]);
-       ret = read(p[0], &v, sizeof(v));
-       close(p[0]);
-       if (wait_for_pid(pid))
-               WARN("do_cgm_set exited with error");
-       if (ret != sizeof(v) || !v)
-               return -1;
-       return 0;
-}
-
-static void free_subsystems(void)
-{
-       int i;
-
-       for (i = 0; i < nr_subsystems; i++)
-               free(subsystems[i]);
-       free(subsystems);
-       subsystems = NULL;
-       nr_subsystems = 0;
-}
-
-static void cull_user_controllers(void)
-{
-       int i, j;
-
-       for (i = 0;  i < nr_subsystems; i++) {
-               if (strncmp(subsystems[i], "name=", 5) != 0)
-                       continue;
-               for (j = i;  j < nr_subsystems-1; j++)
-                       subsystems[j] = subsystems[j+1];
-               nr_subsystems--;
-       }
-}
-
-/*
- * return true if inword is in the comma-delimited list cgroup_use
- */
-static bool in_comma_list(const char *inword, const char *cgroup_use)
-{
-       char *e;
-       size_t inlen = strlen(inword), len;
-
-       do {
-               e = strchr(cgroup_use, ',');
-               len = e ? e - cgroup_use : strlen(cgroup_use);
-               if (len == inlen && strncmp(inword, cgroup_use, len) == 0)
-                       return true;
-               cgroup_use = e + 1;
-       } while (e);
-
-       return false;
-}
-
-/*
- * inlist is a comma-delimited list of cgroups;  so is checklist.  Return
- * true if any member of inlist is in checklist.
- */
-static bool any_in_comma_list(const char *inlist, const char *checklist)
-{
-       char *tmp = alloca(strlen(inlist) + 1), *tok, *saveptr = NULL;
-
-       strcpy(tmp, inlist);
-       for (tok = strtok_r(tmp, ",", &saveptr); tok; tok = strtok_r(NULL, ",", 
&saveptr)) {
-               if (in_comma_list(tok, checklist))
-                       return true;
-       }
-
-       return false;
-}
-
-static bool in_subsystem_list(const char *c)
-{
-       int i;
-
-       for (i = 0; i < nr_subsystems; i++) {
-               if (strcmp(c, subsystems[i]) == 0)
-                       return true;
-       }
-
-       return false;
-}
-
-/*
- * If /etc/lxc/lxc.conf specifies lxc.cgroup.use = "freezer,memory",
- * then clear out any other subsystems, and make sure that freezer
- * and memory are both enabled
- */
-static bool verify_and_prune(const char *cgroup_use)
-{
-       const char *p;
-       char *e;
-       int i, j;
-
-       for (p = cgroup_use; p && *p; p = e + 1) {
-               e = strchr(p, ',');
-               if (e)
-                       *e = '\0';
-
-               if (!in_subsystem_list(p)) {
-                       ERROR("Controller %s required by lxc.cgroup.use but not 
available\n", p);
-                       return false;
-               }
-
-               if (e)
-                       *e = ',';
-               if (!e)
-                       break;
-       }
-
-       for (i = 0; i < nr_subsystems;) {
-               if (in_comma_list(subsystems[i], cgroup_use)) {
-                       i++;
-                       continue;
-               }
-               free(subsystems[i]);
-               for (j = i;  j < nr_subsystems-1; j++)
-                       subsystems[j] = subsystems[j+1];
-               subsystems[nr_subsystems-1] = NULL;
-               nr_subsystems--;
-       }
-
-       return true;
-}
-
-static void drop_subsystem(int which)
-{
-       int i;
-
-       if (which < 0 || which >= nr_subsystems) {
-               ERROR("code error: dropping invalid subsystem index\n");
-               exit(1);
-       }
-
-       free(subsystems[which]);
-       /* note - we have nr_subsystems+1 entries, last one a NULL */
-       for (i = which; i < nr_subsystems; i++)
-               subsystems[i] = subsystems[i+1];
-       nr_subsystems -= 1;
-}
-
-/*
- * Check whether we can create the cgroups we would want
- */
-static bool subsys_is_writeable(const char *controller, const char *probe)
-{
-       int32_t existed;
-       bool ret = true;
-
-       if ( cgmanager_create_sync(NULL, cgroup_manager, controller,
-                                      probe, &existed) != 0) {
-               NihError *nerr;
-               nerr = nih_error_get();
-               ERROR("call to cgmanager_create_sync failed: %s", 
nerr->message);
-               nih_free(nerr);
-               ERROR("Failed to create %s:%s", controller, probe);
-               ret = false;
-       }
-
-       return ret;
-}
-
-static char *get_last_controller_in_list(char *list)
-{
-       char *p;
-
-       while ((p = strchr(list, ',')) != NULL)
-               list = p + 1;
-
-       return list;
-}
-
-/*
- * Make sure that all the controllers are writeable.
- * If any are not, then
- *   - if they are listed in lxc.cgroup.use, refuse to start
- *   - else if they are crucial subsystems, refuse to start
- *   - else warn and do not use them
- */
-static bool verify_final_subsystems(const char *cgroup_use)
-{
-       int i;
-       bool dropped_any = false;
-       bool bret = false;
-       const char *cgroup_pattern;
-       char tmpnam[50], *probe;
-
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               return false;
-       }
-
-       cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
-       i = snprintf(tmpnam, 50, "lxcprobe-%d", lxc_raw_getpid());
-       if (i < 0 || i >= 50) {
-               ERROR("Attack - format string modified?");
-               return false;
-       }
-       probe = lxc_string_replace("%n", tmpnam, cgroup_pattern);
-       if (!probe)
-               goto out;
-
-       i = 0;
-       while (i < nr_subsystems) {
-               char *p = get_last_controller_in_list(subsystems[i]);
-
-               if (!subsys_is_writeable(p, probe)) {
-                       if (is_crucial_cgroup_subsystem(p)) {
-                               ERROR("Cannot write to crucial subsystem %s\n",
-                                       subsystems[i]);
-                               goto out;
-                       }
-                       if (cgroup_use && any_in_comma_list(subsystems[i], 
cgroup_use)) {
-                               ERROR("Cannot write to subsystem %s which is 
requested in lxc.cgroup.use\n",
-                                       subsystems[i]);
-                               goto out;
-                       }
-                       WARN("Cannot write to subsystem %s, continuing with out 
it\n",
-                               subsystems[i]);
-                       dropped_any = true;
-                       drop_subsystem(i);
-               } else {
-                       cgm_remove_cgroup(subsystems[i], probe);
-                       i++;
-               }
-       }
-
-       if (dropped_any)
-               cgm_all_controllers_same = false;
-       bret = true;
-
-out:
-       free(probe);
-       cgm_dbus_disconnect();
-       return bret;
-}
-
-static bool collect_subsystems(void)
-{
-       char *line = NULL;
-       nih_local char **cgm_subsys_list = NULL;
-       size_t sz = 0;
-       FILE *f = NULL;
-
-       if (subsystems) /* already initialized */
-               return true;
-
-       subsystems_inone = malloc(2 * sizeof(char *));
-       if (!subsystems_inone)
-               return false;
-       subsystems_inone[0] = "all";
-       subsystems_inone[1] = NULL;
-
-       if (lxc_list_controllers(&cgm_subsys_list)) {
-               while (cgm_subsys_list[nr_subsystems]) {
-                       char **tmp = NIH_MUST( realloc(subsystems,
-                                               (nr_subsystems+2)*sizeof(char 
*)) );
-                       tmp[nr_subsystems] = NIH_MUST(
-                                       
strdup(cgm_subsys_list[nr_subsystems++]) );
-                       subsystems = tmp;
-               }
-               if (nr_subsystems)
-                       subsystems[nr_subsystems] = NULL;
-               goto collected;
-       }
-
-       INFO("cgmanager_list_controllers failed, falling back to 
/proc/self/cgroups");
-       f = fopen_cloexec("/proc/self/cgroup", "r");
-       if (!f) {
-               f = fopen_cloexec("/proc/1/cgroup", "r");
-               if (!f)
-                       return false;
-       }
-       while (getline(&line, &sz, f) != -1) {
-               /* file format: hierarchy:subsystems:group,
-                * with multiple subsystems being ,-separated */
-               char *slist, *end, *p, *saveptr = NULL, **tmp;
-
-               if (!line[0])
-                       continue;
-
-               slist = strchr(line, ':');
-               if (!slist)
-                       continue;
-               slist++;
-               end = strchr(slist, ':');
-               if (!end)
-                       continue;
-               *end = '\0';
-
-               for (p = strtok_r(slist, ",", &saveptr);
-                               p;
-                               p = strtok_r(NULL, ",", &saveptr)) {
-                       tmp = realloc(subsystems, (nr_subsystems+2)*sizeof(char 
*));
-                       if (!tmp)
-                               goto out_free;
-
-                       subsystems = tmp;
-                       tmp[nr_subsystems] = strdup(p);
-                       tmp[nr_subsystems+1] = NULL;
-                       if (!tmp[nr_subsystems])
-                               goto out_free;
-                       nr_subsystems++;
-               }
-       }
-       fclose(f);
-       f = NULL;
-
-       free(line);
-       line = NULL;
-
-collected:
-       if (!nr_subsystems) {
-               ERROR("No cgroup subsystems found");
-               return false;
-       }
-
-       /* make sure that cgroup.use can be and is honored */
-       const char *cgroup_use = lxc_global_config_value("lxc.cgroup.use");
-       if (!cgroup_use && errno != 0)
-               goto final_verify;
-       if (cgroup_use) {
-               if (!verify_and_prune(cgroup_use)) {
-                       free_subsystems();
-                       return false;
-               }
-               subsystems_inone[0] = NIH_MUST( strdup(cgroup_use) );
-               cgm_all_controllers_same = false;
-       }
-
-final_verify:
-       return verify_final_subsystems(cgroup_use);
-
-out_free:
-       free(line);
-       if (f)
-               fclose(f);
-       free_subsystems();
-       return false;
-}
-
-/*
- * called during cgroup.c:cgroup_ops_init(), at startup.  No threads.
- * We check whether we can talk to cgmanager, escape to root cgroup if
- * we are root, then close the connection.
- */
-struct cgroup_ops *cgm_ops_init(void)
-{
-       check_supports_multiple_controllers(-1);
-       if (!collect_subsystems())
-               return NULL;
-
-       if (api_version < CGM_SUPPORTS_MULT_CONTROLLERS)
-               cgm_all_controllers_same = false;
-
-       /* if root, try to escape to root cgroup */
-       if (geteuid() == 0 && !cgm_escape(NULL)) {
-               free_subsystems();
-               return NULL;
-       }
-
-       return &cgmanager_ops;
-}
-
-/* unfreeze is called by the command api after killing a container.  */
-static bool cgm_unfreeze(void *hdata)
-{
-       struct cgm_data *d = hdata;
-       bool ret = true;
-
-       if (!d || !d->cgroup_path)
-               return false;
-
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               return false;
-       }
-       if (cgmanager_set_value_sync(NULL, cgroup_manager, "freezer", 
d->cgroup_path,
-                       "freezer.state", "THAWED") != 0) {
-               NihError *nerr;
-               nerr = nih_error_get();
-               ERROR("call to cgmanager_set_value_sync failed: %s", 
nerr->message);
-               nih_free(nerr);
-               ERROR("Error unfreezing %s", d->cgroup_path);
-               ret = false;
-       }
-       cgm_dbus_disconnect();
-       return ret;
-}
-
-static bool cgm_setup_limits(void *hdata, struct lxc_conf *conf, bool 
do_devices)
-{
-       struct cgm_data *d = hdata;
-       struct lxc_list *iterator, *sorted_cgroup_settings, *next;
-       struct lxc_cgroup *cg;
-       struct lxc_list *cgroup_settings = &conf->cgroup;
-       bool ret = false;
-
-       if (lxc_list_empty(cgroup_settings))
-               return true;
-
-       if (!d || !d->cgroup_path)
-               return false;
-
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               return false;
-       }
-
-       sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
-       if (!sorted_cgroup_settings) {
-               return false;
-       }
-
-       lxc_list_for_each(iterator, sorted_cgroup_settings) {
-               char controller[100], *p;
-               cg = iterator->elem;
-               if (do_devices != !strncmp("devices", cg->subsystem, 7))
-                       continue;
-               if (strlen(cg->subsystem) > 100) /* i smell a rat */
-                       goto out;
-               strcpy(controller, cg->subsystem);
-               p = strchr(controller, '.');
-               if (p)
-                       *p = '\0';
-               if (cgmanager_set_value_sync(NULL, cgroup_manager, controller,
-                                        d->cgroup_path, cg->subsystem, 
cg->value) != 0) {
-                       NihError *nerr;
-                       nerr = nih_error_get();
-                       if (do_devices) {
-                               WARN("call to cgmanager_set_value_sync failed: 
%s", nerr->message);
-                               nih_free(nerr);
-                               WARN("Error setting cgroup %s:%s limit type 
%s", controller,
-                                       d->cgroup_path, cg->subsystem);
-                               continue;
-                       }
-
-                       ERROR("call to cgmanager_set_value_sync failed: %s", 
nerr->message);
-                       nih_free(nerr);
-                       ERROR("Error setting cgroup %s:%s limit type %s", 
controller,
-                               d->cgroup_path, cg->subsystem);
-                       goto out;
-               }
-
-               DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
-       }
-
-       ret = true;
-       INFO("cgroup limits have been setup");
-out:
-       lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) {
-               lxc_list_del(iterator);
-               free(iterator);
-       }
-       free(sorted_cgroup_settings);
-       cgm_dbus_disconnect();
-       return ret;
-}
-
-static bool cgm_chown(void *hdata, struct lxc_conf *conf)
-{
-       struct cgm_data *d = hdata;
-
-       if (!d || !d->cgroup_path)
-               return false;
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               return false;
-       }
-       if (!chown_cgroup(d->cgroup_path, conf))
-               WARN("Failed to chown %s to container root", d->cgroup_path);
-       cgm_dbus_disconnect();
-       return true;
-}
-
-/*
- * TODO: this should be re-written to use the get_config_item("lxc.idmap")
- * cmd api instead of getting the idmap from c->lxc_conf.  The reason is
- * that the id_maps may be different if the container was started with a
- * -f or -s argument.
- * The reason I'm punting on that is because we'll need to parse the
- * idmap results.
- */
-static bool cgm_attach(const char *name, const char *lxcpath, pid_t pid)
-{
-       bool pass = true;
-       char *cgroup = NULL;
-       char **slist = subsystems;
-       int i;
-
-       if (!cgm_dbus_connect()) {
-               ERROR("Error connecting to cgroup manager");
-               return false;
-       }
-
-       for (i = 0; slist[i]; i++) {
-               cgroup = try_get_abs_cgroup(name, lxcpath, slist[i]);
-               if (!cgroup) {
-                       ERROR("Failed to get cgroup for controller %s", 
slist[i]);
-                       cgm_dbus_disconnect();
-                       return false;
-               }
-
-               if (!lxc_cgmanager_enter(pid, slist[i], cgroup, 
abs_cgroup_supported())) {
-                       pass = false;
-                       break;
-               }
-
-       }
-       cgm_dbus_disconnect();
-       if (!pass)
-               ERROR("Failed to enter group %s", cgroup);
-
-       free_abs_cgroup(cgroup);
-       return pass;
-}
-
-static bool cgm_bind_dir(const char *root, const char *dirname)
-{
-       nih_local char *cgpath = NULL;
-
-       /* /sys should have been mounted by now */
-       cgpath = NIH_MUST( nih_strdup(NULL, root) );
-       NIH_MUST( nih_strcat(&cgpath, NULL, "/sys/fs/cgroup") );
-
-       if (!dir_exists(cgpath)) {
-               ERROR("%s does not exist", cgpath);
-               return false;
-       }
-
-       /* mount a tmpfs there so we can create subdirs */
-       if (safe_mount("cgroup", cgpath, "tmpfs", 0, "size=10000,mode=755", 
root)) {
-               SYSERROR("Failed to mount tmpfs at %s", cgpath);
-               return false;
-       }
-       NIH_MUST( nih_strcat(&cgpath, NULL, "/cgmanager") );
-
-       if (mkdir(cgpath, 0755) < 0) {
-               SYSERROR("Failed to create %s", cgpath);
-               return false;
-       }
-
-       if (safe_mount(dirname, cgpath, "none", MS_BIND, 0, root)) {
-               SYSERROR("Failed to bind mount %s to %s", dirname, cgpath);
-               return false;
-       }
-
-       return true;
-}
-
-/*
- * cgm_mount_cgroup:
- * If /sys/fs/cgroup/cgmanager.lower/ exists, bind mount that to
- * /sys/fs/cgroup/cgmanager/ in the container.
- * Otherwise, if /sys/fs/cgroup/cgmanager exists, bind mount that.
- * Else do nothing
- */
-#define CGMANAGER_LOWER_SOCK "/sys/fs/cgroup/cgmanager.lower"
-#define CGMANAGER_UPPER_SOCK "/sys/fs/cgroup/cgmanager"
-static bool cgm_mount_cgroup(void *hdata, const char *root, int type)
-{
-       if (dir_exists(CGMANAGER_LOWER_SOCK))
-               return cgm_bind_dir(root, CGMANAGER_LOWER_SOCK);
-       if (dir_exists(CGMANAGER_UPPER_SOCK))
-               return cgm_bind_dir(root, CGMANAGER_UPPER_SOCK);
-       /* Host doesn't have cgmanager running?  Then how did we get here? */
-       return false;
-}
-
-static struct cgroup_ops cgmanager_ops = {
-       .init = cgm_init,
-       .destroy = cgm_destroy,
-       .create = cgm_create,
-       .enter = cgm_enter,
-       .create_legacy = NULL,
-       .get_cgroup = cgm_get_cgroup,
-       .escape = cgm_escape,
-       .num_hierarchies = cgm_num_hierarchies,
-       .get_hierarchies = cgm_get_hierarchies,
-       .get = cgm_get,
-       .set = cgm_set,
-       .unfreeze = cgm_unfreeze,
-       .setup_limits = cgm_setup_limits,
-       .name = "cgmanager",
-       .chown = cgm_chown,
-       .attach = cgm_attach,
-       .mount_cgroup = cgm_mount_cgroup,
-       .nrtasks = cgm_get_nrtasks,
-       .disconnect = NULL,
-       .driver = CGMANAGER,
-};
-#endif
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to