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: