From: Tom Hromatka Date: Wed, 23 Feb 2022 15:01:38 +0000 (-0700) Subject: samples: Add C samples X-Git-Tag: v3.0~193 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fb7f397e5e12c95a6ea21f4c19c539548a1ad137;p=thirdparty%2Flibcgroup.git samples: Add C samples 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 Reviewed-by: Kamalesh Babulal --- diff --git a/configure.ac b/configure.ac index 113dcb5d..5f4efef3 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/samples/Makefile.am b/samples/Makefile.am index a85a5bb5..23f64d69 100644 --- a/samples/Makefile.am +++ b/samples/Makefile.am @@ -1 +1 @@ -SUBDIRS = config +SUBDIRS = config c diff --git a/samples/c/Makefile.am b/samples/c/Makefile.am new file mode 100644 index 00000000..8f359397 --- /dev/null +++ b/samples/c/Makefile.am @@ -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 index 00000000..d643c986 --- /dev/null +++ b/samples/c/get_all_controller.c @@ -0,0 +1,34 @@ +#include +#include +#include + +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 index 00000000..1829f5cc --- /dev/null +++ b/samples/c/get_controller.c @@ -0,0 +1,34 @@ +#include +#include +#include + +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 index 00000000..b3720927 --- /dev/null +++ b/samples/c/get_mount_point.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include + +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 index 00000000..caa84448 --- /dev/null +++ b/samples/c/get_procs.c @@ -0,0 +1,36 @@ +#include +#include +#include + +/* + * 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 index 00000000..dc2ef149 --- /dev/null +++ b/samples/c/get_variable_names.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#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 index 00000000..322794b2 --- /dev/null +++ b/samples/c/libcg_ba.cpp @@ -0,0 +1,160 @@ +/* + * Copyright IBM Corporation. 2007 + * + * Author: Balbir Singh + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 00000000..98b1ba9c --- /dev/null +++ b/samples/c/libcgrouptest.h @@ -0,0 +1,158 @@ + +/* + * Copyright IBM Corporation. 2008 + * + * Author: Sudhir Kumar + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../config.h" +#include +#include + +#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 index 00000000..d7770a09 --- /dev/null +++ b/samples/c/libcgrouptest01.c @@ -0,0 +1,756 @@ +/* + * Copyright IBM Corporation. 2008 + * + * Author: Sudhir Kumar + * + * 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 + +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 index 00000000..b7f1b702 --- /dev/null +++ b/samples/c/logger.c @@ -0,0 +1,53 @@ +/* + * Copyright Red Hat Inc., 2012 + * + * Author: Jan Safranek + * + * 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 +#include + +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 index 00000000..8e840c1e --- /dev/null +++ b/samples/c/proctest.c @@ -0,0 +1,52 @@ +/* + * Copyright NEC Soft Ltd. 2009 + * + * Author: Ken'ichi Ohmichi + * + * 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 +#include +#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 index 00000000..0583039d --- /dev/null +++ b/samples/c/read_stats.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include + +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: \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 index 00000000..7afd3c8c --- /dev/null +++ b/samples/c/setuid.c @@ -0,0 +1,80 @@ +/* + * Copyright Red Hat Inc. 2008 + * + * Author: Steve Olivieri + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 \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 index 00000000..f357ab2f --- /dev/null +++ b/samples/c/test_functions.c @@ -0,0 +1,927 @@ +/* + * Copyright IBM Corporation. 2008 + * + * Author: Sudhir Kumar + * + * 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 index 00000000..934c8752 --- /dev/null +++ b/samples/c/test_named_hierarchy.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +/* + * 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 index 00000000..42ef32db --- /dev/null +++ b/samples/c/walk_task.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include + +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 index 00000000..f3112c5f --- /dev/null +++ b/samples/c/walk_test.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include +#include + +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: \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 index 00000000..257ece33 --- /dev/null +++ b/samples/c/wrapper_test.c @@ -0,0 +1,44 @@ +#include +#include +#include +#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; +}