Paul Mundt (lethal) writes:
authorEric Andersen <andersen@codepoet.org>
Sat, 11 Oct 2003 18:47:20 +0000 (18:47 -0000)
committerEric Andersen <andersen@codepoet.org>
Sat, 11 Oct 2003 18:47:20 +0000 (18:47 -0000)
Erik,

The format for /proc/meminfo has changed between 2.4 and 2.6, quite considerably.
In addition to the removal of the two-line summary that was present in 2.4,
MemShared was also removed. Presently (at least in busybox CVS HEAD), top fails
to parse this correctly and spews forth a:

top: failed to read 'meminfo'

message. This patch switches around some of the semantics a little to do sane
parsing for both 2.4 and 2.6. Also, in the event that the summary gets yanked
from 2.4, this patch will deal with that as well. With this patch, I'm able
to run top correctly on 2.6.0-test7 (tested on sh).

Please apply.

 procps/top.c |   60 +++++++++++++++++++++++++++++++++++++++++++++++------------
  1 files changed, 48 insertions(+), 12 deletions(-)

procps/top.c

index cee1b52c18e492d66725d65ec1042dbbf51323b4..9944598c280a461359e54b6388d38d190ab0ba91 100644 (file)
@@ -311,14 +311,47 @@ static unsigned long display_generic(void)
        char buf[80];
        float avg1, avg2, avg3;
        unsigned long total, used, mfree, shared, buffers, cached;
+       unsigned int needs_conversion = 1;
 
        /* read memory info */
        fp = bb_xfopen("meminfo", "r");
-       fgets(buf, sizeof(buf), fp);    /* skip first line */
 
-       if (fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu",
-                  &total, &used, &mfree, &shared, &buffers, &cached) != 6) {
-               bb_error_msg_and_die("failed to read '%s'", "meminfo");
+       /*
+        * Old kernels (such as 2.4.x) had a nice summary of memory info that
+        * we could parse, however this is gone entirely in 2.6. Try parsing
+        * the old way first, and if that fails, parse each field manually.
+        *
+        * First, we read in the first line. Old kernels will have bogus
+        * strings we don't care about, whereas new kernels will start right
+        * out with MemTotal:
+        *                              -- PFM.
+        */
+       if (fscanf(fp, "MemTotal: %lu %s\n", &total, buf) != 2) {
+               fgets(buf, sizeof(buf), fp);    /* skip first line */
+
+               fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu",
+                  &total, &used, &mfree, &shared, &buffers, &cached);
+       } else {
+               /* 
+                * Revert to manual parsing, which incidentally already has the
+                * sizes in kilobytes. This should be safe for both 2.4 and
+                * 2.6.
+                */
+               needs_conversion = 0;
+
+               fscanf(fp, "MemFree: %lu %s\n", &mfree, buf);
+
+               /* 
+                * MemShared: is no longer present in 2.6. Report this as 0,
+                * to maintain consistent behavior with normal procps.
+                */
+               if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2)
+                       shared = 0;
+
+               fscanf(fp, "Buffers: %lu %s\n", &buffers, buf);
+               fscanf(fp, "Cached: %lu %s\n", &cached, buf);
+
+               used = total - mfree;
        }
        fclose(fp);
        
@@ -329,13 +362,16 @@ static unsigned long display_generic(void)
        }
        fclose(fp);
 
-       /* convert to kilobytes */
-       used /= 1024;
-       mfree /= 1024;
-       shared /= 1024;
-       buffers /= 1024;
-       cached /= 1024;
-       
+       if (needs_conversion) {
+               /* convert to kilobytes */
+               used /= 1024;
+               mfree /= 1024;
+               shared /= 1024;
+               buffers /= 1024;
+               cached /= 1024;
+               total /= 1024;
+       }
+               
        /* output memory info and load average */
        /* clear screen & go to top */
        printf("\e[H\e[J" "Mem: "
@@ -344,7 +380,7 @@ static unsigned long display_generic(void)
        printf("Load average: %.2f, %.2f, %.2f    "
                        "(State: S=sleeping R=running, W=waiting)\n",
               avg1, avg2, avg3);
-       return total / 1024;
+       return total;
 }