Commit 72d0e1cb by Stéphane Graber

Merge the liblxc API work by Serge Hallyn.

This turns liblxc into a public library implementing a container structure. The container structure is meant to cover most LXC commands and can easily be used to write bindings in other programming languages. More information on the new functions can be found in src/lxc/lxccontainer.h Test programs using the API can also be found in src/tests/ Signed-off-by: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com> Acked-by: 's avatarStéphane Graber <stgraber@ubuntu.com>
parent 7a0b0b56
...@@ -192,6 +192,8 @@ AC_CONFIG_FILES([ ...@@ -192,6 +192,8 @@ AC_CONFIG_FILES([
src/lxc/lxc-shutdown src/lxc/lxc-shutdown
src/lxc/lxc-destroy src/lxc/lxc-destroy
src/tests/Makefile
]) ])
AC_CONFIG_COMMANDS([default],[[]],[[]]) AC_CONFIG_COMMANDS([default],[[]],[[]])
AC_OUTPUT AC_OUTPUT
......
READMEdir=@LXCROOTFSMOUNT@ READMEdir=@LXCROOTFSMOUNT@
README_DATA=README README_DATA=
\ No newline at end of file
#!/bin/bash
cleanup() {
rm -f /etc/lxc/test-busybox.conf
rm -f liblxc.so.0
}
if [ `id -u` -ne 0 ]; then
echo "Run as root"
exit 1
fi
cat > /etc/lxc/test-busybox.conf << EOF
lxc.network.type=veth
lxc.network.link=lxcbr0
lxc.network.flags=up
EOF
[ -f liblxc.so.0 ] || ln -s src/lxc/liblxc.so ./liblxc.so.0
export LD_LIBRARY_PATH=.
TESTS="containertests locktests startone"
for curtest in $TESTS; do
echo "running $curtest"
./src/tests/$curtest
if [ $? -ne 0 ]; then
echo "Test $curtest failed. Stopping"
cleanup
exit 1
fi
done
echo "All tests passed"
cleanup
#!/bin/bash
cleanup() {
rm -f /etc/lxc/test-busybox.conf
rm -f liblxc.so.0
}
if [ `id -u` -ne 0 ]; then
echo "Run as root"
exit 1
fi
cat > /etc/lxc/test-busybox.conf << EOF
lxc.network.type=veth
lxc.network.link=lxcbr0
lxc.network.flags=up
EOF
[ -f liblxc.so.0 ] || ln -s src/lxc/liblxc.so ./liblxc.so.0
export LD_LIBRARY_PATH=.
TESTS="containertests locktests startone"
for curtest in $TESTS; do
echo "running $curtest"
./src/tests/$curtest
if [ $? -ne 0 ]; then
echo "Test $curtest failed. Stopping"
cleanup
exit 1
fi
done
echo "All tests passed"
cleanup
SUBDIRS = lxc SUBDIRS = lxc tests
...@@ -13,7 +13,9 @@ pkginclude_HEADERS = \ ...@@ -13,7 +13,9 @@ pkginclude_HEADERS = \
list.h \ list.h \
log.h \ log.h \
state.h \ state.h \
attach.h attach.h \
lxccontainer.h \
lxclock.h
sodir=$(libdir) sodir=$(libdir)
# use PROGRAMS to avoid complains from automake # use PROGRAMS to avoid complains from automake
...@@ -55,12 +57,15 @@ liblxc_so_SOURCES = \ ...@@ -55,12 +57,15 @@ liblxc_so_SOURCES = \
af_unix.c af_unix.h \ af_unix.c af_unix.h \
\ \
utmp.c utmp.h \ utmp.c utmp.h \
apparmor.c apparmor.h apparmor.c apparmor.h \
lxclock.h lxclock.c \
lxccontainer.c lxccontainer.h
AM_CFLAGS=-I$(top_srcdir)/src \ AM_CFLAGS=-I$(top_srcdir)/src \
-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \ -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
-DLXCPATH=\"$(LXCPATH)\" \ -DLXCPATH=\"$(LXCPATH)\" \
-DLXCINITDIR=\"$(LXCINITDIR)\" -DLXCINITDIR=\"$(LXCINITDIR)\" \
-DLXCTEMPLATEDIR=\"$(LXCTEMPLATEDIR)\"
if ENABLE_APPARMOR if ENABLE_APPARMOR
AM_CFLAGS += -DHAVE_APPARMOR AM_CFLAGS += -DHAVE_APPARMOR
...@@ -77,7 +82,7 @@ liblxc_so_LDFLAGS = \ ...@@ -77,7 +82,7 @@ liblxc_so_LDFLAGS = \
-shared \ -shared \
-Wl,-soname,liblxc.so.$(firstword $(subst ., ,$(VERSION))) -Wl,-soname,liblxc.so.$(firstword $(subst ., ,$(VERSION)))
liblxc_so_LDADD = -lutil $(CAP_LIBS) $(APPARMOR_LIBS) $(SECCOMP_LIBS) liblxc_so_LDADD = -lutil $(CAP_LIBS) $(APPARMOR_LIBS) $(SECCOMP_LIBS) -lrt
bin_SCRIPTS = \ bin_SCRIPTS = \
lxc-ps \ lxc-ps \
...@@ -116,7 +121,7 @@ AM_LDFLAGS = -Wl,-E ...@@ -116,7 +121,7 @@ AM_LDFLAGS = -Wl,-E
if ENABLE_RPATH if ENABLE_RPATH
AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir) AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir)
endif endif
LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@ @SECCOMP_LIBS@ LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@ @SECCOMP_LIBS@ -lrt
lxc_attach_SOURCES = lxc_attach.c lxc_attach_SOURCES = lxc_attach.c
lxc_cgroup_SOURCES = lxc_cgroup.c lxc_cgroup_SOURCES = lxc_cgroup.c
......
...@@ -327,5 +327,6 @@ extern int lxc_command_mainloop_add(const char *name, ...@@ -327,5 +327,6 @@ extern int lxc_command_mainloop_add(const char *name,
close(fd); close(fd);
} }
handler->conf->maincmd_fd = fd;
return ret; return ret;
} }
...@@ -109,6 +109,9 @@ lxc_log_define(lxc_conf, lxc); ...@@ -109,6 +109,9 @@ lxc_log_define(lxc_conf, lxc);
#define PR_CAPBSET_DROP 24 #define PR_CAPBSET_DROP 24
#endif #endif
char *lxchook_names[NUM_LXC_HOOKS] = {
"pre-start", "mount", "start", "post-stop" };
extern int pivot_root(const char * new_root, const char * put_old); extern int pivot_root(const char * new_root, const char * put_old);
typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *); typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *);
...@@ -1661,7 +1664,7 @@ static int setup_netdev(struct lxc_netdev *netdev) ...@@ -1661,7 +1664,7 @@ static int setup_netdev(struct lxc_netdev *netdev)
ifname, strerror(-err)); ifname, strerror(-err));
if (netdev->ipv6_gateway_auto) { if (netdev->ipv6_gateway_auto) {
char buf[INET6_ADDRSTRLEN]; char buf[INET6_ADDRSTRLEN];
inet_ntop(AF_INET, netdev->ipv6_gateway, buf, sizeof(buf)); inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
ERROR("tried to set autodetected ipv6 gateway '%s'", buf); ERROR("tried to set autodetected ipv6 gateway '%s'", buf);
} }
return -1; return -1;
...@@ -2354,3 +2357,195 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf) ...@@ -2354,3 +2357,195 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf)
} }
return 0; return 0;
} }
static int lxc_remove_nic(struct lxc_list *it)
{
struct lxc_netdev *netdev = it->elem;
struct lxc_list *it2;
lxc_list_del(it);
if (netdev->link)
free(netdev->link);
if (netdev->name)
free(netdev->name);
if (netdev->upscript)
free(netdev->upscript);
if (netdev->hwaddr)
free(netdev->hwaddr);
if (netdev->mtu)
free(netdev->mtu);
if (netdev->ipv4_gateway)
free(netdev->ipv4_gateway);
if (netdev->ipv6_gateway)
free(netdev->ipv6_gateway);
lxc_list_for_each(it2, &netdev->ipv4) {
lxc_list_del(it2);
free(it2->elem);
free(it2);
}
lxc_list_for_each(it2, &netdev->ipv6) {
lxc_list_del(it2);
free(it2->elem);
free(it2);
}
free(it);
}
/* we get passed in something like '0', '0.ipv4' or '1.ipv6' */
int lxc_clear_nic(struct lxc_conf *c, char *key)
{
char *p1;
int ret, idx, i;
struct lxc_list *it;
struct lxc_netdev *netdev;
p1 = index(key, '.');
if (!p1 || *(p1+1) == '\0')
p1 = NULL;
ret = sscanf(key, "%d", &idx);
if (ret != 1) return -1;
if (idx < 0)
return -1;
i = 0;
lxc_list_for_each(it, &c->network) {
if (i == idx)
break;
i++;
}
if (i < idx) // we don't have that many nics defined
return -1;
if (!it || !it->elem)
return -1;
netdev = it->elem;
if (!p1) {
lxc_remove_nic(it);
} else if (strcmp(p1, "ipv4") == 0) {
struct lxc_list *it2;
lxc_list_for_each(it2, &netdev->ipv4) {
lxc_list_del(it2);
free(it2->elem);
free(it2);
}
} else if (strcmp(p1, "ipv6") == 0) {
struct lxc_list *it2;
lxc_list_for_each(it2, &netdev->ipv6) {
lxc_list_del(it2);
free(it2->elem);
free(it2);
}
} else if (strcmp(p1, "link") == 0) {
if (netdev->link) {
free(netdev->link);
netdev->link = NULL;
}
} else if (strcmp(p1, "name") == 0) {
if (netdev->name) {
free(netdev->name);
netdev->name = NULL;
}
} else if (strcmp(p1, "script.up") == 0) {
if (netdev->upscript) {
free(netdev->upscript);
netdev->upscript = NULL;
}
} else if (strcmp(p1, "hwaddr") == 0) {
if (netdev->hwaddr) {
free(netdev->hwaddr);
netdev->hwaddr = NULL;
}
} else if (strcmp(p1, "mtu") == 0) {
if (netdev->mtu) {
free(netdev->mtu);
netdev->mtu = NULL;
}
} else if (strcmp(p1, "ipv4_gateway") == 0) {
if (netdev->ipv4_gateway) {
free(netdev->ipv4_gateway);
netdev->ipv4_gateway = NULL;
}
} else if (strcmp(p1, "ipv6_gateway") == 0) {
if (netdev->ipv6_gateway) {
free(netdev->ipv6_gateway);
netdev->ipv6_gateway = NULL;
}
}
else return -1;
return 0;
}
int lxc_clear_config_network(struct lxc_conf *c)
{
struct lxc_list *it;
lxc_list_for_each(it, &c->network) {
lxc_remove_nic(it);
}
return 0;
}
int lxc_clear_config_caps(struct lxc_conf *c)
{
struct lxc_list *it;
lxc_list_for_each(it, &c->caps) {
lxc_list_del(it);
free(it->elem);
free(it);
}
return 0;
}
int lxc_clear_cgroups(struct lxc_conf *c, char *key)
{
struct lxc_list *it;
bool all = false;
char *k = key + 11;
if (strcmp(key, "lxc.cgroup") == 0)
all = true;
lxc_list_for_each(it, &c->cgroup) {
struct lxc_cgroup *cg = it->elem;
if (!all && strcmp(cg->subsystem, k) != 0)
continue;
lxc_list_del(it);
free(cg->subsystem);
free(cg->value);
free(cg);
free(it);
}
return 0;
}
int lxc_clear_mount_entries(struct lxc_conf *c)
{
struct lxc_list *it;
lxc_list_for_each(it, &c->mount_list) {
lxc_list_del(it);
free(it->elem);
free(it);
}
return 0;
}
int lxc_clear_hooks(struct lxc_conf *c)
{
struct lxc_list *it;
int i;
for (i=0; i<NUM_LXC_HOOKS; i++) {
lxc_list_for_each(it, &c->hooks[i]) {
lxc_list_del(it);
free(it->elem);
free(it);
}
}
return 0;
}
...@@ -209,6 +209,8 @@ struct lxc_rootfs { ...@@ -209,6 +209,8 @@ struct lxc_rootfs {
enum lxchooks { enum lxchooks {
LXCHOOK_PRESTART, LXCHOOK_MOUNT, LXCHOOK_START, LXCHOOK_PRESTART, LXCHOOK_MOUNT, LXCHOOK_START,
LXCHOOK_POSTSTOP, NUM_LXC_HOOKS}; LXCHOOK_POSTSTOP, NUM_LXC_HOOKS};
extern char *lxchook_names[NUM_LXC_HOOKS];
struct lxc_conf { struct lxc_conf {
char *fstab; char *fstab;
int tty; int tty;
...@@ -234,6 +236,7 @@ struct lxc_conf { ...@@ -234,6 +236,7 @@ struct lxc_conf {
int lsm_umount_proc; int lsm_umount_proc;
#endif #endif
char *seccomp; // filename with the seccomp rules char *seccomp; // filename with the seccomp rules
int maincmd_fd;
}; };
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf); int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
...@@ -253,6 +256,13 @@ extern int lxc_find_gateway_addresses(struct lxc_handler *handler); ...@@ -253,6 +256,13 @@ extern int lxc_find_gateway_addresses(struct lxc_handler *handler);
extern int lxc_create_tty(const char *name, struct lxc_conf *conf); extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
extern void lxc_delete_tty(struct lxc_tty_info *tty_info); extern void lxc_delete_tty(struct lxc_tty_info *tty_info);
extern int lxc_clear_config_network(struct lxc_conf *c);
extern int lxc_clear_nic(struct lxc_conf *c, char *key);
extern int lxc_clear_config_caps(struct lxc_conf *c);
extern int lxc_clear_cgroups(struct lxc_conf *c, char *key);
extern int lxc_clear_mount_entries(struct lxc_conf *c);
extern int lxc_clear_hooks(struct lxc_conf *c);
/* /*
* Configure the container from inside * Configure the container from inside
*/ */
......
...@@ -27,6 +27,15 @@ ...@@ -27,6 +27,15 @@
struct lxc_conf; struct lxc_conf;
struct lxc_list; struct lxc_list;
typedef int (*config_cb)(const char *, char *, struct lxc_conf *);
struct lxc_config_t {
char *name;
config_cb cb;
};
extern struct lxc_config_t *lxc_getconfig(const char *key);
extern int lxc_list_nicconfigs(struct lxc_conf *c, char *key, char *retv, int inlen);
extern int lxc_listconfigs(char *retv, int inlen);
extern int lxc_config_read(const char *file, struct lxc_conf *conf); extern int lxc_config_read(const char *file, struct lxc_conf *conf);
extern int lxc_config_readline(char *buffer, struct lxc_conf *conf); extern int lxc_config_readline(char *buffer, struct lxc_conf *conf);
...@@ -37,4 +46,7 @@ extern int lxc_config_define_load(struct lxc_list *defines, ...@@ -37,4 +46,7 @@ extern int lxc_config_define_load(struct lxc_list *defines,
/* needed for lxc-attach */ /* needed for lxc-attach */
extern signed long lxc_config_parse_arch(const char *arch); extern signed long lxc_config_parse_arch(const char *arch);
extern int lxc_get_config_item(struct lxc_conf *c, char *key, char *retv, int inlen);
extern int lxc_clear_config_item(struct lxc_conf *c, char *key);
extern void write_config(FILE *fout, struct lxc_conf *c);
#endif #endif
...@@ -84,6 +84,7 @@ extern int lxc_monitor_open(void); ...@@ -84,6 +84,7 @@ extern int lxc_monitor_open(void);
* data was readen, < 0 otherwise * data was readen, < 0 otherwise
*/ */
extern int lxc_monitor_read(int fd, struct lxc_msg *msg); extern int lxc_monitor_read(int fd, struct lxc_msg *msg);
extern int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout);
/* /*
* Close the fd associated with the monitoring * Close the fd associated with the monitoring
...@@ -178,6 +179,30 @@ extern int lxc_restart(const char *, int, struct lxc_conf *, int); ...@@ -178,6 +179,30 @@ extern int lxc_restart(const char *, int, struct lxc_conf *, int);
*/ */
extern const char const *lxc_version(void); extern const char const *lxc_version(void);
/*
* Create and return a new lxccontainer struct.
*/
extern struct lxc_container *lxc_container_new(char *name);
/*
* Returns 1 on success, 0 on failure.
*/
extern int lxc_container_get(struct lxc_container *c);
/*
* Put a lxccontainer struct reference.
* Return -1 on error.
* Return 0 if this was not the last reference.
* If it is the last reference, free the lxccontainer and return 1.
*/
extern int lxc_container_put(struct lxc_container *c);
/*
* Get a list of valid wait states.
* If states is NULL, simply return the number of states
*/
extern int lxc_get_wait_states(char **states);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
......
...@@ -77,25 +77,6 @@ Options :\n\ ...@@ -77,25 +77,6 @@ Options :\n\
.checker = my_checker, .checker = my_checker,
}; };
static int fillwaitedstates(char *strstates, int *states)
{
char *token, *saveptr = NULL;
int state;
token = strtok_r(strstates, "|", &saveptr);
while (token) {
state = lxc_str2state(token);
if (state < 0)
return -1;
states[state] = 1;
token = strtok_r(NULL, "|", &saveptr);
}
return 0;
}
static void timeout_handler(int signal) static void timeout_handler(int signal)
{ {
exit(-1); exit(-1);
...@@ -114,57 +95,5 @@ int main(int argc, char *argv[]) ...@@ -114,57 +95,5 @@ int main(int argc, char *argv[])
my_args.progname, my_args.quiet)) my_args.progname, my_args.quiet))
return -1; return -1;
if (fillwaitedstates(my_args.states, s)) return lxc_wait(my_args.name, my_args.states, my_args.timeout);
return -1;
fd = lxc_monitor_open();
if (fd < 0)
return -1;
/*
* if container present,
* then check if already in requested state
*/
ret = -1;
state = lxc_getstate(my_args.name);
if (state < 0) {
goto out_close;
} else if ((state >= 0) && (s[state])) {
ret = 0;
goto out_close;
}
signal(SIGALRM, timeout_handler);
alarm(my_args.timeout);
for (;;) {
if (lxc_monitor_read(fd, &msg) < 0)
goto out_close;
if (strcmp(my_args.name, msg.name))
continue;
switch (msg.type) {
case lxc_msg_state:
if (msg.value < 0 || msg.value >= MAX_STATE) {
ERROR("Receive an invalid state number '%d'",
msg.value);
goto out_close;
}
if (s[msg.value]) {
alarm(0);
ret = 0;
goto out_close;
}
break;
default:
/* just ignore garbage */
break;
}
}
out_close:
lxc_monitor_close(fd);
return ret;
} }
#include "lxclock.h"
#include <stdlib.h>
#include <malloc.h>
#include <stdbool.h>
struct lxc_container {
// private fields
char *name;
char *configfile;
sem_t *slock;
sem_t *privlock;
int numthreads; /* protected by privlock. */
struct lxc_conf *lxc_conf; // maybe we'll just want the whole lxc_handler?
// public fields
char *error_string;
int error_num;
int daemonize;
#define LXCDIR "/var/lib/lxc"
bool (*is_defined)(struct lxc_container *c); // did /var/lib/lxc/$name/config exist
const char *(*state)(struct lxc_container *c);
bool (*is_running)(struct lxc_container *c); // true so long as defined and not stopped
bool (*freeze)(struct lxc_container *c);
bool (*unfreeze)(struct lxc_container *c);
pid_t (*init_pid)(struct lxc_container *c);
bool (*load_config)(struct lxc_container *c, char *alt_file);
/* The '...' is the command line. If provided, it must be ended with a NULL */
bool (*start)(struct lxc_container *c, int useinit, char ** argv);
bool (*startl)(struct lxc_container *c, int useinit, ...);
bool (*stop)(struct lxc_container *c);
void (*want_daemonize)(struct lxc_container *c);
// Return current config file name. The result is strdup()d, so free the result.
char *(*config_file_name)(struct lxc_container *c);
// for wait, timeout == -1 means wait forever, timeout == 0 means don't wait.
// otherwise timeout is seconds to wait.
bool (*wait)(struct lxc_container *c, char *state, int timeout);
bool (*set_config_item)(struct lxc_container *c, char *key, char *value);
bool (*destroy)(struct lxc_container *c);
bool (*save_config)(struct lxc_container *c, char *alt_file);
bool (*create)(struct lxc_container *c, char *t, char **argv);
bool (*createl)(struct lxc_container *c, char *t, ...);
/* send SIGPWR. if timeout is not 0 or -1, do a hard stop after timeout seconds */
bool (*shutdown)(struct lxc_container *c, int timeout);
/* clear all network or capability items in the in-memory configuration */
bool (*clear_config_item)(struct lxc_container *c, char *key);
/* print a config item to a in-memory string allocated by the caller. Return
* the length which was our would be printed. */
int (*get_config_item)(struct lxc_container *c, char *key, char *retv, int inlen);
int (*get_keys)(struct lxc_container *c, char *key, char *retv, int inlen);
#if 0
bool (*commit_cgroups)(struct lxc_container *c);
bool (*reread_cgroups)(struct lxc_container *c);
// question with clone: how do we handle non-standard config file in orig?
struct lxc_container (*clone)(struct container *c);
int (*ns_attach)(struct lxc_container *c, int ns_mask);
// we'll need some plumbing to support lxc-console
#endif
};
struct lxc_container *lxc_container_new(char *name);
int lxc_container_get(struct lxc_container *c);
int lxc_container_put(struct lxc_container *c);
int lxc_get_wait_states(char **states);
#if 0
char ** lxc_get_valid_keys();
char ** lxc_get_valid_values(char *key);
#endif
/* liblxcapi
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "lxclock.h"
#include <malloc.h>
#define OFLAG (O_CREAT | O_RDWR)
#define SEMMODE 0660
#define SEMVALUE 1
#define SEMVALUE_LOCKED 0
#define LXCLOCK_PREFIX "/lxcapi."
static char *lxclock_name(char *container)
{
int ret;
int len = strlen(container) + strlen(LXCLOCK_PREFIX) + 1;
char *dest = malloc(len);
if (!dest)
return NULL;
ret = snprintf(dest, len, "%s%s", LXCLOCK_PREFIX, container);
if (ret < 0 || ret >= len) {
free(dest);
return NULL;
}
return dest;
}
static void lxcfree_name(char *name)
{
if (name)
free(name);
}
static sem_t *lxc_new_unnamed_sem(void)
{
sem_t *s;
int ret;
s = malloc(sizeof(*s));
if (!s)
return NULL;
ret = sem_init(s, 0, 1);
if (ret)
return NULL;
return s;
}
sem_t *lxc_newlock(char *name)
{
char *lname;
sem_t *lock;
if (!name)
return lxc_new_unnamed_sem();
lname = lxclock_name(name);
if (!lname)
return NULL;
lock = sem_open(lname, OFLAG, SEMMODE, SEMVALUE);
lxcfree_name(lname);
if (lock == SEM_FAILED)
return NULL;
return lock;
}
int lxclock(sem_t *sem, int timeout)
{
int ret;
if (!timeout) {
ret = sem_wait(sem);
} else {
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
return -2;
ts.tv_sec += timeout;
ret = sem_timedwait(sem, &ts);
}
return ret;
}
int lxcunlock(sem_t *sem)
{
if (!sem)
return -2;
return sem_post(sem);
}
/* liblxcapi
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <semaphore.h>
#include <string.h>
#include <time.h>
/*
* lxc_newlock:
* if name is not given, create an unnamed semaphore. We use these
* to protect against racing threads.
* Note that an unnamed sem was malloced by us and needs to be freed.
*
* If name is given, it is prepended with '/lxcapi.', and used as the
* name for a system-wide (well, ipcns-wide) semaphore. We use that
* to protect the containers as represented on disk.
* A named sem should not be freed.
*
* XXX TODO
* We should probably introduce a lxclock_close() which detecs the type
* of lock and calls sem_close() or sem_destroy()+free() not as appropriate.
* For now, it is up to the caller to do so.
*
* sem is initialized to value of 1
*
* return NULL on failure, else a sem_t * which can be passed to
* lxclock() and lxcunlock().
*/
extern sem_t *lxc_newlock(char *name);
/*
* lxclock: take an existing lock. If timeout is 0, wait
* indefinately. Otherwise use given timeout.
* return 0 if we got the lock, -2 on failure to set timeout, or -1
* otherwise in which case errno will be set by sem_wait()).
*/
extern int lxclock(sem_t *sem, int timeout);
/*
* lxcunlock: unlock given sem. Return 0 on success. Otherwise returns
* -1 and sem_post will leave errno set.
*/
extern int lxcunlock(sem_t *lock);
...@@ -98,11 +98,28 @@ int lxc_monitor_open(void) ...@@ -98,11 +98,28 @@ int lxc_monitor_open(void)
return fd; return fd;
} }
int lxc_monitor_read(int fd, struct lxc_msg *msg) /* timeout of 0 means return immediately; -1 means wait forever */
int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout)
{ {
struct sockaddr_un from; struct sockaddr_un from;
socklen_t len = sizeof(from); socklen_t len = sizeof(from);
int ret; int ret;
fd_set rfds;
struct timeval tv;
if (timeout != -1) {
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
tv.tv_sec = timeout;
tv.tv_usec = 0;
ret = select(fd+1, &rfds, NULL, NULL, &tv);
if (ret == -1)
return -1;
else if (!ret)
return -2; // timed out
}
ret = recvfrom(fd, msg, sizeof(*msg), 0, ret = recvfrom(fd, msg, sizeof(*msg), 0,
(struct sockaddr *)&from, &len); (struct sockaddr *)&from, &len);
...@@ -114,6 +131,11 @@ int lxc_monitor_read(int fd, struct lxc_msg *msg) ...@@ -114,6 +131,11 @@ int lxc_monitor_read(int fd, struct lxc_msg *msg)
return ret; return ret;
} }
int lxc_monitor_read(int fd, struct lxc_msg *msg)
{
return lxc_monitor_read_timeout(fd, msg, -1);
}
int lxc_monitor_close(int fd) int lxc_monitor_close(int fd)
{ {
return close(fd); return close(fd);
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include "nl.h" #include "nl.h"
#include "network.h" #include "network.h"
#include "conf.h"
#ifndef IFLA_LINKMODE #ifndef IFLA_LINKMODE
# define IFLA_LINKMODE 17 # define IFLA_LINKMODE 17
...@@ -1004,3 +1005,18 @@ int lxc_bridge_attach(const char *bridge, const char *ifname) ...@@ -1004,3 +1005,18 @@ int lxc_bridge_attach(const char *bridge, const char *ifname)
return err; return err;
} }
static char* lxc_network_types[LXC_NET_MAXCONFTYPE + 1] = {
[LXC_NET_VETH] = "veth",
[LXC_NET_MACVLAN] = "macvlan",
[LXC_NET_VLAN] = "vlan",
[LXC_NET_PHYS] = "phys",
[LXC_NET_EMPTY] = "empty",
};
const char *lxc_net_type_to_str(int type)
{
if (type < 0 || type > LXC_NET_MAXCONFTYPE)
return NULL;
return lxc_network_types[type];
}
...@@ -122,4 +122,5 @@ extern int lxc_neigh_proxy_on(const char *name, int family); ...@@ -122,4 +122,5 @@ extern int lxc_neigh_proxy_on(const char *name, int family);
*/ */
extern int lxc_neigh_proxy_off(const char *name, int family); extern int lxc_neigh_proxy_off(const char *name, int family);
extern const char *lxc_net_type_to_str(int type);
#endif #endif
...@@ -31,9 +31,11 @@ ...@@ -31,9 +31,11 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/file.h> #include <sys/file.h>
#include <lxc/lxc.h>
#include <lxc/log.h> #include <lxc/log.h>
#include <lxc/start.h> #include <lxc/start.h>
#include <lxc/cgroup.h> #include <lxc/cgroup.h>
#include <lxc/monitor.h>
#include "commands.h" #include "commands.h"
#include "config.h" #include "config.h"
...@@ -162,3 +164,108 @@ out: ...@@ -162,3 +164,108 @@ out:
return ret; return ret;
} }
static int fillwaitedstates(char *strstates, int *states)
{
char *token, *saveptr = NULL;
int state;
token = strtok_r(strstates, "|", &saveptr);
while (token) {
state = lxc_str2state(token);
if (state < 0)
return -1;
states[state] = 1;
token = strtok_r(NULL, "|", &saveptr);
}
return 0;
}
extern int lxc_wait(char *lxcname, char *states, int timeout)
{
struct lxc_msg msg;
int state, ret;
int s[MAX_STATE] = { }, fd;
if (fillwaitedstates(states, s))
return -1;
fd = lxc_monitor_open();
if (fd < 0)
return -1;
/*
* if container present,
* then check if already in requested state
*/
ret = -1;
state = lxc_getstate(lxcname);
if (state < 0) {
goto out_close;
} else if ((state >= 0) && (s[state])) {
ret = 0;
goto out_close;
}
for (;;) {
int elapsed_time, curtime;
struct timeval tv;
int stop = 0;
int retval;
if (timeout != -1) {
retval = gettimeofday(&tv, NULL);
if (retval)
goto out_close;
curtime = tv.tv_sec;
}
if (lxc_monitor_read_timeout(fd, &msg, timeout) < 0)
goto out_close;
if (timeout != -1) {
retval = gettimeofday(&tv, NULL);
if (retval)
goto out_close;
elapsed_time = tv.tv_sec - curtime;
if (timeout - elapsed_time <= 0)
stop = 1;
timeout -= elapsed_time;
}
if (strcmp(lxcname, msg.name)) {
if (stop) {
ret = -2;
goto out_close;
}
continue;
}
switch (msg.type) {
case lxc_msg_state:
if (msg.value < 0 || msg.value >= MAX_STATE) {
ERROR("Receive an invalid state number '%d'",
msg.value);
goto out_close;
}
if (s[msg.value]) {
ret = 0;
goto out_close;
}
break;
default:
if (stop) {
ret = -2;
goto out_close;
}
/* just ignore garbage */
break;
}
}
out_close:
lxc_monitor_close(fd);
return ret;
}
...@@ -33,5 +33,6 @@ extern lxc_state_t lxc_getstate(const char *name); ...@@ -33,5 +33,6 @@ extern lxc_state_t lxc_getstate(const char *name);
extern lxc_state_t lxc_str2state(const char *state); extern lxc_state_t lxc_str2state(const char *state);
extern const char *lxc_state2str(lxc_state_t state); extern const char *lxc_state2str(lxc_state_t state);
extern int lxc_wait(char *lxcname, char *states, int timeout);
#endif #endif
LDADD = ../lxc/liblxc.so -lrt
containertests_SOURCES = containertests.c
locktests_SOURCES = locktests.c
startone_SOURCES = startone.c
destroytest_SOURCES = destroytest.c
saveconfig_SOURCES = saveconfig.c
createtest_SOURCES = createtest.c
shutdowntest_SOURCES = shutdowntest.c
get_item_SOURCES = get_item.c
getkeys_SOURCES = getkeys.c
AM_CFLAGS=-I$(top_srcdir)/src \
-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
-DLXCPATH=\"$(LXCPATH)\" \
-DLXCINITDIR=\"$(LXCINITDIR)\"
bin_PROGRAMS = containertests locktests startone destroytest saveconfig createtest shutdowntest get_item getkeys
/* liblxcapi
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../lxc/lxccontainer.h"
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <errno.h>
#include <lxc/state.h>
#define MYNAME "lxctest1"
static int destroy_busybox(void)
{
int status, ret;
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return -1;
}
if (pid == 0) {
ret = execlp("lxc-destroy", "lxc-destroy", "-f", "-n", MYNAME, NULL);
// Should not return
perror("execl");
exit(1);
}
again:
ret = waitpid(pid, &status, 0);
if (ret == -1) {
if (errno == -EINTR)
goto again;
perror("waitpid");
return -1;
}
if (ret != pid)
goto again;
if (!WIFEXITED(status)) { // did not exit normally
fprintf(stderr, "%d: lxc-create exited abnormally\n", __LINE__);
return -1;
}
return WEXITSTATUS(status);
}
static int create_busybox(void)
{
int status, ret;
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return -1;
}
if (pid == 0) {
ret = execlp("lxc-create", "lxc-create", "-t", "busybox", "-f", "/etc/lxc/lxc.conf", "-n", MYNAME, NULL);
// Should not return
perror("execl");
exit(1);
}
again:
ret = waitpid(pid, &status, 0);
if (ret == -1) {
if (errno == -EINTR)
goto again;
perror("waitpid");
return -1;
}
if (ret != pid)
goto again;
if (!WIFEXITED(status)) { // did not exit normally
fprintf(stderr, "%d: lxc-create exited abnormally\n", __LINE__);
return -1;
}
return WEXITSTATUS(status);
}
int main(int argc, char *argv[])
{
struct lxc_container *c;
int ret = 0;
const char *s;
bool b;
char *str;
ret = 1;
/* test refcounting */
c = lxc_container_new(MYNAME);
if (!c) {
fprintf(stderr, "%d: error creating lxc_container %s\n", __LINE__, MYNAME);
goto out;
}
if (!lxc_container_get(c)) {
fprintf(stderr, "%d: error getting refcount\n", __LINE__);
goto out;
}
/* peek in, inappropriately, make sure refcount is a we'd like */
if (c->numthreads != 2) {
fprintf(stderr, "%d: refcount is %d, not %d\n", __LINE__, c->numthreads, 2);
goto out;
}
if (strcmp(c->name, MYNAME) != 0) {
fprintf(stderr, "%d: container has wrong name (%s not %s)\n", __LINE__, c->name, MYNAME);
goto out;
}
str = c->config_file_name(c);
#define CONFIGFNAM "/var/lib/lxc/" MYNAME "/config"
if (!str || strcmp(str, CONFIGFNAM)) {
fprintf(stderr, "%d: got wrong config file name (%s, not %s)\n", __LINE__, str, CONFIGFNAM);
goto out;
}
free(str);
free(c->configfile);
c->configfile = NULL;
str = c->config_file_name(c);
if (str) {
fprintf(stderr, "%d: config file name was not NULL as it should have been\n", __LINE__);
goto out;
}
if (lxc_container_put(c) != 0) {
fprintf(stderr, "%d: c was freed on non-final put\n", __LINE__);
goto out;
}
if (c->numthreads != 1) {
fprintf(stderr, "%d: refcount is %d, not %d\n", __LINE__, c->numthreads, 1);
goto out;
}
if (lxc_container_put(c) != 1) {
fprintf(stderr, "%d: c was not freed on final put\n", __LINE__);
goto out;
}
/* test a real container */
c = lxc_container_new(MYNAME);
if (!c) {
fprintf(stderr, "%d: error creating lxc_container %s\n", __LINE__, MYNAME);
ret = 1;
goto out;
}
if (c->lxc_conf != NULL) {
fprintf(stderr, "%d: lxc_conf is not NULL as it should be\n", __LINE__);
ret = 1;
goto out;
}
b = c->is_defined(c);
if (b) {
fprintf(stderr, "%d: %s thought it was defined\n", __LINE__, MYNAME);
goto out;
}
s = c->state(c);
if (s && strcmp(s, "STOPPED") != 0) {
// liblxc says a container is STOPPED if it doesn't exist. That's because
// the container may be an application container - it's not wrong, just
// sometimes unintuitive.
fprintf(stderr, "%d: %s thinks it is in state %s\n", __LINE__, c->name, s);
goto out;
}
// create a container
// the liblxc api does not support creation - it probably will eventually,
// but not yet.
// So we just call out to lxc-create. We'll create a busybox container.
ret = create_busybox();
if (ret) {
fprintf(stderr, "%d: failed to create a busybox container\n", __LINE__);
goto out;
}
b = c->is_defined(c);
if (!b) {
fprintf(stderr, "%d: %s thought it was not defined\n", __LINE__, MYNAME);
goto out;
}
s = c->state(c);
if (!s || strcmp(s, "STOPPED")) {
fprintf(stderr, "%d: %s is in state %s, not in STOPPED.\n", __LINE__, c->name, s ? s : "undefined");
goto out;
}
b = c->load_config(c, NULL);
if (!b) {
fprintf(stderr, "%d: %s failed to read its config\n", __LINE__, c->name);
goto out;
}
// test wait states
int numstates = lxc_get_wait_states(NULL);
if (numstates != MAX_STATE) {
fprintf(stderr, "%d: lxc_get_wait_states gave %d not %d\n", __LINE__, numstates, MAX_STATE);
goto out;
}
char **sstr = malloc(numstates * sizeof(char *));
numstates = lxc_get_wait_states(sstr);
int i;
for (i=0; i<numstates; i++) {
fprintf(stderr, "got state %d %s\n", i, sstr[i]);
}
free(sstr);
printf("hit return to start container");
char mychar;
scanf("%c", &mychar);
/* non-daemonized is tested in 'startone' */
c->want_daemonize(c);
if (!c->startl(c, 0, NULL, NULL)) {
fprintf(stderr, "%d: %s failed to start daemonized\n", __LINE__, c->name);
goto out;
}
if (!c->wait(c, "RUNNING", -1)) {
fprintf(stderr, "%d: failed waiting for state RUNNING\n", __LINE__);
goto out;
}
sleep(3);
s = c->state(c);
if (!s || strcmp(s, "RUNNING")) {
fprintf(stderr, "%d: %s is in state %s, not in RUNNING.\n", __LINE__, c->name, s ? s : "undefined");
goto out;
}
printf("hit return to finish");
scanf("%c", &mychar);
fprintf(stderr, "all lxc_container tests passed for %s\n", c->name);
ret = 0;
out:
if (c) {
c->stop(c);
destroy_busybox();
}
lxc_container_put(c);
exit(ret);
}
/* liblxcapi
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../lxc/lxccontainer.h"
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <errno.h>
#define MYNAME "lxctest1"
int main(int argc, char *argv[])
{
struct lxc_container *c;
int ret = 1;
if ((c = lxc_container_new(MYNAME)) == NULL) {
fprintf(stderr, "%d: error opening lxc_container %s\n", __LINE__, MYNAME);
ret = 1;
goto out;
}
if (c->is_defined(c)) {
fprintf(stderr, "%d: %s thought it was defined\n", __LINE__, MYNAME);
goto out;
}
if (!c->set_config_item(c, "lxc.network.type", "veth")) {
fprintf(stderr, "%d: failed to set network type\n", __LINE__);
goto out;
}
c->set_config_item(c, "lxc.network.link", "lxcbr0");
c->set_config_item(c, "lxc.network.flags", "up");
if (!c->createl(c, "ubuntu", "-r", "lucid", NULL)) {
fprintf(stderr, "%d: failed to create a lucid container\n", __LINE__);
goto out;
}
if (!c->is_defined(c)) {
fprintf(stderr, "%d: %s thought it was not defined\n", __LINE__, MYNAME);
goto out;
}
c->load_config(c, NULL);
c->want_daemonize(c);
if (!c->startl(c, 0, NULL)) {
fprintf(stderr, "%d: failed to start %s\n", __LINE__, MYNAME);
goto out;
}
fprintf(stderr, "%d: %s started, you have 60 seconds to test a console\n", __LINE__, MYNAME);
sleep(60); // wait a minute to let user connect to console
if (!c->stop(c)) {
fprintf(stderr, "%d: failed to stop %s\n", __LINE__, MYNAME);
goto out;
}
if (!c->destroy(c)) {
fprintf(stderr, "%d: error deleting %s\n", __LINE__, MYNAME);
goto out;
}
if (c->is_defined(c)) {
fprintf(stderr, "%d: %s thought it was defined\n", __LINE__, MYNAME);
goto out;
}
fprintf(stderr, "all lxc_container tests passed for %s\n", c->name);
ret = 0;
out:
lxc_container_put(c);
exit(ret);
}
/* liblxcapi
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../lxc/lxccontainer.h"
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <errno.h>
#define MYNAME "lxctest1"
static int create_ubuntu(void)
{
int status, ret;
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return -1;
}
if (pid == 0) {
ret = execlp("lxc-create", "lxc-create", "-t", "ubuntu", "-f", "/etc/lxc/lxc.conf", "-n", MYNAME, NULL);
// Should not return
perror("execl");
exit(1);
}
again:
ret = waitpid(pid, &status, 0);
if (ret == -1) {
if (errno == -EINTR)
goto again;
perror("waitpid");
return -1;
}
if (ret != pid)
goto again;
if (!WIFEXITED(status)) { // did not exit normally
fprintf(stderr, "%d: lxc-create exited abnormally\n", __LINE__);
return -1;
}
return WEXITSTATUS(status);
}
int main(int argc, char *argv[])
{
struct lxc_container *c;
int ret = 1;
if ((c = lxc_container_new(MYNAME)) == NULL) {
fprintf(stderr, "%d: error opening lxc_container %s\n", __LINE__, MYNAME);
ret = 1;
goto out;
}
if (c->is_defined(c)) {
fprintf(stderr, "%d: %s thought it was defined\n", __LINE__, MYNAME);
goto out;
}
if (create_ubuntu()) {
fprintf(stderr, "%d: failed to create a ubuntu container\n", __LINE__);
goto out;
}
if (!c->is_defined(c)) {
fprintf(stderr, "%d: %s thought it was not defined\n", __LINE__, MYNAME);
goto out;
}
if (!c->destroy(c)) {
fprintf(stderr, "%d: error deleting %s\n", __LINE__, MYNAME);
goto out;
}
if (c->is_defined(c)) {
fprintf(stderr, "%d: %s thought it was defined\n", __LINE__, MYNAME);
goto out;
}
fprintf(stderr, "all lxc_container tests passed for %s\n", c->name);
ret = 0;
out:
lxc_container_put(c);
exit(ret);
}
/* liblxcapi
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../lxc/lxccontainer.h"
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <errno.h>
#include <lxc/state.h>
#define MYNAME "lxctest1"
int main(int argc, char *argv[])
{
struct lxc_container *c;
int ret;
char v1[2], v2[256], v3[2048];
if ((c = lxc_container_new("testxyz")) == NULL) {
fprintf(stderr, "%d: error opening lxc_container %s\n", __LINE__, MYNAME);
ret = 1;
goto out;
}
if (!c->set_config_item(c, "lxc.hook.pre-start", "hi there")) {
fprintf(stderr, "%d: failed to set hook.pre-start\n", __LINE__);
ret = 1;
goto out;
}
ret = c->get_config_item(c, "lxc.hook.pre-start", v2, 255);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item(lxc.hook.pre-start) returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
fprintf(stderr, "lxc.hook.pre-start returned %d %s\n", ret, v2);
ret = c->get_config_item(c, "lxc.network", v2, 255);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
fprintf(stderr, "%d: get_config_item(lxc.network) returned %d %s\n", __LINE__, ret, v2);
if (!c->set_config_item(c, "lxc.tty", "4")) {
fprintf(stderr, "%d: failed to set tty\n", __LINE__);
ret = 1;
goto out;
}
ret = c->get_config_item(c, "lxc.tty", v2, 255);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item(lxc.tty) returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
fprintf(stderr, "lxc.tty returned %d %s\n", ret, v2);
if (!c->set_config_item(c, "lxc.arch", "x86")) {
fprintf(stderr, "%d: failed to set arch\n", __LINE__);
ret = 1;
goto out;
}
ret = c->get_config_item(c, "lxc.arch", v2, 255);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item(lxc.arch) returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
printf("lxc.arch returned %d %s\n", ret, v2);
#define HNAME "hostname1"
// demonstrate proper usage:
char *alloced;
if (!c->set_config_item(c, "lxc.utsname", HNAME)) {
fprintf(stderr, "%d: failed to set utsname\n", __LINE__);
ret = 1;
goto out;
}
int len;
len = c->get_config_item(c, "lxc.utsname", NULL, 0); // query the size of the string
if (len < 0) {
fprintf(stderr, "%d: get_config_item(lxc.utsname) returned %d\n", __LINE__, len);
ret = 1;
goto out;
}
printf("lxc.utsname returned %d\n", len);
// allocate the length of string + 1 for trailing \0
alloced = malloc(len+1);
if (!alloced) {
fprintf(stderr, "%d: failed to allocate %d bytes for utsname\n", __LINE__, len);
ret = 1;
goto out;
}
// now pass in the malloc'd array, and pass in length of string + 1: again
// because we need room for the trailing \0
ret = c->get_config_item(c, "lxc.utsname", alloced, len+1);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item(lxc.utsname) returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
if (strcmp(alloced, HNAME) != 0 || ret != len) {
fprintf(stderr, "lxc.utsname returned wrong value: %d %s not %d %s\n", ret, alloced, len, HNAME);
ret = 1;
goto out;
}
printf("lxc.utsname returned %d %s\n", len, alloced);
free(alloced);
if (!c->set_config_item(c, "lxc.mount.entry", "hi there")) {
fprintf(stderr, "%d: failed to set mount.entry\n", __LINE__);
ret = 1;
goto out;
}
ret = c->get_config_item(c, "lxc.mount.entry", v2, 255);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item(lxc.mount.entry) returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
printf("lxc.mount.entry returned %d %s\n", ret, v2);
if (!c->set_config_item(c, "lxc.aa_profile", "unconfined")) {
fprintf(stderr, "%d: failed to set aa_profile\n", __LINE__);
ret = 1;
goto out;
}
ret = c->get_config_item(c, "lxc.aa_profile", v2, 255);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item(lxc.aa_profile) returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
printf("lxc.aa_profile returned %d %s\n", ret, v2);
lxc_container_put(c);
// new test with real container
if ((c = lxc_container_new(MYNAME)) == NULL) {
fprintf(stderr, "%d: error opening lxc_container %s\n", __LINE__, MYNAME);
ret = 1;
goto out;
}
c->destroy(c);
lxc_container_put(c);
if ((c = lxc_container_new(MYNAME)) == NULL) {
fprintf(stderr, "%d: error opening lxc_container %s\n", __LINE__, MYNAME);
ret = 1;
goto out;
}
if (!c->createl(c, "ubuntu", "-r", "lucid", NULL)) {
fprintf(stderr, "%d: failed to create a lucid container\n", __LINE__);
ret = 1;
goto out;
}
lxc_container_put(c);
/* XXX TODO load_config needs to clear out any old config first */
if ((c = lxc_container_new(MYNAME)) == NULL) {
fprintf(stderr, "%d: error opening lxc_container %s\n", __LINE__, MYNAME);
ret = 1;
goto out;
}
ret = c->get_config_item(c, "lxc.cap.drop", NULL, 300);
if (ret < 5 || ret > 255) {
fprintf(stderr, "%d: get_config_item(lxc.cap.drop) with NULL returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
ret = c->get_config_item(c, "lxc.cap.drop", v1, 1);
if (ret < 5 || ret > 255) {
fprintf(stderr, "%d: get_config_item(lxc.cap.drop) returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
ret = c->get_config_item(c, "lxc.cap.drop", v2, 255);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item(lxc.cap.drop) returned %d %s\n", __LINE__, ret, v2);
ret = 1;
goto out;
}
printf("%d: get_config_item(lxc.cap.drop) returned %d %s\n", __LINE__, ret, v2);
ret = c->get_config_item(c, "lxc.network", v2, 255);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
printf("%d: get_config_item(lxc.network) returned %d %s\n", __LINE__, ret, v2);
if (!c->set_config_item(c, "lxc.network.ipv4", "10.2.3.4")) {
fprintf(stderr, "%d: failed to set ipv4\n", __LINE__);
ret = 1;
goto out;
}
ret = c->get_config_item(c, "lxc.network.0.ipv4", v2, 255);
if (ret <= 0) {
fprintf(stderr, "%d: lxc.network.0.ipv4 returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
if (!c->clear_config_item(c, "lxc.network.0.ipv4")) {
fprintf(stderr, "%d: failed clearing all ipv4 entries\n", __LINE__);
ret = 1;
goto out;
}
ret = c->get_config_item(c, "lxc.network.0.ipv4", v2, 255);
if (ret != 0) {
fprintf(stderr, "%d: after clearing ipv4 entries get_item(lxc.network.0.ipv4 returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
ret = c->get_config_item(c, "lxc.network.0.link", v2, 255);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
printf("%d: get_config_item (link) returned %d %s\n", __LINE__, ret, v2);
ret = c->get_config_item(c, "lxc.network.0.name", v2, 255);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
printf("%d: get_config_item (name) returned %d %s\n", __LINE__, ret, v2);
if (!c->clear_config_item(c, "lxc.network")) {
fprintf(stderr, "%d: clear_config_item failed\n", __LINE__);
ret = 1;
goto out;
}
ret = c->get_config_item(c, "lxc.network", v2, 255);
if (ret != 0) {
fprintf(stderr, "%d: network was not actually cleared (get_network returned %d)\n", __LINE__, ret);
ret = 1;
goto out;
}
ret = c->get_config_item(c, "lxc.cgroup", v3, 2047);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item(cgroup.devices) returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
printf("%d: get_config_item (cgroup.devices) returned %d %s\n", __LINE__, ret, v3);
ret = c->get_config_item(c, "lxc.cgroup.devices.allow", v3, 2047);
if (ret < 0) {
fprintf(stderr, "%d: get_config_item(cgroup.devices.devices.allow) returned %d\n", __LINE__, ret);
ret = 1;
goto out;
}
printf("%d: get_config_item (cgroup.devices.devices.allow) returned %d %s\n", __LINE__, ret, v3);
if (!c->clear_config_item(c, "lxc.cgroup")) {
fprintf(stderr, "%d: failed clearing lxc.cgroup", __LINE__);
ret = 1;
goto out;
}
if (!c->clear_config_item(c, "lxc.cap.drop")) {
fprintf(stderr, "%d: failed clearing lxc.cap.drop", __LINE__);
ret = 1;
goto out;
}
if (!c->clear_config_item(c, "lxc.mount.entries")) {
fprintf(stderr, "%d: failed clearing lxc.mount.entries", __LINE__);
ret = 1;
goto out;
}
if (!c->clear_config_item(c, "lxc.hook")) {
fprintf(stderr, "%d: failed clearing lxc.hook", __LINE__);
ret = 1;
goto out;
}
c->destroy(c);
printf("All get_item tests passed\n");
ret = 0;
out:
lxc_container_put(c);
exit(ret);
};
/* liblxcapi
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../lxc/lxccontainer.h"
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <errno.h>
#include <lxc/state.h>
#define MYNAME "lxctest1"
int main(int argc, char *argv[])
{
struct lxc_container *c;
int len, ret;
char v1[2], v2[256], v3[2048];
if ((c = lxc_container_new(MYNAME)) == NULL) {
fprintf(stderr, "%d: error opening lxc_container %s\n", __LINE__, MYNAME);
ret = 1;
goto out;
}
c->set_config_item(c, "lxc.network.type", "veth");
len = c->get_keys(c, NULL, NULL, 0);
if (len < 0) {
fprintf(stderr, "%d: failed to get length of all keys (%d)\n", __LINE__, len);
ret = 1;
goto out;
}
ret = c->get_keys(c, NULL, v3, len+1);
if (ret != len) {
fprintf(stderr, "%d: failed to get keys (%d)\n", __LINE__, ret);
ret = 1;
goto out;
}
printf("get_keys returned %d\n%s", ret, v3);
ret = c->get_keys(c, "lxc.network.0", v3, 2000);
if (ret < 0) {
fprintf(stderr, "%d: failed to get nic 0 keys(%d)\n", __LINE__, ret);
ret = 1;
goto out;
}
printf("get_keys for nic 1 returned %d\n%s", ret, v3);
out:
lxc_container_put(c);
exit(ret);
}
/* liblxcapi
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../lxc/lxclock.h"
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#define mycontainername "lxctest.sem"
#define TIMEOUT_SECS 3
int timedout;
int pid_to_kill;
void timeouthandler(int sig)
{
// timeout received
timedout = 1;
kill(pid_to_kill, SIGTERM);
}
void starttimer(int secs)
{
timedout = 0;
signal(SIGALRM, timeouthandler);
alarm(secs);
}
void stoptimer(void)
{
alarm(0);
signal(SIGALRM, NULL);
}
int test_one_lock(sem_t *lock)
{
int ret;
starttimer(TIMEOUT_SECS);
ret = lxclock(lock, TIMEOUT_SECS*2);
stoptimer();
if (ret == 0) {
lxcunlock(lock);
return 0;
}
if (timedout)
fprintf(stderr, "%d: timed out waiting for lock\n", __LINE__);
else
fprintf(stderr, "%d: failed to get single lock\n", __LINE__);
return 1;
}
/*
* get one lock. Fork a second task to try to get a second lock,
* with infinite timeout. If our alarm hits, kill the second
* task. If second task does not
*/
int test_two_locks(sem_t *lock)
{
int status;
int ret;
ret = lxclock(lock, 1);
if (ret) {
fprintf(stderr, "%d: Error getting first lock\n", __LINE__);
return 2;
}
pid_to_kill = fork();
if (pid_to_kill < 0) {
fprintf(stderr, "%d: Failed to fork\n", __LINE__);
lxcunlock(lock);
return 3;
}
if (pid_to_kill == 0) { // child
ret = lxclock(lock, TIMEOUT_SECS*2);
if (ret == 0) {
lxcunlock(lock);
exit(0);
}
fprintf(stderr, "%d: child, was not able to get lock\n", __LINE__);
exit(1);
}
starttimer(TIMEOUT_SECS);
waitpid(pid_to_kill, &status, 0);
stoptimer();
if (WIFEXITED(status)) {
// child exited normally - timeout didn't kill it
if (WEXITSTATUS(status) == 0)
fprintf(stderr, "%d: child was able to get the lock\n", __LINE__);
else
fprintf(stderr, "%d: child timed out too early\n", __LINE__);
lxcunlock(lock);
return 1;
}
lxcunlock(lock);
return 0;
}
/*
* get one lock. try to get second lock, but asking for timeout. If
* should return failure. If our own alarm, set at twice the lock
* request's timeout, hits, then lxclock() did not properly time out.
*/
int test_with_timeout(sem_t *lock)
{
int status;
int ret = 0;
ret = lxclock(lock, 0);
if (ret) {
fprintf(stderr, "%d: Error getting first lock\n", __LINE__);
return 2;
}
pid_to_kill = fork();
if (pid_to_kill < 0) {
fprintf(stderr, "%d: Error on fork\n", __LINE__);
lxcunlock(lock);
return 2;
}
if (pid_to_kill == 0) {
ret = lxclock(lock, TIMEOUT_SECS);
if (ret == 0) {
lxcunlock(lock);
exit(0);
}
exit(1);
}
starttimer(TIMEOUT_SECS * 2);
waitpid(pid_to_kill, &status, 0);
stoptimer();
if (!WIFEXITED(status)) {
fprintf(stderr, "%d: lxclock did not honor its timeout\n", __LINE__);
lxcunlock(lock);
return 1;
}
if (WEXITSTATUS(status) == 0) {
fprintf(stderr, "%d: child was able to get lock, should have failed with timeout\n", __LINE__);
ret = 1;
}
lxcunlock(lock);
return ret;
}
int main(int argc, char *argv[])
{
int ret, sval, r;
sem_t *lock;
lock = lxc_newlock(NULL);
if (!lock) {
fprintf(stderr, "%d: failed to get unnamed lock\n", __LINE__);
exit(1);
}
ret = lxclock(lock, 0);
if (ret) {
fprintf(stderr, "%d: failed to take unnamed lock (%d)\n", __LINE__, ret);
exit(1);
}
ret = lxcunlock(lock);
if (ret) {
fprintf(stderr, "%d: failed to put unnamed lock (%d)\n", __LINE__, ret);
exit(1);
}
sem_destroy(lock);
free(lock);
lock = lxc_newlock(mycontainername);
if (!lock) {
fprintf(stderr, "%d: failed to get lock\n", __LINE__);
exit(1);
}
r = sem_getvalue(lock, &sval);
if (!r) {
fprintf(stderr, "%d: sem value at start is %d\n", __LINE__, sval);
} else {
fprintf(stderr, "%d: failed to get initial value\n", __LINE__);
}
ret = test_one_lock(lock);
if (ret) {
fprintf(stderr, "%d: test failed\n", __LINE__);
goto out;
}
r = sem_getvalue(lock, &sval);
if (!r) {
fprintf(stderr, "%d: sem value is %d\n", __LINE__, sval);
} else {
fprintf(stderr, "%d: failed to get sem value\n", __LINE__);
}
ret = test_two_locks(lock);
if (ret) {
fprintf(stderr, "%d: test failed\n", __LINE__);
goto out;
}
r = sem_getvalue(lock, &sval);
if (!r) {
fprintf(stderr, "%d: sem value is %d\n", __LINE__, sval);
} else {
fprintf(stderr, "%d: failed to get value\n", __LINE__);
}
ret = test_with_timeout(lock);
if (ret) {
fprintf(stderr, "%d: test failed\n", __LINE__);
goto out;
}
r = sem_getvalue(lock, &sval);
if (!r) {
fprintf(stderr, "%d: sem value is %d\n", __LINE__, sval);
} else {
fprintf(stderr, "%d: failed to get value\n", __LINE__);
}
fprintf(stderr, "all tests passed\n");
out:
exit(ret);
}
/* liblxcapi
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../lxc/lxccontainer.h"
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <errno.h>
#define MYNAME "lxctest1"
static int create_ubuntu(void)
{
int status, ret;
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return -1;
}
if (pid == 0) {
ret = execlp("lxc-create", "lxc-create", "-t", "ubuntu", "-f", "/etc/lxc/lxc.conf", "-n", MYNAME, NULL);
// Should not return
perror("execl");
exit(1);
}
again:
ret = waitpid(pid, &status, 0);
if (ret == -1) {
if (errno == -EINTR)
goto again;
perror("waitpid");
return -1;
}
if (ret != pid)
goto again;
if (!WIFEXITED(status)) { // did not exit normally
fprintf(stderr, "%d: lxc-create exited abnormally\n", __LINE__);
return -1;
}
return WEXITSTATUS(status);
}
int main(int argc, char *argv[])
{
struct lxc_container *c;
int ret = 1;
if ((c = lxc_container_new(MYNAME)) == NULL) {
fprintf(stderr, "%d: error opening lxc_container %s\n", __LINE__, MYNAME);
ret = 1;
goto out;
}
if (c->is_defined(c)) {
fprintf(stderr, "%d: %s thought it was defined\n", __LINE__, MYNAME);
goto out;
}
if (create_ubuntu()) {
fprintf(stderr, "%d: failed to create a ubuntu container\n", __LINE__);
goto out;
}
if (!c->is_defined(c)) {
fprintf(stderr, "%d: %s thought it was not defined\n", __LINE__, MYNAME);
goto out;
}
c->load_config(c, NULL);
unlink("/tmp/lxctest1");
if (!c->save_config(c, "/tmp/lxctest1")) {
fprintf(stderr, "%d: failed writing config file /tmp/lxctest1\n", __LINE__);
goto out;
}
rename("/var/lib/lxc/" MYNAME "/config", "/var/lib/lxc/" MYNAME "/config.bak");
if (!c->save_config(c, NULL)) {
fprintf(stderr, "%d: failed writing config file\n", __LINE__);
goto out;
}
fprintf(stderr, "all lxc_container tests passed for %s\n", c->name);
ret = 0;
out:
lxc_container_put(c);
exit(ret);
}
/* liblxcapi
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../lxc/lxccontainer.h"
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <errno.h>
#define MYNAME "lxctest1"
int main(int argc, char *argv[])
{
struct lxc_container *c;
int ret = 1;
if ((c = lxc_container_new(MYNAME)) == NULL) {
fprintf(stderr, "%d: error opening lxc_container %s\n", __LINE__, MYNAME);
ret = 1;
goto out;
}
if (c->is_defined(c)) {
fprintf(stderr, "%d: %s thought it was defined\n", __LINE__, MYNAME);
goto out;
}
if (!c->set_config_item(c, "lxc.network.type", "veth")) {
fprintf(stderr, "%d: failed to set network type\n", __LINE__);
goto out;
}
c->set_config_item(c, "lxc.network.link", "lxcbr0");
c->set_config_item(c, "lxc.network.flags", "up");
if (!c->createl(c, "ubuntu", "-r", "lucid", NULL)) {
fprintf(stderr, "%d: failed to create a lucid container\n", __LINE__);
goto out;
}
if (!c->is_defined(c)) {
fprintf(stderr, "%d: %s thought it was not defined\n", __LINE__, MYNAME);
goto out;
}
c->load_config(c, NULL);
c->want_daemonize(c);
if (!c->startl(c, 0, NULL)) {
fprintf(stderr, "%d: failed to start %s\n", __LINE__, MYNAME);
goto out;
}
fprintf(stderr, "%d: %s started, you have 60 seconds to test a console\n", __LINE__, MYNAME);
sleep(60); // wait a minute to let user connect to console
if (!c->shutdown(c, 60)) {
fprintf(stderr, "%d: failed to shut down %s\n", __LINE__, MYNAME);
goto out;
}
if (!c->destroy(c)) {
fprintf(stderr, "%d: error deleting %s\n", __LINE__, MYNAME);
goto out;
}
if (c->is_defined(c)) {
fprintf(stderr, "%d: %s thought it was defined\n", __LINE__, MYNAME);
goto out;
}
fprintf(stderr, "all lxc_container tests passed for %s\n", c->name);
ret = 0;
out:
lxc_container_put(c);
exit(ret);
}
/* liblxcapi
*
* Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
* Copyright © 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../lxc/lxccontainer.h"
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <errno.h>
#define MYNAME "lxctest1"
static int destroy_ubuntu(void)
{
int status, ret;
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return -1;
}
if (pid == 0) {
ret = execlp("lxc-destroy", "lxc-destroy", "-f", "-n", MYNAME, NULL);
// Should not return
perror("execl");
exit(1);
}
again:
ret = waitpid(pid, &status, 0);
if (ret == -1) {
if (errno == -EINTR)
goto again;
perror("waitpid");
return -1;
}
if (ret != pid)
goto again;
if (!WIFEXITED(status)) { // did not exit normally
fprintf(stderr, "%d: lxc-create exited abnormally\n", __LINE__);
return -1;
}
return WEXITSTATUS(status);
}
static int create_ubuntu(void)
{
int status, ret;
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return -1;
}
if (pid == 0) {
ret = execlp("lxc-create", "lxc-create", "-t", "ubuntu", "-f", "/etc/lxc/lxc.conf", "-n", MYNAME, NULL);
// Should not return
perror("execl");
exit(1);
}
again:
ret = waitpid(pid, &status, 0);
if (ret == -1) {
if (errno == -EINTR)
goto again;
perror("waitpid");
return -1;
}
if (ret != pid)
goto again;
if (!WIFEXITED(status)) { // did not exit normally
fprintf(stderr, "%d: lxc-create exited abnormally\n", __LINE__);
return -1;
}
return WEXITSTATUS(status);
}
int main(int argc, char *argv[])
{
struct lxc_container *c;
int ret = 0;
const char *s;
bool b;
ret = 1;
/* test a real container */
c = lxc_container_new(MYNAME);
if (!c) {
fprintf(stderr, "%d: error creating lxc_container %s\n", __LINE__, MYNAME);
ret = 1;
goto out;
}
if (c->is_defined(c)) {
fprintf(stderr, "%d: %s thought it was defined\n", __LINE__, MYNAME);
goto out;
}
ret = create_ubuntu();
if (ret) {
fprintf(stderr, "%d: failed to create a ubuntu container\n", __LINE__);
goto out;
}
b = c->is_defined(c);
if (!b) {
fprintf(stderr, "%d: %s thought it was not defined\n", __LINE__, MYNAME);
goto out;
}
s = c->state(c);
if (!s || strcmp(s, "STOPPED")) {
fprintf(stderr, "%d: %s is in state %s, not in STOPPED.\n", __LINE__, c->name, s ? s : "undefined");
goto out;
}
b = c->load_config(c, NULL);
if (!b) {
fprintf(stderr, "%d: %s failed to read its config\n", __LINE__, c->name);
goto out;
}
if (!c->set_config_item(c, "lxc.utsname", "bobo")) {
fprintf(stderr, "%d: failed setting lxc.utsname\n", __LINE__);
goto out;
}
printf("hit return to start container");
char mychar;
scanf("%c", &mychar);
if (!lxc_container_get(c)) {
fprintf(stderr, "%d: failed to get extra ref to container\n", __LINE__);
exit(1);
}
pid_t pid = fork();
if (pid < 0) {
fprintf(stderr, "%d: fork failed\n", __LINE__);
goto out;
}
if (pid == 0) {
b = c->startl(c, 0, NULL);
if (!b)
fprintf(stderr, "%d: %s failed to start\n", __LINE__, c->name);
lxc_container_put(c);
exit(!b);
}
sleep(3);
s = c->state(c);
if (!s || strcmp(s, "RUNNING")) {
fprintf(stderr, "%d: %s is in state %s, not in RUNNING.\n", __LINE__, c->name, s ? s : "undefined");
goto out;
}
printf("hit return to finish");
scanf("%c", &mychar);
c->stop(c);
system("mkdir -p /var/lib/lxc/lxctest1/rootfs//usr/local/libexec/lxc");
system("mkdir -p /var/lib/lxc/lxctest1/rootfs/usr/lib/lxc/");
system("cp src/lxc/lxc-init /var/lib/lxc/lxctest1/rootfs//usr/local/libexec/lxc");
system("cp src/lxc/liblxc.so /var/lib/lxc/lxctest1/rootfs/usr/lib/lxc");
system("cp src/lxc/liblxc.so /var/lib/lxc/lxctest1/rootfs/usr/lib/lxc/liblxc.so.0");
system("cp src/lxc/liblxc.so /var/lib/lxc/lxctest1/rootfs/usr/lib");
system("mkdir -p /var/lib/lxc/lxctest1/rootfs/dev/shm");
system("chroot /var/lib/lxc/lxctest1/rootfs apt-get install --no-install-recommends lxc");
// next write out the config file; does it match?
if (!c->startl(c, 1, "/bin/hostname", NULL)) {
fprintf(stderr, "%d: failed to lxc-execute /bin/hostname", __LINE__);
goto out;
}
// auto-check result? ('bobo' is printed on stdout)
fprintf(stderr, "all lxc_container tests passed for %s\n", c->name);
ret = 0;
out:
if (c) {
c->stop(c);
destroy_ubuntu();
}
lxc_container_put(c);
exit(ret);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment