/* * proc.c: * interface to process table entry in /proc * * Copyright (C) 1997, 1998 by Raju Mathur (raju@sgi.com) * * See file COPYING (included in this distribution) for copyright information. */ #include #include #include #include #include #include "common.h" /* * memory (in Kbytes) */ int sysmem = 0 , kernelmem = 0 , freemem = 0 , buffermem = 0 ; /* * Set values for various memory usages */ static void SetMemInfo ( void ) { struct stat s ; char buf [128] ; FILE *meminfo ; int totalmem ; const char *MemLine = "Mem:" ; const int MemLineLen = strlen ( MemLine ) ; /* * Cheap way to get amount of installed mem in the computer -- get size of * /proc/kcore. */ if ( stat ( "/proc/kcore" , &s ) < 0 ) { fprintf ( stderr , "%s: cannot stat /proc/kcore" , progname ) ; perror ( "" ) ; exit ( 1 ) ; } sysmem = s . st_size ; /* in Kilobytes */ /* * Read /proc/meminfo to get usable memory and buffers. Presumably buffers * should be considered a part of the kernel memory. */ if ( ( meminfo = fopen ( "/proc/meminfo" , "r" ) ) == NULL ) { fprintf ( stderr , "%s: cannot open /proc/meminfo" , progname ) ; perror ( "" ) ; exit ( 1 ) ; } while ( fgets ( buf , sizeof ( buf ) , meminfo ) ) { if ( !strncmp ( buf , MemLine , MemLineLen ) ) { /* Mem: total used free shared buffers cached */ sscanf ( buf , "%*s %d %*d %d %*d %d" , &totalmem , &freemem , &buffermem ) ; break ; } } sysmem /= 1024 ; totalmem /= 1024 ; freemem /= 1024 ; buffermem /= 1024 ; kernelmem = sysmem - totalmem ; fclose ( meminfo ) ; return ; } /* * Read /proc to get info about processes. * As a side effect :-) also set variables related to main memory. */ void makeProcs ( void ) { DIR *proc ; struct dirent *procdir ; FILE *StatusFile ; char buf [128] ; char procName [14] ; int procSize , procRSS , procData , procStk , procExe ; const char *NameLine = "Name:" , *VmSizeLine = "VmSize:" , *VmRSSLine = "VmRSS" , *VmDataLine = "VmData" , *VmStkLine = "VmStk" , *VmExeLine = "VmExe" ; const int NameLineLen = strlen ( NameLine ) , VmSizeLineLen = strlen ( VmSizeLine ) , VmDataLineLen = strlen ( VmDataLine ) , VmStkLineLen = strlen ( VmStkLine ) , VmExeLineLen = strlen ( VmExeLine ) , VmRSSLineLen = strlen ( VmRSSLine ) ; if ( ( proc = opendir ( "/proc" ) ) == NULL ) { fprintf ( stderr , "%s: unable to open /proc" , progname ) ; perror ( "" ) ; exit ( 1 ) ; } ClearProcs () ; /* * Get memory info */ SetMemInfo () ; /* * Make sure that the first process is the kernel. We'll be slightly off, * but the alternatives (adding this after the rest of the process list * has been made) are too terrible to contemplate. */ addProc ( kernelname , kernelmem + buffermem , kernelmem + buffermem ) ; /* * NASTY HACK! * Some screwy feature (or my screwy understanding of /proc) causes the * sum(RSS) for all the procs + kernel + buffers + freemem to become > system * memory. Hence we recalculate system memory based on the actual figures * we get from sum(RSS)+kernel+buffers+freemem */ sysmem = 0 ; while ( procdir = readdir ( proc ) ) { if ( !index ( "1234567890" , procdir -> d_name [0] ) ) { continue ; } sprintf ( buf , "/proc/%s/status" , procdir -> d_name ) ; if ( ( StatusFile = fopen ( buf , "r" ) ) == NULL ) { fprintf ( stderr , "%s: cannot open %s for reading" , progname , buf ) ; perror ( "" ) ; continue ; } procRSS = procSize = procData = procStk = procExe = 0 ; while ( fgets ( buf , sizeof ( buf ) , StatusFile ) ) { /* * I hate sscanf's, but am too lazy to replace them with a more elegant, * more efficient method right now. Don't you just love TODO lists? */ if ( !strncmp ( buf , NameLine , NameLineLen ) ) { /* Name: procName */ sscanf ( buf , "%*s %s" , procName ) ; } else if ( !strncmp ( buf , VmSizeLine , VmSizeLineLen ) ) { /* VmSize: procSize kB */ sscanf ( buf , "%*s %d" , &procSize ) ; } else if ( !strncmp ( buf , VmRSSLine , VmRSSLineLen ) ) { /* VmRSS: procRSS kB */ sscanf ( buf , "%*s %d" , &procRSS ) ; } else if ( !strncmp ( buf , VmDataLine , VmDataLineLen ) ) { /* VmData: procData kB */ sscanf ( buf , "%*s %d" , &procData ) ; } else if ( !strncmp ( buf , VmStkLine , VmStkLineLen ) ) { /* VmStk: procStk kB */ sscanf ( buf , "%*s %d" , &procStk ) ; } else if ( !strncmp ( buf , VmExeLine , VmExeLineLen ) ) { /* VmExe: procExe kB */ sscanf ( buf , "%*s %d" , &procExe ) ; } } fclose ( StatusFile ) ; addProc ( procName , procSize , procData + procStk + procExe ) ; sysmem += procData + procStk + procExe ; } closedir ( proc ) ; sysmem += kernelmem + buffermem + freemem ; addProc ( freename , freemem , freemem ) ; return ; } /* makeProcs */ #ifdef DEBUG void printProcs ( void ) { struct ProcInfo *pi , *procs ; int nprocs , nprocs2 , totmem ; register int i ; printf ( "%-20s%8s%8s%8s\n" , "Name" , "Memory" , "RSS" , "Number" ) ; totmem = nprocs2 = 0 ; procs = AllProcs ( &nprocs ) ; for ( i = 0 ; i < nprocs ; i++ ) { pi = &procs[i] ; printf ( "%-20s%8d%8d%8d\n" , pi -> procname , pi -> totMem , pi -> totRSS , pi -> nProcs ) ; nprocs2 += pi -> nProcs ; if ( strcmp ( pi -> procname , kernelname ) ) { totmem += pi -> totRSS ; } } printf ( "%d procs\n" , nprocs ) ; printf ( "Mem: %d procs, %d total, %d kernel, %d buffers, %d free\n" , totmem , sysmem , kernelmem , buffermem , freemem ) ; } char *progname ; void main ( int argc , char **argv ) { register int i = 0 ; progname = *argv ; while ( 1 ) { makeProcs () ; printProcs () ; printf ( "\n" ) ; sleep ( 5 ) ; } } #endif /* DEBUG */