* Ivana Varekova <[email protected]> [2010-07-30 13:54:02]:

> SYNOPSIS:
> cgsnapshot [-h] [-n] [controller] [...]
> Generate the configuration file from the current hierarchie(s) of control 
> groups
>   -h, --help          Display this help
>   -n, --no-errors     Omit the output
> the output have the same format as cgconfig.conf file (the values are in 
> commas)
>

Thanks for working on this, its been on my TODO list.
 
> EXAMPLE:
> $ /home/varekova/bg/libcgroup/20100719/libcg/src/tools/cgsnapshot -n
> # Configuration file generated by cgsnapshot
> mount {
>        cpuset = /cgroup/cpuset;
>        cpu = /cgroup/devices;
>        cpuacct = /cgroup/memoryd;
>        memory = /cgroup/memory;
>        devices = /cgroup/devices;
>        freezer = /cgroup/freezer;
>        net_cls = /cgroup/net_cls;
> }
> 
> group daemons {
>       perm {
>               admin {
>                       uid = root;
>                       gid = root;
>               }
>               task {
>                       uid = root;
>                       gid = root;
>               }
>       }
>       cpuset {
>               cpuset.memory_spread_slab="0";
>               cpuset.memory_spread_page="0";
>               cpuset.memory_migrate="0";
>               cpuset.sched_relax_domain_level="-1";
>               cpuset.sched_load_balance="1";
>               cpuset.mem_hardwall="0";
>               cpuset.mem_exclusive="0";
>               cpuset.cpu_exclusive="0";
>       }
> }
> 
> 
> 
> Signed-off-by: Ivana Hutarova Varekova <[email protected]>
> ---
> 
>  src/tools/Makefile.am  |    4 
>  src/tools/cgsnapshot.c |  519 
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 522 insertions(+), 1 deletions(-)
>  create mode 100644 src/tools/cgsnapshot.c
> 
> diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am
> index f755037..bebdc81 100644
> --- a/src/tools/Makefile.am
> +++ b/src/tools/Makefile.am
> @@ -3,7 +3,7 @@ LDADD = $(top_builddir)/src/.libs/libcgroup.la
> 
>  if WITH_TOOLS
> 
> -bin_PROGRAMS = cgexec cgclassify cgcreate cgset cgget cgdelete lssubsys 
> lscgroup
> +bin_PROGRAMS = cgexec cgclassify cgcreate cgset cgget cgdelete lssubsys 
> lscgroup cgsnapshot
> 
>  sbin_PROGRAMS = cgconfigparser cgclear
> 
> @@ -27,6 +27,8 @@ lssubsys_SOURCES = lssubsys.c
> 
>  lscgroup_SOURCES = tools-common.c lscgroup.c
> 
> +cgsnapshot_SOURCES = cgsnapshot.c
> +
>  install-exec-hook:
>       chmod u+s $(DESTDIR)$(bindir)/cgexec
> 
> diff --git a/src/tools/cgsnapshot.c b/src/tools/cgsnapshot.c
> new file mode 100644
> index 0000000..6d27c31
> --- /dev/null
> +++ b/src/tools/cgsnapshot.c
> @@ -0,0 +1,519 @@
> +/* " Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
> + * " Written by Ivana Hutarova Varekova <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2.1 of the GNU Lesser General Public License
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
> + */
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <getopt.h>
> +
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <libcgroup.h>
> +#include <libcgroup-internal.h>
> +#include <pwd.h>
> +#include <grp.h>
> +
> +enum flag{
> +    FL_LIST = 1,
> +    FL_NOERR = 2,  /* don't show the error messages */
> +};
> +
> +typedef char cont_name_t[FILENAME_MAX];
> +
> +/*
> + * display the usage
> + */
> +static void usage(int status, const char *program_name)
> +{
> +     if (status != 0) {
> +             fprintf(stderr, "Wrong input parameters,"
> +                     " try %s -h' for more information.\n",
> +                     program_name);
> +     } else {
> +             fprintf(stdout, "Usage: %s [-h] [-n] [controller] [...]\n",
> +                     program_name);
> +             fprintf(stdout, "Generate the configuration file from "\
> +                     "the given controllers of control groups\n");
> +             fprintf(stdout, "  -h, --help           Display this help\n");
> +             fprintf(stdout, "  -n, --no-errors      Omit the error "\
> +                     "output\n");
> +     }
> +}
> +
> +/* display the variable name and its value */
> +static int display_variable_data(struct cgroup_file_info info,
> +     int prefix_len, char cont_old[FILENAME_MAX],
> +     const char *program_name)
> +{
> +     char *end;
> +     char path[FILENAME_MAX];
> +     char cont[FILENAME_MAX];
> +
> +     struct cgroup *group = NULL;
> +     struct cgroup_controller *group_controller = NULL;
> +
> +     char *value = NULL;
> +
> +     int ret;
> +     char rel_path[FILENAME_MAX];
> +     struct stat sb;
> +
> +     /* get the controller name
> +        - it is the part before "." sign in variable name */
> +     strncpy(cont, info.path, FILENAME_MAX);
> +     cont[FILENAME_MAX-1] = '\0';
> +     end = strchr(cont, '.');
> +     end[0] = '\0';
> +
> +     /* get the relative path to the control group
> +        - remove the mount poin prefix */
> +     strncpy(path, info.full_path+prefix_len, FILENAME_MAX);
> +     path[FILENAME_MAX-1] = '\0';

This is turning out to be pain, I'll write a wrapper to encapsulate
some of the strncpy parts.

> +
> +     /* get the relative path to the control group
> +        - remove the file name suffix*/
> +     end = strrchr(path, '/');
> +     if (end != NULL)
> +             end[0] = '\0';
> +
> +     /* open the control group for the relevant path */
> +     group = cgroup_new_cgroup(path);
> +     if (group == NULL) {
> +             fprintf(stderr, "%s: cannot create group '%s'\n", program_name,
> +                     path);
> +             return -1;
> +     }
> +
> +     /* get the data for this control group */
> +     ret = cgroup_get_cgroup(group);
> +     if (ret != 0) {
> +             fprintf(stderr, "%s: cannot read group '%s': %s\n",
> +                     program_name, path, cgroup_strerror(ret));
> +             goto err;
> +     }
> +
> +     /* find the relevant controller */
> +     group_controller = cgroup_get_controller(group, cont);
> +     if (group_controller == NULL) {
> +             fprintf(stderr, "%s: cannot find controller " \
> +                     "'%s' in group '%s'\n", program_name,
> +                     cont, path);
> +             ret =  -1;
> +             goto err;
> +     }
> +
> +     ret = cgroup_get_value_string(group_controller, info.path, &value);
> +
> +     /* variable can not be read */
> +     if (ret != 0) {
> +             ret = 0;
> +             goto err;
> +     }
> +
> +     if (strcmp(cont_old, cont)) {
> +             if (cont_old[0] != '\0')
> +                     printf("\t}\n");
> +             printf("\t%s { \n", cont);
> +             strcpy(cont_old, cont);
> +     }
> +
> +     /* if the variable is nonempty */
> +     if (strlen(value) != 0) {
> +             /* test whether the variable file is writable */
> +             strncpy(rel_path, info.full_path, FILENAME_MAX);
> +             rel_path[prefix_len] = '\0';
> +             strncat(rel_path, info.path, FILENAME_MAX);
> +             ret = stat(rel_path, &sb);
> +
> +             /*
> +              * freezer.state is not in root group so ret != 0,
> +              * but it should be listed
> +              */
> +             if ((ret == 0) && ((sb.st_mode & S_IWUSR) == 0)) {
> +                     /* variable is not writable */
> +                     /*
> +                      * TODO - device variables
> +                      * should be handle in some different way
> +                      */

Is this because they have special characters as a part of the values?

> +                     goto err_val;
> +             }
> +
> +             printf("\t\t%s=\"%s\";\n", info.path, value);
> +     }
> +
> +     strcpy(cont_old, cont);
> +
> +err_val:
> +     if (value)
> +             free(value);
> +err:
> +     cgroup_free(&group);
> +
> +     return ret;
> +}
> +
> +static int display_controller_data(char controller[CG_CONTROLLER_MAX],
> +             const char *program_name)

Would appreciate more comments on the function and parameters, helps
code readability.

> +{
> +     int ret;
> +     void *handle;
> +
> +     struct cgroup_file_info info;
> +     int lvl;
> +
> +     char cont_old[FILENAME_MAX];
> +     int start = 0;
> +     int triv = 1;
> +
> +     int prefix_len;
> +     char rel_path[FILENAME_MAX];
> +     char *end;
> +     struct stat sb;
> +     struct passwd *pw;
> +     struct group *gr;
> +
> +     /* start to parse the structure for the first controller -
> +        controller[0] attached to hierarchie */
                                     ^^^ typo
> +     ret = cgroup_walk_tree_begin(controller, "/", 0,
> +             &handle, &info, &lvl);
> +     if (ret != 0)
> +             return ret;
> +
> +     prefix_len = strlen(info.full_path);
> +     cont_old[0] = '\0';
> +     /* go through all files and directories */
> +     while ((ret = cgroup_walk_tree_next(0, &handle, &info, lvl)) == 0) {
> +             /* subgroup of / starts here */
> +             if (info.type != CGROUP_FILE_TYPE_FILE) {
> +                     /* group output was finished */
> +                     start = 0;
> +             }
> +             if ((info.depth > 1) && (info.type == CGROUP_FILE_TYPE_FILE)
> +                && (start == 0)) {
> +                     /* close the previous group here, if there was some */
> +                     if (triv == 1)
> +                             triv = 0;

Usage of start and triv is confusing, could you please add some more
comments on what they do.

> +                     else
> +                             printf("\t}\n}\n");
> +                     start = 1;
> +
> +                     strncpy(rel_path, &info.full_path[prefix_len],
> +                             FILENAME_MAX);
> +                     rel_path[FILENAME_MAX-1] = '\0';
> +
> +                     end = strrchr(rel_path, '/');
> +                     if (end != NULL)
> +                             end[0] = '\0';
> +
> +                     printf("group %s {\n", rel_path);
> +                     cont_old[0] = '\0';
> +
> +                     /* set the permission tags */
> +                     printf("\tperm {\n");
> +
> +                     /* admin permissions */
> +                     strncpy(rel_path, info.full_path, FILENAME_MAX-1);
> +                     rel_path[FILENAME_MAX-1] = '\0';
> +                     end = strrchr(rel_path, '/');
> +                     if (end != NULL)
> +                             end[0] = '\0';
> +
> +                     /* get the directory statistic */
> +                     ret = stat(rel_path, &sb);
> +                     if (ret)
> +                             goto err;
> +
> +                     /*
> +                      * from the statistic find out the
> +                      * user and group name
> +                      */
> +                     pw = getpwuid(sb.st_uid);
> +                     if (pw == NULL) {
> +                             ret = -1;
> +                             goto err;
> +                     }
> +                     gr = getgrgid(sb.st_gid);
> +
> +                     if (gr == NULL) {
> +                             ret = -1;
> +                             goto err;
> +                     }
> +
> +                     printf("\t\tadmin {\n"\
> +                             "\t\t\tuid = %s;\n"\
> +                             "\t\t\tgid = %s;\n"\
> +                             "\t\t}\n", pw->pw_name, gr->gr_name);
> +
> +                     /* tasks permissions */
> +                     strncat(rel_path, "/tasks", NAME_MAX);
> +                     /* get tasks file statistic */
> +                     ret = stat(rel_path, &sb);
> +                     if (ret)
> +                             goto err;
> +
> +                     /*
> +                      * from the statistic find out the
> +                      * user and group name
> +                      */
> +                     pw = getpwuid(sb.st_uid);
> +                     if (pw == NULL) {
> +                             ret = -1;
> +                             goto err;
> +                     }
> +
> +                     gr = getgrgid(sb.st_gid);
> +                     if (gr == NULL) {
> +                             ret = -1;
> +                             goto err;
> +                     }
> +
> +                     printf("\t\ttask {\n" \
> +                             "\t\t\tuid = %s;\n"\
> +                             "\t\t\tgid = %s;\n"\
> +                             "\t\t}\n", pw->pw_name, gr->gr_name);
> +                     printf("\t}\n");
> +             }
> +             /* no output for nonvariable files */
> +             if ((info.type == CGROUP_FILE_TYPE_FILE) &&
> +                     /* files for non-root control group */
> +                     (info.depth > 1) &&
> +                     /* not variable-name file */
> +                     ((strchr(info.path, '.')) != NULL) &&
> +                     /* not variable-name file */
> +                     (strncmp(info.path, "cgroup.", 7) != 0) &&
> +                     /* files which reports data */
> +                     (strcmp(info.path, "memory.stat") != 0) &&
> +                     (strcmp(info.path, "cpuacct.stat") != 0) &&
> +                     /*
> +                      * TODO this file have to be handled
> +                      * in some special way
> +                      */

OK, .stat is read-only anway, I think the S_IWUSR check will filter it
out anyway.

> +                     (strcmp(info.path, "cpuacct.usage") != 0)) {
> +                     ret = display_variable_data(info,
> +                             prefix_len, cont_old, program_name);
> +             }
> +
> +     }
> +
> +
> +err:
> +     if (cont_old[0] != 0)
> +             printf("\t}\n");
> +
> +     if (triv == 0)
> +             printf("}\n");
> +

cont_old, triv are confusing, could you please document the order of
parsing and which variables are used for detecting termination,
parsing, etc.

> +     cgroup_walk_tree_end(&handle);
> +     if (ret == ECGEOF)
> +             ret = 0;
> +
> +     return ret;
> +
> +}
> +
> +static int is_ctlr_on_list(char controllers[CG_CONTROLLER_MAX][FILENAME_MAX],
> +                     cont_name_t wanted_conts[FILENAME_MAX])
> +{
> +     int i = 0;
> +     int j = 0;
> +
> +     while (controllers[i][0] != '\0') {
> +             while (wanted_conts[j][0] != '\0') {
> +                     if (strcmp(controllers[i], wanted_conts[j]) == 0)
> +                             return 1;
> +                     j++;
> +             }
> +             j = 0;
> +             i++;
> +     }
> +
> +     return 0;
> +}
> +
> +
> +/* print data about input cont_name controller */
> +static int parse_controllers(cont_name_t cont_names[CG_CONTROLLER_MAX],
> +     int flags, const char *program_name)
> +{
> +     int ret = 0;
> +     void *handle;
> +     char path[FILENAME_MAX];
> +     struct cgroup_mount_point controller;
> +
> +     char controllers[CG_CONTROLLER_MAX][FILENAME_MAX];
> +     int max = 0;
> +
> +     path[0] = '\0';
> +
> +     ret = cgroup_get_controller_begin(&handle, &controller);
> +
> +     /* go through the list of controllers/mount point pairs */
> +     while (ret == 0) {
> +             if (strcmp(path, controller.path) == 0) {
> +                     /* if it is still the same mount point */
> +                     if (max < CG_CONTROLLER_MAX) {
> +                             strncpy(controllers[max],
> +                                     controller.name, FILENAME_MAX);
> +                             (controllers[max])[FILENAME_MAX-1] = '\0';
> +                             max++;
> +                     }
> +             } else {
> +
> +                     /* we got new mount point, print it if needed */
> +                     if ((!(flags & FL_LIST) ||
> +                             (is_ctlr_on_list(controllers, cont_names)))
> +                             && (max != 0)) {
> +                             (controllers[max])[0] = '\0';
> +                             ret = display_controller_data(
> +                                     controllers[0], program_name);
> +                     }
> +
> +                     strncpy(controllers[0], controller.name, FILENAME_MAX);
> +                     (controllers[0])[FILENAME_MAX-1] = '\0';
> +
> +                     strncpy(path, controller.path, FILENAME_MAX);
> +                     path[FILENAME_MAX-1] = '\0';
> +                     max = 1;
> +             }
> +
> +             /* the actual controller should not be printed */
> +             ret = cgroup_get_controller_next(&handle, &controller);
> +     }
> +
> +     if (max != 0)
> +             ret = display_controller_data(
> +                     controllers[0], program_name);
> +
> +     cgroup_get_controller_end(&handle);
> +     if (ret != ECGEOF)
> +             return ret;
> +     return 0;
> +}
> +
> +/* print data about input mount points */
> +/* TODO only wanted ones */
> +static int parse_mountpoints(cont_name_t cont_names[CG_CONTROLLER_MAX],
> +     int flags, const char *program_name)
> +{
> +     int ret;
> +     void *handle;
> +     struct controller_data info;
> +     char *mount_point;
> +
> +     /* start mount section */
> +     printf("mount {\n");
> +
> +     /* go through the controller list */
> +     ret = cgroup_get_all_controller_begin(&handle, &info);
> +     while (ret != ECGEOF) {
> +
> +             /* the controller attached to some hierarchy */
> +             if  (info.hierarchy != 0) {
> +                     ret = cgroup_get_subsys_mount_point(info.name,
> +                             &mount_point);
> +                     if (ret != 0) {
> +                             /* the controller is not mounted */
> +                             if ((flags &  FL_NOERR) == 0) {
> +                                     fprintf(stderr,
> +                                             "%s hierarchy not mounted\n",
> +                                             info.name);
> +                             }
> +                     } else
> +                             printf("\t%s = %s;\n", info.name, mount_point);
> +             }
> +
> +             /* next controller */
> +             ret = cgroup_get_all_controller_next(&handle, &info);
> +     }
> +     if (ret != ECGEOF) {
> +             if ((flags &  FL_NOERR) == 0) {
> +                     fprintf(stderr,
> +                             "error: in get next controller %s\n",
> +                             cgroup_strerror(ret));
> +                     return ret;
> +             }
> +     }
> +
> +     ret = cgroup_get_all_controller_end(&handle);
> +
> +     /* finish mount section*/
> +     printf("}\n\n");
> +     return ret;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +     int ret = 0;
> +     int c;
> +
> +     int flags = 0;
> +
> +     int i;
> +     int c_number = 0;
> +     cont_name_t wanted_cont[CG_CONTROLLER_MAX];
> +
> +     static struct option options[] = {
> +             {"help", 0, 0, 'h'},
> +             {"no-error" , 0, 0, 'n'},
> +             {0, 0, 0, 0}
> +     };
> +
> +     for (i = 0; i < CG_CONTROLLER_MAX; i++)
> +             wanted_cont[i][0] = '\0';
> +
> +     /* parse arguments */
> +     while ((c = getopt_long(argc, argv, "nh", options, NULL)) > 0) {
> +             switch (c) {
> +             case 'h':
> +                     usage(0, argv[0]);
> +                     return 0;
> +             case 'n':
> +                     flags |= FL_NOERR;
> +                     break;
> +             default:
> +                     usage(1, argv[0]);
> +                     return -1;
> +             }
> +     }
> +
> +     /* read the list of controllers */
> +     while (optind < argc) {
> +             flags |= FL_LIST;
> +             strncpy(wanted_cont[c_number], argv[optind], FILENAME_MAX);
> +             (wanted_cont[c_number])[FILENAME_MAX-1] = '\0';
> +             c_number++;
> +             optind++;
> +             if (optind == CG_CONTROLLER_MAX-1) {
> +                     fprintf(stderr, "too many parameters\n");
> +                     break;
> +             }
> +     }
> +
> +     /* print the header */
> +     printf("# Configuration file generated by cgsnapshot\n");
> +
> +     /* initialize libcgroup */
> +     ret = cgroup_init();
> +
> +     if (ret) {
> +             /* empty configuration file */
> +             return ret;
> +     }
> +
> +     /* print mount points section */
> +     ret = parse_mountpoints(wanted_cont, flags, argv[0]);
> +
> +     /* print hierarchies section */
> +     ret = parse_controllers(wanted_cont, flags, argv[0]);
> +     return ret;
> +}
> 

-- 
        Three Cheers,
        Balbir

------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the
Plug-In Development Kit to bring their C/C++ apps to Palm for a share
of $1 Million in cash or HP Products. Visit us here for more details:
http://p.sf.net/sfu/dev2dev-palm
_______________________________________________
Libcg-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to