summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBalbir Singh <balbir@linux.vnet.ibm.com>2009-02-16 13:34:12 +0000
committerBalbir Singh <balbir@linux.vnet.ibm.com>2009-02-16 13:34:12 +0000
commitdedcfa480ee21b9bb87964eb1e2665fe6a200b4c (patch)
tree61e4516a1f28071d8cb6604f8adb330eb598d3a0
parentb4ca5d9b4a38994aa71fbdb14fd5d65c81bf5216 (diff)
downloadlibcg-dedcfa480ee21b9bb87964eb1e2665fe6a200b4c.tar.gz
libcg-dedcfa480ee21b9bb87964eb1e2665fe6a200b4c.tar.xz
libcg-dedcfa480ee21b9bb87964eb1e2665fe6a200b4c.zip
This patch store the last errno value to last_errno value and add
cgroup_add_last_errno procedure to show this number. Use this procedure to show the cause of the error when ECGOTHER is returned. [balbir@linux.vnet.ibm.com: fix last_errno in config.c] Signed-off-by: Ivana Varekova <varekova@redhat.com> Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com> git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/trunk@329 4f4bb910-9a46-0410-90c8-c897d4f1cd53
-rw-r--r--api.c70
-rw-r--r--cgclassify.c3
-rw-r--r--cgconfig.c2
-rw-r--r--config.c12
-rw-r--r--libcgroup.h13
-rw-r--r--libcgroup.map6
6 files changed, 92 insertions, 14 deletions
diff --git a/api.c b/api.c
index 647841f..72f8c69 100644
--- a/api.c
+++ b/api.c
@@ -49,6 +49,16 @@
#define VERSION(ver) #ver
/*
+ * The errno which happend the last time (have to be thread specific)
+ */
+__thread int last_errno;
+
+#define MAXLEN 256
+
+/* the value have to be thread specific */
+__thread char errtext[MAXLEN];
+
+/*
* Remember to bump this up for major API changes.
*/
const static char cg_version[] = VERSION(PACKAGE_VERSION);
@@ -94,6 +104,7 @@ char *cgroup_strerror_codes[] = {
"Cgroup parsing failed",
"Cgroup, rules file does not exist",
"Cgroup mounting failed",
+ "The config file can not be opend",
};
static int cg_chown_file(FTS *fts, FTSENT *ent, uid_t owner, gid_t group)
@@ -294,14 +305,15 @@ static int cgroup_parse_rules(bool cache, uid_t muid, gid_t mgid)
dbg("Failed to open configuration file %s with"
" error: %s\n", CGRULES_CONF_FILE,
strerror(errno));
- ret = errno;
+ last_errno = errno;
goto finish;
}
buff = calloc(CGROUP_RULE_MAXLINE, sizeof(char));
if (!buff) {
dbg("Out of memory? Error: %s\n", strerror(errno));
- ret = errno;
+ last_errno = errno;
+ ret = ECGOTHER;
goto close_unlock;
}
@@ -442,7 +454,8 @@ static int cgroup_parse_rules(bool cache, uid_t muid, gid_t mgid)
newrule = calloc(1, sizeof(struct cgroup_rule));
if (!newrule) {
dbg("Out of memory? Error: %s\n", strerror(errno));
- ret = errno;
+ last_errno = errno;
+ ret = ECGOTHER;
goto cleanup;
}
@@ -565,6 +578,7 @@ int cgroup_init()
*/
buf = malloc(FILENAME_MAX);
if (!buf) {
+ last_errno = errno;
ret = ECGOTHER;
goto unlock_exit;
}
@@ -777,11 +791,13 @@ int cgroup_attach_task_pid(struct cgroup *cgroup, pid_t tid)
dbg("Error writing tid %d to %s:%s\n",
tid, path, strerror(errno));
fclose(tasks);
+ last_errno = errno;
return ECGOTHER;
}
ret = fflush(tasks);
if (ret) {
+ last_errno = errno;
dbg("Error writing tid %d to %s:%s\n",
tid, path, strerror(errno));
fclose(tasks);
@@ -822,6 +838,7 @@ int cgroup_attach_task_pid(struct cgroup *cgroup, pid_t tid)
}
ret = fprintf(tasks, "%d", tid);
if (ret < 0) {
+ last_errno = errno;
dbg("Error writing tid %d to %s:%s\n",
tid, path, strerror(errno));
fclose(tasks);
@@ -829,6 +846,7 @@ int cgroup_attach_task_pid(struct cgroup *cgroup, pid_t tid)
}
ret = fflush(tasks);
if (ret) {
+ last_errno = errno;
dbg("Error writing tid %d to %s:%s\n",
tid, path, strerror(errno));
fclose(tasks);
@@ -872,12 +890,16 @@ static int cg_mkdir_p(const char *path)
buf = getcwd(cwd, FILENAME_MAX);
- if (!buf)
+ if (!buf) {
+ last_errno = errno;
return ECGOTHER;
+ }
real_path = strdup(path);
- if (!real_path)
+ if (!real_path) {
+ last_errno = errno;
return ECGOTHER;
+ }
do {
while (real_path[j] != '\0' && real_path[j] != '/')
@@ -892,6 +914,7 @@ static int cg_mkdir_p(const char *path)
ret = mkdir(str, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
wd = strdup(str);
if (!wd) {
+ last_errno = errno;
ret = ECGOTHER;
break;
}
@@ -1030,6 +1053,7 @@ int cgroup_modify_cgroup(struct cgroup *cgroup)
ret = asprintf(&path, "%s%s", base,
cgroup->controller[i]->values[j]->name);
if (ret < 0) {
+ last_errno = errno;
error = ECGOTHER;
goto err;
}
@@ -1175,6 +1199,7 @@ int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership)
base = strdup(path);
if (!base) {
+ last_errno = errno;
error = ECGOTHER;
goto err;
}
@@ -1191,6 +1216,7 @@ int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership)
ret = asprintf(&path, "%s%s", base,
cgroup->controller[k]->values[j]->name);
if (ret < 0) {
+ last_errno = errno;
error = ECGOTHER;
goto err;
}
@@ -1215,12 +1241,14 @@ int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership)
free(path);
ret = asprintf(&path, "%s/tasks", base);
if (ret < 0) {
+ last_errno = errno;
error = ECGOTHER;
goto err;
}
error = chown(path, cgroup->tasks_uid,
cgroup->tasks_gid);
if (error) {
+ last_errno = errno;
error = ECGOTHER;
goto err;
}
@@ -1403,6 +1431,7 @@ int cgroup_delete_cgroup(struct cgroup *cgroup, int ignore_migration)
cgroup->controller[i]->name))
continue;
error = rmdir(path);
+ last_errno = errno;
}
open_err:
if (ignore_migration) {
@@ -1411,8 +1440,10 @@ open_err:
cgroup->controller[i]->name))
continue;
error = rmdir(path);
- if (error < 0 && errno == ENOENT)
+ if (error < 0 && errno == ENOENT) {
+ last_errno = errno;
error = 0;
+ }
}
}
if (error)
@@ -1441,8 +1472,10 @@ static int cg_rd_ctrl_file(char *subsys, char *cgroup, char *file, char **value)
return ECGROUPVALUENOTEXIST;
*value = malloc(CG_VALUE_MAX);
- if (!*value)
+ if (!*value) {
+ last_errno = errno;
return ECGOTHER;
+ }
/*
* using %as crashes when we try to read from files like
@@ -1596,11 +1629,13 @@ int cgroup_get_cgroup(struct cgroup *cgroup)
ret = asprintf(&control_path, "%s/tasks", path);
if (ret < 0) {
+ last_errno = errno;
error = ECGOTHER;
goto unlock_error;
}
if (stat(control_path, &stat_buffer)) {
+ last_errno = errno;
free(control_path);
error = ECGOTHER;
goto unlock_error;
@@ -1620,6 +1655,7 @@ int cgroup_get_cgroup(struct cgroup *cgroup)
dir = opendir(path);
if (!dir) {
+ last_errno = errno;
error = ECGOTHER;
goto unlock_error;
}
@@ -1739,8 +1775,10 @@ static int cg_prepare_controller_array(char *cstr, char *controllers[])
if (temp) {
controllers[j] = strdup(temp);
- if (!controllers[j])
+ if (!controllers[j]) {
+ last_errno = errno;
return ECGOTHER;
+ }
}
j++;
} while (temp);
@@ -2137,6 +2175,7 @@ int cgroup_get_current_controller_path(pid_t pid, const char *controller,
*/
if (ret != 3 || ret == EOF) {
dbg("read failed for pid_cgroup_fd ret %d\n", ret);
+ last_errno = errno;
ret = ECGOTHER;
goto done;
}
@@ -2147,6 +2186,7 @@ int cgroup_get_current_controller_path(pid_t pid, const char *controller,
== 0) {
*current_path = strdup(cgroup_path);
if (!*current_path) {
+ last_errno = errno;
ret = ECGOTHER;
goto done;
}
@@ -2168,5 +2208,19 @@ cleanup_path:
char *cgroup_strerror(int code)
{
assert((code >= ECGROUPNOTCOMPILED) && (code < ECGSENTINEL));
+ if (code == ECGOTHER) {
+ snprintf(errtext, MAXLEN, "%s: error message: %s",
+ cgroup_strerror_codes[code % ECGROUPNOTCOMPILED],
+ strerror(cgroup_get_last_errno()));
+ return errtext;
+ }
return cgroup_strerror_codes[code % ECGROUPNOTCOMPILED];
}
+
+/**
+ * Return last errno, which caused ECGOTHER error.
+ */
+int cgroup_get_last_errno()
+{
+ return last_errno;
+}
diff --git a/cgclassify.c b/cgclassify.c
index c41f529..4f7adb4 100644
--- a/cgclassify.c
+++ b/cgclassify.c
@@ -140,7 +140,8 @@ int main(int argc, char *argv[])
ret = cgroup_change_cgroup_uid_gid(euid, egid, pid);
if (ret) {
fprintf(stderr, "Error: change of cgroup failed for"
- " pid %d\n", pid);
+ " pid %d: %s\n",
+ pid, cgroup_strerror(ret));
return ret;
}
}
diff --git a/cgconfig.c b/cgconfig.c
index 043678a..cc33ad9 100644
--- a/cgconfig.c
+++ b/cgconfig.c
@@ -60,7 +60,7 @@ int main(int argc, char *argv[])
ret = cgroup_config_load_config(filename);
if (ret) {
printf("Loading configuration file %s "
- "failed, error: %s\n", filename,
+ "failed\n%s\n", filename,
cgroup_strerror(ret));
exit(3);
}
diff --git a/config.c b/config.c
index 154ebad..95782f6 100644
--- a/config.c
+++ b/config.c
@@ -339,17 +339,22 @@ int cgroup_config_mount_fs()
struct cg_mount_table_s *curr = &(config_mount_table[i]);
ret = stat(curr->path, &buff);
-
- if (ret < 0 && errno != ENOENT)
+
+ if (ret < 0 && errno != ENOENT) {
+ last_errno = errno;
return ECGOTHER;
+ }
if (errno == ENOENT) {
ret = mkdir(curr->path,
S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
- if (ret < 0)
+ if (ret < 0) {
+ last_errno = errno;
return ECGOTHER;
+ }
} else if (!S_ISDIR(buff.st_mode)) {
errno = ENOTDIR;
+ last_errno = errno;
return ECGOTHER;
}
@@ -432,6 +437,7 @@ int cgroup_config_load_config(const char *pathname)
if (!yyin) {
dbg("Failed to open file %s\n", pathname);
+ last_errno = errno;
return ECGOTHER;
}
diff --git a/libcgroup.h b/libcgroup.h
index 37bc888..dee4648 100644
--- a/libcgroup.h
+++ b/libcgroup.h
@@ -68,6 +68,11 @@ enum cgflags {
CGFLAG_USECACHE = 0x01,
};
+/**
+ * per thread errno variable, to be used when return code is ECGOTHER
+ */
+extern __thread int last_errno;
+
enum cgroup_errors {
ECGROUPNOTCOMPILED=50000,
ECGROUPNOTMOUNTED,
@@ -88,7 +93,7 @@ enum cgroup_errors {
/* Represents error coming from other libraries like glibc. libcgroup
* users need to check errno upon encoutering ECGOTHER.
*/
- ECGOTHER,
+ ECGOTHER, /* OS error, see errno */
ECGROUPNOTEQUAL,
ECGCONTROLLERNOTEQUAL,
ECGROUPPARSEFAIL, /* Failed to parse rules configuration file. */
@@ -195,6 +200,12 @@ int cgroup_get_current_controller_path(pid_t pid, const char *controller,
*/
char *cgroup_strerror(int code);
+/**
+ * Return last errno, which caused ECGOTHER error.
+ */
+int cgroup_get_last_errno();
+
+
/* The wrappers for filling libcg structures */
struct cgroup *cgroup_new_cgroup(const char *name);
diff --git a/libcgroup.map b/libcgroup.map
index 3b55ff2..fffe448 100644
--- a/libcgroup.map
+++ b/libcgroup.map
@@ -45,3 +45,9 @@ CGROUP_0.32.1 {
global:
cgroup_strerror;
} CGROUP_0.32;
+
+CGROUP_0.33 {
+global:
+ cgroup_get_last_errno;
+} CGROUP_0.32.1;
+