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
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
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;
+}
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);
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)\" \
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
snapshot.c \
concurrent.c \
may_control.c \
- lxc-test-ubuntu
+ lxc-test-ubuntu \
+ list.c
--- /dev/null
+/* list.c
+ *
+ * Copyright © 2013 Canonical, Inc
+ * Author: Serge Hallyn <serge.hallyn@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);
+}