diff --git a/.gitignore b/.gitignore index 536423a9c..ab0105af6 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 13ed4d202..6f9787911 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 + * + * 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 +#include +#include + +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; iname); + 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 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; iname, 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; iname); + 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 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; iname, names[i]); + free(names[i]); + lxc_container_put(c); + } + if (n2 > 0) { + free(names); + free(clist); + } + + exit(0); +}