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.
If a char ** is passed in, then an array of container names
is returned, after which the caller must free all the names
and the name array, as showsn in the testcase.

Changelog:
        Check for the container config file before trying to
        create an lxc_container *, to save some work. [ per
        stgraber comments]
        Add names ** argument to return only container names.

Signed-off-by: Serge Hallyn <serge.hal...@ubuntu.com>
---
 .gitignore             |   1 +
 src/lxc/lxccontainer.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/lxccontainer.h |  21 +++++
 src/tests/Makefile.am  |   6 +-
 src/tests/list.c       | 117 ++++++++++++++++++++++++
 5 files changed, 378 insertions(+), 2 deletions(-)
 create mode 100644 src/tests/list.c

diff --git a/.gitignore b/.gitignore
index 536423a..ab0105a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,6 +94,7 @@ src/tests/lxc-test-startone
 src/tests/lxc-usernic-test
 src/tests/lxc-test-may-control
 src/tests/lxc-test-reboot
+src/tests/lxc-test-list
 
 config/compile
 config/config.guess
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 13ed4d2..f3d9a93 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -69,6 +69,19 @@ static bool file_exists(char *f)
        return stat(f, &statbuf) == 0;
 }
 
+static bool config_file_exists(const char *lxcpath, const char *cname)
+{
+       /* $lxcpath + '/' + $cname + '/config' + \0 */
+       int ret, len = strlen(lxcpath) + strlen(cname) + 9;
+       char *fname = alloca(len);
+
+       ret = snprintf(fname, len,  "%s/%s/config", lxcpath, cname);
+       if (ret < 0 || ret >= len)
+               return false;
+
+       return file_exists(fname);
+}
+
 /*
  * A few functions to help detect when a container creation failed.
  * If a container creation was killed partway through, then trying
@@ -2744,3 +2757,225 @@ int lxc_get_wait_states(const char **states)
                        states[i] = lxc_state2str(i);
        return MAX_STATE;
 }
+
+
+static bool add_to_names(char ***names, char *cname, int pos)
+{
+       char **newnames = realloc(*names, (pos+1) * sizeof(char *));
+       if (!newnames) {
+               ERROR("Out of memory");
+               return false;
+       }
+       *names = newnames;
+       newnames[pos] = strdup(cname);
+       if (!newnames[pos])
+               return false;
+       return true;
+}
+
+static bool add_to_clist(struct lxc_container ***list, struct lxc_container 
*c, int pos)
+{
+       struct lxc_container **newlist = realloc(*list, (pos+1) * sizeof(struct 
lxc_container *));
+       if (!newlist) {
+               ERROR("Out of memory");
+               return false;
+       }
+
+       *list = newlist;
+       newlist[pos] = c;
+       return true;
+}
+
+/*
+ * These next two could probably be done smarter with reusing a common function
+ * with different iterators and tests...
+ */
+int list_defined_containers(const char *lxcpath, char ***names, struct 
lxc_container ***cret)
+{
+       DIR *dir;
+       int i, cfound = 0, nfound = 0;
+       struct dirent dirent, *direntp;
+       struct lxc_container *c;
+
+       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;
+       if (names)
+               *names = NULL;
+
+       while (!readdir_r(dir, &dirent, &direntp)) {
+               if (!direntp)
+                       break;
+               if (!strcmp(direntp->d_name, "."))
+                       continue;
+               if (!strcmp(direntp->d_name, ".."))
+                       continue;
+
+               if (!config_file_exists(lxcpath, direntp->d_name))
+                       continue;
+
+               if (names) {
+                       if (!add_to_names(names, direntp->d_name, cfound))
+                               goto free_bad;
+               }
+               cfound++;
+
+               if (!cret) {
+                       nfound++;
+                       continue;
+               }
+
+               c = lxc_container_new(direntp->d_name, lxcpath);
+               if (!c) {
+                       INFO("Container %s:%s has a config but could not be 
loaded",
+                               lxcpath, direntp->d_name);
+                       if (names)
+                               free((*names)[cfound--]);
+                       continue;
+               }
+               if (!lxcapi_is_defined(c)) {
+                       INFO("Container %s:%s has a config but is not defined",
+                               lxcpath, direntp->d_name);
+                       if (names)
+                               free((*names)[cfound--]);
+                       lxc_container_put(c);
+                       continue;
+               }
+
+               if (!add_to_clist(cret, c, nfound)) {
+                       lxc_container_put(c);
+                       goto free_bad;
+               }
+               nfound++;
+       }
+
+       process_lock();
+       closedir(dir);
+       process_unlock();
+       return nfound;
+
+free_bad:
+       if (names && *names) {
+               for (i=0; i<cfound; i++)
+                       free((*names)[i]);
+               free(*names);
+       }
+       if (cret && *cret) {
+               for (i=0; i<nfound; i++)
+                       lxc_container_put((*cret)[i]);
+               free(*cret);
+       }
+       process_lock();
+       closedir(dir);
+       process_unlock();
+       return -1;
+}
+
+int list_active_containers(const char *lxcpath, char ***names, struct 
lxc_container ***cret)
+{
+       int i, cfound = 0, 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;
+       if (names)
+               *names = 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';
+
+               if (names) {
+                       if (!add_to_names(names, p, nfound))
+                               goto free_bad;
+               }
+               cfound++;
+
+               if (!cret) {
+                       nfound++;
+                       continue;
+               }
+
+               c = lxc_container_new(p, lxcpath);
+               if (!c) {
+                       INFO("Container %s:%s is running but could not be 
loaded",
+                               lxcpath, p);
+                       if (names)
+                               free((*names)[cfound--]);
+                       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.
+                */
+
+               if (!add_to_clist(cret, c, nfound)) {
+                       lxc_container_put(c);
+                       goto free_bad;
+               }
+               nfound++;
+       }
+
+       process_lock();
+       fclose(f);
+       process_unlock();
+       return nfound;
+
+free_bad:
+       if (names && *names) {
+               for (i=0; i<cfound; i++)
+                       free((*names)[i]);
+               free(*names);
+       }
+       if (cret && *cret) {
+               for (i=0; i<nfound; i++)
+                       lxc_container_put((*cret)[i]);
+               free(*cret);
+       }
+       process_lock();
+       fclose(f);
+       process_unlock();
+       return -1;
+}
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index 20ab8e8..5901066 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -248,6 +248,27 @@ 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.
+ * @names: if not null, then a list of container names will be returned here.
+ * @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, char ***names, 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
+ * @names: if not null, then a list of container names will be returned here.
+ * @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, char ***names, 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 e18693b..509e414 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
 
@@ -62,4 +63,5 @@ EXTRA_DIST = \
        snapshot.c \
        concurrent.c \
        may_control.c \
-       lxc-test-ubuntu
+       lxc-test-ubuntu \
+       list.c
diff --git a/src/tests/list.c b/src/tests/list.c
new file mode 100644
index 0000000..f6704a4
--- /dev/null
+++ b/src/tests/list.c
@@ -0,0 +1,117 @@
+/* list.c
+ *
+ * Copyright © 2013 Canonical, Inc
+ * Author: Serge Hallyn <serge.hal...@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;
+       char **names;
+       int i, n, n2;
+
+       if (argc > 1)
+               lxcpath = argv[1];
+
+       printf("Counting defined containers only\n");
+       n = list_defined_containers(lxcpath, NULL, NULL);
+       printf("Found %d defined containers\n", n);
+       printf("Looking for defined containers only\n");
+       n2 = list_defined_containers(lxcpath, NULL, &clist);
+       if (n2 != n)
+               printf("Warning: first call returned %d, second %d\n", n, n2);
+       for (i=0; i<n2; i++) {
+               struct lxc_container *c = clist[i];
+               printf("Found defined container %s\n", c->name);
+               lxc_container_put(c);
+       }
+       if (n2 > 0)
+               free(clist);
+
+       printf("Looking for defined names only\n");
+       n2 = list_defined_containers(lxcpath, &names, NULL);
+       if (n2 != n)
+               printf("Warning: first call returned %d, second %d\n", n, n2);
+       for (i=0; i<n2; i++) {
+               printf("Found defined container %s\n", names[i]);
+               free(names[i]);
+       }
+       if (n2 > 0)
+               free(names);
+
+       printf("Looking for defined names and containers\n");
+       n2 = list_defined_containers(lxcpath, &names, &clist);
+       if (n2 != n)
+               printf("Warning: first call returned %d, second %d\n", n, n2);
+       for (i=0; i<n2; i++) {
+               struct lxc_container *c = clist[i];
+               printf("Found defined container %s, name was %s\n", c->name, 
names[i]);
+               free(names[i]);
+               lxc_container_put(c);
+       }
+       if (n2 > 0) {
+               free(names);
+               free(clist);
+       }
+
+
+       printf("Counting active containers only\n");
+       n = list_active_containers(lxcpath, NULL, NULL);
+       printf("Found %d active containers\n", n);
+       printf("Looking for active containers only\n");
+       n2 = list_active_containers(lxcpath, NULL, &clist);
+       if (n2 != n)
+               printf("Warning: first call returned %d, second %d\n", n, n2);
+       for (i=0; i<n2; i++) {
+               printf("Found active container %s\n", clist[i]->name);
+               lxc_container_put(clist[i]);
+       }
+       if (n2 > 0)
+               free(clist);
+
+       printf("Looking for active names only\n");
+       n2 = list_active_containers(lxcpath, &names, NULL);
+       if (n2 != n)
+               printf("Warning: first call returned %d, second %d\n", n, n2);
+       for (i=0; i<n2; i++) {
+               printf("Found active container %s\n", names[i]);
+               free(names[i]);
+       }
+       if (n2 > 0)
+               free(names);
+
+       printf("Looking for active names and containers\n");
+       n2 = list_active_containers(lxcpath, &names, &clist);
+       if (n2 != n)
+               printf("Warning: first call returned %d, second %d\n", n, n2);
+       for (i=0; i<n2; i++) {
+               struct lxc_container *c = clist[i];
+               printf("Found active container %s, name was %s\n", c->name, 
names[i]);
+               free(names[i]);
+               lxc_container_put(c);
+       }
+       if (n2 > 0) {
+               free(names);
+               free(clist);
+       }
+
+       exit(0);
+}
-- 
1.8.1.2


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

Reply via email to