Hello, Dave,

I have read your mail and think over the suggestions and done some changes. Firstly, I added a new option "-a" to meet the demand that user can enter a cgroup address and it would display its controller/path name.

Secondly, previously, when user specify controller:path to display
chosen cgroups,there is no option. To make it in accordance with -a
option, I did a little change, that is when user specify
controller:path, there should be a option -g. The following example
illustrates the change.
Previously, user may run : crash> lscgroup cpu:/
but now, user should run  : crash > lscgroup -g cpu:/

Accordingly,the help information was revised. You can refer to the
help information and attachment to see detailed changes.

Many thanks
Yongming Yu

        
Dave Anderson 写道:

----- Original Message -----

And I would suggest a new option, where a user can enter a cgroup
address, and it would find and display its controller/path name:

 crash> lscgroup
      CGROUP       CONTROLLER:PATH
 ffff8801f668c400  cpuacct,cpu:/system/nfs-lock.service
 crash>

Sorry -- I meant something like this:

 crash> lscgroup ffff8801f668c400
      CGROUP       CONTROLLER:PATH
 ffff8801f668c400  cpuacct,cpu:/system/nfs-lock.service
 crash>

Dave



--
--------------------------------------------------
Yu Yongming
Nanjing Fujitsu Nanda Software Tech. Co., Ltd.
(FNST)No. 6 Wenzhu Road, Nanjing, 210012, China
EMail:[email protected]

Regards__
--------------------------------------------------



/* lscgroup.c - list cgroups
 *
 * Copyright (C) 2012 FUJITSU LIMITED
 * Author: Yu Yongming <[email protected]>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.
 */

#include "defs.h"

#define PATHNAME_MAX      200
#define ROOT_MAX          64
#define CG_CONTROLLER_MAX 20
#define CG_HIER_MAX       20
#define LIST_CER          0x1
#define LIST_ADD          0x2


#define CGROUP_MEMBER_OFFSET_INIT(X,Y,Z) 
(cgroup_offset_table.X=MEMBER_OFFSET(Y,Z))
#define CGROUP_OFFSET(X) (OFFSET_verify(cgroup_offset_table.X, (char 
*)__FUNCTION__, __FILE__, __LINE__, #X))

/*
 *struct declaration
 */
struct cgroup_offset_table {
        long cgroupfs_root_root_list;
        long cgroupfs_root_top_cgroup;
        long cgroupfs_root_subsys_list;
        long cgroupfs_root_actual_subsys_bits;
        long cgroupfs_root_name;
        long cgroup_sibling;
        long cgroup_children;
        long cgroup_dentry;
        long cgroup_subsys_name;
        long cgroup_subsys_sibling;
};

struct cgroup_group_spec {
        char path[PATHNAME_MAX];
        char *controllers[CG_CONTROLLER_MAX];
};

/*
 *function declaration
 */
int _init(void);
int _fini(void);

void cmd_lscgroup(void);
char *help_lscgroup[];

static void cgroup_init(void);
static void get_controller_name(ulong);
static void get_cgroup_name(ulong, char *);
static void parse_top_cgroup(ulong, char *);
static void print_all_cgroups(void);
static int in_cgroupfs_root(char *, struct cgroup_group_spec *);
static ulong locate_top_cgroup(struct cgroup_group_spec *);
static void parse_path(char *, char **);
static ulong locate_cgroup(ulong, ulong, char *);
static void standarlize_path(char *);
static void cgroup_elem(struct cgroup_group_spec *);
static void check_addr(ulong, ulong, char *, char *);
static ulong addr_to_cgroup(ulong, char *);
static void cgroup_addr(char *);
static void cgroup_list_cgroups(char **, struct cgroup_group_spec **, int);
static int parse_cgroup_spec(struct cgroup_group_spec **, char *);
static void free_cgroup_spec(char **, struct cgroup_group_spec **);

/*
 * global data
 */

static char controller_name[PATHNAME_MAX];
static int authen = FALSE;

static struct command_table_entry command_table[] = {
        {"lscgroup", cmd_lscgroup, help_lscgroup, 0},
        {NULL},
};

static struct cgroup_offset_table cgroup_offset_table = { 0 };

char *help_lscgroup[] = {
"lscgroup",
"list all cgroups",
"[-g [controllers:path] [...]] [-a [address]]",
"  The command list all present cgroups and their addresses, chosen cgroups",
"  and corresponding addresses or cgroup according to input address.",
"  When no parameter is specified, the command list all cgroups which are ",
"  present. The option -g is used to list subcgroups of cgroup specified by",
"  parameter <controllers>:<path>, controllers in <controllers>:<path> can be",
"  a comma separated controller list. The option -a is used to list cgroup ",
"  whose address equals to the succedent specified parameter. ",
"\nEXAMPLE",
"  display all cgroups:\n",
"    %s>lscgroup",
"         CGROUP       CONTROLLER:PATH",
"    ffff8801188f8030  blkio:/",
"    ffff8801188d3200  blkio:/libvirt",
"    ffff88011a724600  blkio:/libvirt/lxc",
"    ffff88011adac600  blkio:/libvirt/qemu",
"    ffff8801151f6030  net_cls:/",
"    ffff88011522a030  freezer:/",
"    ffff8801158f9200  freezer:/libvirt",
"    ffff88011a724800  freezer:/libvirt/lxc",
"    ffff88011adac800  freezer:/libvirt/qemu",
"    ffff880115264030  devices:/",
"    ffff880115846e00  devices:/libvirt",
"    ffff88011a724a00  devices:/libvirt/lxc",
"    ffff88011adaca00  devices:/libvirt/qemu",
"    ffff88011794c030  memory:/",
"    ffff88011738ca00  memory:/libvirt",
"    ffff88011a724c00  memory:/libvirt/lxc",
"    ffff88011adacc00  memory:/libvirt/qemu",
"    ffff880115b20030  cpuacct:/",
"    ffff8801191ed600  cpuacct:/libvirt",
"    ffff88011a08d200  cpuacct:/libvirt/lxc",
"    ffff8801188d3e00  cpuacct:/libvirt/qemu",
"    ffff88011923a030  cpu:/",
"    ffff880115846600  cpu:/libvirt",
"    ffff88011906e400  cpu:/libvirt/lxc",
"    ffff880117be6400  cpu:/libvirt/qemu",
"    ffff8801173f2030  cpuset:/",
"    ffff8801179e6200  cpuset:/libvirt",
"    ffff88011a08d000  cpuset:/libvirt/lxc",
"    ffff880119fe8000  cpuset:/libvirt/qemu",
"       ",
"  display chosen cgroups:\n",
"    %s>lscgroup -g cpuset:/libvirt  -g cpu:/",
"         CGROUP       CONTROLLER:PATH",
"    ffff880115846600  cpu:/libvirt",
"    ffff88011906e400  cpu:/libvirt/lxc",
"    ffff880117be6400  cpu:/libvirt/qemu",
"         CGROUP       CONTROLLER:PATH",
"    ffff88011923a030  cpu:/",
"    ffff880115846600  cpu:/libvirt",
"    ffff88011906e400  cpu:/libvirt/lxc",
"    ffff880117be6400  cpu:/libvirt/qemu",
"       ",
"  display cgroup according to input address:\n",
"    %s>lscgroup -a ffff880119fe8000 -a ffff880115846600",
"         CGROUP       CONTROLLER:PATH",
"    ffff880119fe8000  cpuset:/libvirt/qemu",
"         CGROUP       CONTROLLER:PATH",
"    ffff880115846600  cpu:/libvirt",
NULL
};

int 
_init(void)
{
        register_extension(command_table);
        return 1;
}

int 
_fini(void)
{
        return 1;
}

static void 
cgroup_init(void)
{
        CGROUP_MEMBER_OFFSET_INIT(cgroupfs_root_root_list, "cgroupfs_root",
                "root_list");
        CGROUP_MEMBER_OFFSET_INIT(cgroupfs_root_top_cgroup, "cgroupfs_root",
                "top_cgroup");
        CGROUP_MEMBER_OFFSET_INIT(cgroupfs_root_subsys_list, "cgroupfs_root",
                "subsys_list");
        CGROUP_MEMBER_OFFSET_INIT(cgroupfs_root_actual_subsys_bits,
                "cgroupfs_root", "actual_subsys_bits");
        CGROUP_MEMBER_OFFSET_INIT(cgroupfs_root_name, "cgroupfs_root",
                "name");
        CGROUP_MEMBER_OFFSET_INIT(cgroup_sibling, "cgroup", "sibling");
        CGROUP_MEMBER_OFFSET_INIT(cgroup_children, "cgroup", "children");
        CGROUP_MEMBER_OFFSET_INIT(cgroup_dentry, "cgroup", "dentry");
        CGROUP_MEMBER_OFFSET_INIT(cgroup_subsys_name, "cgroup_subsys", "name");
        CGROUP_MEMBER_OFFSET_INIT(cgroup_subsys_sibling, "cgroup_subsys", 
                "sibling");
}

static void 
get_controller_name(ulong cgroupfs_root)
{
        char name[PATHNAME_MAX];
        ulong subsys, next, subsys_list, name_buf, name_addr;
        int len;
        
        BZERO(name, PATHNAME_MAX);
        BZERO(controller_name, PATHNAME_MAX);

        readmem(cgroupfs_root + CGROUP_OFFSET(cgroupfs_root_actual_subsys_bits),
                KVADDR, &subsys, sizeof(ulong), "cgroupfs_root_actual_subsys",
                FAULT_ON_ERROR);
        if(subsys == 0) {
                readmem(cgroupfs_root + CGROUP_OFFSET(cgroupfs_root_name), 
                        KVADDR, &name, ROOT_MAX, "cgroupfs_root_name",
                        FAULT_ON_ERROR);
                strcat(controller_name, name);
                return ;
        }
        subsys_list = cgroupfs_root + CGROUP_OFFSET(cgroupfs_root_subsys_list);
        readmem(subsys_list, KVADDR, &next, sizeof(ulong),
                "cgroupfs_root_subsys_list", FAULT_ON_ERROR);
        
        do {
                name_buf = next - CGROUP_OFFSET(cgroup_subsys_sibling)
                        + CGROUP_OFFSET(cgroup_subsys_name);
                readmem(name_buf, KVADDR, &name_addr, sizeof(ulong),
                        "cgroup_subsys_name", FAULT_ON_ERROR);
                readmem(name_addr, KVADDR, name, sizeof(name), 
                        "char* name", FAULT_ON_ERROR);
                        
                strcat(controller_name, name);
                strcat(controller_name, ",");

                readmem(next, KVADDR, &next, sizeof(ulong),
                "list_head", FAULT_ON_ERROR);
        } while(next != subsys_list);
        
        len = strlen(controller_name);  
        controller_name[len-1] = '\0';
}

static void
get_cgroup_name(ulong cgroup, char *name)
{
        ulong dentry, name_addr;
        char *dentry_buf;
        int len;

        readmem(cgroup + CGROUP_OFFSET(cgroup_dentry), KVADDR,
                &dentry, sizeof(ulong), "cgroup dentry",
                FAULT_ON_ERROR);

        dentry_buf = GETBUF(SIZE(dentry));
        readmem(dentry, KVADDR, dentry_buf, SIZE(dentry),
                "dentry", FAULT_ON_ERROR);
        len = UINT(dentry_buf + OFFSET(dentry_d_name) + OFFSET(qstr_len));
        name_addr = ULONG(dentry_buf + OFFSET(dentry_d_name) + 
OFFSET(qstr_name));
        readmem(name_addr, KVADDR, name, len, "qstr name", FAULT_ON_ERROR);
        FREEBUF(dentry_buf);
}

static void 
parse_top_cgroup(ulong top_cgroup, char *path)
{
        int len;
        char tmp_buf[PATHNAME_MAX];
        ulong list_head[2], next, child;

        BZERO(tmp_buf, PATHNAME_MAX);
        get_cgroup_name(top_cgroup, tmp_buf);
        if (strlen(path) > 1) 
                strncat(path, "/", 1);
        strncat(path, tmp_buf, strlen(tmp_buf));

        fprintf(fp, "%lx  %s:%s\n", top_cgroup, controller_name, path);

        child = top_cgroup + CGROUP_OFFSET(cgroup_children);
        readmem(child, KVADDR, list_head, sizeof(ulong) * 2,
                "cgroup children", FAULT_ON_ERROR);

        if ((list_head[0] == child) && (list_head[1] == child))
                return;

        next = list_head[0];
        while (next != child) {
                top_cgroup = next - CGROUP_OFFSET(cgroup_sibling);
                readmem(top_cgroup + CGROUP_OFFSET(cgroup_sibling) +
                        OFFSET(list_head_next), KVADDR, &next, sizeof(ulong),
                        "cgroup siblings", FAULT_ON_ERROR);
                len = strlen(path);
                parse_top_cgroup(top_cgroup, path);
                path[len] = '\0';
        }
}

static void 
print_all_cgroups(void)
{
        struct syment *roots;
        ulong top_cgroup;
        ulong list_head[2], next, cgroupfs_root;;
        char path_name[PATHNAME_MAX];
        char buf1[BUFSIZE];

        BZERO(path_name, PATHNAME_MAX);

        if (!(roots = symbol_search("roots")))
                error(FATAL, "roots symbol does not exist?\n");

        readmem(roots->value, KVADDR, list_head, sizeof(ulong) * 2,
                "list_head", FAULT_ON_ERROR);

        if ((list_head[0] == roots->value) && (list_head[1] == roots->value)) {
                fprintf(fp, "no active cgroup hierarchy in the kernel.");
                return;
        }

        fprintf(fp, "%s  CONTROLLER:PATH\n",
                mkstring(buf1, VADDR_PRLEN, CENTER, "CGROUP"));
        next = list_head[0];
        while (next != roots->value) {
                cgroupfs_root = next - CGROUP_OFFSET(cgroupfs_root_root_list);
                get_controller_name(cgroupfs_root);

                top_cgroup = cgroupfs_root +
                        CGROUP_OFFSET(cgroupfs_root_top_cgroup);
                /* print infomation of cgroup and subcgroup */
                parse_top_cgroup(top_cgroup, path_name);
                readmem(next + OFFSET(list_head_next), KVADDR, &next,
                        sizeof(ulong), "list_head next", FAULT_ON_ERROR);
                BZERO(path_name, PATHNAME_MAX);
                BZERO(controller_name, PATHNAME_MAX);
        }
}

static int
in_cgroupfs_root(char *tmp_name, struct cgroup_group_spec *elem)
{
        char *name;
        int i = 0;
        name = strtok(tmp_name, ",");
        while(name != NULL) {   
                while(elem->controllers[i] != NULL && i < CG_CONTROLLER_MAX) {
                        if(STREQ(name, elem->controllers[i]))
                                return 1;
                        i++;
                }
                name = strtok(NULL, ",");
                i = 0;
        }       
        
        return 0;
}

static ulong 
locate_top_cgroup(struct cgroup_group_spec *elem)
{
        struct syment *roots;
        ulong top_cgroup;
        ulong list_head[2], next, cgroupfs_root;
        char tmp_name[PATHNAME_MAX];

        if (!(roots = symbol_search("roots")))
                error(FATAL, "roots symbol does not exist?");

        readmem(roots->value, KVADDR, list_head, sizeof(ulong)*2,
                "list_head", FAULT_ON_ERROR);

        if ((list_head[0] == roots->value) && (list_head[1] == roots->value))
                return 0;
        
        next = list_head[0];
        while (next != roots->value) {
                /* begin from first root */
                cgroupfs_root = next - CGROUP_OFFSET(cgroupfs_root_root_list);
                get_controller_name(cgroupfs_root);
                strcpy(tmp_name, controller_name);

                if (in_cgroupfs_root(tmp_name, elem)) {
                        top_cgroup = cgroupfs_root +
                                CGROUP_OFFSET(cgroupfs_root_top_cgroup);
                        return top_cgroup;
                }
                readmem(next + OFFSET(list_head_next), KVADDR, &next,
                        sizeof(ulong), "list_head", FAULT_ON_ERROR);
                BZERO(controller_name, PATHNAME_MAX);
        }
        return 0;
}

/*
 * function parse_path and extracts the input path before the first '/' as
 * relatively path which will be used to compare with path name of cgroup.
 * In addition, it ignores the unnecessary '/' in the path
 */
static void 
parse_path(char *path, char **elem_path)
{ 
        char *token;

        token = *elem_path;
        if (token[0] == '/') {
                *path++ = *token++;
        } else {
                while (*token) {
                        if (*token == '/' && *(token + 1) == '/') {
                                token++;
                        } else if (*token == '/' && *(token + 1) != '/') {
                                token++; 
                                break;
                        } else {
                                *path++ = *token++;     
                        }
                }       
        }
        *elem_path = token;
        *path = '\0';
}

static ulong 
locate_cgroup(ulong current, ulong prev_addr, char *elem_path)
{
        char tmp_buf[PATHNAME_MAX];
        char path[PATHNAME_MAX];
        char *tmp_path = elem_path;
        ulong child, sibling, child_offset, sibling_offset;

        if (*elem_path == '\0')
                return prev_addr;

        BZERO(tmp_buf, PATHNAME_MAX);
        get_cgroup_name(current, tmp_buf);

        parse_path(path, &elem_path);

        readmem(current + CGROUP_OFFSET(cgroup_children), KVADDR, &child,
                sizeof(ulong), "cgroup children", FAULT_ON_ERROR);
        readmem(current + CGROUP_OFFSET(cgroup_sibling), KVADDR, &sibling,
                sizeof(ulong), "cgroup sibling", FAULT_ON_ERROR);       

        child_offset = CGROUP_OFFSET(cgroup_children);
        sibling_offset = CGROUP_OFFSET(cgroup_sibling);
        /* parse the children if temp=path_name, do change elem_path */
        if (STREQ(tmp_buf, path)) {
                if ((child - child_offset != current))
                        return locate_cgroup(child - sibling_offset,
                                        current, elem_path);
                else if (*elem_path == '\0')
                        return current;
        } else { 
        /* parse the sibling if temp !=path_name, do not chage elem_path */
                if (((sibling - child_offset) != prev_addr) &&
                    ((sibling - sibling_offset) != current)) {
                        elem_path = tmp_path;
                        return locate_cgroup(sibling - sibling_offset,
                                        prev_addr, elem_path);
                }
        }
        return 0;
}

/*
 * make the input path begin with character '/' and end without character '/'
 * to cope with the situation that the input path may be like "/xxxxx",
 * "xxxxx", "xxxxx/", or "/xxxxx/"
 */
static void 
standarlize_path(char *path)
{
        int len;

        len = strlen(path) - 1;
        if (path[len] == '/')
                path[len] = '\0';

        if (path[0] != '/') {
                len = strlen(path);
                path[len + 1] = '\0';
                while (len) {
                        path[len] = path[len - 1];
                        len--;
                }
                path[0] = '/';
        }
}

static void 
mani_path(char *path)
{       
        int len;

        standarlize_path(path);
        
        if (STREQ(path, "/")) {
                *path = '\0';
                return ;
        }
        len = strlen(path);
        while (path[len] != '/') {
                path[len] = '\0';
                len--;
        }
        path[len] = '\0';
        path[0] = '/';
}

static void 
cgroup_elem(struct cgroup_group_spec *list_elem)
{
        ulong top_cgroup;
        ulong cgroup;
        char path_name[PATHNAME_MAX];
        char buf1[BUFSIZE];

        top_cgroup = locate_top_cgroup(list_elem);
        if (top_cgroup == 0) {
                fprintf(fp, "can not find cgroup %s, check the input.\n",
                        list_elem->path);
                return ;
        }
        
        strcpy(path_name, list_elem->path);
        standarlize_path(path_name);
        cgroup = locate_cgroup(top_cgroup, top_cgroup, path_name);
        if (cgroup == 0) {
                fprintf(fp, "can not find cgroup %s, check the input.\n", 
                        list_elem->path);
                return ;
        }
 
        mani_path(list_elem->path);
        fprintf(fp, "%s  CONTROLLER:PATH\n",
                mkstring(buf1, VADDR_PRLEN, CENTER, "CGROUP"));
        parse_top_cgroup(cgroup, list_elem->path);
}

static void 
check_addr(ulong top_cgroup, ulong addr_num, char *path, char *full_path)
{
        int len;
        char tmp_buf[PATHNAME_MAX];
        ulong list_head[2], next, child;

        BZERO(tmp_buf, PATHNAME_MAX);
        get_cgroup_name(top_cgroup, tmp_buf);
        if (strlen(path) > 1)
                strncat(path, "/", 1);
        strncat(path, tmp_buf, strlen(tmp_buf));

        if (top_cgroup == addr_num) {
                strcpy(full_path, path);
                authen = TRUE;
                return ;
        }

        child = top_cgroup + CGROUP_OFFSET(cgroup_children);
        readmem(child, KVADDR, list_head, sizeof(ulong) * 2,
                "cgroup children", FAULT_ON_ERROR);

        next = list_head[0];
        while (next != child) {
                top_cgroup = next - CGROUP_OFFSET(cgroup_sibling);
                readmem(top_cgroup + CGROUP_OFFSET(cgroup_sibling) +
                        OFFSET(list_head_next), KVADDR, &next, sizeof(ulong),
                        "cgroup siblings", FAULT_ON_ERROR);
                len = strlen(path);
                check_addr(top_cgroup, addr_num, path, full_path);
                path[len] = '\0';
        }
}

static ulong 
addr_to_cgroup(ulong addr_num, char *path)
{
        struct syment *roots;
        ulong top_cgroup;
        ulong list_head[2], next, cgroupfs_root;
        char path_name[PATHNAME_MAX];

        BZERO(path_name, PATHNAME_MAX);
        if (!(roots = symbol_search("roots")))
                error(FATAL, "roots symbol does not exist?");

        readmem(roots->value, KVADDR, list_head, sizeof(ulong)*2,
                "list_head", FAULT_ON_ERROR);

        next = list_head[0];
        while (next != roots->value) {
                /* begin from first root */
                cgroupfs_root = next - CGROUP_OFFSET(cgroupfs_root_root_list);
                get_controller_name(cgroupfs_root);

                top_cgroup = cgroupfs_root +
                        CGROUP_OFFSET(cgroupfs_root_top_cgroup);
                check_addr(top_cgroup, addr_num, path_name, path);
                if (authen) {
                        authen = FALSE;
                        return TRUE;
                }       
                readmem(next + OFFSET(list_head_next), KVADDR, &next,
                        sizeof(ulong), "list_head", FAULT_ON_ERROR);
                BZERO(path_name, PATHNAME_MAX);
                BZERO(controller_name, PATHNAME_MAX);
        }
        return FALSE;           
}

static void 
cgroup_addr(char *addr)
{
        ulong addr_num;
        char path[PATHNAME_MAX];
        char buf1[BUFSIZE];

        BZERO(path, PATHNAME_MAX);
        addr_num = stol (addr, FAULT_ON_ERROR, NULL);

        if (!addr_to_cgroup(addr_num, path)) {
                fprintf(fp, "can not find cgroup with address %lx", addr_num);
                return ;        
        }
        fprintf(fp, "%s  CONTROLLER:PATH\n",
                mkstring(buf1, VADDR_PRLEN, CENTER, "CGROUP"));
        fprintf(fp, "%lx  %s:%s\n", addr_num, controller_name, path);   
}

static void 
cgroup_list_cgroups(char **addr, struct cgroup_group_spec *cgroup_list[],
        int flags)
{
        int i,j;

        i = j = 0;      
        cgroup_init();
        if(cgroup_offset_table.cgroupfs_root_root_list == -1) {
                fprintf(fp, "cgroup does not exist, check kernel version.");
                return ;
        }
        if (flags == 0 ) {
                /* list all the cgroups */
                print_all_cgroups();
        } 
        if (flags & LIST_CER) {
                /* list the specified cgroups */
                while ((cgroup_list[i]->path != NULL)) {
                        cgroup_elem(cgroup_list[i]);
                        i++;
                }
        }
        if (flags & LIST_ADD) {
                /* list specified addr cgroups */
                while ((addr[j] != NULL)) {
                        cgroup_addr(addr[j]);
                        j++;
                }       
        }
}

static int 
parse_cgroup_spec(struct cgroup_group_spec **list, char *optarg)
{
        struct cgroup_group_spec *ptr;
        int i, j;
        char *controller, *path, *temp;

        ptr = *list;

        for (i = 0; i < CG_HIER_MAX; i++, ptr++) {
                if (!list[i])
                        break;
        }

        if (i == CG_HIER_MAX) {
                fprintf(fp, "Max allowed hierarchies %d reached\n",
                        CG_HIER_MAX);
                return -1;
        }

        controller = strtok(optarg, ":");
        if (!controller)
                return -1;

        path = strtok(NULL, ":");
        if (!path)
                return -1;

        list[i] = (struct cgroup_group_spec *)GETBUF(sizeof(**list));
        j = 0;
        do {
                if (j == 0)
                        temp = strtok(controller, ",");
                else
                        temp = strtok(NULL, ",");

                if (temp) {
                        list[i]->controllers[j] = strdup(temp);
                        if (!list[i]->controllers[j]) {
                                FREEBUF(list[i]);
                                fprintf(fp, "%s\n", strerror(errno));
                                return -1;
                        }
                }
                j++;
        } while (temp && (j < (CG_CONTROLLER_MAX - 1)));

        strncpy(list[i]->path, path, strlen(path));

        return 0;
}

static int 
parse_addr_spec(char **addr,char *optarg)
{
        int i;

        for(i = 0; i < CG_HIER_MAX; i++)
                if (!addr[i])
                        break;
        if (i == CG_HIER_MAX) {
                fprintf(fp, "Max allowed hierarchies %d reached\n",
                        CG_HIER_MAX);
                return -1;
        }
        
        addr[i] = strdup(optarg);
        if (!addr[i]) {
                fprintf(fp, "%s\n",strerror(errno));
                return -1;
        }
        return 0;
}

static void 
free_cgroup_spec(char **addr, struct cgroup_group_spec **list)
{
        int i,j;

        for (i = 0; i < CG_HIER_MAX; i++) {
                if (list[i]) {
                        for(j = 0; j< CG_CONTROLLER_MAX; j++)
                                if (list[i]->controllers[j])
                                        free(list[i]->controllers[j]);
                        FREEBUF(list[i]);
                }
                else {
                        break;
                }       
        }
        for (i =0; i< CG_HIER_MAX; i++) {
                if (addr[i])
                        free(addr[i]);
                else 
                        break;
        }

}

void 
cmd_lscgroup(void)
{
        int c, ret, flags;
        char *addr[CG_HIER_MAX];
        struct cgroup_group_spec *cgroup_list[CG_HIER_MAX];

        ret = flags = 0;
        BZERO(cgroup_list, sizeof(cgroup_list));
        BZERO(addr, sizeof(addr));

        while ((c = getopt(argcnt, args, "a:g:")) != EOF) {
                switch(c) {
                case 'a':
                        ret = parse_addr_spec(addr, optarg);    
                        if(ret) {
                                fprintf(fp, "%s: cgroup address parsing failed"
                                        "(%s)\n", args[0], optarg);
                                free_cgroup_spec(addr, cgroup_list);
                                return ;        
                        }
                        flags |= LIST_ADD;
                        break;

                case 'g':
                        ret = parse_cgroup_spec(cgroup_list, optarg);
                        if(ret) {
                                fprintf(fp, "%s: cgroup controller and path "
                                        "parsing failed(%s)\n",
                                        args[0], optarg);
                                free_cgroup_spec(addr, cgroup_list);
                                return ;
                        }
                        flags |= LIST_CER;
                        break;

                default:
                        cmd_usage(pc->curcmd, SYNOPSIS);
                        return ;
                }
        }
        if (argerrs)
                cmd_usage(pc->curcmd, SYNOPSIS);
        if (optind < argcnt)
                cmd_usage(pc->curcmd, SYNOPSIS);

        cgroup_list_cgroups(addr, cgroup_list, flags);
        free_cgroup_spec(addr, cgroup_list);
}

--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to