]> git.proxmox.com Git - mirror_lxc.git/commitdiff
Joined liblxc and lxc directory
authordlezcano <dlezcano>
Thu, 4 Sep 2008 07:57:50 +0000 (07:57 +0000)
committerdlezcano <dlezcano>
Thu, 4 Sep 2008 07:57:50 +0000 (07:57 +0000)
38 files changed:
src/lxc/Makefile.am
src/lxc/create.c [new file with mode: 0644]
src/lxc/destroy.c [new file with mode: 0644]
src/lxc/execute.c [new file with mode: 0644]
src/lxc/freezer.c [new file with mode: 0644]
src/lxc/genl.c [new file with mode: 0644]
src/lxc/genl.h [new file with mode: 0644]
src/lxc/kill.c [new file with mode: 0644]
src/lxc/list.c [new file with mode: 0644]
src/lxc/list.h [new file with mode: 0644]
src/lxc/lxc.h [new file with mode: 0644]
src/lxc/lxc_cgroup.c [new file with mode: 0644]
src/lxc/lxc_cgroup.h [new file with mode: 0644]
src/lxc/lxc_conf.c [new file with mode: 0644]
src/lxc/lxc_conf.h [new file with mode: 0644]
src/lxc/lxc_info.c [new file with mode: 0644]
src/lxc/lxc_list.c [new file with mode: 0644]
src/lxc/lxc_list.h [new file with mode: 0644]
src/lxc/lxc_lock.c [new file with mode: 0644]
src/lxc/lxc_lock.h [new file with mode: 0644]
src/lxc/lxc_log.c [new file with mode: 0644]
src/lxc/lxc_log.h [new file with mode: 0644]
src/lxc/lxc_namespace.h [new file with mode: 0644]
src/lxc/lxc_state.c
src/lxc/lxc_state.h [new file with mode: 0644]
src/lxc/lxc_utils.h [new file with mode: 0644]
src/lxc/monitor.c [new file with mode: 0644]
src/lxc/monitor.h [new file with mode: 0644]
src/lxc/namespace.h [new file with mode: 0644]
src/lxc/network.c [new file with mode: 0644]
src/lxc/network.h [new file with mode: 0644]
src/lxc/nl.c [new file with mode: 0644]
src/lxc/nl.h [new file with mode: 0644]
src/lxc/rtnl.c [new file with mode: 0644]
src/lxc/rtnl.h [new file with mode: 0644]
src/lxc/start.c [new file with mode: 0644]
src/lxc/stop.c [new file with mode: 0644]
src/lxc/utils.h [new file with mode: 0644]

index 5a7c481f0b413b2fe2af2d7d8e26b5946cf581aa..a38c64d7a0d1740b1372615a708d940476adbf56 100644 (file)
@@ -1,4 +1,42 @@
-INCLUDES= -I$(top_srcdir)/src/liblxc -I$(top_srcdir)/src
+INCLUDES= -I$(top_srcdir)/src
+
+lib_LTLIBRARIES = liblxc.la
+pkginclude_HEADERS = \
+               lxc.h \
+               lxc_cgroup.h \
+               lxc_conf.h \
+               lxc_list.h \
+               lxc_lock.h \
+               lxc_log.h \
+               lxc_namespace.h \
+               lxc_state.h \
+               lxc_utils.h
+
+liblxc_la_SOURCES = \
+       create.c \
+       destroy.c \
+       start.c \
+       stop.c \
+       execute.c \
+       monitor.c monitor.h \
+       kill.c \
+       freezer.c \
+       lxc_cgroup.c lxc_cgroup.h \
+       lxc.h \
+       lxc_utils.h \
+       lxc_lock.c lxc_lock.h \
+       lxc_namespace.h \
+       lxc_conf.c lxc_conf.h \
+       lxc_list.h \
+       lxc_state.c lxc_state.h \
+       lxc_log.c lxc_log.h \
+       \
+       network.c network.h \
+        nl.c nl.h \
+        rtnl.c rtnl.h \
+        genl.c genl.h
+
+liblxc_la_LDFLAGS = -release @PACKAGE_VERSION@
 
 bin_SCRIPTS = \
        lxc-ps
@@ -11,56 +49,56 @@ bin_PROGRAMS = \
        lxc-execute \
        lxc-monitor \
        lxc-console \
-       lxc-state \
        lxc-kill \
        lxc-freeze \
+       lxc-info \
        lxc-unfreeze \
        lxc-priority
 
 lxc_create_SOURCES = lxc_create.c lxc_config.c lxc_config.h
 lxc_create_LDADD = \
-       $(top_builddir)/src/liblxc/liblxc.la
+       $(top_builddir)/src/lxc/liblxc.la
 
 lxc_destroy_SOURCES = lxc_destroy.c
 lxc_destroy_LDADD = \
-       $(top_builddir)/src/liblxc/liblxc.la
+       $(top_builddir)/src/lxc/liblxc.la
 
 lxc_start_SOURCES = lxc_start.c
 lxc_start_LDADD = \
-       $(top_builddir)/src/liblxc/liblxc.la
+       $(top_builddir)/src/lxc/liblxc.la
 
 lxc_stop_SOURCES = lxc_stop.c
 lxc_stop_LDADD = \
-       $(top_builddir)/src/liblxc/liblxc.la
+       $(top_builddir)/src/lxc/liblxc.la
 
 lxc_execute_SOURCES = lxc_execute.c
 lxc_execute_LDADD = \
-        $(top_builddir)/src/liblxc/liblxc.la
+        $(top_builddir)/src/lxc/liblxc.la
 
 lxc_monitor_SOURCES = lxc_monitor.c
 lxc_monitor_LDADD = \
-       $(top_builddir)/src/liblxc/liblxc.la
+       $(top_builddir)/src/lxc/liblxc.la
 
 lxc_console_SOURCES = lxc_console.c
 lxc_console_LDADD = \
-        $(top_builddir)/src/liblxc/liblxc.la
+        $(top_builddir)/src/lxc/liblxc.la
 
-lxc_state_SOURCES = lxc_state.c
-lxc_state_LDADD = \
-       $(top_builddir)/src/liblxc/liblxc.la
+lxc_info_SOURCES = lxc_info.c
+lxc_info_LDADD = \
+       $(top_builddir)/src/lxc/liblxc.la
 
 lxc_kill_SOURCES = lxc_kill.c
 lxc_kill_LDADD = \
-        $(top_builddir)/src/liblxc/liblxc.la
+        $(top_builddir)/src/lxc/liblxc.la
 
 lxc_freeze_SOURCES = lxc_freeze.c
 lxc_freeze_LDADD = \
-        $(top_builddir)/src/liblxc/liblxc.la
+        $(top_builddir)/src/lxc/liblxc.la
 
 lxc_unfreeze_SOURCES = lxc_unfreeze.c
 lxc_unfreeze_LDADD = \
-        $(top_builddir)/src/liblxc/liblxc.la
+        $(top_builddir)/src/lxc/liblxc.la
 
 lxc_priority_SOURCES = lxc_priority.c
 lxc_priority_LDADD = \
-        $(top_builddir)/src/liblxc/liblxc.la
+        $(top_builddir)/src/lxc/liblxc.la
diff --git a/src/lxc/create.c b/src/lxc/create.c
new file mode 100644 (file)
index 0000000..2891eba
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/inotify.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <lxc.h>
+
+static int dir_filter(const struct dirent *dirent)
+{
+       if (!strcmp(dirent->d_name, ".") ||
+            !strcmp(dirent->d_name, ".."))
+                return 0;
+        return 1;
+}
+
+static int is_empty_directory(const char *dirname)
+{
+       struct dirent **namelist;
+       int n;
+
+       n = scandir(dirname, &namelist, dir_filter, alphasort);
+       if (n < 0)
+               lxc_log_syserror("failed to scan %s directory", dirname);
+       return n == 0;
+}
+
+static int create_lxc_directory(const char *dirname)
+{
+       char path[MAXPATHLEN];
+
+       if (mkdir(LXCPATH, 0755) && errno != EEXIST) {
+               lxc_log_syserror("failed to created %s directory", LXCPATH);
+               return -1;
+       }
+
+       sprintf(path, LXCPATH "/%s", dirname);
+
+       if (mkdir(path, 0755)) {
+               lxc_log_syserror("failed to created %s directory", path);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int remove_lxc_directory(const char *dirname)
+{
+       char path[MAXPATHLEN];
+
+       sprintf(path, LXCPATH "/%s", dirname);
+
+       if (rmdir(path)) {
+               lxc_log_syserror("failed to remove %s directory", path);
+               return -1;
+       }
+
+       if (is_empty_directory(LXCPATH)) {
+               if (rmdir(LXCPATH)) {
+                       lxc_log_syserror("failed to remove %s directory", LXCPATH);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+int lxc_create(const char *name, struct lxc_conf *conf)
+{
+       int lock, err = -1;
+
+       if (create_lxc_directory(name)) {
+               lxc_log_error("failed to create %s directory", name);
+               return -1;
+       }
+
+       lock = lxc_get_lock(name);
+       if (!lock) {
+               lxc_log_error("'%s' is busy", name);
+               goto err;
+       }
+
+       if (lock < 0) {
+               lxc_log_error("failed to acquire lock on '%s':%s",
+                             name, strerror(-lock));
+               goto err;
+       }
+
+       if (lxc_mkstate(name)) {
+               lxc_log_error("failed to create the state file for %s", name);
+               goto err;
+       }
+
+       if (lxc_setstate(name, STOPPED)) {
+               lxc_log_error("failed to set state for %s", name);
+               goto err_state;
+       }
+
+       if (lxc_configure(name, conf)) {
+               lxc_log_error("failed to set configuration for %s", name);
+               goto err_state;
+       }
+
+       err = 0;
+out:
+       lxc_put_lock(lock);
+       return err;
+
+err_state:
+       lxc_unconfigure(name);
+
+       if (lxc_rmstate(name))
+               lxc_log_error("failed to remove state file for %s", name);
+err:
+       if (remove_lxc_directory(name))
+               lxc_log_error("failed to cleanup lxc directory for %s", name);
+       goto out;
+}
diff --git a/src/lxc/destroy.c b/src/lxc/destroy.c
new file mode 100644 (file)
index 0000000..266a5ae
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/inotify.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <lxc.h>
+
+static int dir_filter(const struct dirent *dirent)
+{
+       if (!strcmp(dirent->d_name, ".") ||
+            !strcmp(dirent->d_name, ".."))
+                return 0;
+        return 1;
+}
+
+static int is_empty_directory(const char *dirname)
+{
+       struct dirent **namelist;
+       int n;
+
+       n = scandir(dirname, &namelist, dir_filter, alphasort);
+       if (n < 0)
+               lxc_log_syserror("failed to scan %s directory", dirname);
+       return n == 0;
+}
+
+static int remove_lxc_directory(const char *dirname)
+{
+       char path[MAXPATHLEN];
+
+       sprintf(path, LXCPATH "/%s", dirname);
+
+       if (rmdir(path)) {
+               lxc_log_syserror("failed to remove %s directory", path);
+               return -1;
+       }
+
+       if (is_empty_directory(LXCPATH)) {
+               if (rmdir(LXCPATH)) {
+                       lxc_log_syserror("failed to remove %s directory", LXCPATH);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+int lxc_destroy(const char *name)
+{
+       int ret = -1, lock;
+
+       lock = lxc_get_lock(name);
+       if (!lock) {
+               lxc_log_error("'%s' is busy", name);
+               goto out;
+       }
+
+       if (lock < 0) {
+               lxc_log_error("failed to acquire the lock for '%s':%s", 
+                             name, strerror(-lock));
+               goto out;
+       }
+
+       if (lxc_rmstate(name)) {
+               lxc_log_error("failed to remove state file for %s", name);
+               goto out_lock;
+       }
+       
+       lxc_monitor_cleanup(name);
+
+       if (lxc_unconfigure(name)) {
+               lxc_log_error("failed to cleanup %s", name);
+               goto out_lock;
+       }
+
+       if (remove_lxc_directory(name)) {
+               lxc_log_syserror("failed to remove '%s'", name);
+               goto out_lock;
+       }
+
+       ret = 0;
+       
+out_lock:
+       lxc_put_lock(lock);
+out:
+       return ret;
+}
diff --git a/src/lxc/execute.c b/src/lxc/execute.c
new file mode 100644 (file)
index 0000000..888a843
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <sys/file.h>
+#include <sys/mount.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <lxc.h>
+
+LXC_TTY_HANDLER(SIGINT);
+LXC_TTY_HANDLER(SIGQUIT);
+
+int lxc_execute(const char *name, int argc, char *argv[], 
+               lxc_callback_t preexec, void *data)
+{
+       char *init = NULL, *val = NULL, *vinit = "[vinit]";
+       int fd, lock, sv[2], sync = 0, err = -1;
+       pid_t pid;
+       int clone_flags;
+
+       lock = lxc_get_lock(name);
+       if (!lock) {
+               lxc_log_error("'%s' is busy", name);
+               return -1;
+       }
+
+       if (lock < 0) {
+               lxc_log_error("failed to acquire lock on '%s':%s",
+                             name, strerror(-lock));
+               return -1;
+       }
+
+       if (lxc_setstate(name, STARTING)) {
+               lxc_log_error("failed to set state %s", lxc_state2str(STARTING));
+               goto out;
+       }
+
+       if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) {
+               lxc_log_syserror("failed to create communication socketpair");
+               goto err;
+       }
+
+       LXC_TTY_ADD_HANDLER(SIGINT);
+       LXC_TTY_ADD_HANDLER(SIGQUIT);
+
+       clone_flags = CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS;
+       if (conf_has_utsname(name))
+               clone_flags |= CLONE_NEWUTS;
+       if (conf_has_network(name))
+               clone_flags |= CLONE_NEWNET;
+
+       pid = fork_ns(clone_flags);
+       if (pid < 0) {
+               lxc_log_syserror("failed to fork into a new namespace");
+               goto err_fork_ns;
+       }
+
+       if (!pid) {
+
+               pid = fork();
+               if (pid < 0) {
+                       lxc_log_syserror("failed to fork");
+                       return 1;
+               }
+
+               if (!pid) {
+                       close(sv[1]);
+                       fcntl(sv[0], F_SETFD, FD_CLOEXEC);
+
+                       if (write(sv[0], &sync, sizeof(sync)) < 0) {
+                               lxc_log_syserror("failed to write socket");
+                               return 1;
+                       }
+
+                       if (read(sv[0], &sync, sizeof(sync)) < 0) {
+                               lxc_log_syserror("failed to read socket");
+                               return 1;
+                       }
+
+                       if (lxc_setup(name)) {
+                               lxc_log_error("failed to setup the container");
+                               goto error;
+                       }
+
+                       if (mount("proc", "/proc", "proc", 0, NULL)) {
+                               lxc_log_syserror("failed to mount '/proc'");
+                               goto error;
+                       }
+
+                       if (conf_has_network(name))
+                               if (mount("sysfs", "/sys", "sysfs", 0, NULL)) {
+                                       lxc_log_syserror("failed to mount '/sys'");
+                                       /* continue: non fatal error until sysfs not per
+                                          namespace */
+                               }
+
+                       if (preexec)
+                               if (preexec(name, argc, argv, data)) {
+                                       lxc_log_error("preexec callback has failed");
+                                       return -1;
+                               }
+
+                       execvp(argv[0], argv);
+                       lxc_log_syserror("failed to exec %s", argv[0]);
+               error:
+                       if (write(sv[0], &sync, sizeof(sync)) < 0)
+                               lxc_log_syserror("failed to write the socket");
+                       
+                       exit(1);
+               }
+
+               setsid();
+               close(0);
+               close(1);
+               close(2);
+
+               if (prctl(PR_SET_NAME, vinit, 0, 0, 0))
+                       lxc_log_syserror("failed to set process name");
+
+               close(sv[0]);
+               close(sv[1]);
+
+               for (;;) {
+                       int status;
+                       if (wait(&status) < 0) {
+                               if (errno == ECHILD)
+                                       return 0;
+                               if (errno == EINTR)
+                                       continue;
+                               lxc_log_syserror("failed to wait child");
+                               return 1;
+                       }
+               }
+       }
+
+       close(sv[0]);
+       
+       if (read(sv[1], &sync, sizeof(sync)) < 0) {
+               lxc_log_syserror("failed to read the socket");
+               goto err_pipe_read;
+       }
+
+       if (clone_flags & CLONE_NEWNET && conf_create_network(name, pid)) {
+               lxc_log_error("failed to create the configured network");
+               goto err_create_network;
+       }
+
+       if (write(sv[1], &sync, sizeof(sync)) < 0) {
+               lxc_log_syserror("failed to write the socket");
+               goto err_pipe_write;
+       }
+
+       err = read(sv[1], &sync, sizeof(sync));
+       if (err < 0) {
+               lxc_log_error("failed to read the socket");
+               goto err_pipe_read2;
+       }
+
+       if (err > 0) {
+               lxc_log_error("something went wrong with %d", pid);
+               /* TODO : check status etc ... */
+               waitpid(pid, NULL, 0);
+               goto err_child_failed;
+       }
+
+       asprintf(&init, LXCPATH "/%s/init", name);
+       fd = open(init, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+       if (fd < 0) {
+               lxc_log_syserror("failed to open %s", init);
+               goto err_open;
+       }
+
+       asprintf(&val, "%d", pid);
+       if (write(fd, val, strlen(val)) < 0) {
+               lxc_log_syserror("failed to write init pid");
+               goto err_write;
+       }
+
+       if (lxc_link_nsgroup(name, pid))
+               lxc_log_warning("cgroupfs not found: cgroup disabled");
+
+       if (lxc_setstate(name, RUNNING)) {
+               lxc_log_error("failed to set state to %s", lxc_state2str(RUNNING));
+               goto err_state_failed;
+       }
+
+wait_again:
+       if (waitpid(pid, NULL, 0) < 0) {
+               if (errno == EINTR) 
+                       goto wait_again;
+               lxc_log_syserror("failed to wait the pid %d", pid);
+               goto err_waitpid_failed;
+       }
+
+       if (lxc_setstate(name, STOPPING))
+               lxc_log_error("failed to set state %s", lxc_state2str(STOPPING));
+
+       if (clone_flags & CLONE_NEWNET && conf_destroy_network(name))
+               lxc_log_error("failed to destroy the network");
+
+       err = 0;
+out:
+       if (lxc_setstate(name, STOPPED))
+               lxc_log_error("failed to set state %s", lxc_state2str(STOPPED));
+
+       lxc_unlink_nsgroup(name);
+       unlink(init);
+       free(init);
+       free(val);
+       lxc_put_lock(lock);
+
+       return err;
+
+err_write:
+       close(fd);
+
+err_state_failed:
+err_child_failed:
+err_pipe_read2:
+err_pipe_write:
+       conf_destroy_network(name);
+err_create_network:
+err_pipe_read:
+err_open:
+err_waitpid_failed:
+       if (lxc_setstate(name, ABORTING))
+               lxc_log_error("failed to set state %s", lxc_state2str(STOPPED));
+
+       kill(pid, SIGKILL);
+err_fork_ns:
+       LXC_TTY_DEL_HANDLER(SIGQUIT);
+       LXC_TTY_DEL_HANDLER(SIGINT);
+       close(sv[0]);
+       close(sv[1]);
+err:
+       goto out;
+}
diff --git a/src/lxc/freezer.c b/src/lxc/freezer.c
new file mode 100644 (file)
index 0000000..38332bd
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/inotify.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <lxc.h>
+
+static int freeze_unfreeze(const char *name, int freeze)
+{
+       char *freezer, *f = freeze?"FROZEN":"RUNNING";
+       int fd, ret = -1;
+       
+       asprintf(&freezer, LXCPATH "/%s/nsgroup/freezer.state", name);
+
+       fd = open(freezer, O_WRONLY);
+       if (fd < 0) {
+               lxc_log_syserror("failed to open freezer for '%s'", name);
+               goto out;
+       }
+
+       ret = write(fd, f, strlen(f) + 1) < 0;
+       close(fd);
+       if (ret) 
+               lxc_log_syserror("failed to write to '%s'", freezer);
+out:
+       free(freezer);
+       return ret;
+}
+
+int lxc_freeze(const char *name)
+{
+       return freeze_unfreeze(name, 1);
+}
+
+int lxc_unfreeze(const char *name)
+{
+       return freeze_unfreeze(name, 0);
+}
+
diff --git a/src/lxc/genl.c b/src/lxc/genl.c
new file mode 100644 (file)
index 0000000..3781be1
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <string.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <linux/genetlink.h>
+#include <linux/rtnetlink.h>
+#include <nl.h>
+#include <genl.h>
+
+static int genetlink_resolve_family(const char *family)
+{
+       struct nl_handler handler;
+       struct nlattr *attr;
+       struct genlmsg *request, *reply;
+       struct genlmsghdr *genlmsghdr;
+
+       int len, ret;
+
+       request = genlmsg_alloc(GENLMSG_GOOD_SIZE);
+       if (!request)
+               return -ENOMEM;
+               
+       reply = genlmsg_alloc(GENLMSG_GOOD_SIZE);
+       if (!reply) {
+               genlmsg_free(request);
+               return -ENOMEM;
+       }
+
+       request->nlmsghdr.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+       request->nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+        request->nlmsghdr.nlmsg_type = GENL_ID_CTRL;
+
+       genlmsghdr = NLMSG_DATA(&request->nlmsghdr);
+        genlmsghdr->cmd = CTRL_CMD_GETFAMILY;
+
+       ret = netlink_open(&handler, NETLINK_GENERIC);
+       if (ret)
+               return ret;
+
+       ret = nla_put_string((struct nlmsg *)&request->nlmsghdr, 
+                            CTRL_ATTR_FAMILY_NAME, family);
+       if (ret)
+               goto out;
+
+       ret = netlink_transaction(&handler, (struct nlmsg *)&request->nlmsghdr,
+                                 (struct nlmsg *)&reply->nlmsghdr);
+       if (ret < 0)
+               goto out;
+
+       genlmsghdr = NLMSG_DATA(&reply->nlmsghdr);
+       len = reply->nlmsghdr.nlmsg_len;
+
+       ret = -ENOMSG;
+       if (reply->nlmsghdr.nlmsg_type !=  GENL_ID_CTRL)
+               goto out;
+
+       if (genlmsghdr->cmd != CTRL_CMD_NEWFAMILY)
+               goto out;
+
+       ret = -EMSGSIZE;
+       len -= NLMSG_LENGTH(GENL_HDRLEN);
+       if (len < 0)
+               goto out;
+       
+       attr = (struct nlattr *)GENLMSG_DATA(reply);
+       attr = (struct nlattr *)((char *)attr + NLA_ALIGN(attr->nla_len));
+       
+       ret = -ENOMSG;
+       if (attr->nla_type != CTRL_ATTR_FAMILY_ID)
+               goto out;
+
+       ret =  *(__u16 *) NLA_DATA(attr);
+out:
+       genlmsg_free(request);
+       genlmsg_free(reply);
+       netlink_close(&handler);
+       return ret;
+}
+
+extern int genetlink_open(struct genl_handler *handler, const char *family)
+{
+       int ret;
+       handler->family = genetlink_resolve_family(family);
+       if (handler->family < 0)
+               return handler->family;
+
+       ret = netlink_open(&handler->nlh, NETLINK_GENERIC);
+
+       return ret;
+}
+
+extern int genetlink_close(struct genl_handler *handler)
+{
+       return netlink_close(&handler->nlh);
+}
+
+extern int genetlink_rcv(struct genl_handler *handler, struct genlmsg *genlmsg)
+{
+       return netlink_rcv(&handler->nlh, (struct nlmsg *)&genlmsg->nlmsghdr);
+}
+
+extern int genetlink_send(struct genl_handler *handler, struct genlmsg *genlmsg)
+{
+
+       return netlink_send(&handler->nlh, (struct nlmsg *)&genlmsg->nlmsghdr);
+}
+
+extern int genetlink_transaction(struct genl_handler *handler, 
+                         struct genlmsg *request, struct genlmsg *answer)
+{
+       return netlink_transaction(&handler->nlh, (struct nlmsg *)&request->nlmsghdr,
+                                  (struct nlmsg *)&answer->nlmsghdr);
+}
+
+extern struct genlmsg *genlmsg_alloc(size_t size)
+{
+       size_t len = NLMSG_LENGTH(GENL_HDRLEN) + size;
+       return  (struct genlmsg *)nlmsg_alloc(len);
+}
+
+extern void genlmsg_free(struct genlmsg *genlmsg)
+{
+       free(genlmsg);
+}
diff --git a/src/lxc/genl.h b/src/lxc/genl.h
new file mode 100644 (file)
index 0000000..4800aac
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __genl_h
+#define __genl_h
+
+/*
+ * Use this as a good size to allocate generic netlink messages
+ */
+#define GENLMSG_GOOD_SIZE NLMSG_GOOD_SIZE
+#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
+
+/*
+ * struct genl_handler : the structure which store the netlink handler 
+ *  and the family number resulting of the auto-generating id family
+ *  for the generic netlink protocol
+ *
+ * @nlh: the netlink socket handler
+ * @family: the generic netlink family assigned number
+ */
+struct genl_handler
+{
+       struct nl_handler nlh;
+       int family;
+};
+
+/*
+ * struct genlmsg : the struct containing the generic netlink message
+ *  format
+ *
+ * @nlmsghdr: a netlink message header
+ * @genlmsghdr: a generic netlink message header pointer
+ *
+ */
+/* __attribute__ ((aligned(4))); */
+struct genlmsg {
+       struct nlmsghdr nlmsghdr;
+       struct genlmsghdr genlmsghdr;
+};
+
+static inline int genetlink_len(const struct genlmsg *genlmsg)
+{
+        return ((genlmsg->nlmsghdr.nlmsg_len) - GENL_HDRLEN - NLMSG_HDRLEN);
+}
+
+/*
+ * genetlink_open : resolve family number id and open a generic netlink socket
+ *
+ * @handler: a struct genl_handler pointer
+ * @family: the family name of the generic netlink protocol
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int genetlink_open(struct genl_handler *handler, const char *family);
+
+/*
+ * genetlink_close : close a generic netlink socket
+ *
+ * @handler: the handler of the socket to be closed
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int genetlink_close(struct genl_handler *handler);
+
+/*
+ * genetlink_rcv : receive a generic netlink socket, it is up
+ *  to the caller to manage the allocation of the generic netlink message
+ *
+ * @handler: the handler of the generic netlink socket
+ * @genlmsg: the pointer to a generic netlink message pre-allocated
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int genetlink_rcv(struct genl_handler *handler, struct genlmsg *genlmsg);
+
+/*
+ * genetlink_send : send a generic netlink socket, it is up
+ *  to the caller to manage the allocation of the generic netlink message
+ *
+ * @handler: the handler of the generic netlink socket
+ * @genlmsg: the pointer to a generic netlink message pre-allocated
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int genetlink_send(struct genl_handler *handler, struct genlmsg *genlmsg);
+
+struct genlmsg *genlmsg_alloc(size_t size);
+
+void genlmsg_free(struct genlmsg *genlmsg);
+
+/*
+ * genetlink_transaction : send and receive a generic netlink message in one shot
+ *
+ * @handler: the handler of the generic netlink socket
+ * @request: a generic netlink message containing the request to be sent
+ * @answer: a pre-allocated generic netlink message to receive the response
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int genetlink_transaction(struct genl_handler *handler, 
+                         struct genlmsg *request, struct genlmsg *answer);
+#endif
diff --git a/src/lxc/kill.c b/src/lxc/kill.c
new file mode 100644 (file)
index 0000000..7af7f34
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <lxc.h>
+
+int lxc_kill(const char *name, int signum)
+{
+       char *freezer = NULL, *signal = NULL;
+       int fd = -1, ret = -1;
+       
+       if (signum < SIGHUP || signum > SIGRTMAX) {
+               lxc_log_error("bad signal value %d", signum);
+               goto out;
+       }
+
+       asprintf(&freezer, LXCPATH "/%s/nsgroup/freezer.kill", name);
+       asprintf(&signal, "%d", signum);
+
+       fd = open(freezer, O_WRONLY);
+       if (fd < 0) {
+               lxc_log_syserror("failed to open %s for %s", freezer, name);
+               goto out;
+       }
+
+       if (write(fd, &signal, strlen(signal)) < 0) {
+               lxc_log_syserror("failed to write to %s", freezer);
+               goto out;
+       }
+
+       ret = 0;
+out:
+       close(fd);
+       free(freezer);
+       free(signal);
+       return ret;
+}
diff --git a/src/lxc/list.c b/src/lxc/list.c
new file mode 100644 (file)
index 0000000..d588ae2
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <list.h>
diff --git a/src/lxc/list.h b/src/lxc/list.h
new file mode 100644 (file)
index 0000000..00d0d16
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef _list_h
+#define _list_h
+
+struct list {
+       void *elem;
+       struct list *next;
+       struct list *prev;
+};
+
+#define init_list(l) { .next = l, .prev = l, }
+
+#define list_for_each(__iterator, __list)                              \
+       for (__iterator = (__list)->next;                               \
+            __iterator != __list;                                      \
+            __iterator = __iterator->next)
+
+static inline void list_init(struct list *list)
+{
+       list->elem = NULL;
+       list->next = list->prev = list;
+}
+
+static inline void list_add_elem(struct list *list, void *elem)
+{
+       list->elem = elem;
+}
+
+static inline void *list_first_elem(struct list *list)
+{
+       return list->next->elem;
+}
+
+static inline int list_empty(struct list *list)
+{
+       return list == list->next;
+}
+
+static inline void list_add(struct list *list, struct list *new)
+{
+       struct list *next = list->next;
+       next->prev = new;
+       new->next = next;
+       new->prev = list;
+       list->next = new;
+}
+
+static inline void list_del(struct list *list)
+{
+       struct list *next, *prev;
+
+       next = list->next;
+       prev = list->prev;
+       next->prev = prev;
+       prev->next = next;
+}
+
+#endif
diff --git a/src/lxc/lxc.h b/src/lxc/lxc.h
new file mode 100644 (file)
index 0000000..b837413
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __lxc_h
+#define __lxc_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ Following code is for liblxc.
+
+ liblxc/lxc.h will contain exports of liblxc
+ **/
+
+#include <lxc/lxc_state.h>
+#include <lxc/lxc_list.h>
+#include <lxc/lxc_conf.h>
+#include <lxc/lxc_log.h>
+#include <lxc/lxc_lock.h>
+#include <lxc/lxc_cgroup.h>
+#include <lxc/lxc_namespace.h>
+#include <lxc/lxc_utils.h>
+
+#define LXCPATH "/var/lxc"
+#define MAXPIDLEN 20
+
+struct lxc_mem_stat;
+
+typedef int (*lxc_callback_t)(const char *name, int argc, 
+                             char *argv[], void *data);
+
+/*
+ * Create the container object. Creates the /lxc/<name> directory
+ * and fills it with the files corresponding to the configuration
+ * structure passed as parameter.
+ * The first container will create the /lxc directory.
+ * @name : the name of the container
+ * @conf : the configuration data for the container
+ * Returns 0 on success, < 0 otherwise
+ */
+extern int lxc_create(const char *name, struct lxc_conf *conf);
+
+/*
+ * Destroy the container object. Removes the files into the /lxc/<name>
+ * directory and removes the <name> directory.
+ * The last container will remove the /lxc directory.
+ * @name : the name of the container to be detroyed
+ * Returns 0 on success, < 0 otherwise
+ */
+extern int lxc_destroy(const char *name);
+
+/*
+ * Start the container previously created with lxc_create.
+ * @name     : the name of the container
+ * @argc     : the number of arguments of the command line
+ * @argv     : an array of char * corresponding to the commande line
+ * @prestart : hooks will be called just before the command execs
+ * Returns 0 on sucess, < 0 otherwise
+ */
+extern int lxc_start(const char *name, int argc, char *argv[], 
+                    lxc_callback_t prestart, void *data);
+
+/*
+ * Create the container and start it directly, using the argc, argv 
+ * parameter. This command is for application container.
+ * At the end of the exec'ed command, the container will
+ * automatically autodestroy.
+ * @name    : the name of the container
+ * @conf    : the configuration data
+ * @argc    : the number of arguments of the command line
+ * @argv    : an array of char * corresponding to the commande line
+ * @preexec : hooks will be called just before the command execs
+ * Returns 0 on success, < 0 otherwise
+ */
+extern int lxc_execute(const char *name, int argc, char *argv[], 
+                      lxc_callback_t preexec, void *data);
+
+/*
+ * Stop the container previously started with lxc_start or lxc_exec
+ * @name : the name of the container
+ * Returns 0 on success, < 0 otherwise
+ */
+extern int lxc_stop(const char *name);
+
+/*
+ * Monitor the container, each time the state of the container
+ * is changed, a state data is send through a file descriptor passed to
+ * the function with output_fd.
+ * The function will block until the container is destroyed.
+ * @name : the name of the container
+ * @output_fd : the file descriptor where to send the states
+ * Returns 0 on success, < 0 otherwise
+ */
+extern int lxc_monitor(const char *name, int output_fd);
+
+/*
+ * Open the monitoring mechanism for a specific container
+ * The function will return an fd corresponding to the events
+ * @name  : the name of the container
+ * Returns a file descriptor on success, < 0 otherwise
+ */
+extern int lxc_monitor_open(const char *name);
+
+/*
+ * Read the state of the container if this one has changed
+ * The function will block until there is an event available
+ * @fd : the file descriptor provided by lxc_monitor_open
+ * @state : the variable which will be filled with the state
+ * Returns 0 if the monitored container has exited, > 0 if
+ * data was readen, < 0 otherwise
+ */
+extern int lxc_monitor_read(int fd, lxc_state_t *state);
+
+/*
+ * Close the fd associated with the monitoring
+ * @fd : the file descriptor provided by lxc_monitor_open
+ * Returns 0 on success, < 0 otherwise
+ */
+extern int lxc_monitor_close(int fd);
+
+/*
+ * Show the console of the container.
+ * @name : the name of container
+ * Returns 0 on sucess, < 0 otherwise
+ */
+extern int lxc_console(const char *name);
+
+/*
+ * Freeze all the tasks running inside the container <name>
+ * @name : the container name
+ * Returns 0 on success, < 0 otherwise
+ */
+extern int lxc_freeze(const char *name);
+
+/*
+ * Unfreeze all previously frozen tasks.
+ * @name : the name of the container
+ * Return 0 on sucess, < 0 otherwise
+ */
+extern int lxc_unfreeze(const char *name);
+
+/*
+ * Retrieve the container state
+ * @name : the name of the container
+ * Returns the state of the container on success, < 0 otherwise
+ */
+extern lxc_state_t lxc_state(const char *name);
+
+/*
+ * Send a signal to all processes of the container. This is the same
+ * behavior of the well-known 'killpg' command except it is related
+ * to all tasks belonging to a container.
+ * @name   : the name of the container
+ * @signum : the signal number to be sent
+ * Returns 0 on success, < 0 otherwise
+ */
+extern int lxc_kill(const char *name, int signum);
+
+/*
+ * Change the priority of the container
+ * @name     : the name of the container
+ * @priority : an integer representing the desired priority
+ * Returns 0 on success, < 0 otherwise
+ */
+extern int lxc_cgroup_set_priority(const char *name, int priority);
+
+/*
+ * Retrieve the priority of the container
+ * @name     : the name of the container
+ * @priority : a pointer to an int where the priority will be stored
+ * Returns 0 on success, < 0 otherwise
+ */
+extern int lxc_cgroup_get_priority(const char *name, int *priority);
+
+/*
+ * Set the maximum memory usable by the container
+ * @name   : the name of the container
+ * @memmax : the maximum usable memory in bytes
+ * Returns 0 on sucess, < 0 otherwise
+ */
+extern int lxc_cgroup_set_memory(const char *name, size_t memmax);
+
+/*
+ * Get the maximum memory usable by the container
+ * @name : the name of the container
+ * @memmax : a pointer to a size_t where the value will be stored
+ * Returns 0 on sucess, < 0 otherwise
+ */
+extern int lxc_cgroup_get_memory(const char *name, size_t *memmax);
+
+/*
+ * Get the memory statistics of the container
+ * @name    : the name of the container
+ * @memstat : a pointer to a structure defining the memory statistic
+ * Returns 0 on sucess, < 0 otherwise
+ */
+extern int lxc_cgroup_get_memstat(const char *name, 
+                                 struct lxc_mem_stat *memstat);
+
+/*
+ * Set the cpuset for the container
+ * @name    : the name of the container
+ * @cpumask : a bitmask representing the cpu maps
+ * @len     : the len of the bitmask
+ * @shared  : a boolean specifying if the cpu could be shared with
+ *            processes not belonging to the container
+ * Returns 0 on sucess, < 0 otherwise
+ */
+extern int lxc_cgroup_set_cpuset(const char *name, long *cpumask, 
+                                int len, int shared);
+
+/*
+ * Get the actual cpuset for the container
+ * @cpumask : a bitmask representing the cpu maps
+ * @len     : the len of the bitmask
+ * @shared  : a boolean specifying if the cpu is shared with
+ *            processes not belonging to the container
+ * Returns 0 on sucess, < 0 otherwise
+ */
+extern int lxc_cgroup_get_cpuset(const char *name, long *cpumask, 
+                                int len, int *shared);
+
+/*
+ * Get the cpu usage of the container
+ * @name  : the name of the container
+ * @usage : a value to be filled with the current container cpu usage
+ * Returns 0 on sucess, < 0 otherwise
+ */
+extern int lxc_cgroup_get_cpu_usage(const char *name, long long *usage);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
new file mode 100644 (file)
index 0000000..f436d66
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+#include <errno.h>
+#include <mntent.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/inotify.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <lxc.h>
+
+#define MAXPRIOLEN 24
+#define MTAB "/etc/mtab"
+
+static int get_cgroup_mount(const char *mtab, char *mnt)
+{
+        struct mntent *mntent;
+        FILE *file = NULL;
+        int err = -1;
+
+        file = setmntent(mtab, "r");
+        if (!file) {
+                lxc_log_syserror("failed to open %s", mtab);
+                goto out;
+        }
+
+        while ((mntent = getmntent(file))) {
+                if (strcmp(mntent->mnt_type, "cgroup"))
+                        continue;
+                strcpy(mnt, mntent->mnt_dir);
+                err = 0;
+                break;
+        };
+
+        fclose(file);
+out:
+        return err;
+}
+
+int lxc_link_nsgroup(const char *name, pid_t pid)
+{
+       char *lxc, *nsgroup, cgroup[MAXPATHLEN];
+       int ret;
+
+       if (get_cgroup_mount(MTAB, cgroup)) {
+               lxc_log_info("cgroup is not mounted");
+               return -1;
+       }
+
+       asprintf(&lxc, LXCPATH "/%s/nsgroup", name);
+       asprintf(&nsgroup, "%s/%d", cgroup, pid);
+
+       unlink(lxc);
+       ret = symlink(nsgroup, lxc);
+       if (ret)
+               lxc_log_syserror("failed to create symlink %s->%s",
+                                nsgroup, lxc);
+       free(lxc);
+       free(nsgroup);
+       return ret;
+}
+
+int lxc_unlink_nsgroup(const char *name)
+{
+       char *nsgroup;
+       int ret;
+
+       asprintf(&nsgroup, LXCPATH "/%s/nsgroup", name);
+       ret = unlink(nsgroup);
+       free(nsgroup);
+
+       return ret;
+}
+
+int lxc_cgroup_set_priority(const char *name, int priority)
+{
+       int fd;
+       char *path = NULL, *prio = NULL;
+
+        asprintf(&path, LXCPATH "/%s/nsgroup/cpu.shares", name);
+
+       fd = open(path, O_WRONLY);
+       if (fd < 0) {
+               lxc_log_syserror("failed to open '%s'", path);
+               goto out;
+       }
+
+       asprintf(&prio, "%d", priority);
+
+       if (write(fd, prio, strlen(prio) + 1) < 0) {
+               lxc_log_syserror("failed to write to '%s'", path);
+               close(fd);
+               goto out;
+       }
+
+       close(fd);
+out:
+       free(path);
+       free(prio);
+       return 0;
+}
+
+int lxc_cgroup_get_priority(const char *name, int *priority)
+{
+       int fd, ret = -1;
+       char *path, prio[MAXPRIOLEN];
+
+        asprintf(&path, LXCPATH "/%s/nsgroup/cpu.shares", name);
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               lxc_log_syserror("failed to open '%s'", path);
+               goto out;
+       }
+
+       if (read(fd, prio, MAXPRIOLEN) < 0) {
+               lxc_log_syserror("failed to read from '%s'", path);
+               close(fd);
+               goto out;
+       }
+
+       close(fd);
+       *priority = atoi(prio);
+
+       ret = 0;
+out:
+       free(path);
+       return ret;
+}
+
+int lxc_set_memory(const char *name, size_t memmax)
+{
+       return 0;
+}
+
+int lxc_get_memory(const char *name, size_t *memmax)
+{
+       return 0;
+}
+
+int lxc_get_memstat(const char *name, struct lxc_mem_stat *memstat)
+{
+       return 0;
+}
+
+int lxc_set_cpuset(const char *name, long *cpumask, int len, int shared)
+{
+       return 0;
+}
+
+int lxc_get_cpuset(const char *name, long *cpumask, int len, int *shared)
+{
+       return 0;
+}
+
+int lxc_get_cpu_usage(const char *name, long long *usage)
+{
+       return 0;
+}
diff --git a/src/lxc/lxc_cgroup.h b/src/lxc/lxc_cgroup.h
new file mode 100644 (file)
index 0000000..8060cdf
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _cgroup_h
+#define _cgroup_h
+
+int lxc_get_cgroup_mount(const char *mtab, char *mnt);
+int lxc_link_nsgroup(const char *name, pid_t pid);
+int lxc_unlink_nsgroup(const char *name);
+
+#endif
diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c
new file mode 100644 (file)
index 0000000..beea5cb
--- /dev/null
@@ -0,0 +1,1234 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <mntent.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/mman.h>
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <lxc.h>
+#include <network.h>
+
+#define MAXHWLEN    18
+#define MAXINDEXLEN 20
+#define MAXLINELEN  128
+
+typedef int (*instanciate_cb)(const char *dirname, 
+                             const char *file, pid_t pid);
+
+typedef int (*dir_cb)(const char *name, const char *dirname, 
+                     const char *file, void *data);
+
+typedef int (*file_cb)(void* buffer, void *data);
+
+struct netdev_conf {
+       const char *type;
+       instanciate_cb cb;
+       int count;
+};
+
+static int instanciate_veth(const char *, const char *, pid_t);
+static int instanciate_macvlan(const char *, const char *, pid_t);
+static int instanciate_phys(const char *, const char *, pid_t);
+static int instanciate_empty(const char *, const char *, pid_t);
+
+static struct netdev_conf netdev_conf[MAXCONFTYPE + 1] = {
+       [VETH]    = { "veth",    instanciate_veth,    0  },
+       [MACVLAN] = { "macvlan", instanciate_macvlan, 0, },
+       [PHYS]    = { "phys",    instanciate_phys,    0, },
+       [EMPTY]   = { "empty",   instanciate_empty,   0, },
+};
+
+static int dir_filter(const struct dirent *dirent)
+{
+       if (!strcmp(dirent->d_name, ".") ||
+            !strcmp(dirent->d_name, ".."))
+                return 0;
+        return 1;
+}
+
+static int dir_for_each(const char *name, const char *dirname, 
+                       dir_cb callback, void *data)
+{
+       struct dirent **namelist;
+       int n;
+       
+       n = scandir(dirname, &namelist, dir_filter, alphasort);
+       if (n < 0) {
+               lxc_log_syserror("failed to scan %s directory", dirname);
+               return -1;
+       }
+       
+       while (n--) {
+               if (callback(name, dirname, namelist[n]->d_name, data)) {
+                       lxc_log_error("callback failed");
+                       free(namelist[n]);
+                       return -1;
+               }
+               free(namelist[n]);
+       }
+
+       return 0;
+}
+
+static int file_for_each_line(const char *file, file_cb callback, 
+                             void *buffer, size_t len, void* data)
+{
+       FILE *f;
+       int err = -1;
+
+       f = fopen(file, "r");
+       if (!f) {
+               lxc_log_syserror("failed to open %s", file);
+               return -1;
+       }
+       
+       while (fgets(buffer, len, f))
+               if (callback(buffer, data))
+                       goto out;
+       err = 0;
+out:
+       fclose(f);
+       return err;
+}
+
+static int write_info(const char *path, const char *file, const char *info)
+{
+       int fd, err = -1;
+       char *f;
+
+       asprintf(&f, "%s/%s", path, file);
+       fd = creat(f, 0755);
+       if (fd < 0)
+               goto out;
+
+       if (write(fd, info, strlen(info)) < 0 ||
+           write(fd, "\n", strlen("\n") + 1) < 0)
+               goto out_write;
+       err = 0;
+out:
+       close(fd);
+       free(f);
+       return err;
+
+out_write:
+       unlink(f);
+       goto out;
+}
+
+static int read_info(const char *path, const char *file, char *info, size_t len)
+{
+       int fd, ret = -1;
+       char *f, *token;
+
+       asprintf(&f, "%s/%s", path, file);
+       fd = open(f, O_RDONLY);
+       if (fd < 0) {
+               if (errno == ENOENT)
+                       ret = 1;
+               goto out;
+       }
+
+       ret = read(fd, info, len);
+       if (ret < 0)
+               goto out;
+
+       token = strstr(info, "\n");
+       if (token)
+               *token = '\0';
+       ret = 0;
+out:
+       close(fd);
+       free(f);
+       return ret;
+}
+
+static int delete_info(const char *path, const char *file)
+{
+       char *info;
+       int ret;
+
+       asprintf(&info, "%s/%s", path, file);
+       ret = unlink(info);
+       free(info);
+
+       return ret;
+}
+
+static int configure_ip4addr(int fd, struct lxc_inetdev *in)
+{
+       char addr[INET6_ADDRSTRLEN];
+       char bcast[INET_ADDRSTRLEN];
+       char *line = NULL; 
+       int err = -1;
+
+       if (!inet_ntop(AF_INET, &in->addr, addr, sizeof(addr))) {
+               lxc_log_syserror("failed to convert ipv4 address");
+               goto err;
+       }
+               
+       if (!inet_ntop(AF_INET, &in->bcast, bcast, sizeof(bcast))) {
+               lxc_log_syserror("failed to convert ipv4 broadcast");
+               goto err;
+       }
+               
+       if (in->prefix)
+               asprintf(&line, "%s/%d %s\n", addr, in->prefix, bcast);
+       else
+               asprintf(&line, "%s %s\n", addr, bcast);
+               
+       if (write(fd, line, strlen(line)) < 0) {
+               lxc_log_syserror("failed to write address info");
+               goto err;
+       }
+
+       err = 0;
+err:
+       free(line);
+       return err;
+}
+
+static int configure_ip6addr(int fd, struct lxc_inet6dev *in6)
+{
+       char addr[INET6_ADDRSTRLEN];
+       char *line = NULL;
+       int err = -1;
+
+       if (!inet_ntop(AF_INET6, &in6->addr, addr, sizeof(addr))) {
+               lxc_log_syserror("failed to convert ipv4 address");
+               goto err;
+       }
+               
+       asprintf(&line, "%s/%d\n", addr, in6->prefix?in6->prefix:64);
+               
+       if (write(fd, line, strlen(line)) < 0) {
+               lxc_log_syserror("failed to write address info");
+               goto err;
+       }
+
+       err = 0;
+err:
+       free(line);
+       return err;
+}
+
+static int configure_ip_address(const char *path, struct lxc_list *ip, int family)
+{
+       char file[MAXPATHLEN];
+       struct lxc_list *iterator;
+       int fd, err = -1;
+
+       if (mkdir(path, 0755)) {
+               lxc_log_syserror("failed to create directory %s", path);
+               return -1;
+       }
+
+       snprintf(file, MAXPATHLEN, "%s/addresses", path);
+       fd = creat(file, 0755);
+       if (fd < 0) {
+               lxc_log_syserror("failed to create %s file", file);
+               goto err;
+       }
+
+       lxc_list_for_each(iterator, ip) {
+               err = family == AF_INET?
+                       configure_ip4addr(fd, iterator->elem):
+                       configure_ip6addr(fd, iterator->elem);
+               if (err)
+                       goto err;
+       }
+out:
+       close(fd);
+       return err;
+err:
+       unlink(file);
+       rmdir(path);
+       goto out;
+}
+
+static int configure_netdev(const char *path, struct lxc_netdev *netdev)
+{
+       int err = -1;
+       char dir[MAXPATHLEN];
+
+       if (mkdir(path, 0755)) {
+               lxc_log_syserror("failed to create %s directory", path);
+               return -1;
+       }
+
+       if (netdev->ifname) {
+               if (write_info(path, "link", netdev->ifname))
+                       goto out_link;
+       }
+
+       if (netdev->newname) {
+               if (write_info(path, "name", netdev->newname))
+                       goto out_newname;
+       }
+
+       if (netdev->hwaddr) {
+               if (write_info(path, "hwaddr", netdev->hwaddr))
+                       goto out_up;
+       }
+
+       if (netdev->flags & IFF_UP) {
+               if (write_info(path, "up", ""))
+                       goto out_hwaddr;
+       }
+
+       if (!lxc_list_empty(&netdev->ipv4)) {
+               snprintf(dir, MAXPATHLEN, "%s/ipv4", path);
+               if (configure_ip_address(dir, &netdev->ipv4, AF_INET))
+                       goto out_ipv4;
+       }
+
+       if (!lxc_list_empty(&netdev->ipv6)) {
+               snprintf(dir, MAXPATHLEN, "%s/ipv6", path);
+               if (configure_ip_address(dir, &netdev->ipv6, AF_INET6))
+                       goto out_ipv6;
+       }
+       err = 0;
+out:
+       return err;
+out_ipv6:
+       delete_info(path, "ipv4");
+out_ipv4:
+       delete_info(path, "up");
+out_hwaddr:
+       delete_info(path, "hwaddr");
+out_up:
+       delete_info(path, "name");
+out_newname:
+       delete_info(path, "link");
+out_link:
+       rmdir(path);
+       goto out;
+}
+
+static int configure_utsname(const char *name, struct utsname *utsname)
+{
+       char path[MAXPATHLEN];
+
+       snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
+
+       if (write_info(path, "utsname", utsname->nodename)) {
+               lxc_log_error("failed to write the utsname info");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int configure_network(const char *name, struct lxc_list *network)
+{
+       struct lxc_list *iterator;
+       struct lxc_network *n;
+       char networkpath[MAXPATHLEN];
+       char path[MAXPATHLEN];
+       int err = -1;
+       
+       if (lxc_list_empty(network))
+               return 0;
+       
+       snprintf(networkpath, MAXPATHLEN, LXCPATH "/%s/network", name);
+       if (mkdir(networkpath, 0755)) {
+               lxc_log_syserror("failed to create %s directory", networkpath);
+               goto out;
+       }
+
+       lxc_list_for_each(iterator, network) {
+
+               n = iterator->elem;
+
+               if (n->type < 0 || n->type > MAXCONFTYPE) {
+                       lxc_log_error("invalid network configuration type '%d'",
+                                     n->type);
+                       goto out;
+               }
+
+               snprintf(path, MAXPATHLEN, "%s/%s%d", networkpath,
+                        netdev_conf[n->type].type, 
+                        netdev_conf[n->type].count++);
+
+               if (configure_netdev(path, lxc_list_first_elem(&n->netdev))) {
+                       lxc_log_error("failed to configure network type %s", 
+                                     netdev_conf[n->type].type);
+                       goto out;
+               }
+       }
+
+       err = 0;
+out:
+       return err;
+}
+
+static int configure_cgroup(const char *name, struct lxc_cgroup *cgroup)
+{
+       return 0;
+}
+
+static int configure_chroot(const char *name, const char *chroot)
+{
+       char path[MAXPATHLEN];
+
+       snprintf(path, MAXPATHLEN, LXCPATH "/%s/chroot", name);
+
+       return symlink(chroot, path);
+
+}
+
+static int configure_mount(const char *name, const char *fstab)
+{
+       char *path;
+       struct stat stat;
+       int infd, outfd;
+       void *src, *dst;
+       char c = '\0';
+       int ret = -1;
+
+       asprintf(&path, LXCPATH "/%s/fstab", name);
+
+       outfd = open(path, O_RDWR|O_CREAT|O_EXCL, 0640);
+       if (outfd < 0) {
+               lxc_log_syserror("failed to creat '%s'", path);
+               goto out;
+       }
+       
+       infd = open(fstab, O_RDONLY);
+       if (infd < 0) {
+               lxc_log_syserror("failed to open '%s'", fstab);
+               goto out;
+       }
+
+       if (fstat(infd, &stat)) {
+               lxc_log_syserror("failed to stat '%s'", fstab);
+               goto out;
+       }
+
+       if (lseek(outfd, stat.st_size - 1, SEEK_SET) < 0) {
+               lxc_log_syserror("failed to seek dest file '%s'", path);
+               goto out;
+       }
+
+       /* fixup length */
+       if (write(outfd, &c, 1) < 0) {
+               lxc_log_syserror("failed to write to '%s'", path);
+               goto out;
+       }
+
+       src = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, infd, 0L);
+       if (src == MAP_FAILED) {
+               lxc_log_syserror("failed to mmap '%s'", fstab);
+               goto out;
+       }
+
+       dst = mmap(NULL, stat.st_size, PROT_WRITE, MAP_SHARED, outfd, 0L);
+       if (dst == MAP_FAILED) {
+               lxc_log_syserror("failed to mmap '%s'", path);
+               goto out;
+       }
+
+       memcpy(dst, src, stat.st_size);
+
+       munmap(src, stat.st_size);
+       munmap(dst, stat.st_size);
+
+       ret = 0;
+out:
+       free(path);
+       return ret;
+}
+
+static int unconfigure_ip_addresses(const char *dirname)
+{
+       char path[MAXPATHLEN];
+
+       snprintf(path, MAXPATHLEN, "%s/ipv4", dirname);
+       delete_info(path, "addresses");
+       rmdir(path);
+
+       snprintf(path, MAXPATHLEN, "%s/ipv6", dirname);
+       delete_info(path, "addresses");
+       rmdir(path);
+
+       return 0;
+}
+
+static int unconfigure_network_cb(const char *name, const char *dirname, 
+                                 const char *file, void *data)
+{
+       char path[MAXPATHLEN];
+
+       snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
+       delete_info(path, "name");
+       delete_info(path, "addr");
+       delete_info(path, "link");
+       delete_info(path, "hwaddr");
+       delete_info(path, "up");
+       unconfigure_ip_addresses(path);
+       rmdir(path);
+
+       return 0;
+}
+
+static int unconfigure_network(const char *name)
+{
+       char dirname[MAXPATHLEN];
+
+       snprintf(dirname, MAXPATHLEN, LXCPATH "/%s/network", name);
+       dir_for_each(name, dirname, unconfigure_network_cb, NULL);
+       rmdir(dirname);
+
+       return 0;
+}
+
+static int unconfigure_cgroup(const char *name)
+{
+       return 0;
+}
+
+static int unconfigure_chroot(const char *name)
+{
+       char path[MAXPATHLEN];
+
+       snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
+       delete_info(path, "chroot");
+
+       return 0;
+}
+
+static int unconfigure_mount(const char *name)
+{
+       char path[MAXPATHLEN];
+       
+       snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
+       delete_info(path, "fstab");
+
+       return 0;
+}
+
+static int unconfigure_utsname(const char *name)
+{
+       char path[MAXPATHLEN];
+
+       snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
+       delete_info(path, "utsname");
+
+       return 0;
+}
+
+static int setup_utsname(const char *name)
+{
+       int ret;
+       char path[MAXPATHLEN];
+       struct utsname utsname;
+
+       snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
+
+       ret = read_info(path, "utsname", utsname.nodename, 
+                       sizeof(utsname.nodename));
+       if (ret < 0) {
+               lxc_log_syserror("failed to read utsname info");
+               return -1;
+       }
+
+       if (!ret && sethostname(utsname.nodename, strlen(utsname.nodename))) {
+               lxc_log_syserror("failed to set the hostname to '%s'",
+                                utsname.nodename);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int setup_chroot(const char *name)
+{
+       char path[MAXPATHLEN], chrt[MAXPATHLEN];
+
+       snprintf(path, MAXPATHLEN, LXCPATH "/%s/chroot", name);
+
+       if (readlink(path, chrt, MAXPATHLEN) > 0) {
+
+               if (chroot(chrt)) {
+                       lxc_log_syserror("failed to set chroot %s", path);
+                       return -1;
+               }
+
+               if (chdir(getenv("HOME")) && chdir("/")) {
+                       lxc_log_syserror("failed to change to home directory");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int setup_mount(const char *name)
+{
+       char path[MAXPATHLEN];
+       struct mntent *mntent;
+       FILE *file;
+       int ret = -1;
+       unsigned long mntflags = 0;
+
+       snprintf(path, MAXPATHLEN, LXCPATH "/%s/fstab", name);
+
+       file = setmntent(path, "r");
+       if (!file) {
+               if (errno == ENOENT)
+                       return 0;
+               lxc_log_syserror("failed to open '%s'", path);
+               goto out;
+       }
+
+       while((mntent = getmntent(file))) {
+
+               if (hasmntopt(mntent, "bind"))
+                       mntflags |= MS_BIND;
+
+               if (mount(mntent->mnt_fsname, mntent->mnt_dir,
+                         mntent->mnt_type, mntflags, NULL)) {
+                       lxc_log_syserror("failed to mount '%s' on '%s'",
+                                        mntent->mnt_fsname, mntent->mnt_dir);
+                       goto out;
+               }
+       }
+       ret = 0;
+out:
+       endmntent(file);
+       return ret;
+}
+
+static int setup_ipv4_addr_cb(void *buffer, void *data)
+{
+       char *ifname = data;
+       char *cursor, *slash, *addr, *bcast = NULL, *prefix = NULL;
+       int p = 24;
+
+       addr = buffer;
+       cursor = strstr(addr, " ");
+       if (cursor) {
+               *cursor = '\0';
+               bcast = cursor + 1;
+               cursor = strstr(bcast, "\n");
+               if (cursor)
+                       *cursor = '\0';
+       }
+
+       slash = strstr(addr, "/");
+       if (slash) {
+               *slash = '\0';
+               prefix = slash + 1;
+       }
+
+       if (prefix)
+               p = atoi(prefix);
+       
+       if (ip_addr_add(ifname, addr, p, bcast)) {
+               lxc_log_error("failed to set %s to addr %s/%d %s", ifname,
+                             addr, p, bcast?bcast:"");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int setup_ipv6_addr_cb(void *buffer, void *data)
+{
+       char *ifname = data;
+       char *cursor, *slash, *addr, *bcast = NULL, *prefix = NULL;
+       int p = 24;
+
+       addr = buffer;
+       cursor = strstr(addr, " ");
+       if (cursor) {
+               *cursor = '\0';
+               bcast = cursor + 1;
+               cursor = strstr(bcast, "\n");
+               if (cursor)
+                       *cursor = '\0';
+       }
+
+       slash = strstr(addr, "/");
+       if (slash) {
+               *slash = '\0';
+               prefix = slash + 1;
+       }
+
+       if (prefix)
+               p = atoi(prefix);
+       
+       if (ip6_addr_add(ifname, addr, p, bcast)) {
+               lxc_log_error("failed to set %s to addr %s/%d %s", ifname,
+                             addr, p, bcast?bcast:"");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int setup_hw_addr(char *hwaddr, const char *ifname)
+{
+       struct sockaddr sockaddr;
+       struct ifreq ifr;
+       int ret, fd;
+
+       if (lxc_convert_mac(hwaddr, &sockaddr)) {
+               fprintf(stderr, "conversion has failed\n");
+               return -1;
+       }
+
+       memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+       memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
+
+       fd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (fd < 0) {
+               perror("socket");
+               return -1;
+       }
+
+       ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
+       close(fd);
+       if (ret)
+               perror("ioctl");
+
+       return ret;
+}
+
+static int setup_ip_addr(const char *dirname, const char *ifname)
+{
+       char path[MAXPATHLEN], line[MAXLINELEN];
+       struct stat s;
+       int ret = 0;
+
+       snprintf(path, MAXPATHLEN, "%s/ipv4/addresses", dirname);
+       if (!stat(path, &s))
+               ret = file_for_each_line(path, setup_ipv4_addr_cb, 
+                                        line, MAXPATHLEN, (void*)ifname);
+       return ret;
+}
+
+static int setup_ip6_addr(const char *dirname, const char *ifname)
+{
+       char path[MAXPATHLEN], line[MAXLINELEN];
+       struct stat s;
+       int ret = 0;
+
+       snprintf(path, MAXLINELEN, "%s/ipv6/addresses", dirname);
+       if (!stat(path, &s))
+               ret = file_for_each_line(path, setup_ipv6_addr_cb, 
+                                        line, MAXPATHLEN, (void*)ifname);      
+       return ret;
+}
+
+static int setup_network_cb(const char *name, const char *dirname, 
+                           const char *file, void *data)
+{
+       char path[MAXPATHLEN];
+       char strindex[MAXINDEXLEN];
+       char ifname[IFNAMSIZ];
+       char newname[IFNAMSIZ];
+       char hwaddr[MAXHWLEN];
+       char *current_ifname = ifname;
+       int ifindex;
+
+       snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
+
+       if (read_info(path, "ifindex", strindex, sizeof(strindex))) {
+               lxc_log_error("failed to read ifindex info");
+               return -1;
+       }
+       
+       ifindex = atoi(strindex);
+       if (!ifindex) {
+               if (!read_info(path, "up", strindex, sizeof(strindex)))
+                   if (device_up("lo")) {
+                           lxc_log_error("failed to set the loopback up");
+                           return -1;
+                   }
+                   return 0;
+       }
+       
+       if (!if_indextoname(ifindex, current_ifname)) {
+               lxc_log_error("no interface corresponding to index '%d'",
+                             ifindex);
+               return -1;
+       }
+       
+       if (!read_info(path, "name", newname, sizeof(newname))) {
+               if (device_rename(ifname, newname)) {
+                       lxc_log_error("failed to rename %s->%s", 
+                                     ifname, newname);
+                       return -1;
+               }
+               current_ifname = newname;
+       }
+
+       if (!read_info(path, "hwaddr", hwaddr, sizeof(hwaddr))) {
+               if (setup_hw_addr(hwaddr, current_ifname)) {
+                       lxc_log_error("failed to setup hw address for '%s'", 
+                                     current_ifname);
+                       return -1;
+               }
+       }
+
+       if (setup_ip_addr(path, current_ifname)) {
+               lxc_log_error("failed to setup ip addresses for '%s'",
+                             ifname);
+               return -1;
+       }
+
+       if (setup_ip6_addr(path, current_ifname)) {
+               lxc_log_error("failed to setup ipv6 addresses for '%s'",
+                             ifname);
+               return -1;
+       }
+
+       if (!read_info(path, "up", strindex, sizeof(strindex))) {
+               if (device_up(current_ifname)) {
+                       lxc_log_error("failed to set '%s' up", current_ifname);
+                       return -1;
+               }
+
+               /* the network is up, make the loopback up too */
+               if (device_up("lo")) {
+                       lxc_log_error("failed to set the loopback up");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int setup_network(const char *name)
+{
+       char dirname[MAXPATHLEN];
+
+       snprintf(dirname, MAXPATHLEN, LXCPATH "/%s/network", name);
+       return dir_for_each(name, dirname, setup_network_cb, NULL);
+}
+
+int conf_has(const char *name, const char *info)
+{
+       int ret;
+       char path[MAXPATHLEN];
+       struct stat st;
+
+       snprintf(path, MAXPATHLEN, LXCPATH "/%s/%s", name, info);
+
+       ret = stat(path, &st);
+       if (!ret) {
+               ret = 1;
+               goto out;
+       }
+
+       if (errno == ENOENT) {
+               ret = 0;
+               goto out;
+       }
+
+       lxc_log_syserror("failed to stat %s info", info);
+out:
+       return ret;
+}
+
+int lxc_configure(const char *name, struct lxc_conf *conf)
+{
+       if (!conf)
+               return 0;
+
+       if (conf->utsname && configure_utsname(name, conf->utsname)) {
+               lxc_log_error("failed to configure the utsname");
+               return -1;
+       }
+
+       if (configure_network(name, &conf->networks)) {
+               lxc_log_error("failed to configure the network");
+               return -1;
+       }
+
+       if (conf->cgroup && configure_cgroup(name, conf->cgroup)) {
+               lxc_log_error("failed to configure the control group");
+               return -1;
+       }
+
+       if (conf->chroot && configure_chroot(name, conf->chroot)) {
+               lxc_log_error("failed to configure the chroot");
+               return -1;
+       }
+
+       if (conf->fstab && configure_mount(name, conf->fstab)) {
+               lxc_log_error("failed to configure the mount points");
+               return -1;
+       }
+
+       return 0;
+}
+
+int lxc_unconfigure(const char *name)
+{
+       if (conf_has_utsname(name) && unconfigure_utsname(name))
+               lxc_log_error("failed to cleanup utsname");
+       
+       if (conf_has_network(name) && unconfigure_network(name))
+               lxc_log_error("failed to cleanup the network");
+
+       if (unconfigure_cgroup(name))
+               lxc_log_error("failed to cleanup cgroup");
+
+       if (conf_has_chroot(name) && unconfigure_chroot(name))
+               lxc_log_error("failed to cleanup chroot");
+
+       if (conf_has_fstab(name) && unconfigure_mount(name))
+               lxc_log_error("failed to cleanup mount");
+
+       return 0;
+}
+
+static int instanciate_veth(const char *dirname, const char *file, pid_t pid)
+{
+       char *path = NULL, *strindex = NULL, *veth1 = NULL, *veth2 = NULL;
+       char bridge[IFNAMSIZ];
+       int ifindex, ret = -1;
+                       
+       asprintf(&veth1, "%s_%d", file, pid);
+       asprintf(&veth2, "%s~%d", file, pid);
+       asprintf(&path, "%s/%s", dirname, file);
+       
+       if (read_info(path, "link", bridge, IFNAMSIZ)) {
+               lxc_log_error("failed to read bridge info");
+               goto out;
+       }
+
+       if (lxc_configure_veth(veth1, veth2, bridge)) {
+               lxc_log_error("failed to create %s-%s/%s", veth1, veth2, bridge);
+               goto out;
+       }
+       
+       ifindex = if_nametoindex(veth2);
+       if (!ifindex) {
+               lxc_log_error("failed to retrieve the index for %s", veth2);
+               goto out;
+       }
+       
+       asprintf(&strindex, "%d", ifindex);
+       if (write_info(path, "ifindex", strindex)) {
+               lxc_log_error("failed to write interface index to %s", path);
+               goto out;
+       }
+
+       if (!read_info(path, "up", strindex, sizeof(strindex))) {
+               if (device_up(veth1)) {
+                       lxc_log_error("failed to set %s up", veth1);
+                       goto out;
+               }
+       }
+
+       ret = 0;
+out:
+       free(path);
+       free(strindex);
+       free(veth1);
+       free(veth2);
+       return ret;
+} 
+static int instanciate_macvlan(const char *dirname, const char *file, pid_t pid)
+{
+       char path[MAXPATHLEN], *strindex = NULL, *peer = NULL;
+       char link[IFNAMSIZ]; 
+       int ifindex, ret = -1;
+                       
+       asprintf(&peer, "%s~%d", file, pid);
+       snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
+       if (read_info(path, "link", link, IFNAMSIZ)) {
+               lxc_log_error("failed to read bridge info");
+               goto out;
+       }
+
+       if (lxc_configure_macvlan(link, peer)) {
+               lxc_log_error("failed to create macvlan interface %s", peer);
+               goto out;
+       }
+
+       ifindex = if_nametoindex(peer);
+       if (!ifindex) {
+               lxc_log_error("failed to retrieve the index for %s", peer);
+               goto out;
+       }
+
+       asprintf(&strindex, "%d", ifindex);
+       if (write_info(path, "ifindex", strindex)) {
+               lxc_log_error("failed to write interface index to %s", path);
+               goto out;
+       }
+
+       ret = 0;
+out:
+       free(strindex);
+       free(peer);
+       return ret;
+}
+
+static int instanciate_phys(const char *dirname, const char *file, pid_t pid)
+{
+       char path[MAXPATHLEN], *strindex = NULL;
+       char link[IFNAMSIZ];
+       int ifindex, ret = -1;
+
+       snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
+       if (read_info(path, "link", link, IFNAMSIZ)) {
+               lxc_log_error("failed to read link info");
+               goto out;
+       }
+
+       ifindex = if_nametoindex(link);
+       if (!ifindex) {
+               lxc_log_error("failed to retrieve the index for %s", link);
+               goto out;
+       }
+
+       asprintf(&strindex, "%d", ifindex);
+       if (write_info(path, "ifindex", strindex)) {
+               lxc_log_error("failed to write interface index to %s", path);
+               goto out;
+       }
+
+       ret = 0;
+out:
+       free(strindex);
+       return ret;
+}
+
+static int instanciate_empty(const char *dirname, const char *file, pid_t pid)
+{
+       char path[MAXPATHLEN], *strindex = NULL;
+       int ret = -1;
+
+       snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
+       if (!asprintf(&strindex, "%d", 0)) {
+               lxc_log_error("not enough memory");
+               return -1;
+       }
+
+       if (write_info(path, "ifindex", strindex)) {
+               lxc_log_error("failed to write interface index to %s", path);
+               goto out;
+       }
+
+       ret = 0;
+out:
+       free(strindex);
+       return ret;
+}
+
+static int instanciate_netdev_cb(const char *name, const char *dirname, 
+                                const char *file, void *data)
+{
+       pid_t *pid = data;
+
+       if (!strncmp("veth", file, strlen("veth")))
+               return instanciate_veth(dirname, file, *pid);
+       else if (!strncmp("macvlan", file, strlen("macvlan")))
+               return instanciate_macvlan(dirname, file, *pid);
+       else if (!strncmp("phys", file, strlen("phys")))
+               return instanciate_phys(dirname, file, *pid);
+       else if (!strncmp("empty", file, strlen("empty")))
+                return instanciate_empty(dirname, file, *pid);
+
+       return -1;
+}
+
+static int instanciate_netdev(const char *name, pid_t pid)
+{
+       char *dirname;
+       int ret;
+
+       asprintf(&dirname, LXCPATH "/%s/network", name);
+       ret =  dir_for_each(name, dirname, instanciate_netdev_cb, &pid);
+       free(dirname);
+
+       return ret;
+}
+
+static int move_netdev_cb(const char *name, const char *dirname, 
+                         const char *file, void *data)
+{
+       char path[MAXPATHLEN], ifname[IFNAMSIZ], strindex[MAXINDEXLEN];
+       pid_t *pid = data;
+       int ifindex;
+
+       snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
+       if (read_info(path, "ifindex", strindex, MAXINDEXLEN) < 0) {
+               lxc_log_error("failed to read index to from %s", path);
+               return -1;
+       }
+       
+       ifindex = atoi(strindex);
+       if (!ifindex)
+               return 0;
+
+       if (!if_indextoname(ifindex, ifname)) {
+               lxc_log_error("interface with index %d does not exist",
+                             ifindex);
+               return -1;
+       }
+       
+       if (device_move(ifname, *pid)) {
+               lxc_log_error("failed to move %s to %d", ifname, *pid);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int move_netdev(const char *name, pid_t pid)
+{
+       char *dirname;
+       int ret;
+
+       asprintf(&dirname, LXCPATH "/%s/network", name);
+       ret = dir_for_each(name, dirname, move_netdev_cb, &pid);
+       free(dirname);
+
+       return ret;
+}
+
+int conf_create_network(const char *name, pid_t pid)
+{
+       if (instanciate_netdev(name, pid)) {
+               lxc_log_error("failed to instantiate the network devices");
+               return -1;
+       }
+
+       if (move_netdev(name, pid)) {
+               lxc_log_error("failed to move the netdev to the container");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int delete_netdev_cb(const char *name, const char *dirname, 
+                           const char *file, void *data)
+{
+       char strindex[MAXINDEXLEN];
+       char path[MAXPATHLEN];
+       char ifname[IFNAMSIZ];
+       int i, ifindex;
+       
+       snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
+       
+       if (read_info(path, "ifindex", strindex, MAXINDEXLEN)) {
+               lxc_log_error("failed to read ifindex info");
+               return -1;
+       }
+               
+       ifindex = atoi(strindex);
+       if (!ifindex)
+               return 0;
+
+       /* TODO : temporary code - needs wait on namespace */
+       for (i = 0; i < 120; i++) {
+               if (if_indextoname(ifindex, ifname))
+                       break;
+               if (!i)
+                       printf("waiting for interface #%d to come back\n", ifindex);
+               else
+                       printf("."); fflush(stdout);
+               sleep(1);
+       }
+
+       /* do not delete a physical network device */
+       if (strncmp("phys", file, strlen("phys")))
+               if (device_delete(ifname)) {
+                       lxc_log_error("failed to remove the netdev %s", ifname);
+               }
+
+       delete_info(path, "ifindex");
+
+       return 0;
+}
+
+static int delete_netdev(const char *name)
+{
+       char *dirname;
+       int ret;
+
+       asprintf(&dirname, LXCPATH "/%s/network", name);
+       ret = dir_for_each(name, dirname, delete_netdev_cb, NULL);
+       free(dirname);
+
+       return ret;
+}
+
+int conf_destroy_network(const char *name)
+{
+       if (delete_netdev(name)) {
+               lxc_log_error("failed to remove the network devices");
+               return -1;
+       }
+
+       return 0;
+}
+
+int lxc_setup(const char *name)
+{
+       if (conf_has_utsname(name) && setup_utsname(name)) {
+               lxc_log_error("failed to setup the utsname for '%s'", name);
+               return -1;
+       }
+
+       if (conf_has_network(name) && setup_network(name)) {
+               lxc_log_error("failed to setup the network for '%s'", name);
+               return -1;
+       }
+
+       if (conf_has_fstab(name) && setup_mount(name)) {
+               lxc_log_error("failed to setup the mount points for '%s'", name);
+               return -1;
+       }
+
+       if (conf_has_chroot(name) && setup_chroot(name)) {
+               lxc_log_error("failed to set chroot for '%s'", name);
+               return -1;
+       }
+
+       return 0;
+}
diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h
new file mode 100644 (file)
index 0000000..a00a4a7
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _conf_h
+#define _conf_h
+
+#include <netinet/in.h>
+
+enum { 
+       EMPTY,
+       VETH,
+       MACVLAN,
+       PHYS,
+       MAXCONFTYPE,
+};
+
+/*
+ * Defines the structure to configure an ipv4 address
+ * @address   : ipv4 address
+ * @broadcast : ipv4 broadcast address
+ * @mask      : network mask
+ */
+struct lxc_inetdev {
+       struct in_addr addr;
+       struct in_addr bcast;
+       int prefix;
+};
+
+struct lxc_route {
+       struct in_addr addr;
+};
+
+/*
+ * Defines the structure to configure an ipv6 address
+ * @flags     : set the address up
+ * @address   : ipv6 address
+ * @broadcast : ipv6 broadcast address
+ * @mask      : network mask
+ */
+struct lxc_inet6dev {
+       struct in6_addr addr;
+       struct in6_addr bcast;
+       struct in6_addr acast;
+       int prefix;
+};
+
+struct lxc_route6 {
+       struct in6_addr addr;
+};
+/*
+ * Defines a structure to configure a network device
+ * @ifname : network device name
+ * @flags  : flag of the network device (IFF_UP, ... )
+ * @ipv4   : a list of ipv4 addresses to be set on the network device
+ * @ipv6   : a list of ipv6 addresses to be set on the network device
+ */
+struct lxc_netdev {
+       int flags;
+       char *ifname;
+       char *newname;
+       char *hwaddr;
+       struct lxc_list ipv4;
+       struct lxc_list ipv6;
+       struct lxc_list route4;
+       struct lxc_list route6;
+};
+
+/*
+ * Defines the kind of the network to use
+ * @type : the type of the network virtualization
+ * @phys : phys configuration type
+ * @veth : veth configuration type
+ * @macvlan : macvlan configuration type
+ */
+struct lxc_network {
+       int type;
+       struct lxc_list netdev;
+};
+
+/*
+ * Defines a structure to configure the control data and path
+ */
+struct lxc_cgroup {
+       ;
+};
+
+/*
+ * Defines the global container configuration
+ * @chroot  : the root directory to run the container
+ * @mount   : the list of mount points
+ * @network : the network configuration
+ * @utsname : the container utsname
+ */
+struct lxc_conf {
+       char *chroot;
+       char *fstab;
+       struct utsname *utsname;
+       struct lxc_cgroup *cgroup;
+       struct lxc_list networks;
+};
+
+/*
+ * Configure the external resources for the container
+ */
+extern int lxc_configure(const char *name, struct lxc_conf *conf);
+
+/*
+ * Remove the resources created by the configuration
+ */
+extern int lxc_unconfigure(const char *name);
+
+extern int conf_create_network(const char *name, pid_t pid);
+
+extern int conf_destroy_network(const char *name);
+
+/*
+ * Configure the container from inside
+ */
+extern int lxc_setup(const char *name);
+
+extern int conf_has(const char *name, const char *info);
+
+#define conf_has_fstab(__name)   conf_has(__name, "fstab")
+#define conf_has_chroot(__name)  conf_has(__name, "chroot")
+#define conf_has_utsname(__name) conf_has(__name, "utsname")
+#define conf_has_network(__name) conf_has(__name, "network")
+
+#endif
diff --git a/src/lxc/lxc_info.c b/src/lxc/lxc_info.c
new file mode 100644 (file)
index 0000000..8939405
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <sys/types.h>
+
+#include <lxc.h>
+
+void usage(char *cmd)
+{
+       fprintf(stderr, "%s <command>\n", basename(cmd));
+       fprintf(stderr, "\t -n <name>   : name of the container\n");
+       _exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+       char opt;
+       char *name = NULL;
+       int state, nbargs = 0;
+
+       while ((opt = getopt(argc, argv, "n:")) != -1) {
+               switch (opt) {
+               case 'n':
+                       name = optarg;
+                       break;
+               }
+
+               nbargs++;
+       }
+
+       if (!name)
+               usage(argv[0]);
+
+       state = lxc_getstate(name);
+       if (state < 0) {
+               fprintf(stderr, "failed to freeze '%s'\n", name);
+               return 1;
+       }
+
+       printf("'%s' is %s\n", name, lxc_state2str(state));
+
+       return 0;
+}
+
diff --git a/src/lxc/lxc_list.c b/src/lxc/lxc_list.c
new file mode 100644 (file)
index 0000000..d588ae2
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <list.h>
diff --git a/src/lxc/lxc_list.h b/src/lxc/lxc_list.h
new file mode 100644 (file)
index 0000000..45c04fb
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef _list_h
+#define _list_h
+
+struct lxc_list {
+       void *elem;
+       struct lxc_list *next;
+       struct lxc_list *prev;
+};
+
+#define lxc_init_list(l) { .next = l, .prev = l, }
+
+#define lxc_list_for_each(__iterator, __list)                          \
+       for (__iterator = (__list)->next;                               \
+            __iterator != __list;                                      \
+            __iterator = __iterator->next)
+
+static inline void lxc_list_init(struct lxc_list *list)
+{
+       list->elem = NULL;
+       list->next = list->prev = list;
+}
+
+static inline void lxc_list_add_elem(struct lxc_list *list, void *elem)
+{
+       list->elem = elem;
+}
+
+static inline void *lxc_list_first_elem(struct lxc_list *list)
+{
+       return list->next->elem;
+}
+
+static inline int lxc_list_empty(struct lxc_list *list)
+{
+       return list == list->next;
+}
+
+static inline void lxc_list_add(struct lxc_list *head, struct lxc_list *list)
+{
+       struct lxc_list *next = head->next;
+       next->prev = list;
+       list->next = next;
+       list->prev = head;
+       head->next = list;
+}
+
+static inline void lxc_list_del(struct lxc_list *list)
+{
+       struct lxc_list *next, *prev;
+
+       next = list->next;
+       prev = list->prev;
+       next->prev = prev;
+       prev->next = next;
+}
+
+#endif
diff --git a/src/lxc/lxc_lock.c b/src/lxc/lxc_lock.c
new file mode 100644 (file)
index 0000000..dcbd49f
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/file.h>
+
+#include <lxc.h>
+
+int lxc_get_lock(const char *name)
+{
+       char *lock;
+       int fd, ret;
+
+       asprintf(&lock, LXCPATH "/%s", name);
+       fd = open(lock, O_RDONLY|O_DIRECTORY, S_IRUSR|S_IWUSR);
+       if (fd < 0) {
+               ret = -errno;
+               goto out;
+       }
+
+        fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+       if (flock(fd, LOCK_EX|LOCK_NB)) {
+               ret = errno == EWOULDBLOCK ? 0 : -errno;
+               close(fd);
+               goto out;
+       }
+
+       ret = fd;
+out:
+       free(lock);
+       return ret;
+}
+
+void lxc_put_lock(int lock)
+{
+       flock(lock, LOCK_UN);
+       close(lock);
+}
diff --git a/src/lxc/lxc_lock.h b/src/lxc/lxc_lock.h
new file mode 100644 (file)
index 0000000..ed72b0e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _lock_h
+#define _lock_h
+
+extern int lxc_get_lock(const char *name);
+
+extern void lxc_put_lock(int lock);
+
+#endif
diff --git a/src/lxc/lxc_log.c b/src/lxc/lxc_log.c
new file mode 100644 (file)
index 0000000..7b962dc
--- /dev/null
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include <lxc_log.h>
+
+#define MAXTIMELEN 47;
+#define ERRNO_FORMAT "%d (%s)"
+
diff --git a/src/lxc/lxc_log.h b/src/lxc/lxc_log.h
new file mode 100644 (file)
index 0000000..620e10c
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _log_h
+#define _log_h
+
+#define lxc_log(format, level, ...) do {                              \
+               fprintf(stderr, "[%s] \t%s:%d - " format "\n", \
+                       level, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+       } while (0)
+
+#define lxc_log_error(format, ...) lxc_log(format, "error", ##__VA_ARGS__);
+#define lxc_log_warning(format, ...) lxc_log(format, "warning", ##__VA_ARGS__);
+#define lxc_log_info(format, ...) lxc_log(format, "info", ##__VA_ARGS__);
+#define lxc_log_debug(format, ...) lxc_log(format, "debug", ##__VA_ARGS__);
+#define lxc_log_trace(format, ...) lxc_log(format, "trace", ##__VA_ARGS__);
+#define lxc_log_syserror(format, ...) do { \
+               fprintf(stderr, "[syserr] \t%s:%d: %s - " format "\n", \
+                       __FUNCTION__, __LINE__, strerror(errno), \
+                       ##__VA_ARGS__);                                 \
+       } while (0)
+
+#endif
diff --git a/src/lxc/lxc_namespace.h b/src/lxc/lxc_namespace.h
new file mode 100644 (file)
index 0000000..4059368
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __namespace_h
+#define __namespace_h
+
+#include <syscall.h>
+#ifndef CLONE_FS
+#  define CLONE_FS                0x00000200
+#endif
+#ifndef CLONE_NEWNS
+#  define CLONE_NEWNS             0x00020000
+#endif
+#ifndef CLONE_NEWUTS
+#  define CLONE_NEWUTS            0x04000000
+#endif
+#ifndef CLONE_NEWIPC
+#  define CLONE_NEWIPC            0x08000000
+#endif
+#ifndef CLONE_NEWUSER
+#  define CLONE_NEWUSER           0x10000000
+#endif
+#ifndef CLONE_NEWPID
+#  define CLONE_NEWPID            0x20000000
+#endif
+#ifndef CLONE_NEWNET
+#  define CLONE_NEWNET            0x40000000
+#endif
+#ifndef __NR_unshare
+#  ifdef __i386__
+#    define __NR_unshare 310
+#  elif __x86_64__
+#    define __NR_unshare 272
+#  elif __ia64__
+#    define __NR_unshare 1296
+#  elif __s390__
+#    define __NR_unshare 303
+#  elif __powerpc__
+#    define __NR_unshare 282
+#else
+#    error "unsupported architecture"
+#  endif
+#endif
+#if __i386__ || __x86_64__ || __s390__ || __powerpc__
+#   define fork_ns(flags) syscall(SYS_clone, flags|SIGCHLD, NULL);
+#elif __ia64__
+#   define fork_ns(flags) syscall(SYS_clone2, flags|SIGCHLD, NULL);
+#else
+#   error "unsupported architecture"
+#endif
+#define unshare_ns(flags) syscall(__NR_unshare, flags, NULL);
+#endif
index 8939405fe17e5393d5f63941d149853eb9d9f041..3ef90803840bc54ef9938ff416b75edec3a16a39 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 #include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
 #include <unistd.h>
-#include <libgen.h>
 #include <sys/types.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/file.h>
 
 #include <lxc.h>
+#include "monitor.h"
+
+static char *strstate[] = {
+       "STOPPED", "STARTING", "RUNNING", "STOPPING",
+       "ABORTING", "FREEZING", "FROZEN",
+};
+
+const char *lxc_state2str(lxc_state_t state)
+{
+       if (state < STOPPED || state > MAX_STATE - 1)
+               return NULL;
+       return strstate[state];
+}
 
-void usage(char *cmd)
+lxc_state_t lxc_str2state(const char *state)
 {
-       fprintf(stderr, "%s <command>\n", basename(cmd));
-       fprintf(stderr, "\t -n <name>   : name of the container\n");
-       _exit(1);
+       int i, len;
+       len = sizeof(strstate)/sizeof(strstate[0]);
+       for (i = 0; i < len; i++)
+               if (!strcmp(strstate[i], state))
+                       return i;
+       return -1;
 }
 
-int main(int argc, char *argv[])
+int lxc_setstate(const char *name, lxc_state_t state)
 {
-       char opt;
-       char *name = NULL;
-       int state, nbargs = 0;
-
-       while ((opt = getopt(argc, argv, "n:")) != -1) {
-               switch (opt) {
-               case 'n':
-                       name = optarg;
-                       break;
-               }
-
-               nbargs++;
+       int fd, err;
+       char file[MAXPATHLEN];
+       const char *str = lxc_state2str(state);
+
+       if (!str)
+               return -1;
+
+       snprintf(file, MAXPATHLEN, LXCPATH "/%s/state", name);
+
+       fd = open(file, O_WRONLY);
+       if (fd < 0) {
+               lxc_log_syserror("failed to open %s file", file);
+               return -1;
        }
 
-       if (!name)
-               usage(argv[0]);
+       if (flock(fd, LOCK_EX)) {
+               lxc_log_syserror("failed to take the lock to %s", file);
+               goto out;
+       }
+
+       if (ftruncate(fd, 0)) {
+               lxc_log_syserror("failed to truncate the file %s", file);
+               goto out;
+       }
 
-       state = lxc_getstate(name);
-       if (state < 0) {
-               fprintf(stderr, "failed to freeze '%s'\n", name);
-               return 1;
+       if (write(fd, str, strlen(str)) < 0) {
+               lxc_log_syserror("failed to write state to %s", file);
+               goto out;
        }
 
-       printf("'%s' is %s\n", name, lxc_state2str(state));
+       err = 0;
+out:
+       close(fd);
 
+       lxc_monitor_send_state(name, state);
+
+       /* let the event to be propagated, crappy but that works,
+        * otherwise the events will be folded into only one event,
+        * and I want to have them to be one by one in order
+        * to follow the different states of the container.
+        */
+       usleep(200000);
+
+       return -err;
+}
+
+int lxc_mkstate(const char *name)
+{
+       int fd;
+       char file[MAXPATHLEN];
+
+       snprintf(file, MAXPATHLEN, LXCPATH "/%s/state", name);
+       fd = creat(file, S_IRUSR|S_IWUSR);
+       if (fd < 0) {
+               lxc_log_syserror("failed to create file %s", file);
+               return -1;
+       }
+       close(fd);
+       return 0;
+}
+
+int lxc_rmstate(const char *name)
+{
+       char file[MAXPATHLEN];
+       snprintf(file, MAXPATHLEN, LXCPATH "/%s/state", name);
+       unlink(file);
        return 0;
 }
 
+lxc_state_t lxc_getstate(const char *name)
+{
+       int fd, err;
+       char file[MAXPATHLEN];
+
+       snprintf(file, MAXPATHLEN, LXCPATH "/%s/state", name);
+
+       fd = open(file, O_RDONLY);
+       if (fd < 0) {
+               lxc_log_syserror("failed to open %s", file);
+               return -1;
+       }
+
+       if (flock(fd, LOCK_SH)) {
+               lxc_log_syserror("failed to take the lock to %s", file);
+               close(fd);
+               return -1;
+       }
+
+       err = read(fd, file, strlen(file));
+       if (err < 0) {
+               lxc_log_syserror("failed to read file %s", file);
+               close(fd);
+               return -1;
+       }
+       file[err] = '\0';
+
+       close(fd);
+       return lxc_str2state(file);
+}
+
+static int freezer_state(const char *name)
+{
+       char freezer[MAXPATHLEN];
+       char status[MAXPATHLEN];
+       FILE *file;
+       int err;
+       
+       snprintf(freezer, MAXPATHLEN,
+                LXCPATH "/%s/freezer.freeze", name);
+
+       file = fopen(freezer, "r");
+       if (!file)
+               return -1;
+
+       err = fscanf(file, "%s", status);
+       fclose(file);
+
+       if (err == EOF) {
+               lxc_log_syserror("failed to read %s", freezer);
+               return -1;
+       }
+
+       return lxc_str2state(status);
+}
+
+lxc_state_t lxc_state(const char *name)
+{
+       int state = freezer_state(name);
+       if (state != FROZEN && state != FREEZING)
+               state = lxc_getstate(name);
+       return state;
+}
diff --git a/src/lxc/lxc_state.h b/src/lxc/lxc_state.h
new file mode 100644 (file)
index 0000000..871d1a8
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _state_h
+#define _state_h
+
+typedef enum {
+       STOPPED, STARTING, RUNNING, STOPPING,
+       ABORTING, FREEZING, FROZEN, MAX_STATE,
+} lxc_state_t;
+
+extern int lxc_mkstate(const char *name);
+extern int lxc_rmstate(const char *name);
+extern int lxc_setstate(const char *name, lxc_state_t state);
+extern lxc_state_t lxc_getstate(const char *name);
+
+extern lxc_state_t lxc_str2state(const char *state);
+extern const char *lxc_state2str(lxc_state_t state);
+
+#endif
diff --git a/src/lxc/lxc_utils.h b/src/lxc/lxc_utils.h
new file mode 100644 (file)
index 0000000..5fc3946
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _utils_h
+#define _utils_h
+
+#define LXC_TTY_HANDLER(s) \
+       static struct sigaction lxc_tty_sa_##s;                         \
+       static void tty_##s##_handler(int sig, siginfo_t *info, void *ctx) \
+       {                                                               \
+               if (lxc_tty_sa_##s.sa_handler == SIG_DFL ||             \
+                   lxc_tty_sa_##s.sa_handler == SIG_IGN)               \
+                       return;                                         \
+               (*lxc_tty_sa_##s.sa_sigaction)(sig, info, ctx); \
+       }
+
+#define LXC_TTY_ADD_HANDLER(s) \
+       do { \
+               struct sigaction sa; \
+               sa.sa_sigaction = tty_##s##_handler; \
+               sa.sa_flags = SA_SIGINFO; \
+               sigfillset(&sa.sa_mask); \
+               /* No error expected with sigaction. */ \
+               sigaction(s, &sa, &lxc_tty_sa_##s); \
+       } while (0)
+
+#define LXC_TTY_DEL_HANDLER(s) \
+       do { \
+               sigaction(s, &lxc_tty_sa_##s, NULL); \
+       } while (0)
+
+#endif
diff --git a/src/lxc/monitor.c b/src/lxc/monitor.c
new file mode 100644 (file)
index 0000000..fec80fe
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/inotify.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <lxc.h>
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX 108
+#endif
+
+int lxc_monitor(const char *name, int output_fd)
+{
+       char path[MAXPATHLEN];
+       int err = -1, nfd, wfd, state;
+
+       nfd = inotify_init();
+       if (nfd < 0) {
+               lxc_log_syserror("failed to initialize inotify");
+               return -1;
+       }
+
+       snprintf(path, MAXPATHLEN, LXCPATH "/%s/state", name);
+
+       wfd = inotify_add_watch(nfd, path, IN_DELETE_SELF|IN_CLOSE_WRITE);
+       if (wfd < 0) {
+               lxc_log_syserror("failed to add a watch on %s", path);
+               goto out;
+       }
+
+       for(;;) {
+               struct inotify_event evt;
+
+               if (read(nfd, &evt, sizeof(evt)) < 0) {
+                       lxc_log_syserror("failed to read inotify event");
+                       goto out;
+               }
+
+               if (evt.mask & IN_CLOSE_WRITE) {
+
+                       state = lxc_getstate(name);
+                       if (state < 0) {
+                               lxc_log_error("failed to get the state for %s",
+                                             name);
+                               goto out;
+                       }
+
+                       if (write(output_fd, &state, sizeof(state)) < 0) {
+                               lxc_log_syserror("failed to send state to %d", 
+                                                output_fd);
+                               goto out;
+                       }
+                       continue;
+               }
+
+               if (evt.mask & IN_DELETE_SELF) {
+                       close(output_fd);
+                       err = 0;
+                       goto out;
+               }
+
+               lxc_log_error("unknown evt for inotity (%d)", evt.mask);
+               goto out;
+       }
+
+out:
+       inotify_rm_watch(nfd, wfd);
+       close(nfd);
+       return err;
+}
+
+void lxc_monitor_send_state(const char *name, lxc_state_t state)
+{
+       int fd;
+       struct sockaddr_un addr;
+
+       fd = socket(PF_UNIX, SOCK_DGRAM, 0);
+       if (fd < 0)
+               lxc_log_syserror("failed to create notification socket");
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       snprintf(addr.sun_path, UNIX_PATH_MAX, LXCPATH "/%s/notification", name);
+
+       sendto(fd, &state, sizeof(state), 0, 
+              (const struct sockaddr *)&addr, sizeof(addr));
+
+       close(fd);
+}
+
+void lxc_monitor_cleanup(const char *name)
+{
+       char path[UNIX_PATH_MAX];
+       snprintf(path, UNIX_PATH_MAX, LXCPATH "/%s/notification", name);
+       unlink(path);
+}
+
+int lxc_monitor_open(const char *name)
+{
+       int fd;
+       struct sockaddr_un addr;
+
+       fd = socket(PF_UNIX, SOCK_DGRAM, 0);
+       if (fd < 0) {
+               lxc_log_syserror("failed to create notification socket");
+               return -1;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+
+       addr.sun_family = AF_UNIX;
+       snprintf(addr.sun_path, UNIX_PATH_MAX, LXCPATH "/%s/notification", name);
+       unlink(addr.sun_path);
+
+       if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr))) {
+               lxc_log_syserror("failed to bind to '%s'", addr.sun_path);
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+int lxc_monitor_read(int fd, lxc_state_t *state)
+{
+       int ret;
+
+       ret = recv(fd, state, sizeof(*state), 0);
+       if (ret < 0) {
+               lxc_log_syserror("failed to received state");
+               return -1;
+       }
+
+       return ret;
+}
+
+int lxc_monitor_close(int fd)
+{
+       return close(fd);
+}
diff --git a/src/lxc/monitor.h b/src/lxc/monitor.h
new file mode 100644 (file)
index 0000000..a282986
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __monitor_h
+#define __monitor_h
+
+void lxc_monitor_send_state(const char *name, lxc_state_t state);
+void lxc_monitor_cleanup(const char *name);
+
+#endif
diff --git a/src/lxc/namespace.h b/src/lxc/namespace.h
new file mode 100644 (file)
index 0000000..4059368
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __namespace_h
+#define __namespace_h
+
+#include <syscall.h>
+#ifndef CLONE_FS
+#  define CLONE_FS                0x00000200
+#endif
+#ifndef CLONE_NEWNS
+#  define CLONE_NEWNS             0x00020000
+#endif
+#ifndef CLONE_NEWUTS
+#  define CLONE_NEWUTS            0x04000000
+#endif
+#ifndef CLONE_NEWIPC
+#  define CLONE_NEWIPC            0x08000000
+#endif
+#ifndef CLONE_NEWUSER
+#  define CLONE_NEWUSER           0x10000000
+#endif
+#ifndef CLONE_NEWPID
+#  define CLONE_NEWPID            0x20000000
+#endif
+#ifndef CLONE_NEWNET
+#  define CLONE_NEWNET            0x40000000
+#endif
+#ifndef __NR_unshare
+#  ifdef __i386__
+#    define __NR_unshare 310
+#  elif __x86_64__
+#    define __NR_unshare 272
+#  elif __ia64__
+#    define __NR_unshare 1296
+#  elif __s390__
+#    define __NR_unshare 303
+#  elif __powerpc__
+#    define __NR_unshare 282
+#else
+#    error "unsupported architecture"
+#  endif
+#endif
+#if __i386__ || __x86_64__ || __s390__ || __powerpc__
+#   define fork_ns(flags) syscall(SYS_clone, flags|SIGCHLD, NULL);
+#elif __ia64__
+#   define fork_ns(flags) syscall(SYS_clone2, flags|SIGCHLD, NULL);
+#else
+#   error "unsupported architecture"
+#endif
+#define unshare_ns(flags) syscall(__NR_unshare, flags, NULL);
+#endif
diff --git a/src/lxc/network.c b/src/lxc/network.c
new file mode 100644 (file)
index 0000000..6e10481
--- /dev/null
@@ -0,0 +1,727 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCe
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/sockios.h>
+#include <linux/if_bridge.h>
+#include <nl.h>
+#include <network.h>
+
+#ifndef IFLA_LINKMODE
+#  define IFLA_LINKMODE 17
+#endif
+
+#ifndef IFLA_LINKINFO
+#  define IFLA_LINKINFO 18
+#endif
+
+#ifndef IFLA_NET_NS_PID
+#  define IFLA_NET_NS_PID 19
+#endif
+
+#ifndef IFLA_INFO_KIND
+# define IFLA_INFO_KIND 1
+#endif
+
+#ifndef IFLA_INFO_DATA
+#  define IFLA_INFO_DATA 2
+#endif
+
+#ifndef VETH_INFO_PEER
+# define VETH_INFO_PEER 1
+#endif
+
+struct link_req {
+       struct nlmsg nlmsg;
+       struct ifinfomsg ifinfomsg;
+};
+
+struct ip_req {
+       struct nlmsg nlmsg;
+       struct ifaddrmsg ifa;
+};
+
+int device_move(const char *name, pid_t pid)
+{
+       struct nl_handler nlh;
+       struct nlmsg *nlmsg = NULL;
+       struct link_req *link_req;
+       int index, len, err = -1;
+
+       if (netlink_open(&nlh, NETLINK_ROUTE))
+               return -1;
+
+       len = strlen(name);
+       if (len == 1 || len > IFNAMSIZ)
+               goto out;
+
+       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!nlmsg)
+               goto out;
+
+       index = if_nametoindex(name);
+       if (!index)
+               goto out;
+
+       link_req = (struct link_req *)nlmsg;
+       link_req->ifinfomsg.ifi_family = AF_UNSPEC;
+       link_req->ifinfomsg.ifi_index = index;
+       nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+       nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+       nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
+
+       if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid))
+               goto out;
+
+       if (nla_put_string(nlmsg, IFLA_IFNAME, name))
+               goto out;
+
+       if (netlink_transaction(&nlh, nlmsg, nlmsg))
+               goto out;
+
+       err = 0;
+out:
+       netlink_close(&nlh);
+       nlmsg_free(nlmsg);
+       return err;
+}
+
+extern int device_delete(const char *name)
+{
+       struct nl_handler nlh;
+       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       struct link_req *link_req;
+       int index, len, err = -1;
+
+       if (netlink_open(&nlh, NETLINK_ROUTE))
+               return -1;
+
+       len = strlen(name);
+       if (len == 1 || len > IFNAMSIZ)
+               goto out;
+
+       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!nlmsg)
+               goto out;
+
+       answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!answer)
+               goto out;
+
+       index = if_nametoindex(name);
+       if (!index)
+               goto out;
+
+       link_req = (struct link_req *)nlmsg;
+       link_req->ifinfomsg.ifi_family = AF_UNSPEC;
+       link_req->ifinfomsg.ifi_index = index;
+       nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+       nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
+       nlmsg->nlmsghdr.nlmsg_type = RTM_DELLINK;
+
+       if (nla_put_string(nlmsg, IFLA_IFNAME, name))
+               goto out;
+
+       if (netlink_transaction(&nlh, nlmsg, answer))
+               goto out;
+
+       err = 0;
+out:
+       netlink_close(&nlh);
+       nlmsg_free(answer);
+       nlmsg_free(nlmsg);
+       return err;
+}
+
+static int device_set_flag(const char *name, int flag)
+{
+       struct nl_handler nlh;
+       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       struct link_req *link_req;
+       int index, len, err = -1;
+
+       if (netlink_open(&nlh, NETLINK_ROUTE))
+               return -1;
+
+       len = strlen(name);
+       if (len == 1 || len > IFNAMSIZ)
+               goto out;
+
+       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!nlmsg)
+               goto out;
+
+       answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!answer)
+               goto out;
+
+       index = if_nametoindex(name);
+       if (!index)
+               goto out;
+
+       link_req = (struct link_req *)nlmsg;
+       link_req->ifinfomsg.ifi_family = AF_UNSPEC;
+       link_req->ifinfomsg.ifi_index = index;
+       link_req->ifinfomsg.ifi_change |= IFF_UP;
+       link_req->ifinfomsg.ifi_flags |= flag;
+       nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+       nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+       nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
+
+       err = netlink_transaction(&nlh, nlmsg, answer);
+       if (err < 0)
+               goto out;
+
+       err = 0;
+out:
+       netlink_close(&nlh);
+       nlmsg_free(nlmsg);
+       nlmsg_free(answer);
+       return err;
+}
+
+int device_up(const char *name)
+{
+       return device_set_flag(name, IFF_UP);
+}
+
+int device_down(const char *name)
+{
+       return device_set_flag(name, 0);
+}
+
+int device_rename(const char *oldname, const char *newname)
+{
+       struct nl_handler nlh;
+       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       struct link_req *link_req;
+       int index, len, err = -1;
+
+       if (netlink_open(&nlh, NETLINK_ROUTE))
+               return -1;
+
+       len = strlen(oldname);
+       if (len == 1 || len > IFNAMSIZ)
+               goto out;
+
+       len = strlen(newname);
+       if (len == 1 || len > IFNAMSIZ)
+               goto out;
+
+       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!nlmsg)
+               goto out;
+
+       answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!answer)
+               goto out;
+
+       index = if_nametoindex(oldname);
+       if (!index)
+               goto out;
+
+       link_req = (struct link_req *)nlmsg;
+       link_req->ifinfomsg.ifi_family = AF_UNSPEC;
+       link_req->ifinfomsg.ifi_index = index;
+       nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+       nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
+       nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
+
+       if (nla_put_string(nlmsg, IFLA_IFNAME, newname))
+               goto out;
+
+       if (netlink_transaction(&nlh, nlmsg, answer))
+               goto out;
+
+       err = 0;
+out:
+       netlink_close(&nlh);
+       nlmsg_free(answer);
+       nlmsg_free(nlmsg);
+       return err;
+}
+
+int veth_create(const char *name1, const char *name2)
+{
+       struct nl_handler nlh;
+       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       struct link_req *link_req;
+       struct rtattr *nest1, *nest2, *nest3;
+       int len, err = -1;
+
+       if (netlink_open(&nlh, NETLINK_ROUTE))
+               return -1;
+
+       len = strlen(name1);
+       if (len == 1 || len > IFNAMSIZ)
+               goto out;
+
+       len = strlen(name2);
+       if (len == 1 || len > IFNAMSIZ)
+               goto out;
+
+       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!nlmsg)
+               goto out;
+
+       answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!answer)
+               goto out;
+
+       link_req = (struct link_req *)nlmsg;
+       link_req->ifinfomsg.ifi_family = AF_UNSPEC;
+       nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+       nlmsg->nlmsghdr.nlmsg_flags = 
+               NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
+       nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
+
+       nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO);
+       if (!nest1)
+               goto out;
+
+       if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth"))
+               goto out;
+
+       nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
+       if (!nest2)
+               goto out;
+
+       nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER);
+       if (!nest3)
+               goto out;
+
+       nlmsg->nlmsghdr.nlmsg_len += sizeof(struct ifinfomsg);
+
+       if (nla_put_string(nlmsg, IFLA_IFNAME, name2))
+               goto out;
+
+       nla_end_nested(nlmsg, nest3);
+
+       nla_end_nested(nlmsg, nest2);
+
+       nla_end_nested(nlmsg, nest1);
+
+       if (nla_put_string(nlmsg, IFLA_IFNAME, name1))
+               goto out;
+
+       if (netlink_transaction(&nlh, nlmsg, answer))
+               goto out;
+
+       err = 0;
+out:
+       netlink_close(&nlh);
+       nlmsg_free(answer);
+       nlmsg_free(nlmsg);
+       return err;
+}
+
+int macvlan_create(const char *master, const char *name)
+{
+       struct nl_handler nlh;
+       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       struct link_req *link_req;
+       struct rtattr *nest;
+       int index, len, err = -1;
+
+       if (netlink_open(&nlh, NETLINK_ROUTE))
+               return -1;
+
+       len = strlen(master);
+       if (len == 1 || len > IFNAMSIZ)
+               goto out;
+
+       len = strlen(name);
+       if (len == 1 || len > IFNAMSIZ)
+               goto out;
+
+       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!nlmsg)
+               goto out;
+
+       answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!answer)
+               goto out;
+
+       index = if_nametoindex(master);
+       if (!index)
+               goto out;
+
+       link_req = (struct link_req *)nlmsg;
+       link_req->ifinfomsg.ifi_family = AF_UNSPEC;
+       nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+       nlmsg->nlmsghdr.nlmsg_flags =
+               NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
+       nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
+
+       nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
+       if (!nest)
+               goto out;
+
+       if (nla_put_string(nlmsg, IFLA_INFO_KIND, "macvlan"))
+               goto out;
+
+       nla_end_nested(nlmsg, nest);
+
+       if (nla_put_u32(nlmsg, IFLA_LINK, index))
+               goto out;
+
+       if (nla_put_string(nlmsg, IFLA_IFNAME, name))
+               goto out;
+
+       if (netlink_transaction(&nlh, nlmsg, answer))
+               goto out;
+
+       err = 0;
+out:
+       netlink_close(&nlh);
+       nlmsg_free(answer);
+       nlmsg_free(nlmsg);
+       return err;
+}
+
+static int proc_sys_net_write(const char *path, const char *value)
+{
+       int fd, err = 0;
+
+       fd = open(path, O_WRONLY);
+       if (fd < 0)
+               return -errno;
+
+       if (write(fd, value, strlen(value)) < 0)
+               err = -errno;
+
+       close(fd);
+       return err;
+}
+
+static int ip_forward_set(const char *ifname, int family, int flag)
+{
+       char *path;
+       int ret;
+
+       if (family != AF_INET && family != AF_INET6)
+               return -1;
+
+       asprintf(&path, "/proc/sys/net/%s/conf/%s/forwarding", 
+                family == AF_INET?"ipv4":"ipv6" , ifname);
+
+       ret = proc_sys_net_write(path, flag?"1":"0");
+       free(path);
+
+       return ret;
+}
+
+int ip_forward_on(const char *ifname, int family)
+{
+       return ip_forward_set(ifname, family, 1);
+}
+
+int ip_forward_off(const char *ifname, int family)
+{
+       return ip_forward_set(ifname, family, 0);
+}
+
+static int neigh_proxy_set(const char *ifname, int family, int flag)
+{
+       char path[MAXPATHLEN];
+
+       if (family != AF_INET && family != AF_INET6)
+               return -1;
+
+       sprintf(path, "/proc/sys/net/%s/conf/%s/%s", 
+               family == AF_INET?"ipv4":"ipv6" , ifname, 
+               family == AF_INET?"proxy_arp":"proxy_ndp");
+
+       return proc_sys_net_write(path, flag?"1":"0");
+}
+
+int neigh_proxy_on(const char *name, int family)
+{
+       return neigh_proxy_set(name, family, 1);
+}
+
+int neigh_proxy_off(const char *name, int family)
+{
+       return neigh_proxy_set(name, family, 0);
+}
+
+int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr)
+{
+    unsigned char *data;
+    char c;
+    int i = 0;
+    unsigned val;
+
+    sockaddr->sa_family = ARPHRD_ETHER;
+    data = (unsigned char *)sockaddr->sa_data;
+
+    while ((*macaddr != '\0') && (i < ETH_ALEN)) {
+       val = 0;
+       c = *macaddr++;
+       if (isdigit(c))
+           val = c - '0';
+       else if (c >= 'a' && c <= 'f')
+           val = c - 'a' + 10;
+       else if (c >= 'A' && c <= 'F')
+           val = c - 'A' + 10;
+       else {
+           return -1;
+       }
+       val <<= 4;
+       c = *macaddr;
+       if (isdigit(c))
+           val |= c - '0';
+       else if (c >= 'a' && c <= 'f')
+           val |= c - 'a' + 10;
+       else if (c >= 'A' && c <= 'F')
+           val |= c - 'A' + 10;
+       else if (c == ':' || c == 0)
+           val >>= 4;
+       else {
+           return -1;
+       }
+       if (c != 0)
+           macaddr++;
+       *data++ = (unsigned char) (val & 0377);
+       i++;
+
+       if (*macaddr == ':')
+           macaddr++;
+    }
+
+    return 0;
+}
+
+int ip_addr_add(const char *ifname, const char *addr, 
+               int prefix, const char *bcast)
+{
+       struct nl_handler nlh;
+       struct in_addr in_addr;
+/*     struct in_addr in_bcast; */
+       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       struct ip_req *ip_req;
+       int ifindex, err = -1;
+
+       if (netlink_open(&nlh, NETLINK_ROUTE))
+               return -1;
+
+       if (inet_pton(AF_INET, addr, (void *)&in_addr) < 0)
+               goto out;
+
+/*     if (inet_pton(AF_INET, bcast, (void *)&in_bcast) < 0) */
+/*                     goto out; */
+
+       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!nlmsg)
+               goto out;
+
+       answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!answer)
+               goto out;
+
+       ifindex = if_nametoindex(ifname);
+       if (!ifindex)
+               goto out;
+
+       ip_req = (struct ip_req *)nlmsg;
+        ip_req->nlmsg.nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+        ip_req->nlmsg.nlmsghdr.nlmsg_flags =
+               NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
+        ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWADDR;
+       ip_req->ifa.ifa_prefixlen = prefix;
+        ip_req->ifa.ifa_index = ifindex;
+        ip_req->ifa.ifa_family = AF_INET;
+       ip_req->ifa.ifa_scope = 0;
+       
+       if (nla_put_buffer(nlmsg, IFA_LOCAL, &in_addr, sizeof(in_addr)))
+               goto out;
+
+       if (nla_put_buffer(nlmsg, IFA_ADDRESS, &in_addr, sizeof(in_addr)))
+               goto out;
+
+/*     if (in_bcast.s_addr != INADDR_ANY) */
+/*             if (nla_put_buffer(nlmsg, IFA_BROADCAST, &in_bcast, */
+/*                                sizeof(in_bcast))) */
+/*                     goto out; */
+
+       if (netlink_transaction(&nlh, nlmsg, answer))
+               goto out;
+
+       err = 0;
+out:
+       netlink_close(&nlh);
+       nlmsg_free(answer);
+       nlmsg_free(nlmsg);
+       return err;
+}
+
+int ip6_addr_add(const char *ifname, const char *addr, 
+               int prefix, const char *bcast)
+{
+       struct nl_handler nlh;
+       struct in6_addr in6_addr;
+/*     struct in6_addr in6_bcast; */
+       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       struct ip_req *ip_req;
+       int ifindex, err = -1;
+
+       if (netlink_open(&nlh, NETLINK_ROUTE))
+               return -1;
+
+       if (inet_pton(AF_INET6, addr, (void *)&in6_addr) < 0)
+               goto out;
+
+
+/*     if (inet_pton(AF_INET6, bcast, (void *)&in6_bcast) < 0) */
+/*                     goto out; */
+
+       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!nlmsg)
+               goto out;
+
+       answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!answer)
+               goto out;
+
+       ifindex = if_nametoindex(ifname);
+       if (!ifindex)
+               goto out;
+
+       ip_req = (struct ip_req *)nlmsg;
+        ip_req->nlmsg.nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+        ip_req->nlmsg.nlmsghdr.nlmsg_flags =
+               NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
+        ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWADDR;
+       ip_req->ifa.ifa_prefixlen = prefix;
+        ip_req->ifa.ifa_index = ifindex;
+        ip_req->ifa.ifa_family = AF_INET6;
+       ip_req->ifa.ifa_scope = 0;
+       
+       if (nla_put_buffer(nlmsg, IFA_LOCAL, &in6_addr, sizeof(in6_addr)))
+               goto out;
+
+       if (nla_put_buffer(nlmsg, IFA_ADDRESS, &in6_addr, sizeof(in6_addr)))
+               goto out;
+
+/*     if (in6_bcast.s6_addr != in6addr_any.s6_addr) */
+/*             if (nla_put_buffer(nlmsg, IFA_BROADCAST, &in6_bcast, */
+/*                                sizeof(in6_bcast))) */
+/*                     goto out; */
+
+       if (netlink_transaction(&nlh, nlmsg, answer))
+               goto out;
+
+       err = 0;
+out:
+       netlink_close(&nlh);
+       nlmsg_free(answer);
+       nlmsg_free(nlmsg);
+       return err;
+}
+
+static int bridge_add_del_interface(const char *bridge, 
+                                   const char *ifname, int detach)
+{
+       int fd, index, err;
+       struct ifreq ifr;
+
+       if (strlen(ifname) > IFNAMSIZ)
+               return -1;
+
+       index = if_nametoindex(ifname);
+       if (!index)
+               return -1;
+
+       fd = socket(AF_INET, SOCK_STREAM, 0);
+       if (fd < 0)
+               return -1;
+
+       strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+       ifr.ifr_ifindex = index;
+       err = ioctl(fd, detach?SIOCBRDELIF:SIOCBRADDIF, &ifr);
+       close(fd);
+
+       return err;
+}
+
+int bridge_attach(const char *bridge, const char *ifname)
+{
+       return bridge_add_del_interface(bridge, ifname, 0);
+}
+
+int bridge_detach(const char *bridge, const char *ifname)
+{
+       return bridge_add_del_interface(bridge, ifname, 1);
+}
+
+int lxc_configure_veth(const char *veth1, const char *veth2, const char *bridge)
+{
+       int err = -1;
+       if (veth_create(veth1, veth2)) {
+               fprintf(stderr, "failed to create veth interfaces %s/%s\n",
+                       veth1, veth2);
+               return -1;
+       }
+
+       if (bridge_attach(bridge, veth1)) {
+               fprintf(stderr, "failed to attach %s to %s\n", 
+                       veth1, bridge);
+               goto err;
+       }
+
+       err = 0;
+out:
+       return err;
+err:
+       device_delete(veth1);
+       goto out;
+}
+
+int lxc_configure_macvlan(const char *link, const char *peer)
+{
+       if (macvlan_create(link, peer)) {
+               fprintf(stderr, "failed to create %s", peer);
+               return -1;
+       }
+       return 0;
+}
diff --git a/src/lxc/network.h b/src/lxc/network.h
new file mode 100644 (file)
index 0000000..223276e
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _network_h
+#define _network_h
+
+/*
+ * Create a macvlan network device
+ */
+extern int lxc_configure_macvlan(const char *link, const char *peer);
+
+/*
+ * Create a veth pair virtual device
+ */
+extern int lxc_configure_veth(const char *veth1, const char *veth2, 
+                             const char *bridge);
+
+/*
+ * Convert a string mac address to a socket structure
+ */
+extern int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr);
+
+/*
+ * Move a device between namespaces
+ */
+extern int device_move(const char *name, pid_t pid);
+
+/*
+ * Delete a network device
+ */
+extern int device_delete(const char *name);
+
+/*
+ * Set the device network up
+ */
+extern int device_up(const char *name);
+
+/*
+ * Set the device network down
+ */
+extern int device_down(const char *name);
+
+/*
+ * Change the device name
+ */
+extern int device_rename(const char *oldname, const char *newname);
+
+/*
+ * Create a veth network device
+ */
+extern int veth_create(const char *name1, const char *name2);
+
+/* 
+ * Create a macvlan network device
+ */
+extern int macvlan_create(const char *master, const char *name);
+
+/*
+ * Activate forwarding
+ */
+extern int ip_forward_on(const char *name, int family);
+
+/*
+ * Disable forwarding
+ */
+extern int ip_forward_off(const char *name, int family);
+
+/*
+ * Set ip address
+ */
+extern int ip_addr_add(const char *ifname, const char *addr, 
+                      int prefix, const char *bcast);
+
+extern int ip6_addr_add(const char *ifname, const char *addr, 
+                       int prefix, const char *bcast);
+
+/*
+ * Attach an interface to the bridge
+ */
+extern int bridge_attach(const char *bridge, const char *ifname);
+
+/*
+ * Detach an interface from the bridge
+ */
+extern int bridge_detach(const char *bridge, const char *ifname);
+
+/* 
+ * Create default gateway
+ */
+extern int route_create_default(const char *addr, const char *ifname, int gateway);
+
+/*
+ * Delete default gateway
+ */
+extern int route_delete_default(const char *addr, const char *ifname, int gateway);
+
+/*
+ * Activate neighbor proxying
+ */
+extern int neigh_proxy_on(const char *name, int family);
+
+/*
+ * Disable neighbor proxying
+ */
+extern int neigh_proxy_off(const char *name, int family);
+
+#endif
diff --git a/src/lxc/nl.c b/src/lxc/nl.c
new file mode 100644 (file)
index 0000000..261ffb5
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <sys/socket.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <nl.h>
+
+#define NLMSG_TAIL(nmsg) \
+        ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+
+extern size_t nlmsg_len(const struct nlmsg *nlmsg)
+{
+       return nlmsg->nlmsghdr.nlmsg_len - NLMSG_HDRLEN;
+}
+
+extern void *nlmsg_data(struct nlmsg *nlmsg)
+{
+       char *data = ((char *)nlmsg) + NLMSG_ALIGN(sizeof(struct nlmsghdr));
+       if (!nlmsg_len(nlmsg))
+               return NULL;
+       return data;
+}
+
+static int nla_put(struct nlmsg *nlmsg, int attr, 
+                  const void *data, size_t len)
+{
+       struct rtattr *rta;
+       size_t rtalen = RTA_LENGTH(len);
+       
+        rta = NLMSG_TAIL(&nlmsg->nlmsghdr);
+        rta->rta_type = attr;
+        rta->rta_len = rtalen;
+        memcpy(RTA_DATA(rta), data, len);
+        nlmsg->nlmsghdr.nlmsg_len =
+               NLMSG_ALIGN(nlmsg->nlmsghdr.nlmsg_len) + RTA_ALIGN(rtalen);
+       return 0;
+}
+
+extern int nla_put_buffer(struct nlmsg *nlmsg, int attr, 
+                         const void *data, size_t size)
+{
+       return nla_put(nlmsg, attr, data, size);
+}
+
+extern int nla_put_string(struct nlmsg *nlmsg, int attr, const char *string)
+{
+        return nla_put(nlmsg, attr, string, strlen(string) + 1);
+}
+
+extern int nla_put_u32(struct nlmsg *nlmsg, int attr, int value)
+{
+       return nla_put(nlmsg, attr, &value, sizeof(value));
+}
+
+extern int nla_put_attr(struct nlmsg *nlmsg, int attr)
+{
+       return nla_put(nlmsg, attr, NULL, 0);
+}
+
+struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr)
+{
+       struct rtattr *rtattr = NLMSG_TAIL(&nlmsg->nlmsghdr);
+
+       if (nla_put_attr(nlmsg, attr))
+               return NULL;
+
+       return rtattr;
+}
+
+void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr)
+{
+       attr->rta_len = (void *)NLMSG_TAIL(&nlmsg->nlmsghdr) - (void *)attr;
+}
+
+extern struct nlmsg *nlmsg_alloc(size_t size)
+{
+       struct nlmsg *nlmsg;
+       size_t len = NLMSG_ALIGN(size) + NLMSG_ALIGN(sizeof(struct nlmsghdr *));
+
+       nlmsg = (struct nlmsg *)malloc(len);
+       if (!nlmsg)
+               return NULL;
+
+       memset(nlmsg, 0, len);
+       nlmsg->nlmsghdr.nlmsg_len = NLMSG_ALIGN(size);
+
+       return nlmsg;
+}
+
+extern void nlmsg_free(struct nlmsg *nlmsg)
+{
+       free(nlmsg);
+}
+
+extern int netlink_rcv(struct nl_handler *handler, struct nlmsg *answer)
+{
+       int ret;
+        struct sockaddr_nl nladdr;
+        struct iovec iov = {
+                .iov_base = answer,
+                .iov_len = answer->nlmsghdr.nlmsg_len,
+        };
+       
+       struct msghdr msg = {
+                .msg_name = &nladdr,
+                .msg_namelen = sizeof(nladdr),
+                .msg_iov = &iov,
+                .msg_iovlen = 1,
+        };
+       
+        memset(&nladdr, 0, sizeof(nladdr));
+        nladdr.nl_family = AF_NETLINK;
+        nladdr.nl_pid = 0;
+        nladdr.nl_groups = 0;
+
+again:
+       ret = recvmsg(handler->fd, &msg, 0);
+       if (ret < 0) {
+               if (errno == EINTR)
+                       goto again;
+               return -errno;
+       }
+
+       if (!ret)
+               return 0;
+
+       if (msg.msg_flags & MSG_TRUNC)
+               return -EMSGSIZE;
+
+       return ret;
+}
+
+extern int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg)
+{
+        struct sockaddr_nl nladdr;
+        struct iovec iov = {
+                .iov_base = (void*)nlmsg,
+                .iov_len = nlmsg->nlmsghdr.nlmsg_len,
+        };
+       struct msghdr msg = {
+                .msg_name = &nladdr,
+                .msg_namelen = sizeof(nladdr),
+                .msg_iov = &iov,
+                .msg_iovlen = 1,
+        };
+       int ret;
+       
+        memset(&nladdr, 0, sizeof(nladdr));
+        nladdr.nl_family = AF_NETLINK;
+        nladdr.nl_pid = 0;
+        nladdr.nl_groups = 0;
+
+       ret = sendmsg(handler->fd, &msg, 0);
+       if (ret < 0) {
+               return -errno;
+       }
+
+       return ret;
+}
+
+extern int netlink_transaction(struct nl_handler *handler, 
+                              struct nlmsg *request, struct nlmsg *answer)
+{
+
+       int ret;
+
+       ret = netlink_send(handler, request);
+       if (ret < 0)
+               return ret;
+
+       ret = netlink_rcv(handler, answer);
+       if (ret < 0)
+               return ret;
+
+       if (answer->nlmsghdr.nlmsg_type == NLMSG_ERROR) {
+               struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(answer);
+               errno = -err->error;
+               return -errno;
+       }
+       
+       return 0;
+}
+
+extern int netlink_open(struct nl_handler *handler, int protocol)
+{
+       socklen_t socklen;
+        int sndbuf = 32768;
+        int rcvbuf = 32768;
+
+        memset(handler, 0, sizeof(*handler));
+
+        handler->fd = socket(AF_NETLINK, SOCK_RAW, protocol);
+        if (handler->fd < 0)
+                return -errno;
+
+        if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF, 
+                      &sndbuf, sizeof(sndbuf)) < 0)
+                return -errno;
+
+        if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF, 
+                      &rcvbuf,sizeof(rcvbuf)) < 0)
+                return -errno;
+
+        memset(&handler->local, 0, sizeof(handler->local));
+        handler->local.nl_family = AF_NETLINK;
+        handler->local.nl_groups = 0;
+
+        if (bind(handler->fd, (struct sockaddr*)&handler->local, 
+                sizeof(handler->local)) < 0)
+                return -errno;
+
+        socklen = sizeof(handler->local);
+        if (getsockname(handler->fd, (struct sockaddr*)&handler->local, 
+                       &socklen) < 0)
+                return -errno;
+
+        if (socklen != sizeof(handler->local))
+                return -EINVAL;
+
+        if (handler->local.nl_family != AF_NETLINK)
+                return -EINVAL;
+
+       handler->seq = time(NULL);
+
+        return 0;
+}
+
+extern int netlink_close(struct nl_handler *handler)
+{
+       close(handler->fd);
+       handler->fd = -1;
+       return 0;
+}
+
diff --git a/src/lxc/nl.h b/src/lxc/nl.h
new file mode 100644 (file)
index 0000000..2f760de
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __nl_h
+#define __nl_h
+
+/*
+ * Use this as a good size to allocate generic netlink messages
+ */
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+#define NLMSG_GOOD_SIZE (2*PAGE_SIZE)
+#define NLMSG_TAIL(nmsg) \
+        ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+#define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN))
+#define NLA_NEXT_ATTR(attr) ((void *)((char *)attr) + NLA_ALIGN(attr->nla_len))
+
+/*
+ * struct nl_handler : the handler for netlink sockets, this structure
+ *  is used all along the netlink socket life cycle to specify the
+ *  netlink socket to be used.
+ * 
+ * @fd: the file descriptor of the netlink socket
+ * @seq: the sequence number of the netlink messages
+ * @local: the bind address
+ * @peer: the peer address
+ */
+struct nl_handler {
+        int fd;
+       int seq;
+        struct sockaddr_nl local;
+        struct sockaddr_nl peer;
+};
+
+/*
+ * struct nlmsg : the netlink message structure, it consists just
+ *  on a definition for a nlmsghdr. This message is to be used to
+ *  be allocated with netlink_alloc.
+ * @nlmsghdr : a pointer to a netlink message header, this field
+ *   _must_ be always the first field of this structure
+ */
+struct nlmsg {
+       struct nlmsghdr nlmsghdr;
+};
+
+/*
+ * netlink_open : open a netlink socket, the function will
+ *  fill the handler with the right value
+ *
+ * @handler: a netlink handler to be used all along the netlink
+ *  socket life cycle
+ * @protocol: specify the protocol to be used when opening the
+ *  netlink socket
+ *
+ * Return 0 on success, < 0 otherwise
+ */
+int netlink_open(struct nl_handler *handler, int protocol);
+
+/*
+ * netlink_close : close a netlink socket, after this call, 
+ *  the handler is no longer valid
+ *
+ * @handler: a handler to the netlink socket
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int netlink_close(struct nl_handler *handler);
+
+/*
+ * netlink_rcv : receive a netlink message from the kernel. 
+ *  It is up to the caller to manage the allocation of the 
+ *  netlink message
+ *
+ * @handler: a handler to the netlink socket
+ * @nlmsg: a netlink message
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int netlink_rcv(struct nl_handler *handler, struct nlmsg *nlmsg);
+
+/*
+ * netlink_send: send a netlink message to the kernel. It is up
+ *  to the caller to manage the allocate of the netlink message
+ *
+ * @handler: a handler to the netlink socket
+ * @nlmsg: a netlink message
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg);
+
+/*
+ * netlink_transaction: send a request to the kernel and read the response. 
+ *  This is useful for transactional protocol. It is up to the caller 
+ *  to manage the allocation of the netlink message.
+ *
+ * @handler: a handler to a opened netlink socket
+ * @request: a netlink message pointer containing the request
+ * @answer: a netlink message pointer to receive the result
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int netlink_transaction(struct nl_handler *handler, 
+                       struct nlmsg *request, struct nlmsg *anwser);
+
+/*
+ * nla_put_string: copy a null terminated string to a netlink message 
+ *  attribute
+ *
+ * @nlmsg: the netlink message to be filled
+ * @attr: the attribute name of the string
+ * @string: a null terminated string to be copied to the netlink message
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int nla_put_string(struct nlmsg *nlmsg, int attr, const char *string);
+
+/*
+ * nla_put_buffer: copy a buffer with a specified size to a netlink
+ * message attribute
+ *
+ * @nlmsg: the netlink message to be filled
+ * @attr: the attribute name of the string
+ * @data: a pointer to a buffer
+ * @size: the size of the buffer
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int nla_put_buffer(struct nlmsg *nlmsg, int attr, 
+                  const void *data, size_t size);
+
+/*
+ * nla_put_u32: copy an integer to a netlink message attribute
+ *
+ * @nlmsg: the netlink message to be filled
+ * @attr: the attribute name of the integer
+ * @string: an integer  to be copied to the netlink message
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int nla_put_u32(struct nlmsg *nlmsg, int attr, int value);
+
+/*
+ * nla_put_attr: add an attribute name to a netlink 
+ *
+ * @nlmsg: the netlink message to be filled
+ * @attr: the attribute name of the integer
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int nla_put_attr(struct nlmsg *nlmsg, int attr);
+
+/*
+ * nla_begin_nested: begin the nesting attribute
+ *
+ * @nlmsg: the netlink message to be filled
+ * @attr: the netsted attribute name 
+ *
+ * Returns current nested pointer to be reused
+ * to nla_end_nested.
+ */
+struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr);
+
+/*
+ * nla_end_nested: end the nesting attribute
+ *
+ * @nlmsg: the netlink message
+ * @nested: the nested pointer
+ *
+ * Returns the current 
+ */
+void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr);
+
+/*
+ * nlmsg_allocate : allocate a netlink message. The netlink format message 
+ *  is a header, a padding, a payload and a padding again.
+ *  When a netlink message is allocated, the size specify the 
+ *  payload we want. So the real size of the allocated message
+ *  is sizeof(header) + sizeof(padding) + payloadsize + sizeof(padding),
+ *  in other words, the function will allocate more than specified. When 
+ *  the buffer is allocated, the content is zeroed.
+ *  The function will also fill the field nlmsg_len with computed size.
+ *  If the allocation must be for the specified size, just use malloc.
+ *
+ * @size: the size of the payload to be allocated
+ *
+ * Returns a pointer to the newly allocated netlink message, NULL otherwise
+ */
+struct nlmsg *nlmsg_alloc(size_t size);
+
+/*
+ * nlmsg_free : free a previously allocate message
+ *
+ * @nlmsg: the netlink message to be freed
+ */
+void nlmsg_free(struct nlmsg *nlmsg);
+
+/*
+ * nlmsg_data : returns a pointer to the data contained in the netlink message
+ * 
+ * @nlmsg : the netlink message to get the data
+ *
+ * Returns a pointer to the netlink data or NULL if there is no data
+ */
+void *nlmsg_data(struct nlmsg *nlmsg);
+
+
+#endif
diff --git a/src/lxc/rtnl.c b/src/lxc/rtnl.c
new file mode 100644 (file)
index 0000000..bc23542
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <string.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <nl.h>
+#include <rtnl.h>
+
+extern int rtnetlink_open(struct rtnl_handler *handler)
+{
+       return netlink_open(&handler->nlh, NETLINK_ROUTE);
+}
+
+extern int rtnetlink_close(struct rtnl_handler *handler)
+{
+       return netlink_close(&handler->nlh);
+}
+
+extern int rtnetlink_rcv(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg)
+{
+       return netlink_rcv(&handler->nlh, (struct nlmsg *)&rtnlmsg->nlmsghdr);
+}
+
+extern int rtnetlink_send(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg)
+{
+
+       return netlink_send(&handler->nlh, (struct nlmsg *)&rtnlmsg->nlmsghdr);
+}
+
+extern int rtnetlink_transaction(struct rtnl_handler *handler, 
+                         struct rtnlmsg *request, struct rtnlmsg *answer)
+{
+       return netlink_transaction(&handler->nlh, (struct nlmsg *)&request->nlmsghdr,
+                                  (struct nlmsg *)&answer->nlmsghdr);
+}
+
+extern struct rtnlmsg *rtnlmsg_alloc(size_t size)
+{
+/*     size_t len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtnlmsghdr))) + size; */
+/*     return  (struct rtnlmsg *)nlmsg_alloc(len); */
+       return NULL;
+}
+
+extern void rtnlmsg_free(struct rtnlmsg *rtnlmsg)
+{
+       free(rtnlmsg);
+}
diff --git a/src/lxc/rtnl.h b/src/lxc/rtnl.h
new file mode 100644 (file)
index 0000000..63aca0a
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __genl_h
+#define __genl_h
+
+/*
+ * Use this as a good size to allocate route netlink messages
+ */
+#define RTNLMSG_GOOD_SIZE NLMSG_GOOD_SIZE
+#define RTNLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + RTNL_HDRLEN))
+
+/*
+ * struct genl_handler : the structure which store the netlink handler 
+ *  and the family number
+ *
+ * @nlh: the netlink socket handler
+ */
+struct rtnl_handler
+{
+       struct nl_handler nlh;
+};
+
+/*
+ * struct rtnlmsg : the struct containing the route netlink message
+ *  format
+ *
+ * @nlmsghdr: a netlink message header
+ * @rtnlmsghdr: a route netlink message header pointer
+ *
+ */
+struct rtnlmsg {
+       struct nlmsghdr nlmsghdr;
+};
+
+/*
+ * rtnetlink_open : open a route netlink socket
+ *
+ * @handler: a struct rtnl_handler pointer
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int rtnetlink_open(struct rtnl_handler *handler);
+
+/*
+ * genetlink_close : close a route netlink socket
+ *
+ * @handler: the handler of the socket to be closed
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int rtnetlink_close(struct rtnl_handler *handler);
+
+/*
+ * rtnetlink_rcv : receive a route netlink socket, it is up
+ *  to the caller to manage the allocation of the route netlink message
+ *
+ * @handler: the handler of the route netlink socket
+ * @rtnlmsg: the pointer to a route netlink message pre-allocated
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int rtnetlink_rcv(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg);
+
+/*
+ * rtnetlink_send : send a route netlink socket, it is up
+ *  to the caller to manage the allocation of the route netlink message
+ *
+ * @handler: the handler of the route netlink socket
+ * @rtnlmsg: the pointer to a netlink message pre-allocated
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int rtnetlink_send(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg);
+
+struct genlmsg *genlmsg_alloc(size_t size);
+
+void rtnlmsg_free(struct rtnlmsg *rtnlmsg);
+
+/*
+ * rtnetlink_transaction : send and receive a route netlink message in one shot
+ *
+ * @handler: the handler of the route netlink socket
+ * @request: a route netlink message containing the request to be sent
+ * @answer: a pre-allocated route netlink message to receive the response
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int rtnetlink_transaction(struct rtnl_handler *handler, 
+                         struct rtnlmsg *request, struct rtnlmsg *answer);
+#endif
diff --git a/src/lxc/start.c b/src/lxc/start.c
new file mode 100644 (file)
index 0000000..08eb5bb
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <mntent.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <lxc.h>
+
+LXC_TTY_HANDLER(SIGINT);
+LXC_TTY_HANDLER(SIGQUIT);
+
+int lxc_start(const char *name, int argc, char *argv[], 
+             lxc_callback_t prestart, void *data)
+{
+       char *init = NULL, *val = NULL;
+       int fd, lock, sv[2], sync = 0, err = -1;
+       pid_t pid;
+       int clone_flags;
+       
+       lock = lxc_get_lock(name);
+       if (!lock) {
+               lxc_log_error("'%s' is busy", name);
+               return -1;
+       }
+
+       if (lock < 0) {
+               lxc_log_error("failed to acquire lock on '%s':%s",
+                             name, strerror(-lock));
+               return -1;
+       }
+
+       fcntl(lock, F_SETFD, FD_CLOEXEC);
+
+       /* Begin the set the state to STARTING*/
+       if (lxc_setstate(name, STARTING)) {
+               lxc_log_error("failed to set state %s", lxc_state2str(STARTING));
+               goto out;
+       }
+
+       /* Synchro socketpair */
+       if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) {
+               lxc_log_syserror("failed to create communication socketpair");
+               goto err;
+       }
+
+       /* Avoid signals from terminal */
+       LXC_TTY_ADD_HANDLER(SIGINT);
+       LXC_TTY_ADD_HANDLER(SIGQUIT);
+
+       clone_flags = CLONE_NEWPID|CLONE_NEWIPC;
+       if (conf_has_fstab(name))
+               clone_flags |= CLONE_NEWNS;
+       if (conf_has_utsname(name))
+               clone_flags |= CLONE_NEWUTS;
+       if (conf_has_network(name))
+               clone_flags |= CLONE_NEWNET;
+
+       /* Create a process in a new set of namespaces */
+       pid = fork_ns(clone_flags);
+       if (pid < 0) {
+               lxc_log_syserror("failed to fork into a new namespace");
+               goto err_fork_ns;
+       }
+
+       if (!pid) {
+
+               close(sv[1]);
+
+               /* Be sure we don't inherit this after the exec */
+               fcntl(sv[0], F_SETFD, FD_CLOEXEC);
+               
+               /* Tell our father he can begin to configure the container */
+               if (write(sv[0], &sync, sizeof(sync)) < 0) {
+                       lxc_log_syserror("failed to write socket");
+                       return 1;
+               }
+
+               /* Wait for the father to finish the configuration */
+               if (read(sv[0], &sync, sizeof(sync)) < 0) {
+                       lxc_log_syserror("failed to read socket");
+                       return 1;
+               }
+
+               /* Setup the container, ip, names, utsname, ... */
+               if (lxc_setup(name)) {
+                       lxc_log_error("failed to setup the container");
+                       if (write(sv[0], &sync, sizeof(sync)) < 0)
+                               lxc_log_syserror("failed to write the socket");
+                       return -1;
+               }
+
+               /* If a callback has been passed, call it before doing exec */
+               if (prestart)
+                       if (prestart(name, argc, argv, data)) {
+                               lxc_log_error("prestart callback has failed");
+                               return -1;
+                       }
+
+               execvp(argv[0], argv);
+               lxc_log_syserror("failed to exec %s", argv[0]);
+
+               /* If the exec fails, tell that to our father */
+               if (write(sv[0], &sync, sizeof(sync)) < 0)
+                       lxc_log_syserror("failed to write the socket");
+               
+               exit(1);
+       }
+
+       close(sv[0]);
+       
+       /* Wait for the child to be ready */
+       if (read(sv[1], &sync, sizeof(sync)) < 0) {
+               lxc_log_syserror("failed to read the socket");
+               goto err_pipe_read;
+       }
+
+       /* Create the network configuration */
+       if (clone_flags & CLONE_NEWNET && conf_create_network(name, pid)) {
+               lxc_log_error("failed to create the configured network");
+               goto err_create_network;
+       }
+
+       /* Tell the child to continue its initialization */
+       if (write(sv[1], &sync, sizeof(sync)) < 0) {
+               lxc_log_syserror("failed to write the socket");
+               goto err_pipe_write;
+       }
+
+       /* Wait for the child to exec or returning an error */
+       err = read(sv[1], &sync, sizeof(sync));
+       if (err < 0) {
+               lxc_log_error("failed to read the socket");
+               goto err_pipe_read2;
+       }
+
+       if (err > 0) {
+               lxc_log_error("something went wrong with %d", pid);
+               /* TODO : check status etc ... */
+               waitpid(pid, NULL, 0);
+               goto err_child_failed;
+       }
+
+       asprintf(&val, "%d\n", pid);
+       asprintf(&init, LXCPATH "/%s/init", name);
+       fd = open(init, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+       if (fd < 0) {
+               lxc_log_syserror("failed to open '%s'", init);
+               goto err_write;
+       }
+       
+       if (write(fd, val, strlen(val)) < 0) {
+               lxc_log_syserror("failed to write the init pid");
+               goto err_write;
+       }
+
+       close(fd);
+
+       if (lxc_link_nsgroup(name, pid))
+               lxc_log_warning("cgroupfs not found: cgroup disabled");
+
+       if (lxc_setstate(name, RUNNING)) {
+               lxc_log_error("failed to set state to %s", 
+                             lxc_state2str(RUNNING));
+               goto err_state_failed;
+       }
+
+wait_again:
+       if (waitpid(pid, NULL, 0) < 0) {
+               if (errno == EINTR) 
+                       goto wait_again;
+               lxc_log_syserror("failed to wait the pid %d", pid);
+               goto err_waitpid_failed;
+       }
+
+       if (lxc_setstate(name, STOPPING))
+               lxc_log_error("failed to set state %s", lxc_state2str(STOPPING));
+
+       if (clone_flags & CLONE_NEWNET && conf_destroy_network(name))
+               lxc_log_error("failed to destroy the network");
+
+       err = 0;
+out:
+       if (lxc_setstate(name, STOPPED))
+               lxc_log_error("failed to set state %s", lxc_state2str(STOPPED));
+
+       lxc_unlink_nsgroup(name);
+       unlink(init);
+       free(init);
+       free(val);
+       lxc_put_lock(lock);
+
+       return err;
+
+err_write:
+       close(fd);
+
+err_state_failed:
+err_child_failed:
+err_pipe_read2:
+err_pipe_write:
+       if (clone_flags & CLONE_NEWNET)
+               conf_destroy_network(name);
+err_create_network:
+err_pipe_read:
+err_waitpid_failed:
+       if (lxc_setstate(name, ABORTING))
+               lxc_log_error("failed to set state %s", lxc_state2str(STOPPED));
+
+       kill(pid, SIGKILL);
+err_fork_ns:
+       LXC_TTY_DEL_HANDLER(SIGQUIT);
+       LXC_TTY_DEL_HANDLER(SIGINT);
+       close(sv[0]);
+       close(sv[1]);
+err:
+       goto out;
+}
diff --git a/src/lxc/stop.c b/src/lxc/stop.c
new file mode 100644 (file)
index 0000000..7428846
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <lxc.h>
+
+int lxc_stop(const char *name)
+{
+       char init[MAXPATHLEN];
+       char val[MAXPIDLEN];
+       int fd, lock, ret = -1;
+       size_t pid;
+
+       lock = lxc_get_lock(name);
+       if (lock > 0) {
+               lxc_log_error("'%s' is not running", name);
+               lxc_put_lock(lock);
+               return -1;
+       }
+
+       if (lock < 0) {
+               lxc_log_error("failed to acquire the lock on '%s':%s", 
+                             name, strerror(-lock));
+               return -1;
+       }
+
+       snprintf(init, MAXPATHLEN, LXCPATH "/%s/init", name);
+       fd = open(init, O_RDONLY);
+       if (fd < 0) {
+               lxc_log_syserror("failed to open init file for %s", name);
+               goto out_unlock;
+       }
+       
+       if (read(fd, val, sizeof(val)) < 0) {
+               lxc_log_syserror("failed to read %s", init);
+               goto out_close;
+       }
+
+       pid = atoi(val);
+
+       if (kill(pid, SIGKILL)) {
+               lxc_log_syserror("failed to kill %zd", pid);
+               goto out_close;
+       }
+
+       if (unlink(init)) {
+               lxc_log_syserror("failed to unlink %s", init);
+               goto out_close;
+       }
+
+       ret = 0;
+
+out_close:
+       close(fd);
+out_unlock:
+       lxc_put_lock(lock);
+       return ret;
+}
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
new file mode 100644 (file)
index 0000000..5fc3946
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _utils_h
+#define _utils_h
+
+#define LXC_TTY_HANDLER(s) \
+       static struct sigaction lxc_tty_sa_##s;                         \
+       static void tty_##s##_handler(int sig, siginfo_t *info, void *ctx) \
+       {                                                               \
+               if (lxc_tty_sa_##s.sa_handler == SIG_DFL ||             \
+                   lxc_tty_sa_##s.sa_handler == SIG_IGN)               \
+                       return;                                         \
+               (*lxc_tty_sa_##s.sa_sigaction)(sig, info, ctx); \
+       }
+
+#define LXC_TTY_ADD_HANDLER(s) \
+       do { \
+               struct sigaction sa; \
+               sa.sa_sigaction = tty_##s##_handler; \
+               sa.sa_flags = SA_SIGINFO; \
+               sigfillset(&sa.sa_mask); \
+               /* No error expected with sigaction. */ \
+               sigaction(s, &sa, &lxc_tty_sa_##s); \
+       } while (0)
+
+#define LXC_TTY_DEL_HANDLER(s) \
+       do { \
+               sigaction(s, &lxc_tty_sa_##s, NULL); \
+       } while (0)
+
+#endif