diff options
Diffstat (limited to 'ksysguard/ksysguardd/Linux/stat.c')
-rw-r--r-- | ksysguard/ksysguardd/Linux/stat.c | 1184 |
1 files changed, 1184 insertions, 0 deletions
diff --git a/ksysguard/ksysguardd/Linux/stat.c b/ksysguard/ksysguardd/Linux/stat.c new file mode 100644 index 000000000..0e03e4d53 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/stat.c @@ -0,0 +1,1184 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "Command.h" +#include "ksysguardd.h" + +#include "stat.h" + +typedef struct +{ + /* A CPU can be loaded with user processes, reniced processes and + * system processes. Unused processing time is called idle load. + * These variable store the percentage of each load type. */ + int userLoad; + int niceLoad; + int sysLoad; + int idleLoad; + + /* To calculate the loads we need to remember the tick values for each + * load type. */ + unsigned long userTicks; + unsigned long niceTicks; + unsigned long sysTicks; + unsigned long idleTicks; +} CPULoadInfo; + +typedef struct +{ + unsigned long delta; + unsigned long old; +} DiskLoadSample; + +typedef struct +{ + /* 5 types of samples are taken: + total, rio, wio, rBlk, wBlk */ + DiskLoadSample s[ 5 ]; +} DiskLoadInfo; + +typedef struct DiskIOInfo +{ + int major; + int minor; + int alive; + DiskLoadSample total; + DiskLoadSample rio; + DiskLoadSample wio; + DiskLoadSample rblk; + DiskLoadSample wblk; + struct DiskIOInfo* next; +} DiskIOInfo; + +#define STATBUFSIZE (32 * 1024) + +static char StatBuf[ STATBUFSIZE ]; +static char VmStatBuf[ STATBUFSIZE ]; +static char IOStatBuf[ STATBUFSIZE ]; /* Buffer for /proc/diskstats */ +static int Dirty = 0; + +/* We have observed deviations of up to 5% in the accuracy of the timer + * interrupts. So we try to measure the interrupt interval and use this + * value to calculate timing dependant values. */ +static float timeInterval = 0; +static struct timeval lastSampling; +static struct timeval currSampling; +static struct SensorModul* StatSM; + +static CPULoadInfo CPULoad; +static CPULoadInfo* SMPLoad = 0; +static unsigned CPUCount = 0; +static DiskLoadInfo* DiskLoad = 0; +static unsigned DiskCount = 0; +static DiskIOInfo* DiskIO = 0; +static unsigned long PageIn = 0; +static unsigned long OldPageIn = 0; +static unsigned long PageOut = 0; +static unsigned long OldPageOut = 0; +static unsigned long Ctxt = 0; +static unsigned long OldCtxt = 0; +static unsigned int NumOfInts = 0; +static unsigned long* OldIntr = 0; +static unsigned long* Intr = 0; + +static int initStatDisk( char* tag, char* buf, const char* label, const char* shortLabel, + int idx, cmdExecutor ex, cmdExecutor iq ); +static void updateCPULoad( const char* line, CPULoadInfo* load ); +static int processDisk( char* tag, char* buf, const char* label, int idx ); +static void processStat( void ); +static int processDiskIO( const char* buf ); +static int process26DiskIO( const char* buf ); +static void cleanupDiskList( void ); + +static int initStatDisk( char* tag, char* buf, const char* label, + const char* shortLabel, int idx, cmdExecutor ex, cmdExecutor iq ) +{ + char sensorName[ 128 ]; + + gettimeofday( &lastSampling, 0 ); + + if ( strcmp( label, tag ) == 0 ) { + unsigned int i; + buf = buf + strlen( label ) + 1; + + for ( i = 0; i < DiskCount; ++i ) { + sscanf( buf, "%lu", &DiskLoad[ i ].s[ idx ].old ); + while ( *buf && isblank( *buf++ ) ); + while ( *buf && isdigit( *buf++ ) ); + sprintf( sensorName, "disk/disk%d/%s", i, shortLabel ); + registerMonitor( sensorName, "integer", ex, iq, StatSM ); + } + + return 1; + } + + return 0; +} + +static void updateCPULoad( const char* line, CPULoadInfo* load ) +{ + unsigned long currUserTicks, currSysTicks, currNiceTicks, currIdleTicks; + unsigned long totalTicks; + + sscanf( line, "%*s %lu %lu %lu %lu", &currUserTicks, &currNiceTicks, + &currSysTicks, &currIdleTicks ); + + totalTicks = ( currUserTicks - load->userTicks ) + + ( currSysTicks - load->sysTicks ) + + ( currNiceTicks - load->niceTicks ) + + ( currIdleTicks - load->idleTicks ); + + if ( totalTicks > 10 ) { + load->userLoad = ( 100 * ( currUserTicks - load->userTicks ) ) / totalTicks; + load->sysLoad = ( 100 * ( currSysTicks - load->sysTicks ) ) / totalTicks; + load->niceLoad = ( 100 * ( currNiceTicks - load->niceTicks ) ) / totalTicks; + load->idleLoad = ( 100 - ( load->userLoad + load->sysLoad + load->niceLoad ) ); + } else + load->userLoad = load->sysLoad = load->niceLoad = load->idleLoad = 0; + + load->userTicks = currUserTicks; + load->sysTicks = currSysTicks; + load->niceTicks = currNiceTicks; + load->idleTicks = currIdleTicks; +} + +static int processDisk( char* tag, char* buf, const char* label, int idx ) +{ + if ( strcmp( label, tag ) == 0 ) { + unsigned long val; + unsigned int i; + buf = buf + strlen( label ) + 1; + + for ( i = 0; i < DiskCount; ++i ) { + sscanf( buf, "%lu", &val ); + while ( *buf && isblank( *buf++ ) ); + while ( *buf && isdigit( *buf++ ) ); + DiskLoad[ i ].s[ idx ].delta = val - DiskLoad[ i ].s[ idx ].old; + DiskLoad[ i ].s[ idx ].old = val; + } + + return 1; + } + + return 0; +} + +static int processDiskIO( const char* buf ) +{ + /* Process disk_io lines as provided by 2.4.x kernels. + * disk_io: (2,0):(3,3,6,0,0) (3,0):(1413012,511622,12155382,901390,26486215) */ + int major, minor; + unsigned long total, rblk, rio, wblk, wio; + DiskIOInfo* ptr = DiskIO; + DiskIOInfo* last = 0; + char sensorName[ 128 ]; + const char* p; + + p = buf + strlen( "disk_io: " ); + while ( p && *p ) { + if ( sscanf( p, "(%d,%d):(%lu,%lu,%lu,%lu,%lu)", &major, &minor, + &total, &rio, &rblk, &wio, &wblk ) != 7 ) + return -1; + + last = 0; + ptr = DiskIO; + while ( ptr ) { + if ( ptr->major == major && ptr->minor == minor ) { + /* The IO device has already been registered. */ + ptr->total.delta = total - ptr->total.old; + ptr->total.old = total; + ptr->rio.delta = rio - ptr->rio.old; + ptr->rio.old = rio; + ptr->wio.delta = wio - ptr->wio.old; + ptr->wio.old = wio; + ptr->rblk.delta = rblk - ptr->rblk.old; + ptr->rblk.old = rblk; + ptr->wblk.delta = wblk - ptr->wblk.old; + ptr->wblk.old = wblk; + ptr->alive = 1; + break; + } + last = ptr; + ptr = ptr->next; + } + + if ( !ptr ) { + /* The IO device has not been registered yet. We need to add it. */ + ptr = (DiskIOInfo*)malloc( sizeof( DiskIOInfo ) ); + ptr->major = major; + ptr->minor = minor; + ptr->total.delta = 0; + ptr->total.old = total; + ptr->rio.delta = 0; + ptr->rio.old = rio; + ptr->wio.delta = 0; + ptr->wio.old = wio; + ptr->rblk.delta = 0; + ptr->rblk.old = rblk; + ptr->wblk.delta = 0; + ptr->wblk.old = wblk; + ptr->alive = 1; + ptr->next = 0; + if ( last ) { + /* Append new entry at end of list. */ + last->next = ptr; + } else { + /* List is empty, so we insert the fist element into the list. */ + DiskIO = ptr; + } + + sprintf( sensorName, "disk/%d:%d/total", major, minor ); + registerMonitor( sensorName, "integer", printDiskIO, printDiskIOInfo, StatSM ); + sprintf( sensorName, "disk/%d:%d/rio", major, minor ); + registerMonitor( sensorName, "integer", printDiskIO, printDiskIOInfo, StatSM ); + sprintf( sensorName, "disk/%d:%d/wio", major, minor ); + registerMonitor( sensorName, "integer", printDiskIO, printDiskIOInfo, StatSM ); + sprintf( sensorName, "disk/%d:%d/rblk", major, minor ); + registerMonitor( sensorName, "integer", printDiskIO, printDiskIOInfo, StatSM ); + sprintf( sensorName, "disk/%d:%d/wblk", major, minor ); + registerMonitor( sensorName, "integer", printDiskIO, printDiskIOInfo, StatSM ); + } + /* Move p after the sencond ')'. We can safely assume that + * those two ')' exist. */ + p = strchr( p, ')' ) + 1; + p = strchr( p, ')' ) + 1; + if ( p && *p ) + p = strchr( p, '(' ); + } + + return 0; +} + +static int process26DiskIO( const char* buf ) +{ + /* Process values from /proc/diskstats (Linux >= 2.6.x) */ + + /* For each disk /proc/diskstats includes lines as follows: + * 3 0 hda 1314558 74053 26451438 14776742 1971172 4607401 52658448 202855090 0 9597019 217637839 + * 3 1 hda1 178 360 0 0 + * 3 2 hda2 354 360 0 0 + * 3 3 hda3 354 360 0 0 + * 3 4 hda4 0 0 0 0 + * 3 5 hda5 529506 9616000 4745856 37966848 + * + * - See Documentation/iostats.txt for details on the changes + */ + int major, minor; + char devname[16]; + unsigned long total, + rio, rmrg, rblk, rtim, + wio, wmrg, wblk, wtim, + ioprog, iotim, iotimw; + DiskIOInfo *ptr = DiskIO; + DiskIOInfo *last = 0; + char sensorName[128]; + + switch (sscanf(buf, "%d %d %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", + &major, &minor, devname, + &rio, &rmrg, &rblk, &rtim, + &wio, &wmrg, &wblk, &wtim, + &ioprog, &iotim, &iotimw)) + { + case 7: + /* Partition stats entry */ + /* Adjust read fields rio rmrg rblk rtim -> rio rblk wio wblk */ + wblk = rtim; + wio = rblk; + rblk = rmrg; + + total = rio + wio; + + break; + case 14: + /* Disk stats entry */ + total = rio + wio; + + break; + default: + /* Something unexepected */ + return -1; + } + + last = 0; + ptr = DiskIO; + while (ptr) + { + if (ptr->major == major && ptr->minor == minor) + { + /* The IO device has already been registered. */ + ptr->total.delta = total - ptr->total.old; + ptr->total.old = total; + ptr->rio.delta = rio - ptr->rio.old; + ptr->rio.old = rio; + ptr->wio.delta = wio - ptr->wio.old; + ptr->wio.old = wio; + ptr->rblk.delta = rblk - ptr->rblk.old; + ptr->rblk.old = rblk; + ptr->wblk.delta = wblk - ptr->wblk.old; + ptr->wblk.old = wblk; + ptr->alive = 1; + break; + } + + last = ptr; + ptr = ptr->next; + } + + if (!ptr) + { + /* The IO device has not been registered yet. We need to add it. */ + ptr = (DiskIOInfo*)malloc( sizeof( DiskIOInfo ) ); + ptr->major = major; + ptr->minor = minor; + ptr->total.delta = 0; + ptr->total.old = total; + ptr->rio.delta = 0; + ptr->rio.old = rio; + ptr->wio.delta = 0; + ptr->wio.old = wio; + ptr->rblk.delta = 0; + ptr->rblk.old = rblk; + ptr->wblk.delta = 0; + ptr->wblk.old = wblk; + ptr->alive = 1; + ptr->next = 0; + if (last) + { + /* Append new entry at end of list. */ + last->next = ptr; + } + else + { + /* List is empty, so we insert the fist element into the list. */ + DiskIO = ptr; + } + + sprintf(sensorName, "disk/%d:%d/total", major, minor); + registerMonitor(sensorName, "integer", printDiskIO, printDiskIOInfo, + StatSM); + sprintf(sensorName, "disk/%d:%d/rio", major, minor); + registerMonitor(sensorName, "integer", printDiskIO, printDiskIOInfo, + StatSM); + sprintf(sensorName, "disk/%d:%d/wio", major, minor); + registerMonitor(sensorName, "integer", printDiskIO, printDiskIOInfo, + StatSM); + sprintf(sensorName, "disk/%d:%d/rblk", major, minor); + registerMonitor(sensorName, "integer", printDiskIO, printDiskIOInfo, + StatSM); + sprintf(sensorName, "disk/%d:%d/wblk", major, minor); + registerMonitor(sensorName, "integer", printDiskIO, printDiskIOInfo, + StatSM); + } + + return 0; +} + +static void cleanupDiskList( void ) +{ + DiskIOInfo* ptr = DiskIO; + DiskIOInfo* last = 0; + + while ( ptr ) { + if ( ptr->alive == 0 ) { + DiskIOInfo* newPtr; + char sensorName[ 128 ]; + + /* Disk device has disappeared. We have to remove it from + * the list and unregister the monitors. */ + sprintf( sensorName, "disk/%d:%d/total", ptr->major, ptr->minor ); + removeMonitor( sensorName ); + sprintf( sensorName, "disk/%d:%d/rio", ptr->major, ptr->minor ); + removeMonitor( sensorName ); + sprintf( sensorName, "disk/%d:%d/wio", ptr->major, ptr->minor ); + removeMonitor( sensorName ); + sprintf( sensorName, "disk/%d:%d/rblk", ptr->major, ptr->minor ); + removeMonitor( sensorName ); + sprintf( sensorName, "disk/%d:%d/wblk", ptr->major, ptr->minor ); + removeMonitor( sensorName ); + if ( last ) { + last->next = ptr->next; + newPtr = ptr->next; + } else { + DiskIO = ptr->next; + newPtr = DiskIO; + last = 0; + } + + free ( ptr ); + ptr = newPtr; + } else { + ptr->alive = 0; + last = ptr; + ptr = ptr->next; + } + } +} + +static void processStat( void ) +{ + char format[ 32 ]; + char tagFormat[ 16 ]; + char buf[ 1024 ]; + char tag[ 32 ]; + char* statBufP = StatBuf; + char* vmstatBufP = VmStatBuf; + char* iostatBufP = IOStatBuf; + + sprintf( format, "%%%d[^\n]\n", (int)sizeof( buf ) - 1 ); + sprintf( tagFormat, "%%%ds", (int)sizeof( tag ) - 1 ); + + while ( sscanf( statBufP, format, buf ) == 1 ) { + buf[ sizeof( buf ) - 1 ] = '\0'; + statBufP += strlen( buf ) + 1; /* move statBufP to next line */ + sscanf( buf, tagFormat, tag ); + + if ( strcmp( "cpu", tag ) == 0 ) { + /* Total CPU load */ + updateCPULoad( buf, &CPULoad ); + } else if ( strncmp( "cpu", tag, 3 ) == 0 ) { + /* Load for each SMP CPU */ + int id; + sscanf( tag + 3, "%d", &id ); + updateCPULoad( buf, &SMPLoad[ id ] ); + } else if ( processDisk( tag, buf, "disk", 0 ) ) { + } else if ( processDisk( tag, buf, "disk_rio", 1 ) ) { + } else if ( processDisk( tag, buf, "disk_wio", 2 ) ) { + } else if ( processDisk( tag, buf, "disk_rblk", 3 ) ) { + } else if ( processDisk( tag, buf, "disk_wblk", 4 ) ) { + } else if ( strcmp( "disk_io:", tag ) == 0 ) { + processDiskIO( buf ); + } else if ( strcmp( "page", tag ) == 0 ) { + unsigned long v1, v2; + sscanf( buf + 5, "%lu %lu", &v1, &v2 ); + PageIn = v1 - OldPageIn; + OldPageIn = v1; + PageOut = v2 - OldPageOut; + OldPageOut = v2; + } else if ( strcmp( "intr", tag ) == 0 ) { + unsigned int i = 0; + char* p = buf + 5; + + for ( i = 0; i < NumOfInts; i++ ) { + unsigned long val; + + sscanf( p, "%lu", &val ); + Intr[ i ] = val - OldIntr[ i ]; + OldIntr[ i ] = val; + while ( *p && *p != ' ' ) + p++; + while ( *p && *p == ' ' ) + p++; + } + } else if ( strcmp( "ctxt", tag ) == 0 ) { + unsigned long val; + + sscanf( buf + 5, "%lu", &val ); + Ctxt = val - OldCtxt; + OldCtxt = val; + } + } + + /* Read Linux 2.5.x /proc/vmstat */ + while ( sscanf( vmstatBufP, format, buf ) == 1 ) { + buf[ sizeof( buf ) - 1 ] = '\0'; + vmstatBufP += strlen( buf ) + 1; /* move vmstatBufP to next line */ + sscanf( buf, tagFormat, tag ); + + if ( strcmp( "pgpgin", tag ) == 0 ) { + unsigned long v1; + sscanf( buf + 7, "%lu", &v1 ); + PageIn = v1 - OldPageIn; + OldPageIn = v1; + } else if ( strcmp( "pgpgout", tag ) == 0 ) { + unsigned long v1; + sscanf( buf + 7, "%lu", &v1 ); + PageOut = v1 - OldPageOut; + OldPageOut = v1; + } + } + + /* Process values from /proc/diskstats (Linux >= 2.6.x) */ + while (sscanf(iostatBufP, format, buf) == 1) + { + buf[sizeof(buf) - 1] = '\0'; + iostatBufP += strlen(buf) + 1; /* move IOstatBufP to next line */ + + process26DiskIO(buf); + } + + /* save exact time inverval between this and the last read of /proc/stat */ + timeInterval = currSampling.tv_sec - lastSampling.tv_sec + + ( currSampling.tv_usec - lastSampling.tv_usec ) / 1000000.0; + lastSampling = currSampling; + + cleanupDiskList(); + + Dirty = 0; +} + +/* +================================ public part ================================= +*/ + +void initStat( struct SensorModul* sm ) +{ + /* The CPU load is calculated from the values in /proc/stat. The cpu + * entry contains 4 counters. These counters count the number of ticks + * the system has spend on user processes, system processes, nice + * processes and idle time. + * + * SMP systems will have cpu1 to cpuN lines right after the cpu info. The + * format is identical to cpu and reports the information for each cpu. + * Linux kernels <= 2.0 do not provide this information! + * + * The /proc/stat file looks like this: + * + * cpu 1586 4 808 36274 + * disk 7797 0 0 0 + * disk_rio 6889 0 0 0 + * disk_wio 908 0 0 0 + * disk_rblk 13775 0 0 0 + * disk_wblk 1816 0 0 0 + * page 27575 1330 + * swap 1 0 + * intr 50444 38672 2557 0 0 0 0 2 0 2 0 0 3 1429 1 7778 0 + * ctxt 54155 + * btime 917379184 + * processes 347 + * + * Linux kernel >= 2.4.0 have one or more disk_io: lines instead of + * the disk_* lines. + * + * Linux kernel >= 2.6.x(?) have disk I/O stats in /proc/diskstats + * and no disk relevant lines are found in /proc/stat + */ + + char format[ 32 ]; + char tagFormat[ 16 ]; + char buf[ 1024 ]; + char tag[ 32 ]; + char* statBufP = StatBuf; + char* vmstatBufP = VmStatBuf; + char* iostatBufP = IOStatBuf; + + StatSM = sm; + + updateStat(); + + sprintf( format, "%%%d[^\n]\n", (int)sizeof( buf ) - 1 ); + sprintf( tagFormat, "%%%ds", (int)sizeof( tag ) - 1 ); + + while ( sscanf( statBufP, format, buf ) == 1 ) { + buf[ sizeof( buf ) - 1 ] = '\0'; + statBufP += strlen( buf ) + 1; /* move statBufP to next line */ + sscanf( buf, tagFormat, tag ); + + if ( strcmp( "cpu", tag ) == 0 ) { + /* Total CPU load */ + registerMonitor( "cpu/user", "integer", printCPUUser, printCPUUserInfo, StatSM ); + registerMonitor( "cpu/nice", "integer", printCPUNice, printCPUNiceInfo, StatSM ); + registerMonitor( "cpu/sys", "integer", printCPUSys, printCPUSysInfo, StatSM ); + registerMonitor( "cpu/idle", "integer", printCPUIdle, printCPUIdleInfo, StatSM ); + } else if ( strncmp( "cpu", tag, 3 ) == 0 ) { + char cmdName[ 24 ]; + /* Load for each SMP CPU */ + int id; + + sscanf( tag + 3, "%d", &id ); + CPUCount++; + sprintf( cmdName, "cpu%d/user", id ); + registerMonitor( cmdName, "integer", printCPUxUser, printCPUxUserInfo, StatSM ); + sprintf( cmdName, "cpu%d/nice", id ); + registerMonitor( cmdName, "integer", printCPUxNice, printCPUxNiceInfo, StatSM ); + sprintf( cmdName, "cpu%d/sys", id ); + registerMonitor( cmdName, "integer", printCPUxSys, printCPUxSysInfo, StatSM ); + sprintf( cmdName, "cpu%d/idle", id ); + registerMonitor( cmdName, "integer", printCPUxIdle, printCPUxIdleInfo, StatSM ); + } else if ( strcmp( "disk", tag ) == 0 ) { + unsigned long val; + char* b = buf + 5; + + /* Count the number of registered disks */ + for ( DiskCount = 0; *b && sscanf( b, "%lu", &val ) == 1; DiskCount++ ) { + while ( *b && isblank( *b++ ) ); + while ( *b && isdigit( *b++ ) ); + } + + if ( DiskCount > 0 ) + DiskLoad = (DiskLoadInfo*)malloc( sizeof( DiskLoadInfo ) * DiskCount ); + initStatDisk( tag, buf, "disk", "disk", 0, printDiskTotal, printDiskTotalInfo ); + } else if ( initStatDisk( tag, buf, "disk_rio", "rio", 1, printDiskRIO, + printDiskRIOInfo ) ); + else if ( initStatDisk( tag, buf, "disk_wio", "wio", 2, printDiskWIO, + printDiskWIOInfo ) ); + else if ( initStatDisk( tag, buf, "disk_rblk", "rblk", 3, printDiskRBlk, + printDiskRBlkInfo ) ); + else if ( initStatDisk( tag, buf, "disk_wblk", "wblk", 4, printDiskWBlk, + printDiskWBlkInfo ) ); + else if ( strcmp( "disk_io:", tag ) == 0 ) + processDiskIO( buf ); + else if ( strcmp( "page", tag ) == 0 ) { + sscanf( buf + 5, "%lu %lu", &OldPageIn, &OldPageOut ); + registerMonitor( "cpu/pageIn", "integer", printPageIn, + printPageInInfo, StatSM ); + registerMonitor( "cpu/pageOut", "integer", printPageOut, + printPageOutInfo, StatSM ); + } else if ( strcmp( "intr", tag ) == 0 ) { + unsigned int i; + char cmdName[ 32 ]; + char* p = buf + 5; + + /* Count the number of listed values in the intr line. */ + NumOfInts = 0; + while ( *p ) + if ( *p++ == ' ' ) + NumOfInts++; + + /* It looks like anything above 24 is always 0. So let's just + * ignore this for the time being. */ + if ( NumOfInts > 25 ) + NumOfInts = 25; + OldIntr = (unsigned long*)malloc( NumOfInts * sizeof( unsigned long ) ); + Intr = (unsigned long*)malloc( NumOfInts * sizeof( unsigned long ) ); + i = 0; + p = buf + 5; + for ( i = 0; p && i < NumOfInts; i++ ) { + sscanf( p, "%lu", &OldIntr[ i ] ); + while ( *p && *p != ' ' ) + p++; + while ( *p && *p == ' ' ) + p++; + sprintf( cmdName, "cpu/interrupts/int%02d", i ); + registerMonitor( cmdName, "integer", printInterruptx, + printInterruptxInfo, StatSM ); + } + } else if ( strcmp( "ctxt", tag ) == 0 ) { + sscanf( buf + 5, "%lu", &OldCtxt ); + registerMonitor( "cpu/context", "integer", printCtxt, + printCtxtInfo, StatSM ); + } + } + + while ( sscanf( vmstatBufP, format, buf ) == 1 ) { + buf[ sizeof( buf ) - 1 ] = '\0'; + vmstatBufP += strlen( buf ) + 1; /* move vmstatBufP to next line */ + sscanf( buf, tagFormat, tag ); + + if ( strcmp( "pgpgin", tag ) == 0 ) { + sscanf( buf + 7, "%lu", &OldPageIn ); + registerMonitor( "cpu/pageIn", "integer", printPageIn, + printPageInInfo, StatSM ); + } else if ( strcmp( "pgpgout", tag ) == 0 ) { + sscanf( buf + 7, "%lu", &OldPageOut ); + registerMonitor( "cpu/pageOut", "integer", printPageOut, + printPageOutInfo, StatSM ); + } + } + + /* Process values from /proc/diskstats (Linux >= 2.6.x) */ + while (sscanf(iostatBufP, format, buf) == 1) + { + buf[sizeof(buf) - 1] = '\0'; + iostatBufP += strlen(buf) + 1; /* move IOstatBufP to next line */ + + process26DiskIO(buf); + } + + if ( CPUCount > 0 ) + SMPLoad = (CPULoadInfo*)malloc( sizeof( CPULoadInfo ) * CPUCount ); + + /* Call processStat to eliminate initial peek values. */ + processStat(); +} + +void exitStat( void ) +{ + free( DiskLoad ); + DiskLoad = 0; + + free( SMPLoad ); + SMPLoad = 0; + + free( OldIntr ); + OldIntr = 0; + + free( Intr ); + Intr = 0; +} + +int updateStat( void ) +{ + size_t n; + int fd; + + if ( ( fd = open( "/proc/stat", O_RDONLY ) ) < 0 ) { + print_error( "Cannot open file \'/proc/stat\'!\n" + "The kernel needs to be compiled with support\n" + "for /proc filesystem enabled!\n" ); + return -1; + } + + if ( ( n = read( fd, StatBuf, STATBUFSIZE - 1 ) ) == STATBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'/proc/stat\'" ); + + close( fd ); + return -1; + } + + gettimeofday( &currSampling, 0 ); + close( fd ); + StatBuf[ n ] = '\0'; + Dirty = 1; + + VmStatBuf[ 0 ] = '\0'; + if ( ( fd = open( "/proc/vmstat", O_RDONLY ) ) < 0 ) + return 0; /* failure is okay, only exists for Linux >= 2.5.x */ + + if ( ( n = read( fd, VmStatBuf, STATBUFSIZE - 1 ) ) == STATBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'/proc/vmstat\'" ); + + close( fd ); + return -1; + } + + close( fd ); + VmStatBuf[ n ] = '\0'; + + /* Linux >= 2.6.x has disk I/O stats in /proc/diskstats */ + IOStatBuf[ 0 ] = '\0'; + if ( ( fd = open( "/proc/diskstats", O_RDONLY ) ) < 0 ) + return 0; /* failure is okay, only exists for Linux >= 2.6.x */ + + if ( ( n = read( fd, IOStatBuf, STATBUFSIZE - 1 ) ) == STATBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'/proc/diskstats\'" ); + + close( fd ); + return -1; + } + + close( fd ); + IOStatBuf[ n ] = '\0'; + + return 0; +} + +void printCPUUser( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%d\n", CPULoad.userLoad ); +} + +void printCPUUserInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "CPU User Load\t0\t100\t%%\n" ); +} + +void printCPUNice( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%d\n", CPULoad.niceLoad ); +} + +void printCPUNiceInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "CPU Nice Load\t0\t100\t%%\n" ); +} + +void printCPUSys( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%d\n", CPULoad.sysLoad ); +} + +void printCPUSysInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "CPU System Load\t0\t100\t%%\n" ); +} + +void printCPUIdle( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%d\n", CPULoad.idleLoad ); +} + +void printCPUIdleInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "CPU Idle Load\t0\t100\t%%\n" ); +} + +void printCPUxUser( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "%d\n", SMPLoad[ id ].userLoad ); +} + +void printCPUxUserInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "CPU%d User Load\t0\t100\t%%\n", id ); +} + +void printCPUxNice( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "%d\n", SMPLoad[ id ].niceLoad ); +} + +void printCPUxNiceInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "CPU%d Nice Load\t0\t100\t%%\n", id ); +} + +void printCPUxSys( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "%d\n", SMPLoad[ id ].sysLoad ); +} + +void printCPUxSysInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "CPU%d System Load\t0\t100\t%%\n", id ); +} + +void printCPUxIdle( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "%d\n", SMPLoad[ id ].idleLoad ); +} + +void printCPUxIdleInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "CPU%d Idle Load\t0\t100\t%%\n", id ); +} + +void printDiskTotal( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "%lu\n", (unsigned long)( DiskLoad[ id ].s[ 0 ].delta + / timeInterval ) ); +} + +void printDiskTotalInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "Disk%d Total Load\t0\t0\tkBytes/s\n", id ); +} + +void printDiskRIO( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "%lu\n", (unsigned long)( DiskLoad[ id ].s[ 1 ].delta + / timeInterval ) ); +} + +void printDiskRIOInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "Disk%d Read\t0\t0\tkBytes/s\n", id ); +} + +void printDiskWIO( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "%lu\n", (unsigned long)( DiskLoad[ id ].s[ 2 ].delta + / timeInterval ) ); +} + +void printDiskWIOInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "Disk%d Write\t0\t0\tkBytes/s\n", id ); +} + +void printDiskRBlk( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 9, "%d", &id ); + /* a block is 512 bytes or 1/2 kBytes */ + fprintf( CurrentClient, "%lu\n", (unsigned long)( DiskLoad[ id ].s[ 3 ].delta + / timeInterval * 2 ) ); +} + +void printDiskRBlkInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "Disk%d Read Data\t0\t0\tkBytes/s\n", id ); +} + +void printDiskWBlk( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 9, "%d", &id ); + /* a block is 512 bytes or 1/2 kBytes */ + fprintf( CurrentClient, "%lu\n", (unsigned long)( DiskLoad[ id ].s[ 4 ].delta + / timeInterval * 2 ) ); +} + +void printDiskWBlkInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "Disk%d Write Data\t0\t0\tkBytes/s\n", id ); +} + +void printPageIn( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%lu\n", (unsigned long)( PageIn / timeInterval ) ); +} + +void printPageInInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Paged in Pages\t0\t0\t1/s\n" ); +} + +void printPageOut( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%lu\n", (unsigned long)( PageOut / timeInterval ) ); +} + +void printPageOutInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Paged out Pages\t0\t0\t1/s\n" ); +} + +void printInterruptx( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + strlen( "cpu/interrupts/int" ), "%d", &id ); + fprintf( CurrentClient, "%lu\n", (unsigned long)( Intr[ id ] / timeInterval ) ); +} + +void printInterruptxInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + strlen( "cpu/interrupt/int" ), "%d", &id ); + fprintf( CurrentClient, "Interrupt %d\t0\t0\t1/s\n", id ); +} + +void printCtxt( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%lu\n", (unsigned long)( Ctxt / timeInterval ) ); +} + +void printCtxtInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Context switches\t0\t0\t1/s\n" ); +} + +void printDiskIO( const char* cmd ) +{ + int major, minor; + char name[ 17 ]; + DiskIOInfo* ptr; + + sscanf( cmd, "disk/%d:%d/%16s", &major, &minor, name ); + + if ( Dirty ) + processStat(); + + ptr = DiskIO; + while ( ptr && ( ptr->major != major || ptr->minor != minor ) ) + ptr = ptr->next; + + if ( !ptr ) { + print_error( "RECONFIGURE" ); + fprintf( CurrentClient, "0\n" ); + + log_error( "Disk device disappeared" ); + return; + } + + if ( strcmp( name, "total" ) == 0 ) + fprintf( CurrentClient, "%lu\n", (unsigned long)( ptr->total.delta + / timeInterval ) ); + else if ( strcmp( name, "rio" ) == 0 ) + fprintf( CurrentClient, "%lu\n", (unsigned long)( ptr->rio.delta + / timeInterval ) ); + else if ( strcmp( name, "wio" ) == 0 ) + fprintf( CurrentClient, "%lu\n", (unsigned long)( ptr->wio.delta + / timeInterval ) ); + else if ( strcmp( name, "rblk" ) == 0 ) + fprintf( CurrentClient, "%lu\n", (unsigned long)( ptr->rblk.delta + / ( timeInterval * 2 ) ) ); + else if ( strcmp( name, "wblk" ) == 0 ) + fprintf( CurrentClient, "%lu\n", (unsigned long)( ptr->wblk.delta + / ( timeInterval * 2 ) ) ); + else { + fprintf( CurrentClient, "0\n" ); + log_error( "Unknown disk device property \'%s\'", name ); + } +} + +void printDiskIOInfo( const char* cmd ) +{ + int major, minor; + char name[ 17 ]; + DiskIOInfo* ptr = DiskIO; + + sscanf( cmd, "disk/%d:%d/%16s", &major, &minor, name ); + + while ( ptr && ( ptr->major != major || ptr->minor != minor ) ) + ptr = ptr->next; + + if ( !ptr ) { + /* Disk device has disappeared. Print a dummy answer. */ + fprintf( CurrentClient, "Dummy\t0\t0\t\n" ); + return; + } + + /* remove trailing '?' */ + name[ strlen( name ) - 1 ] = '\0'; + + if ( strcmp( name, "total" ) == 0 ) + fprintf( CurrentClient, "Total accesses device %d, %d\t0\t0\t1/s\n", + major, minor ); + else if ( strcmp( name, "rio" ) == 0 ) + fprintf( CurrentClient, "Read data device %d, %d\t0\t0\t1/s\n", + major, minor ); + else if ( strcmp( name, "wio" ) == 0 ) + fprintf( CurrentClient, "Write data device %d, %d\t0\t0\t1/s\n", + major, minor ); + else if ( strcmp( name, "rblk" ) == 0 ) + fprintf( CurrentClient, "Read accesses device %d, %d\t0\t0\tkBytes/s\n", + major, minor ); + else if ( strcmp( name, "wblk" ) == 0 ) + fprintf( CurrentClient, "Write accesses device %d, %d\t0\t0\tkBytes/s\n", + major, minor ); + else { + fprintf( CurrentClient, "Dummy\t0\t0\t\n" ); + log_error( "Request for unknown device property \'%s\'", name ); + } +} |