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

Reply via email to