File indexing completed on 2024-12-22 04:17:23

0001 // Copyright (C) 1992-1998 by Michael K. Johnson, johnsonm@redhat.com
0002 // Copyright 1998-2003 Albert Cahalan <albert@users.sf.net>
0003 //
0004 // This file is placed under the conditions of the GNU Library
0005 // General Public License, version 2, or any later version.
0006 // See file COPYING for information on distribution conditions.
0007 //
0008 // File for parsing top-level /proc entities. 
0009 
0010 // This file is from the procps project at http://procps.sourceforge.net/
0011 
0012 #include <config.h>
0013 
0014 #include <stdio.h>
0015 #include <stdlib.h>
0016 #include <string.h>
0017 #include <ctype.h>
0018 #include <locale.h>
0019 
0020 #include <unistd.h>
0021 #include <fcntl.h>
0022 
0023 
0024 #define BAD_OPEN_MESSAGE                    \
0025 "Error: /proc must be mounted\n"                \
0026 "  To mount /proc at boot you need an /etc/fstab line like:\n"  \
0027 "      /proc   /proc   proc    defaults\n"          \
0028 "  In the meantime, mount /proc /proc -t proc\n"
0029 
0030 #define MEMINFO_FILE "/proc/meminfo"
0031 static int meminfo_fd = -1;
0032 
0033 static char buf[1024];
0034 
0035 /* This macro opens filename only if necessary and seeks to 0 so
0036  * that successive calls to the functions are more efficient.
0037  * It also reads the current contents of the file into the global buf.
0038  */
0039 #define FILE_TO_BUF(filename, fd) do{               \
0040     static int local_n;                     \
0041     if (fd == -1 && (fd = open(filename, O_RDONLY)) == -1) {    \
0042     fprintf(stderr, BAD_OPEN_MESSAGE);          \
0043     fflush(NULL);                       \
0044     _exit(102);                     \
0045     }                               \
0046     lseek(fd, 0L, SEEK_SET);                    \
0047     if ((local_n = read(fd, buf, sizeof buf - 1)) < 0) {    \
0048     perror(filename);                   \
0049     fflush(NULL);                       \
0050     _exit(103);                     \
0051     }                               \
0052     buf[local_n] = '\0';                    \
0053 }while(0)
0054 
0055 /* evals 'x' twice */
0056 #define SET_IF_DESIRED(x,y) do{  if(x) *(x) = (y); }while(0)
0057 
0058 /***********************************************************************/
0059 /*
0060  * Copyright 1999 by Albert Cahalan; all rights reserved.
0061  * This file may be used subject to the terms and conditions of the
0062  * GNU Library General Public License Version 2, or any later version
0063  * at your option, as published by the Free Software Foundation.
0064  * This program is distributed in the hope that it will be useful,
0065  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0066  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0067  * GNU Library General Public License for more details.
0068  */
0069 
0070 typedef struct mem_table_struct {
0071   const char *name;     /* memory type name */
0072   unsigned long *slot; /* slot in return struct */
0073 } mem_table_struct;
0074 
0075 static int compare_mem_table_structs(const void *a, const void *b){
0076   return strcmp(((const mem_table_struct*)a)->name,((const mem_table_struct*)b)->name);
0077 }
0078 
0079 /* example data, following junk, with comments added:
0080  *
0081  * MemTotal:        61768 kB    old
0082  * MemFree:          1436 kB    old
0083  * MemShared:           0 kB    old (now always zero; not calculated)
0084  * Buffers:          1312 kB    old
0085  * Cached:          20932 kB    old
0086  * Active:          12464 kB    new
0087  * Inact_dirty:      7772 kB    new
0088  * Inact_clean:      2008 kB    new
0089  * Inact_target:        0 kB    new
0090  * Inact_laundry:       0 kB    new, and might be missing too
0091  * HighTotal:           0 kB
0092  * HighFree:            0 kB
0093  * LowTotal:        61768 kB
0094  * LowFree:          1436 kB
0095  * SwapTotal:      122580 kB    old
0096  * SwapFree:        60352 kB    old
0097  * Inactive:        20420 kB    2.5.41+
0098  * Dirty:               0 kB    2.5.41+
0099  * Writeback:           0 kB    2.5.41+
0100  * Mapped:           9792 kB    2.5.41+
0101  * Slab:             4564 kB    2.5.41+
0102  * Committed_AS:     8440 kB    2.5.41+
0103  * PageTables:        304 kB    2.5.41+
0104  * ReverseMaps:      5738       2.5.41+
0105  * SwapCached:          0 kB    2.5.??+
0106  * HugePages_Total:   220       2.5.??+
0107  * HugePages_Free:    138       2.5.??+
0108  * Hugepagesize:     4096 kB    2.5.??+
0109  */
0110 
0111 /* obsolete */
0112 unsigned long kb_main_shared;
0113 /* old but still kicking -- the important stuff */
0114 unsigned long kb_main_buffers;
0115 unsigned long kb_main_cached;
0116 unsigned long kb_main_free;
0117 unsigned long kb_main_total;
0118 unsigned long kb_swap_free;
0119 unsigned long kb_swap_total;
0120 /* recently introduced */
0121 unsigned long kb_high_free;
0122 unsigned long kb_high_total;
0123 unsigned long kb_low_free;
0124 unsigned long kb_low_total;
0125 /* 2.4.xx era */
0126 unsigned long kb_active;
0127 unsigned long kb_inact_laundry;
0128 unsigned long kb_inact_dirty;
0129 unsigned long kb_inact_clean;
0130 unsigned long kb_inact_target;
0131 unsigned long kb_swap_cached;  /* late 2.4 only */
0132 /* derived values */
0133 unsigned long kb_swap_used;
0134 unsigned long kb_main_used;
0135 /* 2.5.41+ */
0136 unsigned long kb_writeback;
0137 unsigned long kb_slab;
0138 unsigned long nr_reversemaps;
0139 unsigned long kb_committed_as;
0140 unsigned long kb_dirty;
0141 unsigned long kb_inactive;
0142 unsigned long kb_mapped;
0143 unsigned long kb_pagetables;
0144 
0145 void meminfo(void){
0146   char namebuf[16]; /* big enough to hold any row name */
0147   mem_table_struct findme = { namebuf, NULL};
0148   mem_table_struct *found;
0149   char *head;
0150   char *tail;
0151   static const mem_table_struct mem_table[] = {
0152   {"Active",       &kb_active},       
0153   {"Buffers",      &kb_main_buffers}, 
0154   {"Cached",       &kb_main_cached}, 
0155   {"Committed_AS", &kb_committed_as},
0156   {"Dirty",        &kb_dirty},
0157   {"HighFree",     &kb_high_free},
0158   {"HighTotal",    &kb_high_total},
0159   {"Inact_clean",  &kb_inact_clean},
0160   {"Inact_dirty",  &kb_inact_dirty},
0161   {"Inact_laundry",&kb_inact_laundry},
0162   {"Inact_target", &kb_inact_target},
0163   {"Inactive",     &kb_inactive},
0164   {"LowFree",      &kb_low_free},
0165   {"LowTotal",     &kb_low_total},
0166   {"Mapped",       &kb_mapped},
0167   {"MemFree",      &kb_main_free},
0168   {"MemShared",    &kb_main_shared},
0169   {"MemTotal",     &kb_main_total},
0170   {"PageTables",   &kb_pagetables},
0171   {"ReverseMaps",  &nr_reversemaps},
0172   {"Slab",         &kb_slab},
0173   {"SwapCached",   &kb_swap_cached},
0174   {"SwapFree",     &kb_swap_free},
0175   {"SwapTotal",    &kb_swap_total},
0176   {"Writeback",    &kb_writeback},
0177   };
0178   const int mem_table_count = sizeof(mem_table)/sizeof(mem_table_struct);
0179 
0180   FILE_TO_BUF(MEMINFO_FILE,meminfo_fd);
0181 
0182   kb_inactive = ~0UL;
0183 
0184   head = buf;
0185   for(;;){
0186     tail = strchr(head, ':');
0187     if(!tail) break;
0188     *tail = '\0';
0189     if(strlen(head) >= sizeof(namebuf)){
0190       head = tail+1;
0191       goto nextline;
0192     }
0193     strcpy(namebuf,head);
0194     found = bsearch(&findme, mem_table, mem_table_count,
0195         sizeof(mem_table_struct), compare_mem_table_structs
0196     );
0197     head = tail+1;
0198     if(!found) goto nextline;
0199     *(found->slot) = strtoul(head,&tail,10);
0200 nextline:
0201     tail = strchr(head, '\n');
0202     if(!tail) break;
0203     head = tail+1;
0204   }
0205   if(!kb_low_total){  /* low==main except with large-memory support */
0206     kb_low_total = kb_main_total;
0207     kb_low_free  = kb_main_free;
0208   }
0209   if(kb_inactive==~0UL){
0210     kb_inactive = kb_inact_dirty + kb_inact_clean + kb_inact_laundry;
0211   }
0212   kb_swap_used = kb_swap_total - kb_swap_free;
0213   kb_main_used = kb_main_total - kb_main_free;
0214 }