]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
Dhaval's API changes, phase 1, prototype
authorBalbir Singh <balbir@linux.vnet.ibm.com>
Sat, 5 Apr 2008 13:33:32 +0000 (13:33 +0000)
committerBalbir Singh <balbir@linux.vnet.ibm.com>
Sat, 5 Apr 2008 13:33:32 +0000 (13:33 +0000)
git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/trunk@4 4f4bb910-9a46-0410-90c8-c897d4f1cd53

Makefile
api.c [new file with mode: 0644]
libcg.h

index a8ad7a18ef3eacfd33a2fbb7da3a03791e95ce2f..686396e32ffc51f53b0eab2ffe06afe6b6c79e44 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,12 +14,13 @@ YACC_DEBUG=-t
 DEBUG=-DDEBUG
 INC=-I.
 CFLAGS=-g -O2 -Wextra $(DEBUG)  $(INC) 
-LIBS= 
+LIBS= -lcg
+LDFLAGS= -L .
 
-all: cgconfig
+all: cgconfig libcg.so
 
-cgconfig: config.c y.tab.c lex.yy.c libcg.h file-ops.c
-       $(CC) $(CFLAGS) -o $@ y.tab.c lex.yy.c config.c file-ops.c $(LIBS)
+cgconfig: libcg.so config.c y.tab.c lex.yy.c libcg.h file-ops.c
+       $(CXX) $(CFLAGS) -o $@ y.tab.c lex.yy.c config.c file-ops.c $(LDFLAGS) $(LIBS)
 
 y.tab.c: parse.y lex.yy.c
        byacc -v -d parse.y
@@ -27,5 +28,8 @@ y.tab.c: parse.y lex.yy.c
 lex.yy.c: lex.l
        flex lex.l
 
+libcg.so: api.c libcg.h
+       $(CXX) $(CFLAGS) -shared -fPIC -o $@ api.c
+
 clean:
-       \rm -f y.tab.c y.tab.h lex.yy.c y.output cgconfig
+       \rm -f y.tab.c y.tab.h lex.yy.c y.output cgconfig libcg.so
diff --git a/api.c b/api.c
new file mode 100644 (file)
index 0000000..f842040
--- /dev/null
+++ b/api.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright IBM Corporation. 2007
+ *
+ * Author:     Dhaval Giani <dhaval@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.
+ *
+ * TODOs:
+ *     1. Convert comments to Docbook style.
+ *     2. Add more APIs for the control groups.
+ *     3. Handle the configuration related APIs.
+ *     4. Error handling.
+ *
+ * Code initiated and designed by Dhaval Giani. All faults are most likely
+ * his mistake.
+ */
+
+#include <errno.h>
+#include <libcg.h>
+#include <mntent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+static char MOUNT_POINT[FILENAME_MAX];
+
+int cg_init()
+{
+       FILE *proc_mount;
+       struct mntent *ent;
+
+       proc_mount = fopen("/proc/mounts", "r");
+       ent = getmntent(proc_mount);
+
+       while (strcmp(ent->mnt_fsname,"cgroup") != 0) {
+               ent = getmntent(proc_mount);
+               if (ent == NULL)
+                       return ECGROUPNOTMOUNTED;
+       }
+       strcpy(MOUNT_POINT, ent->mnt_dir);
+       return 0;
+}
+
+static int cg_test_mounted_fs()
+{
+       FILE *proc_mount;
+       struct mntent *ent;
+
+       proc_mount = fopen("/proc/mounts", "r");
+       if (proc_mount == NULL) {
+               return -1;
+       }
+       ent = getmntent(proc_mount);
+
+       while (strcmp(ent->mnt_fsname, "cgroup") !=0) {
+               ent = getmntent(proc_mount);
+               if (ent == NULL)
+                       return 0;
+       }
+       return 1;
+}
+
+static inline pid_t cg_gettid()
+{
+       return syscall(__NR_gettid);
+}
+
+/*
+ */
+int cg_attach_task_pid(char *cgroup, pid_t tid)
+{
+       char path[FILENAME_MAX];
+       FILE *tasks;
+
+       if (cgroup == NULL) {
+               cgroup = (char *) malloc(sizeof(char));
+               cgroup = "\0";
+       }
+
+       strcpy(path, MOUNT_POINT);
+       strcat(path, "/");
+       strcat(path, cgroup);
+       strcat(path, "/tasks");
+
+       tasks = fopen(path, "w");
+       if (!tasks) {
+               switch (errno) {
+               case EPERM:
+                       return ECGROUPNOTOWNER;
+               default:
+                       return ECGROUPNOTALLOWED;
+               }
+       }
+       fprintf(tasks, "%d", tid);
+
+       return 0;
+
+}
+
+/*
+ * Used to attach the task to a control group.
+ *
+ * WARNING: Will change to use struct cgroup when it is implemented.
+ */
+int cg_attach_task(char *cgroup)
+{
+       pid_t tid = cg_gettid();
+       int error;
+
+       error = cg_attach_task_pid(cgroup, tid);
+
+       return error;
+}
+
+/*
+ * create_control_group()
+ * This is the basic function used to create the control group. This function
+ * just makes the group. It does not set any permissions, or any control values.
+ * The argument path is the fully qualified path name to make it generic.
+ */
+static int cg_create_control_group(char *path)
+{
+       int error;
+       if (!cg_test_mounted_fs())
+               return ECGROUPNOTMOUNTED;
+       error = mkdir(path, 0700);
+       if (!error) {
+               switch(errno) {
+               case EPERM:
+                       return ECGROUPNOTOWNER;
+               default:
+                       return ECGROUPNOTALLOWED;
+               }
+       }
+       return error;
+}
+
+/*
+ * set_control_value()
+ * This is the low level function for putting in a value in a control file.
+ * This function takes in the complete path and sets the value in val in that
+ * file.
+ *
+ * TODO:
+ * At this point I am not sure what all values the control file can take. So
+ * I put in an int arg. But this has to be made much more robust.
+ */
+static int cg_set_control_value(char *path, char *val)
+{
+       int error;
+       FILE *control_file;
+       if (!cg_test_mounted_fs())
+               return ECGROUPNOTMOUNTED;
+
+       control_file = fopen(path, "a");
+
+       if (!control_file) {
+               if (errno == EPERM) {
+                       /*
+                        * We need to set the correct error value, does the
+                        * group exist but we don't have the subsystem
+                        * mounted at that point, or is it that the group
+                        * does not exist. So we check if the tasks file
+                        * exist. Before that, we need to extract the path.
+                        */
+                       int len = strlen(path);
+
+                       while (*(path+len) != '/')
+                               len--;
+                       *(path+len+1) = '\0';
+                       strcat(path, "tasks");
+                       control_file = fopen(path, "r");
+                       if (!control_file) {
+                               if (errno == ENOENT)
+                                       return ECGROUPSUBSYSNOTMOUNTED;
+                       }
+                       return ECGROUPNOTALLOWED;
+               }
+       }
+
+       fprintf(control_file, "%s", val);
+       return 0;
+}
+
+/*
+ * WARNING: This API is not final. It WILL change format to use
+ * struct cgroup. This API will then become internal and be called something
+ * else.
+ *
+ * I am still not happy with how the data structure is looking at the moment,
+ * plus there are a couple of additional details to be worked out. Please
+ * do not rely on this API.
+ *
+ * Be prepared to change the implementation later once it shifts to
+ * struct cgroup in the real alpha release.
+ *
+ * The final version is expected to be
+ *
+ * int modify_cgroup(struct cgroup *original, struct cgroup *final);
+ *
+ * where original is the cgroup which is to be modified and final is how it
+ * should look.
+ *
+ * Also this version is still at one level since we do not have
+ * multi-hierarchy support in kernel. The real alpha release should have this
+ * issue sorted out as well.
+ */
+
+int cg_modify_cgroup(char *cgroup, struct control_value *values[], int n)
+{
+       char path[FILENAME_MAX], base[FILENAME_MAX];
+       int i;
+       int error;
+
+       strcpy(base, MOUNT_POINT);
+       strcat(base, "/");
+       strcat(base, cgroup);
+       strcat(base, "/");
+
+       for (i = 0; i < n; i++, strcpy(path, base)) {
+               strcat(path, values[i]->name);
+               error = cg_set_control_value(path, values[i]->value);
+               if (error)
+                       goto err;
+       }
+       return 0;
+err:
+       return error;
+
+}
+
+/*
+ * WARNING: This API is not final. It WILL change format to use
+ * struct cgroup. This API will then become internal and be called something
+ * else.
+ *
+ * I am still not happy with how the data structure is looking at the moment,
+ * plus there are a couple of additional details to be worked out. Please
+ * do not rely on this API.
+ *
+ * Be prepared to change the implementation later once it shifts to
+ * struct cgroup in the real alpha release.
+ *
+ * The final version is expected to be
+ *
+ * int create_cgroup(struct cgroup *group);
+ *
+ * where group is the group to be created
+ *
+ * Also this version is still at one level since we do not have
+ * multi-hierarchy support in kernel. The real alpha release should have this
+ * issue sorted out as well.
+ */
+int cg_create_cgroup(char *cgroup, struct control_value *values[], int n)
+{
+       char path[FILENAME_MAX], base[FILENAME_MAX];
+       int i;
+       int error;
+
+       if (MOUNT_POINT == NULL)
+               return ECGROUPNOTMOUNTED;
+
+       strcpy(path, MOUNT_POINT);
+       strcat(path, "/");
+       strcat(path, cgroup);
+
+       error = cg_create_control_group(path);
+       strcat(path, "/");
+       strcpy(base, path);
+
+       for (i = 0; i < n; i++, strcpy(path, base)) {
+               strcat(path, values[i]->name);
+               error = cg_set_control_value(path, values[i]->value);
+               if (!error)
+                       return error;
+       }
+       return error;
+}
+
+/*
+ * WARNING: This API is not final. It WILL change format to use
+ * struct cgroup. This API will then become internal and be called something
+ * else.
+ *
+ * I am still not happy with how the data structure is looking at the moment,
+ * plus there are a couple of additional details to be worked out. Please
+ * do not rely on this API.
+ *
+ * Be prepared to change the implementation later once it shifts to
+ * struct cgroup in the real alpha release.
+ *
+ * The final version is expected to be
+ *
+ * int delete_cgroup(struct cgroup *group);
+ *
+ * where group is the group to be deleted.
+ *
+ * Also this version is still at one level since we do not have
+ * multi-hierarchy support in kernel. The real alpha release should have this
+ * issue sorted out as well.
+ */
+int cg_delete_cgroup(char *cgroup)
+{
+       FILE *delete_tasks, *base_tasks;
+       int tids;
+       char path[FILENAME_MAX];
+       int error;
+
+       strcpy(path, MOUNT_POINT);
+       strcat(path,"/tasks");
+
+       base_tasks = fopen(path, "w");
+
+       strcpy(path, MOUNT_POINT);
+       strcat(path, "/");
+       strcat(path, cgroup);
+       strcat(path,"/tasks");
+
+       delete_tasks = fopen(path, "r");
+
+       while (!feof(delete_tasks)) {
+               fscanf(delete_tasks, "%d", &tids);
+               fprintf(base_tasks, "%d", tids);
+       }
+
+       strcpy(path, MOUNT_POINT);
+       strcat(path, "/");
+       strcat(path, cgroup);
+
+       error = rmdir(path);
+
+       if (!error) {
+                       return ECGROUPNOTALLOWED;
+               }
+
+       return error;
+}
diff --git a/libcg.h b/libcg.h
index 8fcda813db784eaf0ddae139c71089cbf1006b07..91496cad6cfebaf5277cf344f6cb0a0e2b647260 100644 (file)
--- a/libcg.h
+++ b/libcg.h
 #ifndef _LIBCG_H
 #define _LIBCG_H
 
+#include <features.h>
+
+__BEGIN_DECLS
+
 #include <grp.h>
+#include <stdio.h>
 #include <sys/stat.h>
 
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
+
+#ifndef __USE_GNU
 #define __USE_GNU
+#endif
 
 /* Maximum number of mount points/controllers */
 #define MAX_MNT_ELEMENTS       8
@@ -92,6 +102,16 @@ enum cg_msg_type {
        CG_MSG_DONE,
 };
 
+enum cg_errors {
+       ECGROUPNOTCOMPILED=50000,
+       ECGROUPNOTMOUNTED,
+       ECGROUPNOTEXIST,
+       ECGROUPNOTCREATED,
+       ECGROUPSUBSYSNOTMOUNTED,
+       ECGROUPNOTOWNER,
+       ECGROUPNOTALLOWED, // This is the stock error. Default error.
+};
+
 #define CG_MAX_MSG_SIZE                256
 #define CG_SERVER_MSG_PATH     "/tmp/control_group"
 #define CG_BACKLOG             5
@@ -118,4 +138,19 @@ int cg_mount_controllers(void);
 int cg_unmount_controllers(void);
 int cg_load_config(const char *pathname);
 void cg_unload_current_config(void);
+
+/* Functions and structures that can be used by the application*/
+struct control_value {
+       char name[FILENAME_MAX];
+       char *value;
+};
+
+int cg_init(void);
+int cg_attach_task(char *cgroup);
+int cg_modify_cgroup(char *cgroup, struct control_value *values[], int n);
+int cg_create_cgroup(char *cgroup, struct control_value *values[], int n);
+int cg_delete_cgroup(char *cgroup);
+
+__END_DECLS
+
 #endif /* _LIBCG_H  */