]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
samples: Add C samples
authorTom Hromatka <tom.hromatka@oracle.com>
Wed, 23 Feb 2022 15:01:38 +0000 (08:01 -0700)
committerTom Hromatka <tom.hromatka@oracle.com>
Wed, 23 Feb 2022 15:01:38 +0000 (08:01 -0700)
Move the legacy tests from libcgroup-tests [1] to the
samples/c/ directory.  While these files are no longer
being run as automated tests, they provide helpful insight
into how to utilize the libcgroup C APIs.

[1] https://github.com/libcgroup/libcgroup-tests/

Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>
Reviewed-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
20 files changed:
configure.ac
samples/Makefile.am
samples/c/Makefile.am [new file with mode: 0644]
samples/c/get_all_controller.c [new file with mode: 0644]
samples/c/get_controller.c [new file with mode: 0644]
samples/c/get_mount_point.c [new file with mode: 0644]
samples/c/get_procs.c [new file with mode: 0644]
samples/c/get_variable_names.c [new file with mode: 0644]
samples/c/libcg_ba.cpp [new file with mode: 0644]
samples/c/libcgrouptest.h [new file with mode: 0644]
samples/c/libcgrouptest01.c [new file with mode: 0644]
samples/c/logger.c [new file with mode: 0644]
samples/c/proctest.c [new file with mode: 0644]
samples/c/read_stats.c [new file with mode: 0644]
samples/c/setuid.c [new file with mode: 0644]
samples/c/test_functions.c [new file with mode: 0644]
samples/c/test_named_hierarchy.c [new file with mode: 0644]
samples/c/walk_task.c [new file with mode: 0644]
samples/c/walk_test.c [new file with mode: 0644]
samples/c/wrapper_test.c [new file with mode: 0644]

index 113dcb5d65744d6d70fe4158af70b7f2c3834b2a..5f4efef3c70ec899098ed8642948af9327b46d83 100644 (file)
@@ -216,6 +216,7 @@ AC_CONFIG_FILES([Makefile
        scripts/init.d/cgconfig
        scripts/init.d/cgred
        samples/Makefile
+       samples/c/Makefile
        samples/config/Makefile
        include/Makefile
        include/libcgroup/init.h
index a85a5bb53ea01770b61ad61729cd496f24736f3b..23f64d691b5359742f115601a4ae0cdcad34de9e 100644 (file)
@@ -1 +1 @@
-SUBDIRS = config
+SUBDIRS = config c
diff --git a/samples/c/Makefile.am b/samples/c/Makefile.am
new file mode 100644 (file)
index 0000000..8f35939
--- /dev/null
@@ -0,0 +1,18 @@
+INCLUDES = -I$(top_srcdir)/include
+LDADD = $(top_builddir)/src/.libs/libcgroup.la
+
+libcgrouptest01_SOURCES=libcgrouptest01.c test_functions.c libcgrouptest.h
+libcg_ba_SOURCES=libcg_ba.cpp
+setuid_SOURCES=setuid.c
+walk_test_SOURCES=walk_test.c
+read_stats_SOURCES=read_stats.c
+walk_task_SOURCES=walk_task.c
+get_controller_SOURCES=get_controller.c
+get_mount_point_SOURCES=get_mount_point.c
+proctest_SOURCES=proctest.c
+get_all_controller_SOURCES=get_all_controller.c
+get_variable_names_SOURCES=get_variable_names.c
+test_named_hierarchy_SOURCES=test_named_hierarchy.c
+get_procs_SOURCES=get_procs.c
+wrapper_test_SOURCES=wrapper_test.c
+logger_SOURCES=logger.c
diff --git a/samples/c/get_all_controller.c b/samples/c/get_all_controller.c
new file mode 100644 (file)
index 0000000..d643c98
--- /dev/null
@@ -0,0 +1,34 @@
+#include <libcgroup.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main()
+{
+       int error;
+       void *handle;
+       struct controller_data info;
+
+       error = cgroup_init();
+
+       if (error) {
+               printf("cgroup_init failed with %s\n", cgroup_strerror(error));
+               exit(1);
+       }
+
+       error = cgroup_get_all_controller_begin(&handle, &info);
+
+       while (error != ECGEOF) {
+               printf("Controller %10s %5d %5d %5d\n", info.name,
+                       info.hierarchy, info.num_cgroups, info.enabled);
+               error = cgroup_get_all_controller_next(&handle, &info);
+               if (error && error != ECGEOF) {
+                       printf("cgroup_get_controller_next failed with %s\n",
+                                                       cgroup_strerror(error));
+                       exit(1);
+               }
+       }
+
+       error = cgroup_get_all_controller_end(&handle);
+
+       return 0;
+}
diff --git a/samples/c/get_controller.c b/samples/c/get_controller.c
new file mode 100644 (file)
index 0000000..1829f5c
--- /dev/null
@@ -0,0 +1,34 @@
+#include <libcgroup.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main()
+{
+       int error;
+       void *handle;
+       struct cgroup_mount_point info;
+
+       error = cgroup_init();
+
+       if (error) {
+               printf("cgroup_init failed with %s\n", cgroup_strerror(error));
+               exit(1);
+       }
+
+       error = cgroup_get_controller_begin(&handle, &info);
+
+       while (error != ECGEOF) {
+               printf("Controller %s is mounted at %s\n", info.name,
+                                                               info.path);
+               error = cgroup_get_controller_next(&handle, &info);
+               if (error && error != ECGEOF) {
+                       printf("cgroup_get_contrller_next failed with %s",
+                                                       cgroup_strerror(error));
+                       exit(1);
+               }
+       }
+
+       error = cgroup_get_controller_end(&handle);
+
+       return 0;
+}
diff --git a/samples/c/get_mount_point.c b/samples/c/get_mount_point.c
new file mode 100644 (file)
index 0000000..b372092
--- /dev/null
@@ -0,0 +1,49 @@
+#include <libcgroup.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int main()
+{
+       int ret;
+       char *mount_point;
+       char string[100];
+
+       strcpy(string, "cpu");
+
+       ret = cgroup_init();
+       if (ret) {
+               printf("cgroup_init failed with %s\n", cgroup_strerror(ret));
+               exit(3);
+       }
+
+       ret = cgroup_get_subsys_mount_point(string, &mount_point);
+       if (ret) {
+               printf("get_mount_point failed with %s\n",
+                                       cgroup_strerror(ret));
+               exit(3);
+       }
+
+       printf("The mount point is %s\n", mount_point);
+       free(mount_point);
+
+       strcpy(string, "obviouslynonexistsubsys");
+
+       ret = cgroup_get_subsys_mount_point(string, &mount_point);
+
+       if (!ret) {
+               printf("get_mount_point failed as it got a "
+                                       "non existant subsys\n");
+               exit(3);
+       }
+
+       if (ret == ECGROUPNOTEXIST) {
+               printf("get_mount_point worked as expected\n");
+               return 0;
+       }
+
+       printf("get_mount_point failed with %s\n", cgroup_strerror(ret));
+
+       return 3;
+}
diff --git a/samples/c/get_procs.c b/samples/c/get_procs.c
new file mode 100644 (file)
index 0000000..caa8444
--- /dev/null
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include <libcgroup.h>
+#include <stdlib.h>
+
+/*
+ * Assumes the cgroup is already mounted at /cgroup/memory/a
+ *
+ * Assumes some processes are already in the cgroup
+ *
+ * Assumes it is the memory controller is mounted in at that
+ * point
+ */
+int main()
+{
+       int size;
+       pid_t *pids;
+       int ret;
+       int i;
+
+       ret = cgroup_init();
+       if (ret) {
+               printf("FAIL: cgroup_init failed with %s\n", cgroup_strerror(ret));
+               exit(3);
+       }
+
+       ret = cgroup_get_procs("a", "memory", &pids, &size);
+       if (ret) {
+               printf("FAIL: cgroup_get_procs failed with %s\n", cgroup_strerror(ret));
+               exit(3);
+       }
+
+       for (i = 0; i < size; i++)
+               printf("%u\n", pids[i]);
+
+       return 0;
+}
diff --git a/samples/c/get_variable_names.c b/samples/c/get_variable_names.c
new file mode 100644 (file)
index 0000000..dc2ef14
--- /dev/null
@@ -0,0 +1,59 @@
+#include <libcgroup.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../src/libcgroup-internal.h"
+
+int main(int argc, char *argv[])
+{
+       int ret;
+       int i, j;
+       int count;
+       char *name;
+       struct cgroup_controller *group_controller = NULL;
+       struct cgroup *group = NULL;
+       char group_name[] = "/";
+
+       if (argc < 2) {
+               printf("no list of groups provided\n");
+               return -1;
+       }
+
+       ret = cgroup_init();
+
+       if (ret) {
+               printf("cgroup_init failed with %s\n", cgroup_strerror(ret));
+               exit(1);
+       }
+
+       group = cgroup_new_cgroup(group_name);
+       if (group == NULL) {
+               printf("cannot create group '%s'\n", group_name);
+               return -1;
+       }
+
+       ret = cgroup_get_cgroup(group);
+       if (ret != 0) {
+               printf("cannot read group '%s': %s\n",
+                       group_name, cgroup_strerror(ret));
+       }
+
+       for (i = 1; i < argc; i++) {
+
+               group_controller = cgroup_get_controller(group, argv[i]);
+               if (group_controller == NULL) {
+                       printf("cannot find controller "\
+                           "'%s' in group '%s'\n", argv[i], group_name);
+                       ret = -1;
+                       continue;
+               }
+               count = cgroup_get_value_name_count(group_controller);
+               for (j = 0; j < count; j++) {
+                       name = cgroup_get_value_name(group_controller, j);
+                       if (name != NULL)
+                               printf("%s \n", name);
+               }
+       }
+
+       return ret;
+}
diff --git a/samples/c/libcg_ba.cpp b/samples/c/libcg_ba.cpp
new file mode 100644 (file)
index 0000000..322794b
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright IBM Corporation. 2007
+ *
+ * Author:     Balbir Singh <balbir@linux.vnet.ibm.com>
+ *
+ * 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.
+ *
+ * Basic acceptance test for libcgroup - Written one late night by Balbir Singh
+ */
+using namespace std;
+
+#include <string>
+#include <stdexcept>
+#include <iostream>
+#include <libcgroup.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <grp.h>
+
+#include "../config.h"
+
+#ifdef CGROUP_DBG
+#define cgroup_dbg(p...)       printf(p...)
+#else
+#define cgroup_dbg(p...)       do {} while (0)
+#endif
+
+namespace cgtest {
+
+class cg {
+private:
+public:
+       cg();
+       ~cg()
+       { }
+       struct cgroup *makenode(const string &name, const string &task_uid,
+                       const string &task_gid, const string &control_uid,
+                       const string &control_gid);
+       struct cgroup *makenodefromparent(const string &name);
+};
+
+cg::cg(void)
+{
+       int ret;
+
+       ret = cgroup_init();
+       if (ret)
+               throw logic_error("Control Group Initialization failed..."
+                               "Please check that cgroups are mounted and\n"
+                               "at a single place");
+}
+
+struct cgroup *cg::makenode(const string &name, const string &task_uid,
+               const string &task_gid, const string &control_uid,
+               const string &control_gid)
+{
+       uid_t tuid, cuid;
+       gid_t tgid, cgid;
+       char *cgroup_name;
+       struct cgroup *ccg;
+       struct cgroup_controller *cpu, *cpuacct;
+       struct passwd *passwd;
+       struct group *grp;
+       int ret;
+
+       passwd = getpwnam(task_uid.c_str());
+       if (!passwd)
+               return NULL;
+       tuid = passwd->pw_uid;
+
+       grp = getgrnam(task_gid.c_str());
+       if (!grp)
+               return NULL;
+       tgid = grp->gr_gid;
+
+       passwd = getpwnam(control_uid.c_str());
+       if (!passwd)
+               return NULL;
+       cuid = passwd->pw_uid;
+
+       grp = getgrnam(control_gid.c_str());
+       if (!grp)
+               return NULL;
+       cgid = grp->gr_gid;
+
+       cgroup_dbg("tuid %d, tgid %d, cuid %d, cgid %d\n", tuid, tgid, cuid, cgid);
+
+       cgroup_name = (char *) malloc(name.length());
+       strncpy(cgroup_name, name.c_str(), name.length() + 1);
+
+       ccg = cgroup_new_cgroup(cgroup_name);
+       cgroup_set_uid_gid(ccg, tuid, tgid, cuid, cgid);
+       cpu = cgroup_add_controller(ccg, "cpu");
+       cgroup_add_value_uint64(cpu, "cpu.shares", 2048);
+       cpuacct = cgroup_add_controller(ccg, "cpuacct");
+       cgroup_add_value_uint64(cpuacct, "cpuacct.usage", 0);
+
+
+       ret = cgroup_create_cgroup(ccg, 1);
+       if (ret) {
+               cout << "cg create group failed " << errno << endl;
+               ret = cgroup_delete_cgroup(ccg, 1);
+               if (ret)
+                       cout << "cg delete group failed " << errno << endl;
+       }
+       return ccg;
+}
+
+struct cgroup *cg::makenodefromparent(const string &name)
+{
+       char *cgroup_name;
+       struct cgroup *ccg;
+       int ret;
+
+       cgroup_name = (char *) malloc(name.length());
+       memset(cgroup_name, '\0', name.length());
+       strcpy(cgroup_name, name.c_str());
+
+       ccg = cgroup_new_cgroup(cgroup_name);
+       ret = cgroup_create_cgroup_from_parent(ccg, 1);
+       if (ret) {
+               cout << "cg create group failed " << errno << endl;
+               ret = cgroup_delete_cgroup(ccg, 1);
+               if (ret)
+                       cout << "cg delete group failed " << errno << endl;
+       }
+       return ccg;
+}
+
+} // namespace
+
+using namespace cgtest;
+int main(int argc, char *argv[])
+{
+       try {
+               cg *app = new cg();
+               struct cgroup *ccg, *ccg_child1, *ccg_child2;
+               ccg = app->makenode("database", "root", "root", "balbir",
+                                       "balbir");
+               ccg_child1 = app->makenodefromparent("mysql");
+               ccg_child2 = app->makenodefromparent("mysql/db1");
+               cgroup_free(&ccg);
+               cgroup_free(&ccg_child1);
+               cgroup_free(&ccg_child2);
+               delete app;
+       } catch (exception &e) {
+               cout << e.what() << endl;
+               exit(1);
+       }
+       return 0;
+}
diff --git a/samples/c/libcgrouptest.h b/samples/c/libcgrouptest.h
new file mode 100644 (file)
index 0000000..98b1ba9
--- /dev/null
@@ -0,0 +1,158 @@
+
+/*
+ * Copyright IBM Corporation. 2008
+ *
+ * Author:     Sudhir Kumar <skumar@linux.vnet.ibm.com>
+ *
+ * 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.
+ *
+ * Description: This file is the header file for libcgroup test programs.
+ */
+
+#ifndef __LIBCGROUPTEST_H
+#define __LIBCGROUPTEST_H
+
+#include <errno.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libcgroup.h>
+#include "../config.h"
+#include <unistd.h>
+#include <inttypes.h>
+
+#define SIZE 100       /* Max size of a message to be printed */
+#define NUM_MSGS 20    /* Number of such messsages */
+#define PASS 1         /* test passed */
+#define FAIL 0         /* test failed */
+
+enum cgroup_mount_t {
+       FS_NOT_MOUNTED,
+       FS_MOUNTED,
+       FS_MULTI_MOUNTED,
+};
+
+enum controller_t {
+       CPU,
+       MEMORY,
+       CPUSET,
+       /* Add new controllers here */
+};
+
+enum cgroup_control_val_t {
+       BOOL,
+       INT64,
+       UINT64,
+       STRING,
+};
+
+enum info_message_t {
+       NULLGRP,
+       COMMONGRP,
+       NOTCRTDGRP,
+       SAMEGRP,
+       TASKINGRP,
+       TASKNOTINGRP,
+       TASKNOTINANYGRP,
+       GRPINFS,
+       GRPNOTINFS,
+       GRPINBOTHCTLS,
+       GRPNOTIN2NDCTL,
+       GRPNOTIN1STCTL,
+       GRPMODINBOTHCTLS,
+       GRPNOTMODIN2NDCTL,
+       GRPNOTMODINANYCTL,
+       GRPDELETEDINFS,
+       GRPNOTDELETEDINFS,
+       GRPNOTDELETEDGLOBALY,
+       NOMESSAGE,
+};
+
+/* Keep a single struct of all ids */
+struct uid_gid_t {
+       uid_t control_uid;
+       gid_t control_gid;
+       uid_t tasks_uid;
+       gid_t tasks_gid;
+};
+
+/* Keep a single struct of all control values */
+struct cntl_val_t {
+       int64_t val_int64;
+       u_int64_t val_uint64;
+       bool val_bool;
+       /* size worth of 100 digit num is fair enough */
+       char val_string[100];   /* string value of control parameter */
+};
+
+extern int cpu, memory;
+
+/* The set of verbose messages useful to the user */
+extern char info[NUM_MSGS][SIZE];
+
+/* this variable is never modified */
+extern int fs_mounted;
+
+/* The mountpoints as received from script
+ * We use mountpoint for single mount.
+ * For multimount we use mountpoint and mountpoint2.
+ */
+extern char mountpoint[], mountpoint2[];
+
+/* Functions to test each API */
+void test_cgroup_init(int retcode, int i);
+void test_cgroup_attach_task(int retcode, struct cgroup *cgroup1,
+               const char *group1, const char *group2, pid_t pid,
+               int k, int i);
+struct cgroup *create_new_cgroup_ds(int ctl, const char *grpname,
+        int value_type, struct cntl_val_t cval, struct uid_gid_t ids, int i);
+void test_cgroup_create_cgroup(int retcode, struct cgroup *cgrp,
+                const char *name, int common, int mpnt, int ign, int i);
+void test_cgroup_delete_cgroup(int retcode, struct cgroup *cgrp,
+                const char *name, int common, int mpnt, int ign, int i);
+void test_cgroup_modify_cgroup(int retcode, struct cgroup *cgrp,
+                const char *name, int which_ctl, int ctl1, int ctl2,
+                                                int value_type, int i);
+void test_cgroup_get_cgroup(int ctl1, int ctl2, struct uid_gid_t ids, int i);
+/* API test functions end here */
+
+void test_cgroup_compare_cgroup(int ctl1, int ctl2, int i);
+void test_cgroup_add_free_controller(int i);
+void is_subsystem_enabled(const char *name, int *exist);
+int group_exist(char *path_group);
+int set_controller(int controller, char *controller_name,
+                                                char *control_file);
+int group_modified(char *path_control_file, int value_type,
+                                                struct cntl_val_t cval);
+int add_control_value(struct cgroup_controller *newcontroller,
+        char *control_file, char *wr, int value_type, struct cntl_val_t cval);
+struct cgroup *new_cgroup(char *group, char *controller_name,
+        char *control_file, int value_type, struct cntl_val_t cval,
+                                        struct uid_gid_t ids, int i);
+int check_fsmounted(int multimnt);
+int check_task(char *tasksfile, pid_t pid);
+/* function to print messages in better format */
+void message(int num, int pass, const char *api,
+                                                int ret, char *extra);
+void build_path(char *target, char *mountpoint,
+                                const char *group, const char *file);
+pid_t cgrouptest_gettid();
+
+#ifdef CGROUP_DEBUG
+#define cgroup_dbg(p...)       printf(p)
+#else
+#define cgroup_dbg(p...)       do {} while (0);
+#endif
+
+#endif
diff --git a/samples/c/libcgrouptest01.c b/samples/c/libcgrouptest01.c
new file mode 100644 (file)
index 0000000..d7770a0
--- /dev/null
@@ -0,0 +1,756 @@
+/*
+ * Copyright IBM Corporation. 2008
+ *
+ * Author:     Sudhir Kumar <skumar@linux.vnet.ibm.com>
+ *
+ * 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.
+ *
+ * Description: This file contains the test code for testing libcgroup apis.
+ */
+
+#include "libcgrouptest.h"
+#include <errno.h>
+
+int cpu, memory;
+int fs_mounted;
+/* We use mountpoint for single mount.
+ * For multimount we use mountpoint and mountpoint2.
+ */
+char mountpoint[FILENAME_MAX], mountpoint2[FILENAME_MAX];
+
+int main(int argc, char *argv[])
+{
+       int retval;
+       struct uid_gid_t ids = {0}; /* Set default control permissions */
+
+       struct cntl_val_t cval;
+       cval.val_int64 = 200000;
+       cval.val_uint64 = 200000;
+       cval.val_bool = 1;
+       strcpy(cval.val_string, "200000");
+
+       struct cgroup *cgroup1, *cgroup2, *cgroup3, *nullcgroup = NULL;
+       struct cgroup_controller *sec_controller;
+       /* In case of multimount for readability we use the controller name
+        * before the cgroup structure name */
+       struct cgroup *ctl1_cgroup1, *ctl2_cgroup1, *ctl2_cgroup2;
+       struct cgroup *mod_ctl1_cgroup1, *mod_ctl2_cgroup1, *mod_common_cgroup;
+       struct cgroup *common_cgroup;
+       char controller_name[FILENAME_MAX], control_file[FILENAME_MAX];
+       char path_control_file[FILENAME_MAX];
+
+       /* Get controllers name from script */
+       int ctl1 = CPU, ctl2 = MEMORY;
+
+       if ((argc < 2) || (argc > 6) || (atoi(argv[1]) < 0)) {
+               printf("ERROR: Wrong no of parameters recieved from script\n");
+               printf("Exiting the libcgroup testset\n");
+               exit(1);
+       }
+       fs_mounted = atoi(argv[1]);
+       cgroup_dbg("C:DBG: fs_mounted as recieved from script=%d\n",
+                                                               fs_mounted);
+       /* All possible controller will be element of an enum */
+       if (fs_mounted) {
+               ctl1 = atoi(argv[2]);
+               ctl2 = atoi(argv[3]);
+               strncpy(mountpoint, argv[4], sizeof(mountpoint) - 1);
+               cgroup_dbg("C:DBG: mountpoint1 as recieved from script=%s\n",
+                                                                mountpoint);
+               if (fs_mounted == FS_MULTI_MOUNTED) {
+                       strncpy(mountpoint2, argv[5], sizeof(mountpoint2) - 1);
+                       cgroup_dbg("C:DBG: mountpoint2 as recieved from "
+                                       "script=%s\n", mountpoint2);
+               }
+
+       }
+
+       /*
+        * check if one of the supported controllers is cpu or memory
+        */
+       is_subsystem_enabled("cpu", &cpu);
+       is_subsystem_enabled("memory", &memory);
+       if (cpu == 0 && memory == 0) {
+               fprintf(stderr, "none of cpu and memory controllers"
+                                               " is enabled in kernel\n");
+               fprintf(stderr, "Exiting the libcgroup testcases......\n");
+               exit(1);
+       }
+
+       /*
+        * Testsets: Testcases are broadly devided into 3 categories based on
+        * filesystem(fs) mount scenario. fs not mounted, fs mounted, fs multi
+        * mounted. Call different apis in these different scenarios.
+        */
+
+       switch (fs_mounted) {
+
+       case FS_NOT_MOUNTED:
+
+               /*
+                * Test01: call cgroup_init() and check return values
+                * Exp outcome: error ECGROUPNOTMOUNTED
+                */
+
+               test_cgroup_init(ECGROUPNOTMOUNTED, 1);
+
+               /*
+                * Test02: call cgroup_attach_task() with null group
+                * Exp outcome: error non zero return value
+                */
+
+               test_cgroup_attach_task(ECGROUPNOTINITIALIZED, nullcgroup,
+                                                NULL, NULL, 0, NULLGRP, 2);
+
+               /*
+                * Test03: Create a valid cgroup ds and check all return values
+                * Exp outcome: no error
+                */
+
+               cgroup1 = create_new_cgroup_ds(0, "group1",
+                                                STRING, cval, ids, 3);
+
+               /*
+                * Test04: Then Call cgroup_create_cgroup() with this valid grp
+                * Exp outcome: non zero return value
+                */
+               test_cgroup_create_cgroup(ECGROUPNOTINITIALIZED, cgroup1,
+                                                        "group1", 0, 1, 1, 4);
+
+               /*
+                * Test05: delete cgroup
+                * Exp outcome: non zero return value but what ?
+                */
+               test_cgroup_delete_cgroup(ECGROUPNOTINITIALIZED, cgroup1,
+                                                        "group1", 0, 1, 1, 5);
+
+               /*
+                * Test06: Check if cgroup_create_cgroup() handles a NULL cgroup
+                * Exp outcome: error ECGROUPNOTALLOWED
+                */
+               test_cgroup_create_cgroup(ECGROUPNOTINITIALIZED, nullcgroup,
+                                                        "group1", 0, 1, 1, 6);
+
+               /*
+                * Test07: delete nullcgroup
+                */
+               test_cgroup_delete_cgroup(ECGROUPNOTINITIALIZED, nullcgroup,
+                                                        "group1", 0, 1, 1, 7);
+               /* Test08: test the wrapper */
+               test_cgroup_add_free_controller(8);
+
+               cgroup_free(&nullcgroup);
+               cgroup_free(&cgroup1);
+
+               break;
+
+       case FS_MOUNTED:
+
+               /* Do a sanity check if cgroup fs is mounted */
+               if (check_fsmounted(0)) {
+                       printf("Sanity check fails. cgroup fs not mounted\n");
+                       printf("Exiting without running this set of tests\n");
+                       exit(1);
+               }
+
+               /*
+                * Test01: call cgroup_attach_task() with null group
+                * without calling cgroup_init(). We can check other apis too.
+                * Exp outcome: error ECGROUPNOTINITIALIZED
+                */
+
+               test_cgroup_attach_task(ECGROUPNOTINITIALIZED, nullcgroup,
+                                                NULL, NULL, 0, NULLGRP, 1);
+
+               /*
+                * Test02: call cgroup_init() and check return values
+                * Exp outcome:  no error. return value 0
+                */
+
+               test_cgroup_init(0, 2);
+
+               /*
+                * Test03: Call cgroup_attach_task() with null group and check
+                * if return values are correct. If yes check if task exists in
+                * root group tasks file
+                * TODO: This test needs some modification in script
+                * Exp outcome: current task should be attached to root group
+                */
+
+               test_cgroup_attach_task(0, nullcgroup, NULL, NULL, 0,
+                                                        NULLGRP, 3);
+               /*
+                * Test04: Call cgroup_attach_task_pid() with null group
+                * and invalid pid
+                * Exp outcome: error
+                */
+               retval = cgroup_attach_task_pid(nullcgroup, -1);
+               if (retval != 0)
+                       message(4, PASS, "attach_task_pid()", retval,
+                                                        info[NOMESSAGE]);
+               else
+                       message(4, FAIL, "attach_task_pid()", retval,
+                                                        info[NOMESSAGE]);
+
+               /*
+                * Test05: Create a valid cgroup structure
+                * Exp outcome: no error. 0 return value
+                */
+               cgroup1 = create_new_cgroup_ds(ctl1, "group1",
+                                                        STRING, cval, ids, 5);
+               if (!cgroup1) {
+                       fprintf(stderr, "Failed to create new cgroup ds. "
+                                       "Trying with second controller\n");
+                       cgroup1 = create_new_cgroup_ds(ctl2, "group1", STRING,
+                                                               cval, ids, 5);
+                       if (!cgroup1) {
+                               fprintf(stderr, "Failed to create cgroup ds. "
+                                       "Tests dependent on this structure "
+                                       "will fail. So exiting...\n");
+                               exit(1);
+                       }
+               }
+
+               /*
+                * Test06: Then Call cgroup_create_cgroup() with this group
+                * Exp outcome: zero return value
+                */
+               test_cgroup_create_cgroup(0, cgroup1, "group1", 0, 1, 1, 6);
+
+               /*
+                * Test07: Call cgroup_attach_task() with valid cgroup and check
+                * if return values are correct. If yes check if task exists in
+                * that group's tasks file
+                * Exp outcome: current task should be attached to that group
+                */
+
+               test_cgroup_attach_task(0, cgroup1, "group1", NULL,
+                                                        0, NOMESSAGE, 7);
+
+               /*
+                * Test08: modify cgroup with the same cgroup
+                * Exp outcome: zero return value. No change.
+                */
+               set_controller(ctl1, controller_name, control_file);
+               build_path(path_control_file, mountpoint,
+                                                "group1", control_file);
+               strncpy(cval.val_string, "260000", sizeof(cval.val_string));
+               retval = cgroup_modify_cgroup(cgroup1);
+               /* Check if the values are changed. cval contains orig values */
+               if (!retval && !group_modified(path_control_file, STRING, cval))
+                       message(8, PASS, "modify_cgroup()", retval,
+                                                        info[SAMEGRP]);
+               else
+                       message(8, FAIL, "modify_cgroup()", retval,
+                                                        info[SAMEGRP]);
+
+               /*
+                * Create another valid cgroup structure with same group
+                * to modify the existing group
+                */
+               cgroup2 = create_new_cgroup_ds(ctl1, "group1",
+                                                STRING, cval, ids, 9);
+               if (!cgroup2) {
+                       fprintf(stderr, "Failed to create new cgroup ds. "
+                                       "Trying with second controller\n");
+                       cgroup2 = create_new_cgroup_ds(ctl2, "group1",
+                                                        STRING, cval, ids, 9);
+                       if (!cgroup2) {
+                               fprintf(stderr, "Failed to create cgroup ds. "
+                                       "Tests dependent on this structure "
+                                       "will fail. So exiting...\n");
+                               exit(1);
+                       }
+               }
+
+               /*
+                * Test10: modify cgroup with this new cgroup
+                * Exp outcome: zero return value
+                * Drawback: In case of first attempt failure above for
+                * create_new_cgroup_ds(), this test will fail
+                */
+               test_cgroup_modify_cgroup(0, cgroup2, "group1",
+                                        1, ctl1, ctl2, STRING, 10);
+
+               /*
+                * Test11: modify cgroup with the null cgroup
+                * Exp outcome: zero return value.
+                */
+
+               test_cgroup_modify_cgroup(ECGROUPNOTALLOWED, nullcgroup,
+                                        "group1", 1, ctl1, ctl2, STRING, 11);
+
+               /*
+                * Create another valid cgroup structure with diff controller
+                * to modify the existing group
+                */
+               cval.val_int64 = 262144;
+               cgroup3 = create_new_cgroup_ds(ctl2, "group1",
+                                                INT64, cval, ids, 12);
+               if (!cgroup3) {
+                       fprintf(stderr, "Failed to create new cgroup ds. "
+                                       "Tests dependent on this structure "
+                                       "will fail. So exiting...\n");
+                       exit(1);
+               }
+
+               /*
+                * Test13: modify existing group with this cgroup
+                * Exp outcome: zero return value
+                */
+               test_cgroup_modify_cgroup(0, cgroup3, "group1",
+                                                2, ctl1, ctl2, INT64, 13);
+
+               /* Test14: Test cgroup_get_cgroup() api
+                * The group group1 has been created and modified in the
+                * filesystem. Read it using the api and check if the values
+                * are correct as we know all the control values now.
+                * WARN: If any of the previous api fails and control reaches
+                * here, this api also will fail. Also the test function assumes
+                * that "group1" exists in fs. So call cgroup_create_cgroup()
+                * with "group1" named group before calling this test function.
+                */
+               test_cgroup_get_cgroup(ctl1, ctl2, ids, 14);
+
+               /*
+                * Test16: delete cgroup
+                * Exp outcome: zero return value
+                */
+               test_cgroup_delete_cgroup(0, cgroup1, "group1", 0, 1, 1, 16);
+
+               /*
+                * Test16: Check if cgroup_create_cgroup() handles a NULL cgroup
+                * Exp outcome: error ECGROUPNOTALLOWED
+                */
+               test_cgroup_create_cgroup(ECGROUPNOTALLOWED, nullcgroup,
+                                                        "group1", 0, 1, 1, 17);
+
+               /*
+                * Test16: delete nullcgroup
+                */
+               test_cgroup_delete_cgroup(ECGROUPNOTALLOWED, NULL,
+                                                        "group1", 0, 1, 1, 18);
+
+               /* Test17: Test the wrapper to compare cgroup
+                * Create 2 cgroups and test it
+                */
+               test_cgroup_compare_cgroup(ctl1, ctl2, 19);
+
+               cgroup_free(&nullcgroup);
+               cgroup_free(&cgroup1);
+               cgroup_free(&cgroup2);
+               cgroup_free(&cgroup3);
+
+               break;
+
+       case FS_MULTI_MOUNTED:
+
+               /* Do a sanity check if cgroup fs is multi mounted */
+               if (check_fsmounted(1)) {
+                       printf("Sanity check fails. cgroup fs is not multi "
+                               "mounted. Exiting without running this set "
+                                       "of testcases\n");
+                       exit(1);
+               }
+
+               /*
+                * Test01: call apis and check return values
+                * Exp outcome:
+                */
+
+               /*
+                * Scenario 1: cgroup fs is multi mounted
+                * Exp outcome: no error. 0 return value
+                */
+
+               test_cgroup_init(0, 1);
+
+               /*
+                * Test02: Call cgroup_attach_task() with null group and check
+                * if return values are correct. If yes check if task exists in
+                * root group tasks file for each controller
+                * TODO: This test needs some modification in script
+                * Exp outcome: current task should be attached to root groups
+                */
+
+               test_cgroup_attach_task(0, nullcgroup, NULL, NULL,
+                                                        0, NULLGRP, 2);
+
+               /*
+                * Test03: Create a valid cgroup structure
+                * Exp outcome: no error. 0 return value
+                */
+               ctl1_cgroup1 = create_new_cgroup_ds(ctl1, "ctl1_group1",
+                                                        STRING, cval, ids, 3);
+               if (!ctl1_cgroup1) {
+                       fprintf(stderr, "Failed to create new cgroup ds. "
+                                       "Tests dependent on this structure "
+                                       "will fail. So exiting...\n");
+                       exit(1);
+               }
+
+               /*
+                * Test04: Then Call cgroup_create_cgroup() with this valid grp
+                * Exp outcome: zero return value
+                */
+               test_cgroup_create_cgroup(0, ctl1_cgroup1,
+                                                "ctl1_group1", 0, 1, 1, 4);
+
+               /*
+                * Test05: Create a valid cgroup structure
+                * Exp outcome: no error. 0 return value
+                */
+               ctl2_cgroup1 = create_new_cgroup_ds(ctl2, "ctl2_group1",
+                                                        STRING, cval, ids, 5);
+               if (!ctl2_cgroup1) {
+                       fprintf(stderr, "Failed to create new cgroup ds. "
+                                       "Tests dependent on this structure "
+                                       "will fail. So exiting...\n");
+                       exit(1);
+               }
+
+               /*
+                * Test06: Then Call cgroup_create_cgroup() with this valid grp
+                * Exp outcome: zero return value
+                */
+               test_cgroup_create_cgroup(0, ctl2_cgroup1,
+                                                "ctl2_group1", 0, 2, 1, 6);
+
+               /*
+                * Test07: Call cgroup_create_cgroup() with the same group
+                * Exp outcome: zero return value as the latest changes in api
+                */
+               test_cgroup_create_cgroup(0, ctl2_cgroup1,
+                                                "ctl2_group1", 0, 2, 1, 7);
+
+               /*
+                * Test06: Call cgroup_attach_task() with a group with ctl1
+                * controller and check if return values are correct. If yes
+                * check if task exists in that group under only ctl1 controller
+                * hierarchy and in the root group under other controllers
+                * hierarchy.
+                */
+
+               test_cgroup_attach_task(0, ctl1_cgroup1, "ctl1_group1",
+                                                NULL, 0, NOMESSAGE, 8);
+
+               /*
+                * Test07: Call cgroup_attach_task() with a group with ctl2
+                * controller and check if return values are correct. If yes
+                * check if task exists in the groups under both controller's
+                * hierarchy.
+                */
+
+               test_cgroup_attach_task(0, ctl2_cgroup1, "ctl1_group1",
+                                        "ctl2_group1", 0, NOMESSAGE, 9);
+
+               /*
+                * Test: Create a valid cgroup structure
+                * Exp outcome: no error. 0 return value
+                */
+               ctl2_cgroup2 = create_new_cgroup_ds(ctl2, "ctl2_group2",
+                                                        STRING, cval, ids, 10);
+               if (!ctl2_cgroup2) {
+                       fprintf(stderr, "Failed to create new cgroup ds. "
+                                       "Tests dependent on this structure "
+                                       "will fail. So exiting...\n");
+                       exit(1);
+               }
+
+               /*
+                * Test08: Try to attach a task to this non existing group.
+                * Group does not exist in fs so should return ECGROUPNOTEXIST
+                */
+
+               test_cgroup_attach_task(ECGROUPNOTEXIST, ctl2_cgroup2,
+                                        NULL, NULL, 0, NOTCRTDGRP, 11);
+
+               /*
+                * Create another valid cgroup structure with same group name
+                * to modify the existing group ctl1_group1
+                * Exp outcome: no error. 0 return value
+                */
+               mod_ctl1_cgroup1 = create_new_cgroup_ds(ctl1, "ctl1_group1",
+                                                        STRING, cval, ids, 12);
+               if (!mod_ctl1_cgroup1) {
+                       fprintf(stderr, "Failed to create new cgroup ds. "
+                                       "Tests dependent on this structure "
+                                       "will fail. So exiting...\n");
+                       exit(1);
+               }
+
+               /*
+                * Test09: modify existing cgroup with this new cgroup
+                * Exp outcome: zero return value and control value modified
+                */
+               test_cgroup_modify_cgroup(0, mod_ctl1_cgroup1, "ctl1_group1",
+                                                1, ctl1, ctl2, STRING, 13);
+
+               /*
+                * Create another valid cgroup structure with same group name
+                * to modify the existing group ctl2_group1
+                * Exp outcome: no error. 0 return value
+                */
+               mod_ctl2_cgroup1 = create_new_cgroup_ds(ctl2, "ctl2_group1",
+                                                        STRING, cval, ids, 14);
+               if (!mod_ctl2_cgroup1) {
+                       fprintf(stderr, "Failed to create new cgroup ds. "
+                                       "Tests dependent on this structure "
+                                       "will fail. So exiting...\n");
+                       exit(1);
+               }
+
+               /*
+                * Test10: modify existing cgroup with this new cgroup
+                * Exp outcome: zero return value and control value modified
+                */
+               test_cgroup_modify_cgroup(0, mod_ctl2_cgroup1, "ctl2_group1",
+                                                2, ctl1, ctl2, STRING, 15);
+
+               /*
+                * Test11: delete cgroups
+                * Exp outcome: zero return value
+                */
+               test_cgroup_delete_cgroup(0, ctl1_cgroup1,
+                                                "ctl1_group1", 0, 1, 1, 16);
+
+               /*
+                * Test09: delete other cgroups too
+                * Exp outcome: zero return value
+                */
+               test_cgroup_delete_cgroup(0, ctl2_cgroup1,
+                                                "ctl2_group1", 0, 1, 1, 17);
+
+               /*
+                * Test15: Create a valid cgroup structure
+                * which has multiple controllers
+                * Exp outcome: no error. 0 return value
+                */
+               common_cgroup = create_new_cgroup_ds(ctl1, "commongroup",
+                                                        STRING, cval, ids, 18);
+               if (!common_cgroup) {
+                       fprintf(stderr, "Failed to create new cgroup ds. "
+                                       "Tests dependent on this structure "
+                                       "will fail. So exiting...\n");
+                       exit(1);
+               }
+
+               /* Add one more controller to the cgroup */
+               /* This also needs to be a function.. will do?? */
+               retval = set_controller(ctl2, controller_name, control_file);
+               if (retval) {
+                       fprintf(stderr, "Setting controller failled "
+                               " Exiting without running further testcases\n");
+                       exit(1);
+               }
+               if (!cgroup_add_controller(common_cgroup, controller_name)) {
+                       message(15, FAIL, "add_controller()", retval,
+                                                        info[NOMESSAGE]);
+                       fprintf(stderr, "Adding second controller failled "
+                               " Exiting without running further testcases\n");
+                       exit(1);
+               }
+
+               /*
+                * Test11: Then Call cgroup_create_cgroup() with this valid grp
+                * Exp outcome: zero return value
+                */
+               test_cgroup_create_cgroup(0, common_cgroup,
+                                                "commongroup", 1, 2, 1, 19);
+
+               /*
+                * Test12: Call cgroup_attach_task() with this common group
+                * and check if return values are correct. If yes check if
+                * task exists in the group under both controller's hierarchy
+                */
+
+               test_cgroup_attach_task(0, common_cgroup, "commongroup",
+                                        "commongroup", 0, COMMONGRP, 20);
+
+               /*
+                * Test18: Create a valid cgroup structure to modify the
+                * commongroup which is under multiple controllers
+                * Exp outcome: no error. 0 return value
+                */
+               mod_common_cgroup = create_new_cgroup_ds(ctl1, "commongroup",
+                                                        STRING, cval, ids, 21);
+               if (!common_cgroup) {
+                       fprintf(stderr, "Failed to create new cgroup ds. "
+                                       "Tests dependent on this structure "
+                                       "will fail. So exiting...\n");
+                       exit(1);
+               }
+
+               /* Add one more controller to the cgroup */
+               /* This also needs to be a function.. will do?? */
+               retval = set_controller(ctl2, controller_name, control_file);
+               if (retval) {
+                       fprintf(stderr, "Setting controller failled "
+                               " Exiting without running further testcases\n");
+                       exit(1);
+               }
+               sec_controller = cgroup_add_controller(mod_common_cgroup,
+                                                        controller_name);
+               if (!sec_controller) {
+                       message(18, FAIL, "add_controller()", retval,
+                                                        info[NOMESSAGE]);
+                       fprintf(stderr, "Adding second controller failled "
+                               " Exiting without running further testcases\n");
+                       exit(1);
+               }
+
+               strncpy(cval.val_string, "7000064", sizeof(cval.val_string));
+               retval = cgroup_add_value_string(sec_controller,
+                                                control_file, cval.val_string);
+               if (retval)
+                       printf("The cgroup_modify_cgroup() test will fail\n");
+
+               /*
+                * Test14: modify existing cgroup with this new cgroup
+                * Exp outcome: zero return value and control value modified
+                */
+               test_cgroup_modify_cgroup(0, mod_common_cgroup, "commongroup",
+                                                0, ctl1, ctl2, STRING, 22);
+
+               /*
+                * Test15: delete this common cgroup
+                * Exp outcome: zero return value
+                */
+               test_cgroup_delete_cgroup(0, common_cgroup,
+                                                "commongroup", 1, 2, 1, 23);
+               test_cgroup_get_cgroup(ctl1, ctl2, ids, 24);
+
+               /* Free the cgroup structures */
+               cgroup_free(&nullcgroup);
+               cgroup_free(&ctl1_cgroup1);
+               cgroup_free(&ctl2_cgroup1);
+               cgroup_free(&ctl2_cgroup2);
+
+               break;
+
+       default:
+               fprintf(stderr, "ERROR: Wrong parameters recieved from script. \
+                                               Exiting tests\n");
+               exit(1);
+               break;
+       }
+       return 0;
+}
+
+void test_cgroup_modify_cgroup(int retcode, struct cgroup *cgrp,
+                        const char *name, int which_ctl, int ctl1,
+                                        int ctl2, int value_type, int i)
+{
+       int retval;
+       struct cntl_val_t cval = {0, 0, 0, "1000"};
+       char path1_control_file[FILENAME_MAX], path2_control_file[FILENAME_MAX];
+       char controller_name[FILENAME_MAX], control_file[FILENAME_MAX];
+
+       /* Check, In case some error is expected due to a negative scenario */
+       if (retcode) {
+               retval = cgroup_modify_cgroup(cgrp);
+               if (retval == retcode)
+                       message(i, PASS, "modify_cgroup()", retval,
+                                                        info[NOMESSAGE]);
+               else
+                       message(i, FAIL, "modify_cgroup()", retval,
+                                                        info[NOMESSAGE]);
+
+               return;
+       }
+
+       /* Now there is no error and it is a genuine call */
+       retval = cgroup_modify_cgroup(cgrp);
+       if (retval) {
+               message(i, FAIL, "modify_cgroup()", retval,  info[NOMESSAGE]);
+               return;
+       }
+
+       /* Let us now check if the group modified in file system */
+       switch (which_ctl) { /* group modified under which controllers */
+
+       case 1: /* group is modified under ctl1 which is always
+                * mounted at mountpoint in both cases */
+               set_controller(ctl1, controller_name, control_file);
+               build_path(path1_control_file, mountpoint, name, control_file);
+               /* this approach will be changed in coming patches */
+               strncpy(cval.val_string, "260000", sizeof(cval.val_string));
+
+               if (!group_modified(path1_control_file, value_type, cval))
+                       message(i, PASS, "modify_cgroup()", retval,
+                                                        info[NOMESSAGE]);
+               else
+                       message(i, FAIL, "modify_cgroup()", retval,
+                                                        info[NOMESSAGE]);
+
+               break;
+       case 2: /* group is modified under ctl2 which may be
+                * mounted at mountpoint or mountpoint2 */
+               set_controller(ctl2, controller_name, control_file);
+
+               if (fs_mounted == FS_MOUNTED)   /* group under mountpoint */
+                       build_path(path2_control_file, mountpoint,
+                                                name, control_file);
+               else    /* group under mountpoint2 */
+                       build_path(path2_control_file, mountpoint2,
+                                                name, control_file);
+
+               /* this approach will be changed in coming patches */
+               strncpy(cval.val_string, "7000064", sizeof(cval.val_string));
+               cval.val_int64 = 262144;
+               if (!group_modified(path2_control_file, value_type, cval))
+                       message(i, PASS, "modify_cgroup()", retval,
+                                                        info[NOMESSAGE]);
+               else
+                       message(i, FAIL, "modify_cgroup()", retval,
+                                                        info[NOMESSAGE]);
+
+               break;
+       case 0:
+               /* ctl1 is always mounted at mountpoint */
+               set_controller(ctl1, controller_name, control_file);
+               build_path(path1_control_file, mountpoint,
+                                                name, control_file);
+               /* ctl2 may be mounted at mountpoint or mountpoint2 depending
+                * on single or multiple mount case */
+               if (fs_mounted == FS_MOUNTED) { /* group under mountpoint */
+                       set_controller(ctl2, controller_name, control_file);
+                       build_path(path2_control_file, mountpoint,
+                                                name, control_file);
+               } else {        /* group under mountpoint2 */
+                       set_controller(ctl2, controller_name, control_file);
+                       build_path(path2_control_file, mountpoint2,
+                                                name, control_file);
+               }
+               /* this approach will be changed in coming patches */
+               strncpy(cval.val_string, "260000", sizeof(cval.val_string));
+               if (!group_modified(path1_control_file, value_type, cval)) {
+                       strncpy(cval.val_string, "7000064",
+                                                sizeof(cval.val_string));
+                       if (!group_modified(path2_control_file,
+                                                        value_type, cval))
+                               message(i, PASS, "modify_cgroup()",
+                                        retval, info[GRPMODINBOTHCTLS]);
+                       else
+                               message(i, FAIL, "modify_cgroup()",
+                                        retval, info[GRPNOTMODIN2NDCTL]);
+               } else {
+                       message(i, FAIL, "modify_cgroup()", retval,
+                                                info[GRPNOTMODINANYCTL]);
+               }
+
+               break;
+       default:
+               printf("Wrong controller parameter received....\n");
+               message(i, FAIL, "modify_cgroup()", retval, info[NOMESSAGE]);
+               break;
+       }
+
+       return;
+}
diff --git a/samples/c/logger.c b/samples/c/logger.c
new file mode 100644 (file)
index 0000000..b7f1b70
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright Red Hat Inc., 2012
+ *
+ * Author:     Jan Safranek <jsafrane@redhat.com>
+ *
+ * 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.
+ *
+ * Description: This file contains the test code for libcgroup logging.
+ */
+
+#include "config.h"
+#include "libcgroup.h"
+#include "../src/libcgroup-internal.h"
+#include <string.h>
+#include <stdlib.h>
+
+static void mylogger(void *userdata, int loglevel, const char *fmt, va_list ap)
+{
+       printf("custom: ");
+       vprintf(fmt, ap);
+}
+
+int main(int argc, char **argv)
+{
+       int custom = 0;
+       int loglevel = -1;
+       int i;
+
+       for (i = 1; i < argc; i++) {
+               if (strcmp("custom", argv[i]) == 0)
+                       custom = 1;
+               else
+                       loglevel = atoi(argv[i]);
+       }
+
+       if (custom)
+               cgroup_set_logger(mylogger, loglevel, NULL);
+       else
+               cgroup_set_default_logger(loglevel);
+
+       cgroup_dbg("DEBUG message\n");
+       cgroup_info("INFO message\n");
+       cgroup_warn("WARNING message\n");
+       cgroup_err("ERROR message\n");
+
+       return 0;
+}
diff --git a/samples/c/proctest.c b/samples/c/proctest.c
new file mode 100644 (file)
index 0000000..8e840c1
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright NEC Soft Ltd. 2009
+ *
+ * Author:     Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp>
+ *
+ * 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 <stdlib.h>
+#include "../src/libcgroup-internal.h"
+
+int main(int argc, char *argv[])
+{
+       int i;
+       int ret;
+       pid_t pid;
+       uid_t uid;
+       gid_t gid;
+       char *procname;
+
+       if (argc < 2) {
+               printf("Specify process-id.\n");
+               return 1;
+       }
+       printf("  Pid  |        Process name              |  Uid  |  Gid  \n");
+       printf("-------+----------------------------------+-------+-------\n");
+
+       for (i = 1; i < argc; i++) {
+               pid = atoi(argv[i]);
+
+               ret = cgroup_get_uid_gid_from_procfs(pid, &uid, &gid);
+               if (ret) {
+                       printf("%6d | ret = %d\n", pid, ret);
+                       continue;
+               }
+               ret = cgroup_get_procname_from_procfs(pid, &procname);
+               if (ret) {
+                       printf("%6d | ret = %d\n", pid, ret);
+                       continue;
+               }
+               printf("%6d | %32s | %5d | %5d\n", pid, procname, uid, gid);
+               free(procname);
+       }
+       return 0;
+}
diff --git a/samples/c/read_stats.c b/samples/c/read_stats.c
new file mode 100644 (file)
index 0000000..0583039
--- /dev/null
@@ -0,0 +1,84 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <libcgroup.h>
+
+int read_stats(char *path, char *controller)
+{
+       int ret;
+       void *handle;
+       struct cgroup_stat stat;
+
+       ret = cgroup_read_stats_begin(controller, path,  &handle, &stat);
+
+       if (ret != 0) {
+               fprintf(stderr, "stats read failed\n");
+               return -1;
+       }
+
+       printf("Stats for %s:\n", path);
+       printf("%s: %s", stat.name, stat.value);
+
+       while ((ret = cgroup_read_stats_next(&handle, &stat)) !=
+                       ECGEOF) {
+               printf("%s: %s", stat.name, stat.value);
+       }
+
+       cgroup_read_stats_end(&handle);
+       printf("\n");
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       int ret;
+       char *controller;
+       void *handle;
+       struct cgroup_file_info info;
+       int lvl;
+       char cgroup_path[FILENAME_MAX];
+       int root_len;
+
+       if (argc < 2) {
+               fprintf(stderr, "Usage %s: <controller name>\n",
+                       argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       controller = argv[1];
+
+       ret = cgroup_init();
+       if (ret != 0) {
+               fprintf(stderr, "init failed\n");
+               exit(EXIT_FAILURE);
+       }
+
+       ret = cgroup_walk_tree_begin(controller, "/", 0, &handle, &info, &lvl);
+
+       if (ret != 0) {
+               fprintf(stderr, "Walk failed\n");
+               exit(EXIT_FAILURE);
+       }
+
+       root_len = strlen(info.full_path) - 1;
+       strncpy(cgroup_path, info.path, FILENAME_MAX - 1);
+       ret = read_stats(cgroup_path, controller);
+       if (ret < 0)
+               exit(EXIT_FAILURE);
+
+       while ((ret = cgroup_walk_tree_next(0, &handle, &info, lvl)) !=
+                       ECGEOF) {
+               if (info.type != CGROUP_FILE_TYPE_DIR)
+                       continue;
+               strncpy(cgroup_path, info.full_path + root_len, FILENAME_MAX - 1);
+               strcat(cgroup_path, "/");
+               ret = read_stats(cgroup_path, controller);
+               if (ret < 0)
+                       exit(EXIT_FAILURE);
+       }
+       cgroup_walk_tree_end(&handle);
+
+       return EXIT_SUCCESS;
+}
diff --git a/samples/c/setuid.c b/samples/c/setuid.c
new file mode 100644 (file)
index 0000000..7afd3c8
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright Red Hat Inc. 2008
+ *
+ * Author:      Steve Olivieri <sjo@redhat.com>
+ *
+ * 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 <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+#include <string.h>
+
+/*
+ * This is just a simple program for changing a UID or a GID.  Comment out
+ * whichever block you don't want to use.
+ */
+int main(int argc, char *argv[])
+{
+       /* User data */
+       struct passwd *pwd;
+
+       /* UID of user */
+       uid_t uid;
+
+       /* Return codes */
+       int ret = 0;
+
+       if (argc < 2) {
+               printf("Usage: %s <uid_value> \n", argv[0]);
+               goto finished;
+       }
+
+       pwd = getpwnam(argv[1]);
+       if (!pwd) {
+               fprintf(stderr, "getpwnam() failed: %s\n",
+                               strerror(errno));
+               ret = -errno;
+               goto finished;
+       }
+       uid = pwd->pw_uid;
+       fprintf(stdout, "Setting UID to %s (%d).\n", pwd->pw_name, uid);
+       if ((ret = setuid(uid))) {
+               fprintf(stderr, "Call to setuid() failed with error: %s\n",
+                               strerror(errno));
+               ret = -errno;
+               goto finished;
+       }
+
+//     while(1) {
+//             grp = getgrnam("root");
+//             gid = grp->gr_gid;
+//             fprintf(stdout, "Setting GID to %s (%d).\n",
+//                             grp->gr_name, gid);
+//             if ((ret = setgid(gid))) {
+//                     fprintf(stderr, "Call to setgid() failed with error:"
+//                                     " %s\n", strerror(errno));
+//                     ret = -errno;
+//                     goto finished;
+//             }
+//     }
+
+       while (1) {
+               usleep(3000000);
+       }
+
+finished:
+       return ret;
+}
diff --git a/samples/c/test_functions.c b/samples/c/test_functions.c
new file mode 100644 (file)
index 0000000..f357ab2
--- /dev/null
@@ -0,0 +1,927 @@
+/*
+ * Copyright IBM Corporation. 2008
+ *
+ * Author:     Sudhir Kumar <skumar@linux.vnet.ibm.com>
+ *
+ * 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.
+ *
+ * Description: This file contains the functions for testing libcgroup apis.
+ */
+
+#include "libcgrouptest.h"
+
+/* The messages that may be useful to the user */
+char info[][SIZE] = {
+       " Parameter nullcgroup\n",                      /* NULLGRP */
+       " Parameter commoncgroup\n",                    /* COMMONGRP */
+       " Parameter not created group\n",               /* NOTCRTDGRP */
+       " Parameter same cgroup\n",                     /* SAMEGRP */
+       " Task found in group/s\n",                     /* TASKINGRP */
+       " Task not found in group/s\n",                 /* TASKNOTINGRP */
+       " Task not found in all groups\n",              /* TASKNOTINANYGRP */
+       " group found in filesystem\n",                 /* GRPINFS */
+       " group not found in filesystem\n",             /* GRPNOTINFS */
+       " group found under both controllers\n",        /* GRPINBOTHCTLS */
+       " group not found under second controller\n",   /* GRPNOTIN2NDCTL */
+       " group not found under first controller\n",    /* GRPNOTIN1STCTL */
+       " group modified under both controllers\n",     /* GRPMODINBOTHCTLS */
+       " group not modified under second controller\n",/* GRPNOTMODIN2NDCTL */
+       " group not modified under any controller\n",   /* GRPNOTMODINANYCTL */
+       " Group deleted from filesystem\n",             /* GRPDELETEDINFS */
+       " Group not deleted from filesystem\n",         /* GRPNOTDELETEDINFS */
+       " Group not deleted globally\n",                /* GRPNOTDELETEDGLOBALY */
+       /* In case there is no extra info messages to be printed */
+       "\n",                                           /* NOMESSAGE */
+};
+
+/**
+ * Tests the cgroup_init_cgroup() api under different scenarios
+ * @param retcode error code in case any error is expected from api
+ * @param i the test number
+ */
+void test_cgroup_init(int retcode, int i)
+{
+       int retval;
+
+       retval = cgroup_init();
+       if (retval == retcode)
+               message(i, PASS, "init()\t", retval, info[NOMESSAGE]);
+       else
+               message(i, FAIL, "init()",  retval, info[NOMESSAGE]);
+}
+
+/**
+ * Tests the cgroup_attach_cgroup() api under different scenarios
+ * @param retcode error code in case any error is expected from api
+ * @param cgrp the group to assign the task to
+ * @param group1 the name of the group under first (single) mountpoint
+ * @param group2 the name of the group under 2nd moutpoint for multimount
+ * @param i the test number
+ * @param k the message enum number to print the useful message
+ */
+void test_cgroup_attach_task(int retcode, struct cgroup *cgrp,
+        const char *group1, const char *group2, pid_t pid, int k, int i)
+{
+       int retval;
+       char tasksfile[FILENAME_MAX], tasksfile2[FILENAME_MAX];
+       /* Check, In case some error is expected due to a negative scenario */
+       if (retcode) {
+               if (pid)
+                       retval = cgroup_attach_task_pid(cgrp, pid);
+               else
+                       retval = cgroup_attach_task(cgrp);
+
+               if (retval == retcode)
+                       message(i, PASS, "attach_task()", retval, info[k]);
+               else
+                       message(i, FAIL, "attach_task()", retval, info[k]);
+
+               return;
+       }
+
+       /* Now there is no error and it is a genuine call */
+       if (pid)
+               retval = cgroup_attach_task_pid(cgrp, pid);
+       else
+               retval = cgroup_attach_task(cgrp);
+
+       /* API returned success, so perform check */
+       if (retval == 0) {
+               build_path(tasksfile, mountpoint,
+                                        group1, "tasks");
+
+               if (check_task(tasksfile, 0)) {
+                       if (fs_mounted == 2) {
+                               /* multiple mounts */
+                               build_path(tasksfile2, mountpoint2,
+                                                        group2, "tasks");
+                               if (check_task(tasksfile2, 0)) {
+                                       message(i, PASS, "attach_task()",
+                                                retval, info[TASKINGRP]);
+                               } else {
+                                       message(i, FAIL, "attach_task()",
+                                                retval, info[TASKNOTINANYGRP]);
+                               }
+                       } else {
+                               /* single mount */
+                               message(i, PASS, "attach_task()",
+                                                retval, info[TASKINGRP]);
+                       }
+               } else {
+                       message(i, FAIL, "attach_task()", retval,
+                                                        info[TASKNOTINGRP]);
+               }
+       } else {
+               message(i, FAIL, "attach_task()", retval, (char *)"\n");
+       }
+}
+
+/**
+ * This function creates a cgroup data structure
+ * This function is a bit ugly for now and need to be changed
+ * @param ctl the controller under which group is to be created
+ * @param grpname the name of the group
+ * @param value_type which value out of four types
+ * @param struct cval the control value structure
+ * @param struct ids the permissions struct
+ * @param the test number
+ */
+struct cgroup *create_new_cgroup_ds(int ctl, const char *grpname,
+        int value_type, struct cntl_val_t cval, struct uid_gid_t ids, int i)
+{
+       int retval;
+       char group[FILENAME_MAX];
+       char controller_name[FILENAME_MAX], control_file[FILENAME_MAX];
+
+       strncpy(group, grpname, sizeof(group) - 1);
+       retval = set_controller(ctl, controller_name, control_file);
+       if (retval) {
+               fprintf(stderr, "Setting controller failled\n");
+               return NULL;
+       }
+
+       switch (ctl) {
+               /* control values are controller specific, so will be set
+                * accordingly from the config file */
+       case CPU:
+               strncpy(cval.val_string, "260000", sizeof(cval.val_string));
+               break;
+
+       case MEMORY:
+               strncpy(cval.val_string, "7000064", sizeof(cval.val_string));
+               break;
+
+       /* To be added for other controllers */
+       default:
+               printf("Invalid controller name passed. Setting control value"
+                                       " failed. Dependent tests may fail\n");
+               return NULL;
+               break;
+       }
+
+       return new_cgroup(group, controller_name, control_file,
+                                                value_type, cval, ids, i);
+}
+
+/**
+ * Tests the cgroup_create_cgroup() api under different scenarios
+ * @param retcode error code in case any error is expected from api
+ * @param cgrp the group to be created
+ * @param name the name of the group
+ * @param common to test if group will be created under one or both mountpoints
+ * @param mpnt to test if group under mountpoint or mountpoint2
+ * @param ign parameter for api if to ignore the ownership
+ * @param the test number
+ */
+void test_cgroup_create_cgroup(int retcode, struct cgroup *cgrp,
+                        const char *name, int common, int mpnt, int ign, int i)
+{
+       int retval;
+       char path1_group[FILENAME_MAX], path2_group[FILENAME_MAX];
+       /* Check, In case some error is expected due to a negative scenario */
+       if (retcode) {
+               retval = cgroup_create_cgroup(cgrp, ign);
+               if (retval == retcode)
+                       message(i, PASS, "create_cgroup()", retval,
+                                                        info[NOMESSAGE]);
+               else
+                       message(i, FAIL, "create_cgroup()", retval,
+                                                        info[NOMESSAGE]);
+
+               return;
+       }
+
+       /* Now there is no error and it is a genuine call */
+       retval = cgroup_create_cgroup(cgrp, ign);
+       if (retval) {
+               message(i, FAIL, "create_cgroup()", retval,  info[NOMESSAGE]);
+               return;
+       }
+
+       /* Let us now check if the group exist in file system */
+       if (!common) {
+               /* group only under one mountpoint */
+               if (mpnt == 1)
+                       /* group under mountpoint */
+                       build_path(path1_group, mountpoint, name, NULL);
+               else
+                       /* group under mountpoint2 */
+                       build_path(path1_group, mountpoint2, name, NULL);
+
+               if (group_exist(path1_group) == 0)
+                       message(i, PASS, "create_cgroup()", retval,
+                                                        info[GRPINFS]);
+               else
+                       message(i, FAIL, "create_cgroup()", retval,
+                                                        info[GRPNOTINFS]);
+
+        /* group under both mountpoints */
+       } else {
+               /* check if the group exists under both controllers */
+               build_path(path1_group, mountpoint, name, NULL);
+               if (group_exist(path1_group) == 0) {
+                       build_path(path2_group, mountpoint2, name, NULL);
+
+                       if (group_exist(path2_group) == 0)
+                               message(i, PASS, "create_cgroup()",
+                                                retval, info[GRPINBOTHCTLS]);
+                       else
+                               message(i, FAIL, "create_cgroup()",
+                                                retval, info[GRPNOTIN2NDCTL]);
+               } else {
+                       message(i, FAIL, "create_cgroup()", retval,
+                                                        info[GRPNOTIN1STCTL]);
+               }
+       }
+
+       return;
+}
+
+/**
+ * Tests the cgroup_delete_cgroup() api under different scenarios
+ * @param retcode error code in case any error is expected from api
+ * @param cgrp the group to be deleted
+ * @param name the name of the group
+ * @param common to test if group was created under one or both mountpoints
+ * @param mpnt to test if group under mountpoint or mountpoint2
+ * @param ign parameter for api if to ignore the ownership
+ * @param the test number
+ */
+void test_cgroup_delete_cgroup(int retcode, struct cgroup *cgrp,
+                        const char *name, int common, int mpnt, int ign, int i)
+{
+       int retval;
+       char path1_group[FILENAME_MAX], path2_group[FILENAME_MAX];
+       /* Check, In case some error is expected due to a negative scenario */
+       if (retcode) {
+               retval = cgroup_delete_cgroup(cgrp, ign);
+               if (retval == retcode)
+                       message(i, PASS, "delete_cgroup()", retval,
+                                                        info[NOMESSAGE]);
+               else
+                       message(i, FAIL, "delete_cgroup()", retval,
+                                                        info[NOMESSAGE]);
+
+               return;
+       }
+
+       /* Now there is no error and it is a genuine call */
+       retval = cgroup_delete_cgroup(cgrp, ign);
+       if (retval) {
+               message(i, FAIL, "delete_cgroup()", retval,  info[NOMESSAGE]);
+               return;
+       }
+
+       /* Let us now check if the group has been deleted from file system */
+       if (!common) {
+               /* check only under one mountpoint */
+               if (mpnt == 1)
+                       /* check group under mountpoint */
+                       build_path(path1_group, mountpoint, name, NULL);
+               else
+                       /* check group under mountpoint2 */
+                       build_path(path1_group, mountpoint2, name, NULL);
+
+               if (group_exist(path1_group) == ENOENT)
+                       message(i, PASS, "delete_cgroup()", retval,
+                                                info[GRPDELETEDINFS]);
+               else
+                       message(i, FAIL, "delete_cgroup()", retval,
+                                                info[GRPNOTDELETEDINFS]);
+
+       } else {
+               /* check group under both mountpoints */
+               /* Check if the group deleted under both mountpoints */
+               build_path(path1_group, mountpoint, name, NULL);
+               if (group_exist(path1_group) == ENOENT) {
+                       build_path(path2_group, mountpoint2, name, NULL);
+
+                       if (group_exist(path2_group) == ENOENT)
+                               message(i, PASS, "delete_cgroup()",
+                                                retval, info[GRPDELETEDINFS]);
+                       else
+                               message(i, FAIL, "delete_cgroup()",
+                                        retval, info[GRPNOTDELETEDGLOBALY]);
+               } else {
+                       message(i, FAIL, "delete_cgroup()", retval,
+                                                info[GRPNOTDELETEDINFS]);
+               }
+       }
+
+}
+
+/**
+ * The function tests if the given controller is enabled in kernel
+ * @param name the name of the controller to be checked
+ * @param exist set to 1 if the controller exists
+ */
+void is_subsystem_enabled(const char *name, int *exist)
+{
+       int hierarchy, num_cgroups, enabled;
+       FILE *fd;
+       char subsys_name[FILENAME_MAX];
+
+       fd = fopen("/proc/cgroups", "r");
+       if (!fd)
+               return;
+
+       while (!feof(fd)) {
+               fscanf(fd, "%s, %d, %d, %d", subsys_name,
+                                        &hierarchy, &num_cgroups, &enabled);
+               if (strncmp(name, subsys_name, sizeof(*name)) == 0)
+                       *exist = 1;
+       }
+
+       fclose(fd);
+}
+
+/**
+ * This function tests if the given group exists in filesystem
+ * @param path_group path to the group to be tested for existence
+ */
+int group_exist(char *path_group)
+{
+       struct stat statbuf;
+       if (stat(path_group, &statbuf) == -1) {
+               /* Group deleted. OK */
+               if (errno == ENOENT)
+                       return ENOENT;
+               /* There is some other failure */
+               printf("stat failed, return code is %d\n", errno);
+               return -1;
+       }
+
+       if (S_ISDIR(statbuf.st_mode))
+               return 0;
+       else
+               return -1;
+}
+
+/**
+ * Sets the controller name and control file name
+ * @param controller the enum for the name of the controller
+ * @param controller_name name of the controller
+ * @param control_file corresponding control file
+ */
+int set_controller(int controller, char *controller_name, char *control_file)
+{
+       switch (controller) {
+       case MEMORY:
+               if (memory == 0)
+                       return 1;
+
+               strncpy(controller_name, "memory", FILENAME_MAX);
+               strncpy(control_file, "memory.limit_in_bytes", FILENAME_MAX);
+               return 0;
+               break;
+
+       case CPU:
+               if (cpu == 0)
+                       return 1;
+
+               strncpy(controller_name, "cpu", FILENAME_MAX);
+               strncpy(control_file, "cpu.shares", FILENAME_MAX);
+               return 0;
+               break;
+
+       case CPUSET:
+               strncpy(controller_name, "cpuset", FILENAME_MAX);
+               strncpy(control_file, "cpuset.cpus", FILENAME_MAX);
+               return 0;
+               break;
+               /* Future controllers can be added here */
+
+       default:
+               printf("Invalid controller name passed. Setting controller"
+                                       " failed. Dependent tests may fail\n");
+               return 1;
+               break;
+       }
+}
+
+/**
+ * Tests if a group has been modified
+ * @param path_control_file path to the control file of the controller
+ * @param value_type which value out of four types
+ * @param struct cval the control value structure
+ */
+int group_modified(char *path_control_file, int value_type,
+                                                struct cntl_val_t cval)
+{
+       bool bool_val;
+       int64_t int64_val;
+       u_int64_t uint64_val;
+       /* 100 char looks ok for a control value as string */
+       char string_val[100];
+       FILE *fd;
+       int error = 1;
+       int aux;
+
+       fd = fopen(path_control_file, "r");
+       if (!fd) {
+               fprintf(stderr, "Error in opening %s\n", path_control_file);
+               fprintf(stderr, "Skipping modified values check....\n");
+               return 1;
+       }
+
+       switch (value_type) {
+
+       case BOOL:
+               fscanf(fd, "%d", &aux);
+               bool_val = aux;
+               if (bool_val == cval.val_bool)
+                       error = 0;
+               break;
+       case INT64:
+               fscanf(fd, "%" SCNi64, &int64_val);
+               if (int64_val == cval.val_int64)
+                       error = 0;
+               break;
+       case UINT64:
+               fscanf(fd, "%" SCNu64, &uint64_val);
+               if (uint64_val == cval.val_uint64)
+                       error = 0;
+               break;
+       case STRING:
+               fscanf(fd, "%s", string_val);
+               if (!strncmp(string_val, cval.val_string, strlen(string_val)))
+                       error = 0;
+               break;
+       default:
+               fprintf(stderr, "Wrong value_type passed "
+                                               "in group_modified()\n");
+               fprintf(stderr, "Skipping modified values check....\n");
+               /* Can not report test result as failure */
+               error = 0;
+               break;
+       }
+
+       fclose(fd);
+       return error;
+}
+
+/**
+ * Adds the control value to a controller using wrapper apis
+ * @param newcontroller the controller to be added the value to
+ * @param control_file name of the control file of the controller
+ * @param wr the name of wrapper api
+ * @param value_type which value out of four types
+ * @param struct cval the control value structure
+ */
+int add_control_value(struct cgroup_controller *newcontroller,
+        char *control_file, char *wr, int value_type, struct cntl_val_t cval)
+{
+       int retval;
+
+       switch (value_type) {
+
+       case BOOL:
+               retval = cgroup_add_value_bool(newcontroller,
+                                        control_file, cval.val_bool);
+               snprintf(wr, SIZE, "add_value_bool()");
+               break;
+       case INT64:
+               retval = cgroup_add_value_int64(newcontroller,
+                                        control_file, cval.val_int64);
+               snprintf(wr, SIZE, "add_value_int64()");
+               break;
+       case UINT64:
+               retval = cgroup_add_value_uint64(newcontroller,
+                                        control_file, cval.val_uint64);
+               snprintf(wr, SIZE, "add_value_uint64()");
+               break;
+       case STRING:
+               retval = cgroup_add_value_string(newcontroller,
+                                        control_file, cval.val_string);
+               snprintf(wr, SIZE, "add_value_string()");
+               break;
+       default:
+               printf("ERROR: wrong value in add_control_value()\n");
+               return 1;
+               break;
+       }
+       return retval;
+}
+
+/**
+ * This function creates and returns a cgroup data structure
+ * @param group the name of the group
+ * @param controller_name the name of the controller to be added to the group
+ * @param control_file name of the control file of the controller
+ * @param value_type which value out of four types
+ * @param struct cval the control value structure
+ * @param struct ids the permissions struct
+ * @param the test number
+ */
+struct cgroup *new_cgroup(char *group, char *controller_name,
+                        char *control_file, int value_type,
+                        struct cntl_val_t cval, struct uid_gid_t ids, int i)
+{
+       int retval;
+       /* Names of wrapper apis */
+       char wr[SIZE];
+       struct cgroup *newcgroup;
+       struct cgroup_controller *newcontroller;
+
+       newcgroup = cgroup_new_cgroup(group);
+
+       if (newcgroup) {
+               retval = cgroup_set_uid_gid(newcgroup, ids.tasks_uid,
+                        ids.tasks_gid, ids.control_uid, ids.control_gid);
+
+               if (retval) {
+                       snprintf(wr, SIZE, "set_uid_gid()");
+                       message(i++, FAIL, wr, retval, info[NOMESSAGE]);
+               }
+
+               newcontroller = cgroup_add_controller(newcgroup,
+                                                        controller_name);
+               if (newcontroller) {
+                       retval =  add_control_value(newcontroller,
+                                        control_file, wr, value_type, cval);
+
+                       if (!retval) {
+                               message(i++, PASS, "new_cgroup()",
+                                                retval, info[NOMESSAGE]);
+                       } else {
+                               message(i++, FAIL, wr, retval ,
+                                                        info[NOMESSAGE]);
+                               cgroup_free(&newcgroup);
+                               return NULL;
+                       }
+                } else {
+                       /* Since these wrappers do not return an int so -1 */
+                       message(i++, FAIL, "add_controller", -1,
+                                                        info[NOMESSAGE]);
+                       cgroup_free(&newcgroup);
+                       return NULL;
+               }
+       } else {
+               message(i++, FAIL, "new_cgroup", -1, info[NOMESSAGE]);
+               return NULL;
+       }
+       return newcgroup;
+}
+
+/**
+ * Checks if the cgroup filesystem has been mounted
+ * @param multimnt to decide if check is for single mount or multimount
+ */
+int check_fsmounted(int multimnt)
+{
+       int count = 0;
+       int ret = 1;
+       struct mntent *entry = NULL, *tmp_entry = NULL;
+       /* Need a better mechanism to decide memory allocation size here */
+       char entry_buffer[FILENAME_MAX * 4];
+       FILE *proc_file = NULL;
+
+       tmp_entry = (struct mntent *) malloc(sizeof(struct mntent));
+       if (!tmp_entry) {
+               perror("Error: failled to mallloc for mntent\n");
+               ret = errno;
+               goto error;
+       }
+
+       proc_file = fopen("/proc/mounts", "r");
+       if (!proc_file) {
+               printf("Error in opening /proc/mounts.\n");
+               ret = errno;
+               goto error;
+       }
+       while ((entry = getmntent_r(proc_file, tmp_entry, entry_buffer,
+                                                FILENAME_MAX*4)) != NULL) {
+               if (!strncmp(entry->mnt_type, "cgroup", strlen("cgroup"))) {
+                       count++;
+                       if (multimnt) {
+                               if (count >= 2) {
+                                       printf("sanity check pass. %s\n",
+                                                        entry->mnt_type);
+                                       ret = 0;
+                                       goto error;
+                               }
+                       } else {
+                               printf("sanity check pass. %s\n",
+                                                        entry->mnt_type);
+                               ret = 0;
+                               goto error;
+                       }
+               }
+       }
+error:
+       if (tmp_entry)
+               free(tmp_entry);
+       if (proc_file)
+               fclose(proc_file);
+       return ret;
+}
+
+/**
+ * Checks if the current task belongs to the given tasks file
+ * @param tasksfile the task file to be tested for the task
+ */
+int check_task(char *tasksfile, pid_t pid)
+{
+       FILE *file;
+       pid_t curr_tid, tid;
+       int pass = 0;
+
+       file = fopen(tasksfile, "r");
+       if (!file) {
+               printf("ERROR: in opening %s\n", tasksfile);
+               printf("Exiting without running other testcases in this set\n");
+               exit(1);
+       }
+
+       if (pid)
+               curr_tid = pid;
+       else
+               curr_tid = cgrouptest_gettid();
+
+       while (!feof(file)) {
+               fscanf(file, "%u", &tid);
+               if (tid == curr_tid) {
+                       pass = 1;
+                       break;
+               }
+       }
+       fclose(file);
+
+       return pass;
+}
+
+/**
+ * Prints the test result in a readable format with some verbose messages
+ * @param num the test number
+ * @param pass test passed or failed
+ * @param api the name of the api tested
+ * @param retval the return value of the api
+ * @param extra the extra message to the user about the scenario tested
+ */
+void message(int num, int pass, const char *api, int retval, char *extra)
+{
+       char res[10];
+       char buf[2*SIZE];
+       if (pass)
+               strncpy(res, "PASS :", 10);
+       else
+               strncpy(res, "FAIL :", 10);
+
+       /* Populate message buffer for the api */
+       snprintf(buf, sizeof(buf), "cgroup_%s\t\t Ret Value = ", api);
+       fprintf(stdout, "TEST%2d:%s %s%d\t%s", num, res, buf, retval, extra);
+}
+
+/**
+ * Builds the path to target file/group
+ * @param target to write the built path to
+ * @param mountpoint for which mountpoint the path to be built
+ * @param group the name of the group (directory)
+ * @param file what file under the group
+ */
+void
+build_path(char *target, char *mountpoint, const char *group, const char *file)
+{
+       if (!target)
+               return;
+
+       strncpy(target, mountpoint, FILENAME_MAX);
+
+       if (group) {
+               strncat(target, "/", FILENAME_MAX - strlen(target));
+               strncat(target, group, FILENAME_MAX - strlen(target));
+       }
+
+       if (file) {
+               strncat(target, "/", FILENAME_MAX - strlen(target));
+               strncat(target, file, FILENAME_MAX - strlen(target));
+       }
+}
+
+/**
+ * Tests the cgroup_compare_cgroup() api under different scenarios
+ * @param ctl1 controller 1 to be used for testing
+ * @param ctl2 controller 1 to be used for testing
+ * @param the test number
+ */
+void test_cgroup_compare_cgroup(int ctl1, int ctl2, int i)
+{
+       int retval;
+
+       struct cntl_val_t cval;
+       cval.val_int64 = 0;
+       cval.val_uint64 = 0;
+       cval.val_bool = 0;
+       strcpy(cval.val_string, "5000");
+
+       struct cgroup *cgroup1 = NULL, *cgroup2 = NULL;
+       struct cgroup_controller *controller = NULL;
+       char controller_name[FILENAME_MAX], control_file[FILENAME_MAX];
+       char wr[SIZE], extra[] = "in cgroup_compare_cgroup";
+
+       retval = cgroup_compare_cgroup(NULL, NULL);
+       if (retval)
+               message(i++, PASS, "compare_cgroup()", retval, info[NULLGRP]);
+       else
+               message(i++, FAIL, "compare_cgroup()", retval, info[NULLGRP]);
+
+       cgroup1 = cgroup_new_cgroup("testgroup");
+       cgroup2 = cgroup_new_cgroup("testgroup");
+       cgroup_set_uid_gid(cgroup1, 0, 0, 0, 0);
+       cgroup_set_uid_gid(cgroup2, 0, 0, 0, 0);
+
+       retval = set_controller(ctl1, controller_name, control_file);
+
+       controller = cgroup_add_controller(cgroup1, controller_name);
+       if (controller) {
+               retval =  add_control_value(controller,
+                                        control_file, wr, STRING, cval);
+               if (retval)
+                       message(i++, FAIL, wr, retval, extra);
+       }
+
+       controller = cgroup_add_controller(cgroup2, controller_name);
+       if (controller) {
+               retval =  add_control_value(controller,
+                                        control_file, wr, STRING, cval);
+               if (retval)
+                       message(i++, FAIL, wr, retval, extra);
+       }
+
+       retval = cgroup_compare_cgroup(cgroup1, cgroup2);
+       if (retval)
+               message(i++, FAIL, "compare_cgroup()", retval, info[NOMESSAGE]);
+       else
+               message(i++, PASS, "compare_cgroup()", retval, info[NOMESSAGE]);
+
+       /* Test the api by putting diff number of controllers in cgroups */
+       retval = set_controller(ctl2, controller_name, control_file);
+       controller = cgroup_add_controller(cgroup2, controller_name);
+       if (controller) {
+               retval =  add_control_value(controller,
+                                        control_file, wr, STRING, cval);
+               if (retval)
+                       message(i++, FAIL, wr, retval, extra);
+       }
+
+       retval = cgroup_compare_cgroup(cgroup1, cgroup2);
+       if (retval == ECGROUPNOTEQUAL)
+               message(i++, PASS, "compare_cgroup()", retval, info[NOMESSAGE]);
+       else
+               message(i++, FAIL, "compare_cgroup()", retval, info[NOMESSAGE]);
+
+       cgroup_free(&cgroup1);
+       cgroup_free(&cgroup2);
+}
+
+/**
+ * Tests the cgroup_get_cgroup() api under different scenarios
+ * @param ctl1 controller 1 to be used for testing
+ * @param ctl2 controller 1 to be used for testing
+ * @param struct ids the permissions struct
+ * @param the test number
+ */
+void test_cgroup_get_cgroup(int ctl1, int ctl2, struct uid_gid_t ids, int i)
+{
+       struct cgroup *cgroup_filled = NULL, *cgroup_a = NULL, *cgroup_b = NULL;
+       struct cgroup_controller *controller = NULL;
+       char controller_name[FILENAME_MAX], control_file[FILENAME_MAX];
+       struct cntl_val_t cval = {0, 0, 0, "5000"};
+       int ret;
+
+       /*
+        * No need to test the next 3 scenarios separately for Multimnt
+        * so testing them only under single mount
+        */
+       if (fs_mounted == FS_MOUNTED) {
+               /* 1. Test with nullcgroup first */
+               ret = cgroup_get_cgroup(NULL);
+               if (ret == ECGROUPNOTALLOWED)
+                       message(i++, PASS, "get_cgroup()", ret, info[NULLGRP]);
+               else
+                       message(i++, FAIL, "get_cgroup()", ret, info[NULLGRP]);
+
+               /* 2. Test with invalid name filled cgroup(non existing) */
+               cgroup_filled = cgroup_new_cgroup("nogroup");
+               if (!cgroup_filled)
+                       message(i++, FAIL, "new_cgroup()", 0, info[NOMESSAGE]);
+
+               ret = cgroup_get_cgroup(cgroup_filled);
+               if (ret)
+                       message(i++, PASS, "get_cgroup()", ret,
+                                                        info[NOTCRTDGRP]);
+               else
+                       message(i++, FAIL, "get_cgroup()", ret,
+                                                        info[NOTCRTDGRP]);
+               /* Free the allocated cgroup before reallocation */
+               cgroup_free(&cgroup_filled);
+
+               /* 3.
+                * Test with name filled cgroup. Ensure the group group1 exists
+                * in the filesystem before calling this test function
+                */
+               cgroup_filled = cgroup_new_cgroup("group1");
+               if (!cgroup_filled)
+                       message(i++, FAIL, "new_cgroup()", 0, info[NOMESSAGE]);
+
+               ret = cgroup_get_cgroup(cgroup_filled);
+               if (!ret)
+                       message(i++, PASS, "get_cgroup()", ret,
+                                                        info[NOMESSAGE]);
+               else
+                       message(i++, FAIL, "get_cgroup()", ret,
+                                                        info[NOMESSAGE]);
+       }
+
+       /* SINGLE & MULTI MOUNT: Create, get and compare a cgroup */
+
+       /* get cgroup_a ds and create group_a in filesystem */
+       cgroup_a = create_new_cgroup_ds(ctl1, "group_a", STRING, cval, ids, 0);
+       if (fs_mounted == FS_MULTI_MOUNTED) {
+               /* Create under another controller also */
+               ret = set_controller(ctl2, controller_name, control_file);
+               controller = cgroup_add_controller(cgroup_a, controller_name);
+               if (controller)
+                       message(i++, PASS, "cgroup_add_controller()",
+                                       0, info[NOMESSAGE]);
+               else
+                       message(i++, FAIL, "cgroup_add_controller()",
+                                       -1, info[NOMESSAGE]);
+       }
+       test_cgroup_create_cgroup(0, cgroup_a, "group_a", 0, 1, 1, 00);
+
+       /* create group_b ds to be filled by cgroup_get_cgroup */
+       cgroup_b = cgroup_new_cgroup("group_a");
+       if (!cgroup_b)
+               message(i++, FAIL, "new_cgroup()", 0, info[NOMESSAGE]);
+       /* Fill the ds and compare the two */
+       ret = cgroup_get_cgroup(cgroup_b);
+       if (!ret) {
+               ret = cgroup_compare_cgroup(cgroup_a, cgroup_b);
+               if (ret == 0)
+                       message(i++, PASS, "get_cgroup()", ret, info[SAMEGRP]);
+               else
+                       message(i++, FAIL, "get_cgroup()", ret,
+                                                        info[NOMESSAGE]);
+       } else {
+               message(i++, FAIL, "get_cgroup()", ret, info[NOMESSAGE]);
+       }
+
+       /* Delete this created group from fs to leave fs clean */
+       if (fs_mounted == FS_MULTI_MOUNTED)
+               test_cgroup_delete_cgroup(0, cgroup_a, "group_a", 1, 1, 0, 0);
+       else
+               test_cgroup_delete_cgroup(0, cgroup_a, "group_a", 0, 1, 0, 0);
+
+       cgroup_free(&cgroup_a);
+       cgroup_free(&cgroup_b);
+       cgroup_free(&cgroup_filled);
+}
+
+/**
+ * Tests the cgroup_add_controller() and cgroup_free_controller() wrapper
+ * apis under different scenarios
+ * @param the test number
+ */
+void test_cgroup_add_free_controller(int i)
+{
+       struct cgroup *cgroup1 = NULL, *cgroup2 = NULL;
+       struct cgroup_controller *cgctl1, *cgctl2;
+
+       /* Test with a Null cgroup */
+       cgctl1 = cgroup_add_controller(cgroup1, "cpu");
+       if (!cgctl1)
+               message(i++, PASS, "add_controller()", 0, info[NOMESSAGE]);
+       else
+               message(i++, FAIL, "add_controller()", -1, info[NOMESSAGE]);
+
+       cgroup1 = cgroup_new_cgroup("testgroup");
+       cgctl1 = cgroup_add_controller(cgroup1, "cpuset");
+       if (cgctl1)
+               message(i++, PASS, "add_controller()", 0, info[NOMESSAGE]);
+       else
+               message(i++, FAIL, "add_controller()", -1, info[NOMESSAGE]);
+
+       cgctl2 = cgroup_add_controller(cgroup1, "cpu");
+       if (cgctl2)
+               message(i++, PASS, "add_controller()", 0, info[NOMESSAGE]);
+       else
+               message(i++, FAIL, "add_controller()", -1, info[NOMESSAGE]);
+
+       cgroup_free(&cgroup1);
+       cgroup_free_controllers(cgroup2);
+}
+
+/**
+ * Returns the tid of the current thread
+ */
+pid_t cgrouptest_gettid()
+{
+       return syscall(__NR_gettid);
+}
diff --git a/samples/c/test_named_hierarchy.c b/samples/c/test_named_hierarchy.c
new file mode 100644 (file)
index 0000000..934c875
--- /dev/null
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libcgroup.h>
+
+/*
+ * Assumes cgroup is mounted at /cgroup using
+ *
+ * mount -t cgroup -o none,name=test none /cgroup
+ */
+int main()
+{
+       int ret;
+       struct cgroup *cgroup;
+       struct cgroup_controller *cgc;
+
+       ret = cgroup_init();
+       if (ret) {
+               printf("FAIL: cgroup_init failed with %s\n", cgroup_strerror(ret));
+               exit(3);
+       }
+
+       cgroup = cgroup_new_cgroup("test");
+       if (!cgroup) {
+               printf("FAIL: cgroup_new_cgroup failed\n");
+               exit(3);
+       }
+
+       cgc = cgroup_add_controller(cgroup, "name=test");
+       if (!cgc) {
+               printf("FAIL: cgroup_add_controller failed\n");
+               exit(3);
+       }
+
+       ret = cgroup_create_cgroup(cgroup, 1);
+       if (ret) {
+               printf("FAIL: cgroup_create_cgroup failed with %s\n", cgroup_strerror(ret));
+               exit(3);
+       }
+
+       if (access("/cgroup/test", F_OK))
+               printf("PASS\n");
+       else
+               printf("Failed to create cgroup\n");
+
+       return 0;
+}
diff --git a/samples/c/walk_task.c b/samples/c/walk_task.c
new file mode 100644 (file)
index 0000000..42ef32d
--- /dev/null
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <libcgroup.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+       int ret, i;
+       char *group = NULL;
+       void *handle;
+
+       if (argc < 2) {
+               printf("No list of groups provided\n");
+               return -1;
+       }
+
+       ret = cgroup_init();
+
+       if (ret) {
+               printf("cgroup_init failed with %s\n", cgroup_strerror(ret));
+               return -1;
+       }
+
+       for (i = 1; i < argc; i++) {
+               pid_t pid;
+               group = strdup(argv[i]);
+               printf("Printing the details of groups %s\n", group);
+               ret = cgroup_get_task_begin(group, "cpu", &handle, &pid);
+               while (!ret) {
+                       printf("Pid is %u\n", pid);
+                       ret = cgroup_get_task_next(&handle, &pid);
+                       if (ret && ret != ECGEOF) {
+                               printf("cgroup_get_task_next failed with %s\n",
+                                                       cgroup_strerror(ret));
+                               if (ret == ECGOTHER)
+                                       printf("failure with %s\n",
+                                                       strerror(errno));
+                               return -1;
+                       }
+               }
+               free(group);
+               group = NULL;
+               ret = cgroup_get_task_end(&handle);
+       }
+
+       return 0;
+
+}
diff --git a/samples/c/walk_test.c b/samples/c/walk_test.c
new file mode 100644 (file)
index 0000000..f3112c5
--- /dev/null
@@ -0,0 +1,121 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <libcgroup.h>
+
+void visit_node(struct cgroup_file_info *info, char *root)
+{
+       if (info->type == CGROUP_FILE_TYPE_DIR) {
+               printf("path %s, parent %s, relative %s, full %s\n",
+                       info->path, info->parent, info->full_path +
+                               + strlen(root) - 1,
+                               info->full_path);
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       int ret;
+       char *controller;
+       void *handle;
+       struct cgroup_file_info info;
+       char root[FILENAME_MAX];
+       int lvl, i;
+
+       if (argc < 2) {
+               fprintf(stderr, "Usage %s: <controller name>\n",
+                       argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       controller = argv[1];
+
+       ret = cgroup_init();
+       if (ret != 0) {
+               fprintf(stderr, "Init failed\n");
+               exit(EXIT_FAILURE);
+       }
+
+       ret = cgroup_walk_tree_begin(controller, "/", 0, &handle, &info, &lvl);
+
+       if (ret != 0) {
+               fprintf(stderr, "Walk failed\n");
+               exit(EXIT_FAILURE);
+       }
+       strcpy(root, info.full_path);
+       printf("Begin pre-order walk\n");
+       printf("root is %s\n", root);
+       visit_node(&info, root);
+       while ((ret = cgroup_walk_tree_next(0, &handle, &info, lvl)) !=
+                       ECGEOF) {
+               visit_node(&info, root);
+       }
+       cgroup_walk_tree_end(&handle);
+
+       printf("pre-order walk finished\n");
+       ret = cgroup_walk_tree_begin(controller, "/", 0, &handle, &info, &lvl);
+
+       if (ret != 0) {
+               fprintf(stderr, "Walk failed\n");
+               exit(EXIT_FAILURE);
+       }
+
+       ret = cgroup_walk_tree_set_flags(&handle, CGROUP_WALK_TYPE_POST_DIR);
+
+       if (ret) {
+               fprintf(stderr, "Walk failed with %s\n", cgroup_strerror(ret));
+               exit(EXIT_FAILURE);
+       }
+
+       strcpy(root, info.full_path);
+       printf("Begin post-order walk\n");
+       printf("root is %s\n", root);
+       visit_node(&info, root);
+       while ((ret = cgroup_walk_tree_next(0, &handle, &info, lvl)) !=
+                       ECGEOF) {
+               visit_node(&info, root);
+       }
+       cgroup_walk_tree_end(&handle);
+       printf("post order walk finished\n");
+
+       ret = cgroup_walk_tree_begin(controller, "/a", 2, &handle, &info, &lvl);
+
+       if (ret != 0) {
+               fprintf(stderr, "Walk failed\n");
+               exit(EXIT_FAILURE);
+       }
+       strcpy(root, info.full_path);
+       printf("root is %s\n", root);
+       visit_node(&info, root);
+       while ((ret = cgroup_walk_tree_next(2, &handle, &info, lvl)) !=
+                       ECGEOF) {
+               visit_node(&info, root);
+       }
+       cgroup_walk_tree_end(&handle);
+
+       /*
+        * Walk only the first five nodes
+        */
+       i = 0;
+       printf("Walking the first 5 nodes\n");
+       ret = cgroup_walk_tree_begin(controller, "/", 0, &handle, &info, &lvl);
+
+       if (ret != 0) {
+               fprintf(stderr, "Walk failed\n");
+               exit(EXIT_FAILURE);
+       }
+       strcpy(root, info.full_path);
+       printf("root is %s\n", root);
+       visit_node(&info, root);
+       i++;
+       while ((ret = cgroup_walk_tree_next(0, &handle, &info, lvl)) !=
+                       ECGEOF) {
+               visit_node(&info, root);
+               if (++i >= 5)
+                       break;
+       }
+       cgroup_walk_tree_end(&handle);
+       return EXIT_SUCCESS;
+}
diff --git a/samples/c/wrapper_test.c b/samples/c/wrapper_test.c
new file mode 100644 (file)
index 0000000..257ece3
--- /dev/null
@@ -0,0 +1,44 @@
+#include <libcgroup.h>
+#include <stdio.h>
+#include <string.h>
+#include "../src/libcgroup-internal.h"
+
+int main()
+{
+       struct cgroup *cgroup;
+       struct cgroup_controller *cgc;
+       int fail = 0;
+
+       cgroup = cgroup_new_cgroup("test");
+       cgc = cgroup_add_controller(cgroup, "cpu");
+
+       cgroup_add_value_int64(cgc, "cpu.shares", 2048);
+       cgroup_add_value_uint64(cgc, "cpu.something", 1000);
+       cgroup_add_value_bool(cgc, "cpu.bool", 1);
+
+       if (!strcmp(cgroup->controller[0]->values[0]->name, "cpu.shares")) {
+               if (strcmp(cgroup->controller[0]->values[0]->value, "2048")) {
+                       printf("FAIL for add_value_int\n");
+                       fail = 1;
+               }
+       }
+
+       if (!strcmp(cgroup->controller[0]->values[1]->name, "cpu.something")) {
+               if (strcmp(cgroup->controller[0]->values[1]->value, "1000")) {
+                       printf("FAIL for add_value_uint\n");
+                       fail = 1;
+               }
+       }
+
+       if (!strcmp(cgroup->controller[0]->values[2]->name, "cpu.bool")) {
+               if (strcmp(cgroup->controller[0]->values[2]->value, "1")) {
+                       printf("FAIL for add_value_bool\n");
+                       fail = 1;
+               }
+       }
+
+       if (!fail)
+               printf("PASS!\n");
+
+       return fail;
+}