[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

memstat-0.9 hurd patch (PATH_MAX)



Dear Hurd developers,

Here is my first attempt to fix a PATH_MAX related FTBFS. So please, be indulgent!

1) Why memstat?
Because of PATH_MAX, I though would be easy to fix. Also because the source code was relatively small.
This package maybe useless but I needed something to start with...

2) Parts to fix
 a) use of PATH_MAX to create a char[] to store a path 
 b) use of PATH_MAX to read line from a file (that contains 1 file path on each line) in a char[] buffer 
 c) use of readlink(str1, str2, PATH_MAX)

3) Fix...
 a) "piece of cake" (TM), but include <math.h> (for log10() function) to get an accurate length for the buffer... which may be an overhead!
 b) read file lines in a dynamically re-sized buffer
 c) use lstat as described in readlink man page

4) Results
The code build on Hurd. dpkg-buildpackage successful.

5) But...
 - memstat uses /proc/XYZ/exe and /proc/XYZ/maps... and the output of memstat on Hurd is different than the one on Linux
 - implement (copy/paste mostly) a get_line function. Might have been better to use the GNU get_line()... or not?!

Feel free to make comments on everything (code, decisions, style), I know that I still have a lot to learn! 

Hope to be more helpful in the future,
Tanguy
diff -Naur old/memstat-0.9/Makefile memstat-0.9/Makefile
--- old/memstat-0.9/Makefile	2012-01-20 13:22:55.000000000 +0000
+++ memstat-0.9/Makefile	2012-01-20 13:23:03.000000000 +0000
@@ -4,6 +4,7 @@
 # This file is under the GPL.
 #
 CFLAGS = -g -Wall -O2
+LDLIBS = -lm
 prefix = $(DESTDIR)/
 exec_prefix = $(prefix)/usr
 
diff -Naur old/memstat-0.9/memstat.c memstat-0.9/memstat.c
--- old/memstat-0.9/memstat.c	2012-01-20 13:22:55.000000000 +0000
+++ memstat-0.9/memstat.c	2012-01-20 13:23:09.000000000 +0000
@@ -19,6 +19,11 @@
 #include <unistd.h>
 #include <getopt.h>
 #include <errno.h>
+#include <math.h>
+
+#ifndef BUFSIZ
+#define BUFSIZ 1024
+#endif
 
 /* blacklist devices that just map physical memory */
 char *blacklist[] = { "/dev/mem",
@@ -58,11 +63,47 @@
     maptab_size = maptab_size * 2 + 100;
 }
 
+static int 
+intlen(int value)
+{
+    if (value == 0) { return 1; }
+    return log10(value) + 1;
+}
+
+static char * 
+get_line(FILE * f)
+{
+    size_t size = 0;
+    size_t len  = 0;
+    size_t last = 0;
+    char * buf  = NULL;
+
+    while (!feof(f))
+    {
+        size += BUFSIZ;
+        buf = realloc(buf, size);
+        if (fgets(buf+last,size,f) == NULL) 
+        {
+            free(buf);
+            return NULL;
+        }
+
+        len = strlen(buf);
+        last = len - 1;
+        
+        if (buf[last+1] != '\n') { return buf; }
+    }
+
+    return buf;
+}
+
 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;
+    int buff_size = 0;
     DIR *d;
     struct dirent *ent;
     FILE *f;
@@ -85,11 +126,22 @@
 	}
 	if (pid == 0 || (only_pid != 0 && pid != only_pid))
 	    continue;
+	
+	buff_size = 11; /* size of the format string without "%x" expressions */
+	buff_size += intlen(pid);
+	buff = (char *)malloc((buff_size + 1) * sizeof(char));
 	sprintf(buff, "/proc/%d/maps", pid);
 	f = fopen(buff, "r");
+	free(buff);
 	if (f == NULL)
 	    continue;
-	while (fgets(buff, sizeof(buff), f)) {
+	
+	/* Read the file line by line. */
+	while (!feof(f)) 
+	{
+        buff = get_line(f);
+        if (buff == NULL) { break; }
+        
 	    p = strchr(buff, '-');
 	    if (p)
 		*p = ' ';
@@ -97,11 +149,16 @@
 	    if (p)
 		*p = ' ';
 	    path = NULL;
-	    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);
 	    if (nread < 7) {
 		fprintf(stderr, "I don't recognize format of /proc/%d/maps. (nread=%d)\n", pid, nread);
+		fclose(f);
+		closedir(d);
 		exit(1);
 	    }
 	    if (maptab_fill == maptab_size)
@@ -121,13 +178,17 @@
 	    m->valid = 1;
 	    if ((nread == 8) && path && path[0]) {
 		int i;
-
 		m->path = path;
 		for (i = 0; i < sizeof(blacklist) / sizeof(blacklist[0]); i++) {
 		    if (!strncmp(path, blacklist[i], strlen(blacklist[i])))
 			m->valid = 0;
 		}
 	    } else {
+        buff_size = 4; /* size of the format string without "%x" expressions */
+    	buff_size += strlen(major);
+    	buff_size += strlen(minor);
+    	buff_size += intlen(inode);
+	    buff = (char *)malloc((buff_size + 1) * sizeof(char));
 		sprintf(buff, "[%s:%s]:%lu", major, minor, inode);
 		m->path = strdup(buff);
 		needinode = 1;
@@ -251,17 +312,42 @@
     grand = sharedgrand = 0;
     qsort(maptab_data, maptab_fill, sizeof(struct mapping), (qcmp) sort_by_pid);
     for (offs = 0; offs < maptab_fill; offs = scan) {
-	char linkname[PATH_MAX], filename[PATH_MAX];
+	char *linkname = NULL;
+	char *filename = NULL;
+    unsigned int filename_size = 0;
+    struct stat sb;
 	ssize_t len;
 	int deleted = 0;
 
 	pid = maptab_data[offs].pid;
+	filename_size = 10; /* size of the format string without "%x" expressions */
+	filename_size += intlen(pid);
+	filename = (char *)malloc((filename_size + 1) * sizeof(char));
 	sprintf(filename, "/proc/%d/exe", pid);
-	if ((len = readlink(filename, linkname, PATH_MAX)) == -1) {
+	
+	if (lstat(filename, &sb) == -1) {
+        perror("lstat");
+        exit(EXIT_FAILURE);
+    }
+    linkname = malloc(sb.st_size + 1);
+    if (linkname == NULL) {
+        fprintf(stderr, "insufficient memory\n");
+        exit(EXIT_FAILURE);
+    }
+    
+	len = readlink(filename, linkname, sb.st_size + 1);
+	free(filename);
+	
+	if (len < 0) {
+    	fprintf(stderr, "Cannot read link information for %s\n", filename);
+	    deleted = 1;
+	}	
+	if (len > sb.st_size) {
 	    fprintf(stderr, "Cannot read link information for %s\n", filename);
 	    deleted = 1;
-	}
-	linkname[len] = '\0';
+	}	
+	linkname[sb.st_size] = '\0';
+	
 	total = 0;
 	for (scan = offs; scan < maptab_fill; scan++) {
 	    m = maptab_data + scan;
@@ -277,6 +363,7 @@
 		printline(buffer);
 		grand += total;
 	}
+    free(linkname);
     }
 
     qsort(maptab_data, maptab_fill, sizeof(struct mapping), (qcmp) sort_by_inode);

Reply to: