On Fri, Oct 11, 2013 at 10:44:39AM -0500, Serge Hallyn wrote:
> 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.

Sorry, missed that one in my mailbox...

I quite like the new implementation, I think it'll be flexible enough
for all our needs.

Acked-by: Stéphane Graber <stgra...@ubuntu.com>

> 
> 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
> 

-- 
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com

Attachment: signature.asc
Description: Digital signature

------------------------------------------------------------------------------
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