[lxc-devel] [PATCH] define list container api

Serge Hallyn serge.hallyn at ubuntu.com
Wed Oct 9 12:17:43 UTC 2013


Two new commands are defined: list_defined_containers() and
list_active_containers().  Both take an lxcpath (NULL means
use the default lxcpath) and return the number of containers
found.  If a lxc_container ** is passed in, then an array of
lxc_container's is returned, one for each container found.
The caller must then lxc_container_put() each container and
free the array, as shown in the new list testcase.

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 src/lxc/lxccontainer.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/lxccontainer.h |  19 ++++++
 src/tests/Makefile.am  |   6 +-
 src/tests/list.c       |  57 ++++++++++++++++++
 4 files changed, 235 insertions(+), 2 deletions(-)
 create mode 100644 src/tests/list.c

diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 13ed4d2..5a0edce 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -2744,3 +2744,158 @@ int lxc_get_wait_states(const char **states)
 			states[i] = lxc_state2str(i);
 	return MAX_STATE;
 }
+
+
+bool add_to_clist(struct lxc_container ***list, struct lxc_container *c, int pos)
+{
+	struct lxc_container **newlist = realloc(*list, pos * sizeof(struct lxc_container *));
+	if (!newlist) {
+		free(*list);
+		*list = NULL;
+		ERROR("Out of memory");
+		return false;
+	}
+
+	*list = newlist;
+	newlist[pos-1] = c;
+	return true;
+}
+
+int list_defined_containers(const char *lxcpath, struct lxc_container ***cret)
+{
+	DIR *dir;
+	int nfound = 0;
+	struct dirent dirent, *direntp;
+
+	if (!lxcpath)
+		lxcpath = default_lxc_path();
+
+	process_lock();
+	dir = opendir(lxcpath);
+	process_unlock();
+
+	if (!dir) {
+		SYSERROR("opendir on lxcpath");
+		return -1;
+	}
+
+	if (cret)
+		*cret = NULL;
+
+	while (!readdir_r(dir, &dirent, &direntp)) {
+		if (!direntp)
+			break;
+		if (!strcmp(direntp->d_name, "."))
+			continue;
+		if (!strcmp(direntp->d_name, ".."))
+			continue;
+
+		struct lxc_container *c = lxc_container_new(direntp->d_name, lxcpath);
+		if (!c)
+			continue;
+		if (!lxcapi_is_defined(c)) {
+			lxc_container_put(c);
+			continue;
+		}
+
+		nfound++;
+
+		if (cret) {
+			if (!add_to_clist(cret, c, nfound))
+				goto free_bad;
+		} else {
+			lxc_container_put(c);
+		}
+	}
+
+	process_lock();
+	closedir(dir);
+	process_unlock();
+	return nfound;
+
+free_bad:
+	if (cret && *cret) {
+		while (--nfound >= 0)
+			lxc_container_put((*cret)[nfound]);
+		free(*cret);
+	}
+	process_lock();
+	closedir(dir);
+	process_unlock();
+	return -1;
+}
+
+int list_active_containers(const char *lxcpath, struct lxc_container ***cret)
+{
+	int nfound = 0;
+	int lxcpath_len;
+	char *line = NULL;
+	size_t len = 0;
+	struct lxc_container *c;
+
+	if (!lxcpath)
+		lxcpath = default_lxc_path();
+	lxcpath_len = strlen(lxcpath);
+	if (cret)
+		*cret = NULL;
+	process_lock();
+	FILE *f = fopen("/proc/net/unix", "r");
+	process_unlock();
+	if (!f)
+		return -1;
+
+	while (getline(&line, &len, f) != -1) {
+		char *p = rindex(line, ' '), *p2;
+		if (!p)
+			continue;
+		p++;
+		if (*p != 0x40)
+			continue;
+		p++;
+		if (strncmp(p, lxcpath, lxcpath_len) != 0)
+			continue;
+		p += lxcpath_len;
+		while (*p == '/')
+			p++;
+		// Now p is the start of lxc_name
+		p2 = index(p, '/');
+		if (!p2 || strncmp(p2, "/command", 8) != 0)
+			continue;
+		*p2 = '\0';
+		c = lxc_container_new(p, lxcpath);
+		if (!c)
+			continue;
+		
+		/* 
+		 * If this is an anonymous container, then is_defined *can*
+		 * return false.  So we don't do that check.  Count on the
+		 * fact that the command socket exists.
+		 */
+
+		nfound++;
+
+		if (cret) {
+			if (!add_to_clist(cret, c, nfound))
+				goto free_bad;
+		} else {
+			lxc_container_put(c);
+		}
+
+	}
+
+	process_lock();
+	fclose(f);
+	process_unlock();
+	return nfound;
+
+free_bad:
+	if (cret && *cret) {
+		while (--nfound >= 0)
+			lxc_container_put((*cret)[nfound]);
+		free(*cret);
+	}
+	process_lock();
+	fclose(f);
+	process_unlock();
+	return -1;
+}
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index 20ab8e8..691e7d9 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -248,6 +248,25 @@ const char *lxc_get_default_lvm_vg(void);
 const char *lxc_get_default_zfs_root(void);
 const char *lxc_get_version(void);
 
+/*
+ * Get a list of defined containers in a lxcpath.
+ * @lxcpath: lxcpath under which to look.
+ * @cret: if not null, then a list of lxc_containers will be returned here.
+ *
+ * Returns the number of containers found, or -1 on error.
+ */
+int list_defined_containers(const char *lxcpath, struct lxc_container ***cret);
+
+/*
+ * Get a list of active containers in a lxcpath.  Note that some of these
+ * containers may not be "defined".
+ * @lxcpath: lxcpath under which to look
+ * @cret: if not null, then a list of lxc_containers will be returned here.
+ *
+ * Returns the number of containers found, or -1 on error.
+ */
+int list_active_containers(const char *lxcpath, struct lxc_container ***cret);
+
 #if 0
 char ** lxc_get_valid_keys();
 char ** lxc_get_valid_values(char *key);
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index 1814c4b..5fce195 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -21,6 +21,7 @@ lxc_test_snapshot_SOURCES = snapshot.c
 lxc_test_concurrent_SOURCES = concurrent.c
 lxc_test_may_control_SOURCES = may_control.c
 lxc_test_reboot_SOURCES = reboot.c
+lxc_test_list_SOURCES = list.c
 
 AM_CFLAGS=-I$(top_srcdir)/src \
 	-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
@@ -34,7 +35,7 @@ bin_PROGRAMS = lxc-test-containertests lxc-test-locktests lxc-test-startone \
 	lxc-test-shutdowntest lxc-test-get_item lxc-test-getkeys lxc-test-lxcpath \
 	lxc-test-cgpath lxc-test-clonetest lxc-test-console lxc-usernic-test \
 	lxc-test-snapshot lxc-test-concurrent lxc-test-may-control \
-	lxc-test-reboot
+	lxc-test-reboot lxc-test-list
 
 bin_SCRIPTS = lxc-test-usernic
 
@@ -61,4 +62,5 @@ EXTRA_DIST = \
 	lxc-test-usernic \
 	snapshot.c \
 	concurrent.c \
-	may_control.c
+	may_control.c \
+	list.c
diff --git a/src/tests/list.c b/src/tests/list.c
new file mode 100644
index 0000000..01018eb
--- /dev/null
+++ b/src/tests/list.c
@@ -0,0 +1,57 @@
+/* list.c
+ *
+ * Copyright © 2013 Canonical, Inc
+ * Author: Serge Hallyn <serge.hallyn at ubuntu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <lxc/lxccontainer.h>
+
+int main(int argc, char *argv[])
+{
+	char *lxcpath = NULL;
+	struct lxc_container **clist;
+	int n, n2;
+
+	if (argc > 1)
+		lxcpath = argv[1];
+
+	n = list_defined_containers(lxcpath, NULL);
+	printf("Found %d defined containers\n", n);
+	n2 = list_defined_containers(lxcpath, &clist);
+	if (n2 != n)
+		printf("Warning: first call returned %d, second %d\n", n, n2);
+	for (n=0; n<n2; n++) {
+		struct lxc_container *c = clist[n];
+		printf("Found defined container %s\n", c->name);
+		lxc_container_put(c);
+	}
+	free(clist);
+
+	n = list_active_containers(lxcpath, NULL);
+	printf("Found %d active containers\n", n);
+	n2 = list_active_containers(lxcpath, &clist);
+	if (n2 != n)
+		printf("Warning: first call returned %d, second %d\n", n, n2);
+	for (n=0; n<n2; n++) {
+		printf("Found active container %s\n", clist[n]->name);
+		lxc_container_put(clist[n]);
+	}
+	free(clist);
+
+	exit(0);
+}
-- 
1.8.1.2





More information about the lxc-devel mailing list