Hi, This patch adds a new function cgroup_get_procname_from_procfs() for getting a process name.
This function allocates the memory for a process name, and writes the name to the memory, and returns the pointer of the memory. So a caller should free the memory if unusing it. The process name, which is wrotten by this function, depends on the specified process: If a command process) the full path of command. If a shell script process) the full path of shell script. If a kernel thread) the process name of kernel thread. Thanks Ken'ichi Ohmichi Signed-off-by: Ken'ichi Ohmichi <[email protected]> --- include/libcgroup.h | 12 +++++ src/api.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/libcgroup.map | 1 + 3 files changed, 142 insertions(+), 0 deletions(-) diff --git a/include/libcgroup.h b/include/libcgroup.h index 5272a45..5da5ed6 100644 --- a/include/libcgroup.h +++ b/include/libcgroup.h @@ -48,6 +48,8 @@ __BEGIN_DECLS * would require us to use a scanner/parser that can parse beyond ASCII */ +/* Task command name length */ +#define TASK_COMM_LEN 16 /* Maximum length of a line in the daemon config file */ #define CGROUP_RULE_MAXLINE (FILENAME_MAX + LOGIN_NAME_MAX + \ @@ -294,6 +296,16 @@ int cgroup_get_task_begin(char *cgroup, char *controller, void **handle, int cgroup_get_uid_gid_from_procfs(pid_t pid, uid_t *euid, gid_t *egid); /** + * Get a process name from /proc file system. + * This function allocates memory for a process name, writes a process + * name onto it, and returns the pointer. So a caller should free the + * memory when unusing it. If error internally, this function returns NULL. + * @param pid: The process id + * @return pointer to a process name, NULL on error. + */ +char *cgroup_get_procname_from_procfs(pid_t pid); + +/** * Read the next task value * @handle: The handle used for iterating * @pid: The variable where the value will be stored diff --git a/src/api.c b/src/api.c index c471532..d6a9122 100644 --- a/src/api.c +++ b/src/api.c @@ -2528,3 +2528,132 @@ int cgroup_get_uid_gid_from_procfs(pid_t pid, uid_t *euid, gid_t *egid) return 0; } +static char *cg_get_procname_from_proc_status(pid_t pid) +{ + FILE *f; + char path[FILENAME_MAX]; + char buf[4092]; + char *ret = NULL; + + sprintf(path, "/proc/%d/status", pid); + f = fopen(path, "r"); + if (!f) + return NULL; + + while (fgets(buf, sizeof(buf), f)) { + if (!strncmp(buf, "Name:", 5)) { + ret = strdup(buf + 6); + if (ret[strlen(ret) - 1] == '\n') + ret[strlen(ret) - 1] = '\0'; + break; + } + } + fclose(f); + return ret; +} + +static char *cg_get_procname_from_proc_cmdline(pid_t pid, char *pname_status) +{ + char *ret = NULL; + FILE *f; + int c; + char path[FILENAME_MAX]; + char buf_pname[FILENAME_MAX]; + char buf_cwd[FILENAME_MAX]; + + sprintf(path, "/proc/%d/cwd", pid); + if (readlink(path, buf_cwd, sizeof(buf_cwd)) < 0) + return NULL; + + sprintf(path, "/proc/%d/cmdline", pid); + f = fopen(path, "r"); + if (!f) + return NULL; + + memset(buf_pname, '\0', sizeof(buf_pname)); + while (1) { + c = fgetc(f); + if ((c != EOF) && (c != '\0')) { + buf_pname[strlen(buf_pname)] = c; + continue; + } + if (((strlen(basename(buf_pname)) < TASK_COMM_LEN - 1) + && !strcmp(pname_status, basename(buf_pname))) + || ((strlen(basename(buf_pname)) >= TASK_COMM_LEN - 1) + && !strncmp(pname_status, basename(buf_pname), + TASK_COMM_LEN - 1))) { + /* + * The taken process name from /proc/<pid>/status is + * shortened to 15 characters if it is over. So the + * name should be compared by its length. + */ + if (buf_pname[0] == '/') { + ret = strdup(buf_pname); + break; + } + if ((buf_pname[0] == '.') && (buf_pname[1] == '/')) { + strcat(buf_cwd, buf_pname + 1); + ret = strdup(buf_cwd); + break; + } + } + if (c == EOF) + break; + memset(buf_pname, '\0', sizeof(buf_pname)); + } + fclose(f); + return ret; +} + +char *cgroup_get_procname_from_procfs(pid_t pid) +{ + char *pname_status; + char *pname_cmdline; + char path[FILENAME_MAX]; + char buf[FILENAME_MAX]; + + pname_status = cg_get_procname_from_proc_status(pid); + if (!pname_status) + return NULL; + + /* + * Get the full patch of process name from /proc/<pid>/exe. + */ + sprintf(path, "/proc/%d/exe", pid); + if (readlink(path, buf, sizeof(buf)) < 0) { + /* + * readlink() fails if a kernel thread, and a process + * name is taken from /proc/<pid>/status. + */ + return pname_status; + } + if (((strlen(basename(buf)) < TASK_COMM_LEN - 1) + && !strcmp(pname_status, basename(buf))) + || ((strlen(basename(buf)) >= TASK_COMM_LEN - 1) + && !strncmp(pname_status, basename(buf), + TASK_COMM_LEN - 1))) { + + /* + * The taken process name from /proc/<pid>/status is + * shortened to 15 characters if it is over. So the + * name should be compared by its length. + */ + free(pname_status); + return strdup(buf); + } + + /* + * The above strncmp() is not 0 if a shell script, because + * /proc/<pid>/exe links a shell command (/bin/bash etc.) + * and the pname_status represents a shell script name. + * Then the full path of a shell script is taken from + * /proc/<pid>/cmdline. + */ + pname_cmdline = cg_get_procname_from_proc_cmdline(pid, pname_status); + if (pname_cmdline) { + free(pname_status); + return pname_cmdline; + } + return pname_status; +} + diff --git a/src/libcgroup.map b/src/libcgroup.map index e6f825a..10f74dc 100644 --- a/src/libcgroup.map +++ b/src/libcgroup.map @@ -63,4 +63,5 @@ global: cgroup_read_stats_next; cgroup_read_stats_end; cgroup_get_uid_gid_from_procfs; + cgroup_get_procname_from_procfs; } CGROUP_0.33; ------------------------------------------------------------------------------ OpenSolaris 2009.06 is a cutting edge operating system for enterprises looking to deploy the next generation of Solaris that includes the latest innovations from Sun and the OpenSource community. Download a copy and enjoy capabilities such as Networking, Storage and Virtualization. Go to: http://p.sf.net/sfu/opensolaris-get _______________________________________________ Libcg-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/libcg-devel
