1
/* " Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
2
* " Written by Ivana Hutarova Varekova <varekova@redhat.com>
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of version 2.1 of the GNU Lesser General Public License
6
* as published by the Free Software Foundation.
8
* This program is distributed in the hope that it would be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20
#include <sys/types.h>
22
#include <libcgroup.h>
23
#include <libcgroup-internal.h>
29
FL_SILENT = 2, /* do-not show any warning/error output */
30
FL_STRICT = 4, /* don show the variables which are not on
32
FL_OUTPUT = 8, /* output should be redirect to the given file */
33
FL_BLACK = 16, /* blacklist set */
34
FL_WHITE = 32, /* whitelist set */
37
#define BLACKLIST_CONF "/etc/cgsnapshot_blacklist.conf"
38
#define WHITELIST_CONF "/etc/cgsnapshot_whitelist.conf"
40
struct black_list_type {
41
char *name; /* variable name */
42
struct black_list_type *next; /* pointer to the next record */
45
struct black_list_type *black_list;
46
struct black_list_type *white_list;
48
typedef char cont_name_t[FILENAME_MAX];
56
static void usage(int status, const char *program_name)
59
fprintf(stderr, "Wrong input parameters,"
60
" try %s -h' for more information.\n",
63
fprintf(stdout, "Usage: %s [-h] [-s] [-b file] "\
64
"[-w file] [-f output_file] "\
65
"[controller] [...]\n", program_name);
66
fprintf(stdout, "Generate the configuration file from "\
67
"the given controllers of control groups\n");
68
fprintf(stdout, " -b,--blacklist file Set the blacklist"\
69
" configuration file (default %s)\n", BLACKLIST_CONF);
70
fprintf(stdout, " -f,--file Redirect the output"\
72
fprintf(stdout, " -h,--help Display this help\n");
73
fprintf(stdout, " -s,--silent Ignore all "\
75
fprintf(stdout, " -t,--strict Don't show the "\
76
"variables which are not on the whitelist\n");
77
fprintf(stdout, " -w,--whitelist file Set the whitelist"\
78
" configuration file (don't used by default)\n");
82
/* cache values from blacklist file to the list structure */
84
int load_list(char *filename, struct black_list_type **p_list)
89
char buf[FILENAME_MAX];
90
char name[FILENAME_MAX];
92
struct black_list_type *start = NULL;
93
struct black_list_type *end = NULL;
94
struct black_list_type *new;
96
fw = fopen(filename, "r");
98
fprintf(stderr, "ERROR: Failed to open file %s: %s\n",
99
filename, strerror(errno));
104
/* go through the all configuration file and search the line */
105
while (fgets(buf, FILENAME_MAX, fw) != NULL) {
106
buf[FILENAME_MAX-1] = '\0';
109
/* if the record start with # then skip it */
110
while ((buf[i] == ' ') || (buf[i] == '\n'))
113
if ((buf[i] == '#') || (buf[i] == '\0'))
116
new = (struct black_list_type *)malloc(sizeof
117
(struct black_list_type));
119
fprintf(stderr, "ERROR: Memory allocation problem "
120
"(%s)\n", strerror(errno));
125
ret = sscanf(buf, "%s", name);
126
new->name = strdup(name);
130
/* update the variables list */
145
/* free list structure */
146
void free_list(struct black_list_type *list)
148
struct black_list_type *now;
149
struct black_list_type *next;
152
while (now != NULL) {
161
/* Test whether the variable is on the list
164
* 0 ... no record was found
166
int is_on_list(char *name, struct black_list_type *list)
168
struct black_list_type *record;
171
/* go through the list of all values */
172
while (record != NULL) {
173
/* if the variable name is found */
174
if (strcmp(record->name, name) == 0) {
175
/* return its value */
178
record = record->next;
181
/* the variable was not found */
186
/* Display permissions record for the given group
189
static int display_permissions(const char *path,
190
const char *program_name)
197
char tasks_path[FILENAME_MAX];
199
/* admin permissions record */
200
/* get the directory statistic */
201
ret = stat(path, &sba);
203
fprintf(stderr, "ERROR: can't read statistics about %s\n",
208
/* tasks permissions record */
209
/* get tasks file statistic */
210
strncpy(tasks_path, path, FILENAME_MAX);
211
tasks_path[FILENAME_MAX-1] = '\0';
212
strncat(tasks_path, "/tasks", FILENAME_MAX);
213
tasks_path[FILENAME_MAX-1] = '\0';
214
ret = stat(tasks_path, &sbt);
216
fprintf(stderr, "ERROR: can't read statistics about %s\n",
221
if ((sba.st_uid) || (sba.st_gid) ||
222
(sbt.st_uid) || (sbt.st_gid)) {
223
/* some uid or gid is nonroot, admin permission
226
/* print the header */
227
fprintf(of, "\tperm {\n");
229
/* find out the user and group name */
230
pw = getpwuid(sba.st_uid);
232
fprintf(stderr, "ERROR: can't get %d user name\n",
237
gr = getgrgid(sba.st_gid);
239
fprintf(stderr, "ERROR: can't get %d group name\n",
244
/* print the admin record */
245
fprintf(of, "\t\tadmin {\n"\
248
"\t\t}\n", pw->pw_name, gr->gr_name);
250
/* find out the user and group name */
251
pw = getpwuid(sbt.st_uid);
253
fprintf(stderr, "ERROR: can't get %d user name\n",
258
gr = getgrgid(sbt.st_gid);
260
fprintf(stderr, "ERROR: can't get %d group name\n",
265
/* print the task record */
266
fprintf(of, "\t\ttask {\n"\
269
"\t\t}\n", pw->pw_name, gr->gr_name);
271
fprintf(of, "\t}\n");
277
/* Displey the control group record:
280
* controllers records
284
static int display_cgroup_data(struct cgroup *group,
285
char controller[CG_CONTROLLER_MAX][FILENAME_MAX],
286
const char *group_path, int root_path_len, int first,
287
const char *program_name)
290
int bl, wl = 0; /* is on the blacklist/whitelist flag */
294
struct cgroup_controller *group_controller = NULL;
296
char var_path[FILENAME_MAX];
300
/* print the group definition header */
301
fprintf(of, "group %s {\n", group->name);
303
/* display the permission tags */
304
ret = display_permissions(group_path, program_name);
308
/* for all wanted controllers display controllers tag */
309
while (controller[i][0] != '\0') {
311
group_controller = cgroup_get_controller(group, controller[i]);
312
if (group_controller == NULL) {
313
printf("cannot find controller "\
314
"'%s' in group '%s'\n",
315
controller[i], group->name);
321
/* print the controller header */
322
fprintf(of, "\t%s {\n", controller[i]);
324
nr_var = cgroup_get_value_name_count(group_controller);
326
for (j = 0; j < nr_var; j++) {
327
name = cgroup_get_value_name(group_controller, j);
329
/* For the non-root groups cgconfigparser set
330
permissions of variable files to 777. Thus
331
It is necessary to test the permissions of
332
variable files in the root group to find out
333
whether the variable is writable.
335
strncpy(var_path, group_path, root_path_len);
336
var_path[root_path_len] = '\0';
337
strncat(var_path, "/", FILENAME_MAX);
338
var_path[FILENAME_MAX-1] = '\0';
339
strncat(var_path, name, FILENAME_MAX);
340
var_path[FILENAME_MAX-1] = '\0';
342
/* test whether the write permissions */
343
ret = stat(var_path, &sb);
344
/* freezer.state is not in root group so ret != 0,
345
* but it should be listed
346
* device.list should be read to create
349
if ((ret == 0) && ((sb.st_mode & S_IWUSR) == 0) &&
350
(strcmp("devices.list", name) != 0)) {
351
/* variable is not writable */
355
/* find whether the variable is blacklisted or
357
bl = is_on_list(name, black_list);
358
wl = is_on_list(name, white_list);
360
/* if it is blacklisted skip it and continue */
364
/* if it is not whitelisted and strict tag is used
365
skip it and continue too */
366
if ((!wl) && (flags & FL_STRICT))
369
/* if it is not whitelisted and silent tag is not
370
used write an warning */
371
if ((!wl) && !(flags & FL_SILENT) && (first))
372
fprintf(stderr, "WARNING: variable %s is "\
373
"neither blacklisted nor "\
374
"whitelisted\n", name);
378
/* deal with devices variables:
379
* - omit devices.deny and device.allow,
380
* - generate devices.{deny,allow} from
381
* device.list variable (deny all and then
382
* all device.list devices */
383
if ((strcmp("devices.deny", name) == 0) ||
384
(strcmp("devices.allow", name) == 0)) {
387
if (strcmp("devices.list", name) == 0) {
388
output_name = "devices.allow";
390
"\t\tdevices.deny=\"a *:* rwm\";\n");
393
ret = cgroup_get_value_string(group_controller,
396
/* variable can not be read */
399
fprintf(stderr, "ERROR: Value of "\
400
"variable %s can be read\n",
404
fprintf(of, "\t\t%s=\"%s\";\n", output_name, value);
406
fprintf(of, "\t}\n");
409
/* tail of the record */
410
fprintf(of, "}\n\n");
417
* creates the record about the hierarchie which contains
418
* "controller" subsystem
420
static int display_controller_data(
421
char controller[CG_CONTROLLER_MAX][FILENAME_MAX],
422
const char *program_name)
428
struct cgroup_file_info info;
432
char cgroup_name[FILENAME_MAX];
434
struct cgroup *group = NULL;
436
/* start to parse the structure for the first controller -
437
controller[0] attached to hierarchie */
438
ret = cgroup_walk_tree_begin(controller[0], "/", 0,
439
&handle, &info, &lvl);
443
prefix_len = strlen(info.full_path);
445
/* go through all files and directories */
446
while ((ret = cgroup_walk_tree_next(0, &handle, &info, lvl)) == 0) {
447
/* some group starts here */
448
if (info.type == CGROUP_FILE_TYPE_DIR) {
449
/* parse the group name from full_path*/
450
strncpy(cgroup_name, &info.full_path[prefix_len],
452
cgroup_name[FILENAME_MAX-1] = '\0';
455
/* start to grab data about the new group */
456
group = cgroup_new_cgroup(cgroup_name);
458
printf("cannot create group '%s'\n",
463
ret = cgroup_get_cgroup(group);
465
printf("cannot read group '%s': %s\n",
466
cgroup_name, cgroup_strerror(ret));
470
display_cgroup_data(group, controller, info.full_path,
471
prefix_len, first, program_name);
478
cgroup_walk_tree_end(&handle);
486
static int is_ctlr_on_list(char controllers[CG_CONTROLLER_MAX][FILENAME_MAX],
487
cont_name_t wanted_conts[FILENAME_MAX])
492
while (controllers[i][0] != '\0') {
493
while (wanted_conts[j][0] != '\0') {
494
if (strcmp(controllers[i], wanted_conts[j]) == 0)
506
/* print data about input cont_name controller */
507
static int parse_controllers(cont_name_t cont_names[CG_CONTROLLER_MAX],
508
const char *program_name)
512
char path[FILENAME_MAX];
513
struct cgroup_mount_point controller;
515
char controllers[CG_CONTROLLER_MAX][FILENAME_MAX];
520
ret = cgroup_get_controller_begin(&handle, &controller);
522
/* go through the list of controllers/mount point pairs */
524
if (strcmp(path, controller.path) == 0) {
525
/* if it is still the same mount point */
526
if (max < CG_CONTROLLER_MAX) {
527
strncpy(controllers[max],
528
controller.name, FILENAME_MAX);
529
(controllers[max])[FILENAME_MAX-1] = '\0';
534
/* we got new mount point, print it if needed */
535
if ((!(flags & FL_LIST) ||
536
(is_ctlr_on_list(controllers, cont_names)))
538
(controllers[max])[0] = '\0';
539
ret = display_controller_data(
540
controllers, program_name);
543
strncpy(controllers[0], controller.name, FILENAME_MAX);
544
(controllers[0])[FILENAME_MAX-1] = '\0';
546
strncpy(path, controller.path, FILENAME_MAX);
547
path[FILENAME_MAX-1] = '\0';
551
/* the actual controller should not be printed */
552
ret = cgroup_get_controller_next(&handle, &controller);
556
(controllers[max])[0] = '\0';
557
ret = display_controller_data(
558
controllers, program_name);
561
cgroup_get_controller_end(&handle);
567
/* print data about input mount points */
568
/* TODO only wanted ones */
569
static int parse_mountpoints(cont_name_t cont_names[CG_CONTROLLER_MAX],
570
const char *program_name)
574
struct controller_data info;
577
/* start mount section */
578
fprintf(of, "mount {\n");
580
/* go through the controller list */
581
ret = cgroup_get_all_controller_begin(&handle, &info);
584
/* the controller attached to some hierarchy */
585
if (info.hierarchy != 0) {
586
ret = cgroup_get_subsys_mount_point(info.name,
589
/* the controller is not mounted */
590
if ((flags & FL_SILENT) == 0) {
591
fprintf(stderr, "ERROR: %s hierarchy "\
592
"not mounted\n", info.name);
595
fprintf(of, "\t%s = %s;\n",
596
info.name, mount_point);
599
/* next controller */
600
ret = cgroup_get_all_controller_next(&handle, &info);
603
if ((flags & FL_SILENT) != 0) {
605
"E: in get next controller %s\n",
606
cgroup_strerror(ret));
611
ret |= cgroup_get_all_controller_end(&handle);
613
/* finish mount section */
614
fprintf(of, "}\n\n");
618
int main(int argc, char *argv[])
625
cont_name_t wanted_cont[CG_CONTROLLER_MAX];
627
char bl_file[FILENAME_MAX]; /* blacklist file name */
628
char wl_file[FILENAME_MAX]; /* whitelist file name */
630
static struct option long_opts[] = {
631
{"help", no_argument, NULL, 'h'},
632
{"silent" , no_argument, NULL, 's'},
633
{"blacklist", required_argument, NULL, 'b'},
634
{"whitelist", required_argument, NULL, 'w'},
635
{"strict", no_argument, NULL, 't'},
636
{"file", required_argument, NULL, 'f'},
640
for (i = 0; i < CG_CONTROLLER_MAX; i++)
641
wanted_cont[i][0] = '\0';
644
/* parse arguments */
645
while ((c = getopt_long(argc, argv, "hsb:w:tf:", long_opts, NULL))
656
strncpy(bl_file, optarg, FILENAME_MAX);
660
strncpy(wl_file, optarg, FILENAME_MAX);
667
of = fopen(optarg, "w");
669
fprintf(stderr, "%s: Failed to open file %s\n",
680
/* read the list of controllers */
681
while (optind < argc) {
683
strncpy(wanted_cont[c_number], argv[optind], FILENAME_MAX);
684
(wanted_cont[c_number])[FILENAME_MAX-1] = '\0';
687
if (optind == CG_CONTROLLER_MAX-1) {
688
fprintf(stderr, "too many parameters\n");
693
if ((flags & FL_OUTPUT) == 0)
697
if (flags & FL_BLACK) {
698
ret = load_list(bl_file, &black_list);
700
/* load the blacklist from the default location */
701
ret = load_list(BLACKLIST_CONF, &black_list);
707
if (flags & FL_WHITE)
708
ret = load_list(wl_file, &white_list);
712
/* print the header */
713
fprintf(of, "# Configuration file generated by cgsnapshot\n");
715
/* initialize libcgroup */
719
/* empty configuration file */
723
/* print mount points section */
724
ret = parse_mountpoints(wanted_cont, argv[0]);
726
/* print hierarchies section */
727
ret = parse_controllers(wanted_cont, argv[0]);
729
free_list(black_list);
730
free_list(white_list);