- Add attach test cases

- Moved setting of LSM label later to avoid failure of IPC between parent
  and child during attach

Signed-off-by: Dwight Engen <dwight.en...@oracle.com>
---
v2: detect which lsm to test at runtime vs. compile time

 .gitignore                     |   1 +
 src/lxc/attach.c               |  20 ++-
 src/lxc/attach_options.h       |   5 +-
 src/lxc/lsm/apparmor.c         |  25 +--
 src/lxc/lsm/lsm.c              |   4 +-
 src/lxc/lsm/lsm.h              |   7 +-
 src/lxc/lsm/nop.c              |   3 +-
 src/lxc/lsm/selinux.c          |  22 ++-
 src/lxc/lxc_attach.c           |   2 +-
 src/lxc/start.c                |   8 +-
 src/python-lxc/lxc.c           |   3 +-
 src/python-lxc/lxc/__init__.py |   3 +-
 src/tests/Makefile.am          |  11 +-
 src/tests/attach.c             | 392 +++++++++++++++++++++++++++++++++++++++++
 14 files changed, 463 insertions(+), 43 deletions(-)
 create mode 100644 src/tests/attach.c

diff --git a/.gitignore b/.gitignore
index df8d5e1..b1223cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,6 +77,7 @@ src/lxc/lxc-user-nic
 src/python-lxc/build/
 src/python-lxc/lxc/__pycache__/
 
+src/tests/lxc-test-attach
 src/tests/lxc-test-cgpath
 src/tests/lxc-test-clonetest
 src/tests/lxc-test-concurrent
diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 37cefb0..aea0c33 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -918,15 +918,6 @@ int attach_child_main(void* data)
                rexit(-1);
        }
 
-       /* load apparmor profile */
-       if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & 
LXC_ATTACH_APPARMOR)) {
-               ret = lsm_process_label_set(init_ctx->lsm_label, 0);
-               if (ret < 0) {
-                       shutdown(ipc_socket, SHUT_RDWR);
-                       rexit(-1);
-               }
-       }
-
        /* A description of the purpose of this functionality is
         * provided in the lxc-attach(1) manual page. We have to
         * remount here and not in the parent process, otherwise
@@ -1023,6 +1014,17 @@ int attach_child_main(void* data)
 
        shutdown(ipc_socket, SHUT_RDWR);
        close(ipc_socket);
+
+       /* set new apparmor profile/selinux context */
+       if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & 
LXC_ATTACH_LSM)) {
+               int on_exec;
+
+               on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0;
+               ret = lsm_process_label_set(init_ctx->lsm_label, 0, on_exec);
+               if (ret < 0) {
+                       rexit(-1);
+               }
+       }
        lxc_proc_put_context_info(init_ctx);
 
        /* The following is done after the communication socket is
diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h
index 5291e4f..c8c4d0a 100644
--- a/src/lxc/attach_options.h
+++ b/src/lxc/attach_options.h
@@ -36,10 +36,11 @@ enum {
        LXC_ATTACH_MOVE_TO_CGROUP        = 0x00000001,
        LXC_ATTACH_DROP_CAPABILITIES     = 0x00000002,
        LXC_ATTACH_SET_PERSONALITY       = 0x00000004,
-       LXC_ATTACH_APPARMOR              = 0x00000008,
+       LXC_ATTACH_LSM_EXEC              = 0x00000008,
 
        /* the following are off by default */
        LXC_ATTACH_REMOUNT_PROC_SYS      = 0x00010000,
+       LXC_ATTACH_LSM_NOW               = 0x00020000,
 
        /* we have 16 bits for things that are on by default
         * and 16 bits that are off by default, that should
@@ -49,6 +50,8 @@ enum {
        LXC_ATTACH_DEFAULT               = 0x0000FFFF
 };
 
+#define LXC_ATTACH_LSM (LXC_ATTACH_LSM_EXEC | LXC_ATTACH_LSM_NOW)
+
 typedef struct lxc_attach_options_t lxc_attach_options_t;
 typedef int (*lxc_attach_exec_t)(void* payload);
 
diff --git a/src/lxc/lsm/apparmor.c b/src/lxc/lsm/apparmor.c
index 146564f..cf8020d 100644
--- a/src/lxc/lsm/apparmor.c
+++ b/src/lxc/lsm/apparmor.c
@@ -130,13 +130,14 @@ static int apparmor_am_unconfined(void)
  *
  * @label   : the profile to set
  * @default : use the default profile if label is NULL
+ * @on_exec : the new profile will take effect on exec(2) not immediately
  *
  * Returns 0 on success, < 0 on failure
  *
- * Notes: This relies on /proc being available. The new context
- * will take effect immediately.
+ * Notes: This relies on /proc being available.
  */
-static int apparmor_process_label_set(const char *label, int use_default)
+static int apparmor_process_label_set(const char *label, int use_default,
+                                     int on_exec)
 {
        if (!apparmor_enabled())
                return 0;
@@ -153,15 +154,19 @@ static int apparmor_process_label_set(const char *label, 
int use_default)
                return 0;
        }
 
-       /* XXX: instant instead of aa_change_onexec(), may be used by attach
-        * when using a function that doesn't exec
-        */
-       if (aa_change_profile(label) < 0) {
-               SYSERROR("failed to change apparmor profile to %s", label);
-               return -1;
+       if (on_exec) {
+               if (aa_change_onexec(label) < 0) {
+                       SYSERROR("failed to change exec apparmor profile to 
%s", label);
+                       return -1;
+               }
+       } else {
+               if (aa_change_profile(label) < 0) {
+                       SYSERROR("failed to change apparmor profile to %s", 
label);
+                       return -1;
+               }
        }
 
-       INFO("changed apparmor profile to %s", label);
+       INFO("changed apparmor%s profile to %s", on_exec ? " exec" : "", label);
        return 0;
 }
 
diff --git a/src/lxc/lsm/lsm.c b/src/lxc/lsm/lsm.c
index 508d640..9273101 100644
--- a/src/lxc/lsm/lsm.c
+++ b/src/lxc/lsm/lsm.c
@@ -85,13 +85,13 @@ char *lsm_process_label_get(pid_t pid)
        return drv->process_label_get(pid);
 }
 
-int lsm_process_label_set(const char *label, int use_default)
+int lsm_process_label_set(const char *label, int use_default, int on_exec)
 {
        if (!drv) {
                ERROR("LSM driver not inited");
                return -1;
        }
-       return drv->process_label_set(label, use_default);
+       return drv->process_label_set(label, use_default, on_exec);
 }
 
 /*
diff --git a/src/lxc/lsm/lsm.h b/src/lxc/lsm/lsm.h
index 5a6cf15..4128575 100644
--- a/src/lxc/lsm/lsm.h
+++ b/src/lxc/lsm/lsm.h
@@ -33,7 +33,8 @@ struct lsm_drv {
 
        int   (*enabled)(void);
        char *(*process_label_get)(pid_t pid);
-       int   (*process_label_set)(const char *label, int use_default);
+       int   (*process_label_set)(const char *label, int use_default,
+                                  int on_exec);
 };
 
 #if HAVE_APPARMOR || HAVE_SELINUX
@@ -41,7 +42,7 @@ void        lsm_init(void);
 int         lsm_enabled(void);
 const char *lsm_name(void);
 char       *lsm_process_label_get(pid_t pid);
-int         lsm_process_label_set(const char *label, int use_default);
+int         lsm_process_label_set(const char *label, int use_default, int 
on_exec);
 int         lsm_proc_mount(struct lxc_conf *lxc_conf);
 void        lsm_proc_unmount(struct lxc_conf *lxc_conf);
 #else
@@ -49,7 +50,7 @@ static inline void        lsm_init(void) { }
 static inline int         lsm_enabled(void) { return 0; }
 static inline const char *lsm_name(void) { return NULL; }
 static inline char       *lsm_process_label_get(pid_t pid) { return NULL; }
-static inline int         lsm_process_label_set(char *label, int use_default) 
{ return 0; }
+static inline int         lsm_process_label_set(char *label, int use_default, 
int on_exec) { return 0; }
 static inline int         lsm_proc_mount(struct lxc_conf *lxc_conf) { return 
0; }
 static inline void        lsm_proc_unmount(struct lxc_conf *lxc_conf) { }
 #endif
diff --git a/src/lxc/lsm/nop.c b/src/lxc/lsm/nop.c
index e39b0f5..e5db124 100644
--- a/src/lxc/lsm/nop.c
+++ b/src/lxc/lsm/nop.c
@@ -29,7 +29,8 @@ static char *nop_process_label_get(pid_t pid)
        return NULL;
 }
 
-static int nop_process_label_set(const char *label, int use_default)
+static int nop_process_label_set(const char *label, int use_default,
+                                int on_exec)
 {
        return 0;
 }
diff --git a/src/lxc/lsm/selinux.c b/src/lxc/lsm/selinux.c
index ef5beb0..b1b0253 100644
--- a/src/lxc/lsm/selinux.c
+++ b/src/lxc/lsm/selinux.c
@@ -61,13 +61,14 @@ static char *selinux_process_label_get(pid_t pid)
  *
  * @label   : the context to set
  * @default : use the default context if label is NULL
+ * @on_exec : the new context will take effect on exec(2) not immediately
  *
  * Returns 0 on success, < 0 on failure
  *
- * Notes: This relies on /proc being available. The new context
- * will take effect on the next exec(2).
+ * Notes: This relies on /proc being available.
  */
-static int selinux_process_label_set(const char *label, int use_default)
+static int selinux_process_label_set(const char *label, int use_default,
+                                    int on_exec)
 {
        if (!label) {
                if (use_default)
@@ -78,12 +79,19 @@ static int selinux_process_label_set(const char *label, int 
use_default)
        if (!strcmp(label, "unconfined_t"))
                return 0;
 
-       if (setexeccon_raw((char *)label) < 0) {
-               SYSERROR("failed to set new SELinux context %s", label);
-               return -1;
+       if (on_exec) {
+               if (setexeccon_raw((char *)label) < 0) {
+                       SYSERROR("failed to set new SELinux exec context %s", 
label);
+                       return -1;
+               }
+       } else {
+               if (setcon_raw((char *)label) < 0) {
+                       SYSERROR("failed to set new SELinux context %s", label);
+                       return -1;
+               }
        }
 
-       INFO("changed SELinux context to %s", label);
+       INFO("changed SELinux%s context to %s", on_exec ? " exec" : "", label);
        return 0;
 }
 
diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c
index bd4e674..142d605 100644
--- a/src/lxc/lxc_attach.c
+++ b/src/lxc/lxc_attach.c
@@ -199,7 +199,7 @@ int main(int argc, char *argv[])
        if (remount_sys_proc)
                attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS;
        if (elevated_privileges)
-               attach_options.attach_flags &= ~(LXC_ATTACH_MOVE_TO_CGROUP | 
LXC_ATTACH_DROP_CAPABILITIES | LXC_ATTACH_APPARMOR);
+               attach_options.attach_flags &= ~(LXC_ATTACH_MOVE_TO_CGROUP | 
LXC_ATTACH_DROP_CAPABILITIES | LXC_ATTACH_LSM_EXEC);
        attach_options.namespaces = namespace_flags;
        attach_options.personality = new_personality;
        attach_options.env_policy = env_policy;
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 7538403..2bf417e 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -556,14 +556,10 @@ static int do_start(void *data)
        if (lxc_sync_barrier_parent(handler, LXC_SYNC_CGROUP))
                return -1;
 
-       /* XXX: hmm apparmor switches right away since it uses
-        * aa_change_profile() and not aa_change_onexec(). SELinux on the other
-        * hand is going to transition on exec(). Is it bad to run the stuff
-        * between here and exec() in the more privileged context?
-        */
+       /* Set the label to change to when we exec(2) the container's init */
        if (lsm_process_label_set(handler->conf->lsm_aa_profile ?
                                  handler->conf->lsm_aa_profile :
-                                 handler->conf->lsm_se_context, 1) < 0)
+                                 handler->conf->lsm_se_context, 1, 1) < 0)
                goto out_warn_father;
        lsm_proc_unmount(handler->conf);
 
diff --git a/src/python-lxc/lxc.c b/src/python-lxc/lxc.c
index b6e0804..e42ed35 100644
--- a/src/python-lxc/lxc.c
+++ b/src/python-lxc/lxc.c
@@ -1268,7 +1268,8 @@ PyInit__lxc(void)
     PYLXC_EXPORT_CONST(LXC_ATTACH_MOVE_TO_CGROUP);
     PYLXC_EXPORT_CONST(LXC_ATTACH_DROP_CAPABILITIES);
     PYLXC_EXPORT_CONST(LXC_ATTACH_SET_PERSONALITY);
-    PYLXC_EXPORT_CONST(LXC_ATTACH_APPARMOR);
+    PYLXC_EXPORT_CONST(LXC_ATTACH_LSM_NOW);
+    PYLXC_EXPORT_CONST(LXC_ATTACH_LSM_EXEC);
     PYLXC_EXPORT_CONST(LXC_ATTACH_REMOUNT_PROC_SYS);
     PYLXC_EXPORT_CONST(LXC_ATTACH_DEFAULT);
 
diff --git a/src/python-lxc/lxc/__init__.py b/src/python-lxc/lxc/__init__.py
index 6a29903..8ae7852 100644
--- a/src/python-lxc/lxc/__init__.py
+++ b/src/python-lxc/lxc/__init__.py
@@ -472,7 +472,8 @@ LXC_ATTACH_CLEAR_ENV = _lxc.LXC_ATTACH_CLEAR_ENV
 LXC_ATTACH_MOVE_TO_CGROUP = _lxc.LXC_ATTACH_MOVE_TO_CGROUP
 LXC_ATTACH_DROP_CAPABILITIES = _lxc.LXC_ATTACH_DROP_CAPABILITIES
 LXC_ATTACH_SET_PERSONALITY = _lxc.LXC_ATTACH_SET_PERSONALITY
-LXC_ATTACH_APPARMOR = _lxc.LXC_ATTACH_APPARMOR
+LXC_ATTACH_LSM_NOW = _lxc.LXC_ATTACH_LSM_NOW
+LXC_ATTACH_LSM_EXEC = _lxc.LXC_ATTACH_LSM_EXEC
 LXC_ATTACH_REMOUNT_PROC_SYS = _lxc.LXC_ATTACH_REMOUNT_PROC_SYS
 LXC_ATTACH_DEFAULT = _lxc.LXC_ATTACH_DEFAULT
 CLONE_NEWUTS = _lxc.CLONE_NEWUTS
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index 509e414..cae82bf 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -22,6 +22,7 @@ lxc_test_concurrent_SOURCES = concurrent.c
 lxc_test_may_control_SOURCES = may_control.c
 lxc_test_reboot_SOURCES = reboot.c
 lxc_test_list_SOURCES = list.c
+lxc_test_attach_SOURCES = attach.c
 
 AM_CFLAGS=-I$(top_srcdir)/src \
        -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
@@ -30,12 +31,20 @@ AM_CFLAGS=-I$(top_srcdir)/src \
        -DLXCINITDIR=\"$(LXCINITDIR)\" \
        -DLXC_DEFAULT_CONFIG=\"$(LXC_DEFAULT_CONFIG)\"
 
+if ENABLE_APPARMOR
+AM_CFLAGS += -DHAVE_APPARMOR
+endif
+
+if ENABLE_SELINUX
+AM_CFLAGS += -DHAVE_SELINUX
+endif
+
 bin_PROGRAMS = lxc-test-containertests lxc-test-locktests lxc-test-startone \
        lxc-test-destroytest lxc-test-saveconfig lxc-test-createtest \
        lxc-test-shutdowntest lxc-test-get_item lxc-test-getkeys 
lxc-test-lxcpath \
        lxc-test-cgpath lxc-test-clonetest lxc-test-console lxc-usernic-test \
        lxc-test-snapshot lxc-test-concurrent lxc-test-may-control \
-       lxc-test-reboot lxc-test-list
+       lxc-test-reboot lxc-test-list lxc-test-attach
 
 bin_SCRIPTS = lxc-test-usernic
 
diff --git a/src/tests/attach.c b/src/tests/attach.c
new file mode 100644
index 0000000..54650bd
--- /dev/null
+++ b/src/tests/attach.c
@@ -0,0 +1,392 @@
+/* liblxcapi
+ *
+ * Copyright © 2013 Oracle.
+ *
+ * Authors:
+ * Dwight Engen <dwight.en...@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <lxc/lxccontainer.h>
+#include <lxc/utils.h>
+#include <lxc/lsm/lsm.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#define TSTNAME    "lxc-attach-test"
+#define TSTERR(fmt, ...) do { \
+       fprintf(stderr, "%s:%d " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
+} while (0)
+
+#if HAVE_APPARMOR || HAVE_SELINUX
+static const char *lsm_config_key = NULL;
+static const char *lsm_label = NULL;
+
+static void test_lsm_detect(void)
+{
+       if (lsm_enabled()) {
+               if (!strcmp(lsm_name(), "SELinux")) {
+                       lsm_config_key = "lxc.se_context";
+                       lsm_label      = 
"unconfined_u:unconfined_r:lxc_t:s0-s0:c0.c1023";
+               }
+               else if (!strcmp(lsm_name(), "AppArmor")) {
+                       lsm_config_key = "lxc.aa_profile";
+                       lsm_label      = "lxc-container-default";
+               }
+               else {
+                       TSTERR("unknown lsm %s enabled, add test code here", 
lsm_name());
+                       exit(EXIT_FAILURE);
+               }
+       }
+}
+
+static void test_attach_lsm_set_config(struct lxc_container *ct)
+{
+       ct->load_config(ct, NULL);
+       ct->set_config_item(ct, lsm_config_key, lsm_label);
+       ct->save_config(ct, NULL);
+}
+
+static int test_attach_lsm_func_func(void* payload)
+{
+       printf("%s", lsm_process_label_get(getpid()));
+       return 0;
+}
+
+static int test_attach_lsm_func(struct lxc_container *ct)
+{
+       int ret;
+       pid_t pid;
+       int pipefd[2];
+       char result[1024];
+       lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
+
+       printf("Testing attach lsm label with func...\n");
+
+       ret = pipe(pipefd);
+       if (ret < 0) {
+               TSTERR("pipe failed %d", ret);
+               return ret;
+       }
+       attach_options.stdout_fd = pipefd[1];
+       attach_options.attach_flags &= 
~(LXC_ATTACH_LSM_EXEC|LXC_ATTACH_DROP_CAPABILITIES);
+       attach_options.attach_flags |= LXC_ATTACH_LSM_NOW;
+       ret = ct->attach(ct, test_attach_lsm_func_func, NULL, &attach_options, 
&pid);
+       if (ret < 0) {
+               TSTERR("attach failed");
+               goto err1;
+       }
+
+       ret = read(pipefd[0], result, sizeof(result)-1);
+       if (ret < 0) {
+               TSTERR("read failed %d", ret);
+               goto err2;
+       }
+
+       result[ret] = '\0';
+       if (strcmp(lsm_label, result)) {
+               TSTERR("LSM label mismatch expected:%s got:%s", lsm_label, 
result);
+               ret = -1;
+               goto err2;
+       }
+       ret = 0;
+
+err2:
+       wait_for_pid(pid);
+err1:
+       close(pipefd[0]);
+       close(pipefd[1]);
+       return ret;
+}
+
+static int test_attach_lsm_cmd(struct lxc_container *ct)
+{
+       int ret;
+       pid_t pid;
+       int pipefd[2];
+       char result[1024];
+       char *space;
+       char *argv[] = {"cat", "/proc/self/attr/current", NULL};
+       lxc_attach_command_t command = {"cat", argv};
+       lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
+
+       printf("Testing attach lsm label with cmd...\n");
+
+       ret = pipe(pipefd);
+       if (ret < 0) {
+               TSTERR("pipe failed %d", ret);
+               return ret;
+       }
+       attach_options.stdout_fd = pipefd[1];
+
+       ret = ct->attach(ct, lxc_attach_run_command, &command, &attach_options, 
&pid);
+       if (ret < 0) {
+               TSTERR("attach failed");
+               goto err1;
+       }
+
+       ret = read(pipefd[0], result, sizeof(result)-1);
+       if (ret < 0) {
+               TSTERR("read failed %d", ret);
+               goto err2;
+       }
+       result[ret] = '\0';
+       space = index(result, '\n');
+       if (space)
+               *space = '\0';
+       space = index(result, ' ');
+       if (space)
+               *space = '\0';
+
+       ret = -1;
+       if (strcmp(lsm_label, result)) {
+               TSTERR("LSM label mismatch expected:%s got:%s", lsm_label, 
result);
+               goto err2;
+       }
+       ret = 0;
+
+err2:
+       wait_for_pid(pid);
+err1:
+       close(pipefd[0]);
+       close(pipefd[1]);
+       return ret;
+}
+#else
+static void test_attach_lsm_set_config(struct lxc_container *ct) {}
+static int  test_attach_lsm_func(struct lxc_container *ct) { return 0; }
+static int  test_attach_lsm_cmd(struct lxc_container *ct) { return 0; }
+#endif /* HAVE_APPARMOR || HAVE_SELINUX */
+
+static int test_attach_func_func(void* payload)
+{
+       printf("%d", getpid());
+       return 0;
+}
+
+static int test_attach_func(struct lxc_container *ct)
+{
+       int ret;
+       pid_t pid,nspid;
+       int pipefd[2];
+       char result[1024];
+       lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
+
+       printf("Testing attach with func...\n");
+
+       /* XXX: We can't just use &nspid and have test_attach_func_func fill
+        * it in because the function doesn't run in our process context but
+        * in a fork()ed from us context. We read the result through a pipe.
+        */
+       ret = pipe(pipefd);
+       if (ret < 0) {
+               TSTERR("pipe failed %d", ret);
+               return ret;
+       }
+       attach_options.stdout_fd = pipefd[1];
+
+       ret = ct->attach(ct, test_attach_func_func, NULL, &attach_options, 
&pid);
+       if (ret < 0) {
+               TSTERR("attach failed");
+               goto err1;
+       }
+
+       ret = read(pipefd[0], result, sizeof(result)-1);
+       if (ret < 0) {
+               TSTERR("read failed %d", ret);
+               goto err2;
+       }
+       result[ret] = '\0';
+
+       /* There is a small chance the pid is reused inside the NS, so we
+        * just print it and don't actually do this check
+        *
+        * if (pid == nspid) TSTERR(...)
+        */
+       nspid = atoi(result);
+       printf("Pid:%d in NS:%d\n", pid, nspid);
+       ret = 0;
+
+err2:
+       wait_for_pid(pid);
+err1:
+       close(pipefd[0]);
+       close(pipefd[1]);
+       return ret;
+}
+
+static int test_attach_cmd(struct lxc_container *ct)
+{
+       int ret;
+       pid_t pid;
+       char *argv[] = {"cmp", "-s", "/sbin/init", "/bin/busybox", NULL};
+       lxc_attach_command_t command = {"cmp", argv};
+       lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
+
+       printf("Testing attach with success command...\n");
+       ret = ct->attach(ct, lxc_attach_run_command, &command, &attach_options, 
&pid);
+       if (ret < 0) {
+               TSTERR("attach failed");
+               return ret;
+       }
+
+       ret = wait_for_pid(pid);
+       if (ret < 0) {
+               TSTERR("attach success command got bad return %d", ret);
+               return ret;
+       }
+
+       printf("Testing attach with failure command...\n");
+       argv[2] = "/etc/fstab";
+       ret = ct->attach(ct, lxc_attach_run_command, &command, &attach_options, 
&pid);
+       if (ret < 0) {
+               TSTERR("attach failed");
+               return ret;
+       }
+
+       ret = wait_for_pid(pid);
+       if (ret == 0) {
+               TSTERR("attach failure command got bad return %d", ret);
+               return -1;
+       }
+       return 0;
+}
+
+/* test_ct_destroy: stop and destroy the test container
+ *
+ * @ct       : the container
+ */
+static void test_ct_destroy(struct lxc_container *ct)
+{
+       ct->stop(ct);
+       ct->destroy(ct);
+       lxc_container_put(ct);
+}
+
+/* test_ct_create: create and start test container
+ *
+ * @lxcpath  : the lxcpath in which to create the container
+ * @group    : name of the container group or NULL for default "lxc"
+ * @name     : name of the container
+ * @template : template to use when creating the container
+ */
+static struct lxc_container *test_ct_create(const char *lxcpath,
+                               const char *group, const char *name,
+                               const char *template)
+{
+       int ret;
+       struct lxc_container *ct = NULL;
+
+       if (lxcpath) {
+               ret = mkdir(lxcpath, 0755);
+               if (ret < 0 && errno != EEXIST) {
+                       TSTERR("failed to mkdir %s %s", lxcpath, 
strerror(errno));
+                       goto out1;
+               }
+       }
+
+       if ((ct = lxc_container_new(name, lxcpath)) == NULL) {
+               TSTERR("instantiating container %s", name);
+               goto out1;
+       }
+       if (ct->is_defined(ct)) {
+               ct->stop(ct);
+               ct->destroy(ct);
+               ct = lxc_container_new(name, lxcpath);
+       }
+       if (!ct->createl(ct, template, NULL, NULL, 0, NULL)) {
+               TSTERR("creating container %s", name);
+               goto out2;
+       }
+
+       if (lsm_enabled())
+               test_attach_lsm_set_config(ct);
+
+       ct->want_daemonize(ct);
+       if (!ct->startl(ct, 0, NULL)) {
+               TSTERR("starting container %s", name);
+               goto out2;
+       }
+       return ct;
+
+out2:
+       test_ct_destroy(ct);
+       ct = NULL;
+out1:
+       return ct;
+}
+
+
+int test_attach(const char *lxcpath, const char *name, const char *template)
+{
+       int ret = -1;
+       struct lxc_container *ct;
+
+       printf("Testing attach with on lxcpath:%s\n", lxcpath ? lxcpath : 
"<default>");
+       ct = test_ct_create(lxcpath, NULL, name, template);
+       if (!ct)
+               goto err1;
+
+       ret = test_attach_cmd(ct);
+       if (ret < 0) {
+               TSTERR("attach cmd test failed");
+               goto err2;
+       }
+
+       ret = test_attach_func(ct);
+       if (ret < 0) {
+               TSTERR("attach func test failed");
+               goto err2;
+       }
+
+       if (lsm_enabled()) {
+               ret = test_attach_lsm_cmd(ct);
+               if (ret < 0) {
+                       TSTERR("attach lsm cmd test failed");
+                       goto err2;
+               }
+
+               ret = test_attach_lsm_func(ct);
+               if (ret < 0) {
+                       TSTERR("attach lsm func test failed");
+                       goto err2;
+               }
+       }
+       ret = 0;
+
+err2:
+       test_ct_destroy(ct);
+err1:
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       int ret;
+
+       test_lsm_detect();
+       ret = test_attach(NULL, TSTNAME, "busybox");
+       if (ret < 0)
+               return EXIT_FAILURE;
+
+       printf("\n");
+       ret = test_attach(LXCPATH "/alternate-path-test", TSTNAME, "busybox");
+       if (ret < 0)
+               return EXIT_FAILURE;
+
+       printf("All tests passed\n");
+       return EXIT_SUCCESS;
+}
-- 
1.8.3.1


------------------------------------------------------------------------------
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60135031&iu=/4140/ostg.clktrk
_______________________________________________
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel

Reply via email to