memstat

Lists all the processes, executables, and shared libraries that are using up virtual memory. It's helpful to see how the shared memory is used and which 'old' libs are loaded.
Home page: http://sourceforge.net/projects/memstattool


Log

  • Started: 2012-01-20
  • Discussed: 2012-01-21
  • Draft Submitted: 2012-01-25
  • Submitted: 2012-02-02, Bug#658384
  • Stopped: 2012-02-07, depends on /proc which is not yet totally implemented on the Hurd.
  • Accepted: -

ToDo

Here is the output of grep -R PATH_MAX memstat-0.9/*:

memstat.c:    char *p, major[8], minor[8], buff[PATH_MAX + 300], *path, perm[4];
memstat.c:    char linkname[PATH_MAX], filename[PATH_MAX];
memstat.c:    if ((len = readlink(filename, linkname, PATH_MAX)) == -1) {

Comments

Here are comments on the patch...

+#define FMT_PROC_MAPS "/proc/%d/maps"
+#define FMT_PROC_EXE  "/proc/%d/exe"

Define string formats.

 static void read_proc(void)
 {
     unsigned int nread, pid;
     unsigned long inode, lo, hi, offs;
-    char *p, major[8], minor[8], buff[PATH_MAX + 300], *path, perm[4];
+    char *p, major[8], minor[8], *path, perm[4];
+    char *buff = NULL;
+    size_t buff_size = 0;

In this function we turn buff into dynamically allocated string.

-   sprintf(buff, "/proc/%d/maps", pid);
-   f = fopen(buff, "r");
+   char filename[sizeof(FMT_PROC_MAPS) + (sizeof(int) * 3) + 1];
+   sprintf(filename, FMT_PROC_MAPS, pid);
+   f = fopen(filename, "r");

Compute the maximum size of filename using sizeof(int) * 3 as explainend in the porting guide.

-   while (fgets(buff, sizeof(buff), f)) {
+   while (!feof(f)) {
+       buff = get_line(f);
+       if (buff == NULL)
+       break;

Read a line from the file using get line().

-       if ((strlen(buff) == 10) && (strcmp(buff, " (deleted)") == 0))
+       if ((strlen(buff) == 10) && (strcmp(buff, " (deleted)") == 0)) {
+       free(buff);
        continue;
+       }
        nread = sscanf(buff, "%lx %lx %4s %lx %s %s %lu %as", &lo, &hi, perm, &offs, major, minor, &inode, &path);
+       free(buff);

Free the buff when it's not used anymore.

+       buff_size = 4; /* size of the format string without "%x" expressions */
+       buff_size += strlen(major);
+       buff_size += strlen(minor);
+       buff_size += sizeof(int) * 3 + 1; /* inode */
+       buff_size += 1; /* '\0' */
+       buff = malloc(buff_size);
+       if (buff == NULL) {
+           perror("Cannot allocate memory!");
+           exit(1);
+       }

Compute the size that the buff must have.

-   char linkname[PATH_MAX], filename[PATH_MAX];
-   ssize_t len;
+   char *linkname = NULL;
+   struct stat sb;
+   ssize_t len = -1;

In this function we turn linkname into dynamically allocated string. filename will be declared later.

-   sprintf(filename, "/proc/%d/exe", pid);
-   if ((len = readlink(filename, linkname, PATH_MAX)) == -1) {
+   char filename[sizeof(FMT_PROC_EXE) + (sizeof(int) * 3) + 1];
+   sprintf(filename, FMT_PROC_EXE, pid);

Same as above with FMT_PROC_MAPS.

+        char filename[sizeof(FMT_PROC_EXE) + (sizeof(int) * 3) + 1];
+        sprintf(filename, FMT_PROC_EXE, pid);
+        linkname = readlink_malloc(filename);
+        if (linkname == NULL) {

Use readlink_malloc() as explained in the porting guide because /proc/PID/exe doesn't work with readlink()

+   free(linkname);

Free dynamically allocated variable that is not used anymore.