Package: lphdisk
Version: 0.9-1.1

lphdisk fails to parse both /proc/mtrr and /proc/meminfo, at least in
2.6 kernels, leading to incorrect memory size estimates.

One problem seems to be that these proc files don't like being read a
bit at at time - reading all of them into a buffer, then scanning the
buffer seems to give better (i.e.  correct) results.

Another problem is that the program is simply expecting a different
format in these files - possibly an old 2.4 one. It doesn't work for
2.6.

Another problem is that the program, wrongly rounds up its results to a
power of two (after missing half the memory through misparsing). It's
quite possible to have 384MB of memory!

This patch adds two routines - one to read all of a file into a fixed
size buffer, stopping when the buffer is full, and another to read that
buffer a line at a time into a line-buffer, rather like fgets does.
(The original code's attempts to fscanf the proc files directly just
wasn't working on repeats of the fscanf).

That accounts for mtrr.  In addition, for reading meminfo, this patch
takes account that there are two different formats to scan, the 2.4
format and the 2.6 format meminfo files.

This patch takes out the useless rounding to a power of two, and just
adds 16MB to its calculated result, for good luck.

It adds slightly altered debugging messages to say which of the two
files was used to calculate the final result. It adds debugging on the
way through scanning the files contents too.


--- lphdisk-0.9/lphdisk.c       Thu Aug 23 23:10:48 2001
+++ lphdisk-0.9a/lphdisk.c      Fri Mar 24 00:52:50 2006
@@ -525,24 +536,80 @@
   return 0;
 }
 
+/*
+ * PTB read a line from @source chars into @buf, like fgets and gets
+ */
+char *sgets(char *buf, int n, char **source) {
+
+    int k = 0;
+
+    while (n-- > 1 && **source && **source != '\n')  {
+        buf[k++] = *(*source)++;
+    }
+    buf[k] = 0;
+    if (n < 1)
+        return buf;
+    if (!**source) {
+        if (k <= 0)
+            return NULL;
+        buf[k++] = '\n';
+        buf[k] = 0;
+        (*source)++;
+        return buf;
+    }
+    buf[k++] = *(*source)++;
+    buf[k] = 0;
+    return buf;
+}
+
+int sreadf(char *buf, int len, FILE *f) {
+
+  int n = len - 1, k = 0;
+
+  while (n > 0)  {
+      int m = fread( buf+k, 1, n, f);
+      if (m <= 0)
+          break;
+      n -= m;
+      k += m;
+  }
+  buf[k] = 0;
+  return k;
+}
+
 /* mtrr_physmem(): Use /proc/mtrr to attempt to determine the amount of   */
 /* physical RAM in the system.  Returns the size of RAM (in KB) indicated */
 /* by /proc/mtrr, or zero if it could not determine an appropriate value. */
 
 int mtrr_physmem(void) {
+
   FILE *f;
-  int base, size;
+  int base, size = 0;
+  char buf[1024];
+  int k;
+  char line[128];
+  char *ptr;
 
+  /* PTB read the whole of mtrr at once , as it doesn't like being reread */
   if (!(f = fopen(mtrr_filename, "r"))) {
     debug("Unable to open %s: %s\n", mtrr_filename, strerror(errno));
     return 0;
   }
-  if ((fscanf(f, "reg%*d: base=0x%*x (%dMB), size=%dMB", &base, &size) != 2) ||
-      (base != 0)) {
-    debug("Parse of %s failed.\n", mtrr_filename);
-    return 0;
-  }
+  k = sreadf(buf, sizeof(buf), f);
   fclose(f);
+  debug("Read total %d chars from %s\n", k, mtrr_filename);
+  
+  /* PTB now read each captured line and parse it */
+  ptr = buf;
+  while (sgets(line, sizeof(line), &ptr)) {
+      int s;
+      if ((sscanf(line, "reg%*o: base=%*x (%dMB), size=%dMB", &base, &s) < 2) 
|| s < 0) {
+        debug("Parse of %s:%s failed.\n", mtrr_filename, line);
+        continue;
+      }
+      debug("Parse of %s:%s succeeded.\n", mtrr_filename, line);
+      size += s;
+  }
 
   size *= 1024;
   debug("%s reports main RAM as %d KB\n", mtrr_filename, size);
@@ -555,28 +622,78 @@
 /* by /proc/meminfo, or zero if it could not determine an appropriate value. */
 
 int meminfo_physmem(void) {
+
   FILE *f;
   unsigned int size;
+  char buf[1024];
+  int k;
+  char line[128];
+  char *ptr;
   int ramsize;
+  char c;
 
   if (!(f = fopen(meminfo_filename, "r"))) {
     debug("Unable to open %s: %s\n", meminfo_filename, strerror(errno));
     return 0;
   }
-  fscanf(f, "%*[^\n]\n");             /* Read the header line and discard it */
- 
-  if (fscanf(f, "Mem: %u", &size) != 1) {
-    debug("Parse of %s failed.\n", meminfo_filename);
+  k = sreadf(buf, sizeof(buf), f);
+  fclose(f);
+  debug("Read total %d chars from %s\n", k, meminfo_filename);
+
+  ptr = buf;
+  /* Read the header line and discard it */
+  if (!sgets(line, sizeof(line), &ptr)) {
+    debug("Read of first line of %s failed.\n", meminfo_filename);
+    return 0;
+  }
+  debug("Read %s:%s OK.\n", meminfo_filename, line);
+
+  if (sscanf(line, " total%c used%c ", &c, &c) >= 2) {
+    /* PTB looks like 2.4 format meminfo */
+
+    /* PTB read the Mem line */
+    if (!sgets(line, sizeof(line), &ptr)) {
+      debug("Read of second line of %s failed.\n", meminfo_filename);
+      return 0;
+    }
+    debug("Read %s:%s OK.\n", meminfo_filename, line);
+    /* PTB scan the Mem line */
+    if (sscanf(line, "Mem: %u", &size) < 1) {
+      debug("Parse of %s:%s failed.\n", meminfo_filename, line);
+      return 0;
+    }
+    /* convert to KB */
+    size >>= 10;
+
+  } else if (sscanf(line, "MemTotal%c ", &c) >= 1) {
+    /* PTB looks like 2.6 format meminfo */
+
+    /* PTB read the MemTotal line */
+    if (sscanf(line, "MemTotal: %u kB ", &size) < 1) {
+      debug("Parse of %s:%s failed.\n", meminfo_filename, line);
+      return 0;
+    }
+  } else {
+    /* PTB neither 2.4 nor 2.6 */
+
+    debug("Parse of %s:%s failed.\n", meminfo_filename, line);
     return 0;
   }
-  fclose(f);
 
-  /* convert to KB and then round up to the next power of 2 (since RAM */
-  /* sizes don't come in anything else, so this should correct for the */
-  /* kernel size, etc)                                                 */
-  size >>= 10;
   debug("%s reports memory size of %d KB", meminfo_filename, size);
-  for (ramsize = 1; size; size >>= 1) ramsize <<= 1;
+
+  /* round up to the next power of 2 (since RAM 
+   * sizes don't come in anything else, so this should correct for the 
+   * kernel size, etc) 
+   *
+   * for (ramsize = 1; size; size >>= 1) ramsize <<= 1;
+   */
+
+  /* PTB FIXME! It's a wrong assumption that ram comes in powers of 2!
+   * One can have 512M + 256M, for example, which is not a power of 2.
+   * Instead, add 16MB for luck.
+   */
+   ramsize += 16 * 1024;
 
   debug(" (adjusted=%d)\n", ramsize);
 
@@ -609,10 +726,10 @@
   meminfo_size = meminfo_physmem();
 
   if (mtrr_size >= meminfo_size) {
-    debug("get_physmem: RAM size is %d KB\n", mtrr_size);
+    debug("get_physmem: RAM size is %d KB (mtrr)\n", mtrr_size);
     return mtrr_size;
   } else {
-    debug("get_physmem: RAM size is %d KB\n", meminfo_size);
+    debug("get_physmem: RAM size is %d KB (meminfo)\n", meminfo_size);
     return meminfo_size;
   }
 }
 

Peter


-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to