CHANGELOG v1
* more verbose comments
* tune the variable names/description/usage in display_controller_data function
* remove unnecesary .stat exception
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)
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 | 546 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 549 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..f7d0142
--- /dev/null
+++ b/src/tools/cgsnapshot.c
@@ -0,0 +1,546 @@
+/* " 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';
+
+ /* 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
+ * here have to be written some wrapper to
+ * transform the data from devices.allow and
+ * devices.deny to devices.list
+ */
+ 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;
+}
+
+
+/*
+ * creates the record about the hierarchie which contains
+ * "controller" subsystem
+ */
+static int display_controller_data(char controller[CG_CONTROLLER_MAX],
+ const char *program_name)
+{
+ int ret;
+ void *handle;
+
+ struct cgroup_file_info info;
+ int lvl;
+
+ /*
+ * the controller which was used in the last variable-name
+ * pair output. (Used to detect whether the controller header
+ * have to be output or not)
+ */
+ char cont_old[FILENAME_MAX];
+ /*
+ * header is one if the header part of ontrol group of
+ * currentlly read hierarchy have to be print
+ */
+ int header = 0;
+ /*
+ * empty_h is one if there is no output record
+ * in the given hierarchy yet
+ */
+ int empty_h = 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 */
+ 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) {
+
+ /* some group starts here */
+ if (info.type != CGROUP_FILE_TYPE_FILE) {
+ /* group output was finished */
+ header = 1;
+ }
+
+ /*
+ * if it is nonroot group and the header is not print yet,
+ * print the header now
+ */
+ if ((info.depth > 1) && (info.type == CGROUP_FILE_TYPE_FILE)
+ && (header == 1)) {
+ if (empty_h == 1) {
+ /*
+ * there was no group output
+ * before the actual one
+ */
+ empty_h = 0;
+ } else {
+ /* close the previous group here */
+ printf("\t}\n}\n");
+ }
+
+ /* the header of the current group is just in process */
+ header = 0;
+
+ 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) &&
+ /*
+ * TODO this file have to be handled
+ * in some special way
+ */
+ (strcmp(info.path, "cpuacct.usage") != 0)) {
+ ret = display_variable_data(info,
+ prefix_len, cont_old, program_name);
+ }
+
+ }
+
+
+err:
+ if (empty_h != 1)
+ printf("\t}\n}\n");
+
+ 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;
+}
------------------------------------------------------------------------------
This SF.net email is sponsored by
Make an app they can't live without
Enter the BlackBerry Developer Challenge
http://p.sf.net/sfu/RIM-dev2dev
_______________________________________________
Libcg-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libcg-devel