From 519012fa31068611096605447061bc90ffeef474 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= <fx@dotcloud.com>
Date: Wed, 13 Apr 2011 10:13:39 -0700
Subject: [PATCH 1/2] add lxc_browse function

This function provide an interface to browse containers. It call a
callback for every containers, giving the name as an argument. This
function also return the number of containers browsed.
---
 src/lxc/Makefile.am  |    3 +-
 src/lxc/lxc.h        |   16 +++++++
 src/lxc/lxc_browse.c |  108 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 126 insertions(+), 1 deletions(-)
 create mode 100644 src/lxc/lxc_browse.c

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index df3d4dd..907b2c3 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -50,7 +50,8 @@ liblxc_so_SOURCES = \
 	mainloop.c mainloop.h \
 	af_unix.c af_unix.h \
 	\
-	utmp.c utmp.h
+	utmp.c utmp.h \
+	lxc_browse.c
 
 AM_CFLAGS=-I$(top_srcdir)/src
 
diff --git a/src/lxc/lxc.h b/src/lxc/lxc.h
index a091baa..b420010 100644
--- a/src/lxc/lxc.h
+++ b/src/lxc/lxc.h
@@ -161,6 +161,22 @@ extern int lxc_checkpoint(const char *name, int sfd, int flags);
  */
 extern int lxc_restart(const char *, int, struct lxc_conf *, int);
 
+/**
+ * @brief Browse containers
+ *
+ * Browse all registered containers.
+ *
+ * @param [in] cb A function pointer to a callback which takes a pointer to an
+ * user context and a pointer to lxcst structure. If not null, the callback
+ * will be called with the ctx as well as the container name.
+ * @param [in] ctx A pointer to an user defined variable which will be used as
+ * an argument to the callback. If the callback returns non zero
+ * lxcst_browse_containers stops and return with -1 with errno set to EINTR.
+ *
+ * @return the number of containers on success, -1 on error with errno set.
+ */
+int lxc_browse(int (*cb)(void *ctx, const char *name), void *ctx);
+
 /*
  * Returns the version number of the library
  */
diff --git a/src/lxc/lxc_browse.c b/src/lxc/lxc_browse.c
new file mode 100644
index 0000000..194ea7a
--- /dev/null
+++ b/src/lxc/lxc_browse.c
@@ -0,0 +1,108 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2010
+ *
+ * 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>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <err.h>
+#undef _GNU_SOURCE
+
+#include "lxc.h"
+#include "config.h"
+
+static int _unselect_current_and_parent(const struct dirent* d)
+{
+    return (strcmp(d->d_name, ".") && strcmp(d->d_name, ".."));
+}
+
+static int _isdir(const char *path)
+{
+    struct stat sb;
+
+    if (stat(path, &sb) == -1) {
+        warn("_isdir, can't stat path: %s", path);
+        return 0;
+    }
+
+    return (sb.st_mode & S_IFDIR);
+}
+
+static char *_join_path(char *dest, size_t size,
+		const char *left, const char *right)
+{
+    if (*right != '/') {
+		if (strlen(left) + 1 + strlen(right) > size) {
+			warn("_join_path, path overflow: %s + / + %s", left, right);
+			return 0;
+		}
+        strcpy(dest, left);
+        strcat(dest, "/");
+        strcat(dest, right);
+    } else {
+		if (strlen(left) + strlen(right) > size) {
+			warn("_join_path, path overflow: %s", right);
+			return 0;
+		}
+        strcpy(dest, right);
+    }
+    return dest;
+}
+
+int lxc_browse(int (*cb)(void*, const char*), void *ctx)
+{
+	int             i;
+	struct dirent   **c_vec;
+	char            buf[PATH_MAX];
+	int             count;
+
+	count = scandir(LXCPATH, &c_vec, &_unselect_current_and_parent, &versionsort);
+	if (count == -1)
+		return (-1);
+
+	for (i = 0; i < count; ++i)
+	{
+		if (_isdir(
+					_join_path(buf, sizeof(buf), LXCPATH, c_vec[i]->d_name))
+				)
+		{
+			if (cb(ctx, c_vec[i]->d_name)) {
+				errno = EINTR;
+				goto abort_by_cb;
+			}
+		}
+		free(c_vec[i]);
+	}
+	free(c_vec);
+	return count;
+
+abort_by_cb:
+	for (; i < count; ++i)
+		free(c_vec[i]);
+	free(c_vec);
+	return -1;
+}
-- 
1.7.1

