#include #include #ifndef __USE_GNU #define __USE_GNU #endif #include #include #include #include #include #include #include /* From old ganglia 2.5.x... */ #include "file.h" #include "libmetrics.h" /* End old ganglia 2.5.x headers */ #define OSNAME "Linux" #define OSNAME_LEN strlen(OSNAME) /* /proc/net/dev hash table stuff */ typedef struct net_dev_stats net_dev_stats; struct net_dev_stats { char *name; double pkts_in; double pkts_out; double bytes_in; double bytes_out; net_dev_stats *next; }; #define NHASH 101 #define MULTIPLIER 31 static net_dev_stats *netstats[NHASH]; /* Never changes */ #ifndef BUFFSIZE #define BUFFSIZE 8192 #endif char proc_cpuinfo[BUFFSIZE]; char proc_sys_kernel_osrelease[BUFFSIZE]; char sys_devices_system_cpu[32]; int cpufreq; typedef struct { uint32_t last_read; uint32_t thresh; char *name; char buffer[BUFFSIZE]; } timely_file; timely_file proc_stat = { 0, 1, "/proc/stat" }; timely_file proc_loadavg = { 0, 5, "/proc/loadavg" }; timely_file proc_meminfo = { 0, 5, "/proc/meminfo" }; timely_file proc_net_dev = { 0, 1, "/proc/net/dev" }; char *update_file(timely_file *tf) { int now,rval; now = time(0); if(now - tf->last_read > tf->thresh) { rval = slurpfile(tf->name, tf->buffer, BUFFSIZE); if(rval == SYNAPSE_FAILURE) { err_msg("update_file() got an error from slurpfile() reading %s", tf->name); return (char *)SYNAPSE_FAILURE; } else tf->last_read = now; } return tf->buffer; } /* ** A helper function to determine the number of cpustates in /proc/stat (MKN) */ #define NUM_CPUSTATES_24X 4 #define NUM_CPUSTATES_26X 7 static unsigned int num_cpustates; unsigned int num_cpustates_func ( void ) { char *p; unsigned int i=0; proc_stat.last_read=0; p = update_file(&proc_stat); proc_stat.last_read=0; /* ** Skip initial "cpu" token */ p = skip_token(p); p = skip_whitespace(p); /* ** Loop over file until next "cpu" token is found. ** i=4 : Linux 2.4.x ** i=7 : Linux 2.6.x */ while (strncmp(p,"cpu",3)) { p = skip_token(p); p = skip_whitespace(p); i++; } return i; } /* ** Helper functions to hash /proc/net/dev stats (Kernighan & Pike) */ static unsigned int hashval(const char *s) { unsigned int hval; unsigned char *p; hval = 0; for (p = (unsigned char *)s; *p != '\0'; p++) hval = MULTIPLIER * hval + *p; return hval % NHASH; } static net_dev_stats *hash_lookup(char *name, const int enter, const double pkts_in, const double pkts_out, const double bytes_in, const double bytes_out) { int hval; net_dev_stats *stats; hval = hashval(name); for (stats = netstats[hval]; stats != NULL; stats = stats->next) { if (strcmp(name, stats->name) == 0) return stats; } if (enter) { stats = (net_dev_stats *)malloc(sizeof(net_dev_stats)); if ( stats == NULL ) { err_msg("unable to allocate memory for /proc/net/dev/stats in hash_lookup()"); return NULL; } stats->name = name; stats->pkts_in = pkts_in; stats->pkts_out = pkts_out; stats->bytes_in = bytes_in; stats->bytes_out = bytes_out; stats->next = netstats[hval]; netstats[hval] = stats; } return stats; } /* * This function is called only once by the gmond. Use to * initialize data structures, etc or just return SYNAPSE_SUCCESS; */ g_val_t metric_init(void) { g_val_t rval; char * dummy; num_cpustates = num_cpustates_func(); cpufreq = 1; rval.int32 = slurpfile("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", sys_devices_system_cpu, BUFFSIZE); if ( rval.int32 == SYNAPSE_FAILURE ) cpufreq = 0; rval.int32 = slurpfile("/proc/cpuinfo", proc_cpuinfo, BUFFSIZE); if ( rval.int32 == SYNAPSE_FAILURE ) { err_msg("metric_init() got an error from slurpfile() /proc/cpuinfo"); return rval; } rval.int32 = slurpfile( "/proc/sys/kernel/osrelease", proc_sys_kernel_osrelease, BUFFSIZE); if ( rval.int32 == SYNAPSE_FAILURE ) { err_msg("metric_init() got an error from slurpfile()"); return rval; } /* Get rid of pesky \n in osrelease */ proc_sys_kernel_osrelease[rval.int32-1] = '\0'; dummy = update_file(&proc_net_dev); if ( dummy == (char *)SYNAPSE_FAILURE ) { err_msg("metric_init() got an error from update_file()"); rval.int32 = SYNAPSE_FAILURE; return rval; } rval.int32 = SYNAPSE_SUCCESS; return rval; } g_val_t pkts_in_func ( void ) { char *p; register int i; static g_val_t val; static int stamp; double bytes_in=0, bytes_out=0, pkts_in=0, pkts_out=0, t = 0; p = update_file(&proc_net_dev); if (proc_net_dev.last_read != stamp) { /* skip past the two-line header ... */ p = index (p, '\n')+1; p = index (p, '\n')+1; while (*p != 0x00 ) { /* skip past the interface tag portion of this line */ /* but save the name of the interface (hash key) */ char *devname, *src; size_t n = 0; while (p != 0x00 && isblank(*p)) p++; src = p; while (p != 0x00 && *p != ':') { n++; p++; } devname = strndup(src, n); p = index(p, ':')+1; if ( ((*(p-2) != 'o') && (*(p-3) != 'l')) && ((*(p-3) != 'd') && (*(p-4) != 'n') && (*(p-5) != 'o') && (*(p-6) != 'b')) ) { double temp = 0.; /* Check for data from the last read for this */ /* interface. If nothing exists, add to the table. */ net_dev_stats *ns = hash_lookup(devname, 1, 0., 0., 0., 0.); if ( ns == NULL ) { val.f = 0.; debug_msg(" ********** BYTES_OUT RETURN: %f", val.f); return val; } t = strtod( p, &p ) - ns->bytes_in; if ( t < 0. ) { t += ULONG_MAX; } bytes_in += t; temp = strtod( p, &p ); t = temp - ns->pkts_in; if ( t < 0. ) { t += ULONG_MAX; } pkts_in += t; for (i = 0; i < 6; i++) strtol(p, &p, 10); /* Fixed 2003 by Dr Michael Wirtz and Phil Radden */ t = strtod( p, &p ) - ns->bytes_out; if ( t < 0. ) { t += ULONG_MAX; } bytes_out += t; t = strtod( p, &p ) - ns->pkts_out; if ( t < 0. ) { t += ULONG_MAX; } pkts_out += t; /* Update the hash for this measurement */ ns->pkts_in = temp; } p = index (p, '\n') + 1; // skips a line } val.f = 0.; if ( pkts_in >= 1. ) { t = proc_net_dev.last_read - stamp; val.f = pkts_in / t; } stamp = proc_net_dev.last_read; } debug_msg(" ********** PKTS_IN RETURN: %f", val.f); return val; } g_val_t pkts_out_func ( void ) { char *p; register int i; static g_val_t val; static int stamp; double bytes_in=0, bytes_out=0, pkts_in=0, pkts_out=0, t = 0; p = update_file(&proc_net_dev); if (proc_net_dev.last_read != stamp) { /* skip past the two-line header ... */ p = index (p, '\n')+1; p = index (p, '\n')+1; while (*p != 0x00 ) { /* skip past the interface tag portion of this line */ /* but save the name of the interface (hash key) */ char *devname, *src; size_t n = 0; while (p != 0x00 && isblank(*p)) p++; src = p; while (p != 0x00 && *p != ':') { n++; p++; } devname = strndup(src, n); p = index(p, ':')+1; if ( ((*(p-2) != 'o') && (*(p-3) != 'l')) && ((*(p-3) != 'd') && (*(p-4) != 'n') && (*(p-5) != 'o') && (*(p-6) != 'b')) ) { double temp = 0.; /* Check for data from the last read for this */ /* interface. If nothing exists, add to the table. */ net_dev_stats *ns = hash_lookup(devname, 1, 0., 0., 0., 0.); if ( ns == NULL ) { val.f = 0.; debug_msg(" ********** BYTES_OUT RETURN: %f", val.f); return val; } t = strtod( p, &p ) - ns->bytes_in; if ( t < 0. ) { t += ULONG_MAX; } bytes_in += t; t = strtod( p, &p ) - ns->pkts_in; if ( t < 0. ) { t += ULONG_MAX; } pkts_in += t; for (i = 0; i < 6; i++) strtol(p, &p, 10); /* Fixed 2003 by Dr Michael Wirtz and Phil Radden */ t = strtod( p, &p ) - ns->bytes_out; if ( t < 0. ) { t += ULONG_MAX; } bytes_out += t; temp = strtod( p, &p ); t = temp - ns->pkts_out; if ( t < 0. ) { t += ULONG_MAX; } pkts_out += t; /* Update the hash for this measurement */ ns->pkts_out = temp; } p = index (p, '\n') + 1; // skips a line } val.f = 0.; if ( pkts_out >= 1. ) { t = proc_net_dev.last_read - stamp; val.f = pkts_out / t; } stamp = proc_net_dev.last_read; } debug_msg(" ********** PKTS_OUT RETURN: %f", val.f); return val; } g_val_t bytes_out_func ( void ) { char *p; register int i; static g_val_t val; static int stamp; double bytes_in=0, bytes_out=0, pkts_in=0, pkts_out=0, t = 0; p = update_file(&proc_net_dev); if (proc_net_dev.last_read != stamp) { /* skip past the two-line header ... */ p = index (p, '\n')+1; p = index (p, '\n')+1; while (*p != 0x00 ) { /* skip past the interface tag portion of this line */ /* but save the name of the interface (hash key) */ char *devname, *src; size_t n = 0; while (p != 0x00 && isblank(*p)) p++; src = p; while (p != 0x00 && *p != ':') { n++; p++; } devname = strndup(src, n); p = index(p, ':')+1; if ( ((*(p-2) != 'o') && (*(p-3) != 'l')) && ((*(p-3) != 'd') && (*(p-4) != 'n') && (*(p-5) != 'o') && (*(p-6) != 'b')) ) { double temp = 0.; /* Check for data from the last read for this */ /* interface. If nothing exists, add to the table. */ net_dev_stats *ns = hash_lookup(devname, 1, 0., 0., 0., 0.); if ( ns == NULL ) { val.f = 0.; debug_msg(" ********** BYTES_OUT RETURN: %f", val.f); return val; } t = strtod( p, &p ) - ns->bytes_in; if ( t < 0. ) { t += ULONG_MAX; } bytes_in += t; t = strtod( p, &p ) - ns->pkts_in; if ( t < 0. ) { t += ULONG_MAX; } pkts_in += t; for (i = 0; i < 6; i++) strtol(p, &p, 10); /* Fixed 2003 by Dr Michael Wirtz and Phil Radden */ temp = strtod( p, &p ); t = temp - ns->bytes_out; if ( t < 0. ) { t += ULONG_MAX; } bytes_out += t; t = strtod( p, &p ) - ns->pkts_out; if ( t < 0. ) { t += ULONG_MAX; } pkts_out += t; /* Update the hash for this measurement */ ns->bytes_out = temp; } p = index (p, '\n') + 1; // skips a line } val.f = 0.; if ( bytes_out >= 1. ) { t = proc_net_dev.last_read - stamp; val.f = bytes_out / t; } stamp = proc_net_dev.last_read; } debug_msg(" ********** BYTES_OUT RETURN: %f", val.f); return val; } g_val_t bytes_in_func ( void ) { char *p; register int i; static g_val_t val; static int stamp; double bytes_in=0, bytes_out=0, pkts_in=0, pkts_out=0, t = 0; p = update_file(&proc_net_dev); if (proc_net_dev.last_read != stamp) { /* skip past the two-line header ... */ p = index (p, '\n')+1; p = index (p, '\n')+1; while (*p != 0x00 ) { /* skip past the interface tag portion of this line */ /* but save the name of the interface (hash key) */ char *devname, *src; size_t n = 0; while (p != 0x00 && isblank(*p)) p++; src = p; while (p != 0x00 && *p != ':') { n++; p++; } devname = strndup(src, n); p = index(p, ':')+1; if ( ((*(p-2) != 'o') && (*(p-3) != 'l')) && ((*(p-3) != 'd') && (*(p-4) != 'n') && (*(p-5) != 'o') && (*(p-6) != 'b')) ) { double temp = 0.; /* Check for data from the last read for this */ /* interface. If nothing exists, add to the table. */ net_dev_stats *ns = hash_lookup(devname, 1, 0., 0., 0., 0.); if ( ns == NULL ) { val.f = 0.; debug_msg(" ********** BYTES_OUT RETURN: %f", val.f); return val; } temp = strtod( p, &p ); t = temp - ns->bytes_in; if ( t < 0. ) { t += ULONG_MAX; } bytes_in += t; t = strtod( p, &p ) - ns->pkts_in; if ( t < 0. ) { t += ULONG_MAX; } pkts_in += t; for (i = 0; i < 6; i++) strtol(p, &p, 10); /* Fixed 2003 by Dr Michael Wirtz and Phil Radden */ t = strtod( p, &p ) - ns->bytes_out; if ( t < 0. ) { t += ULONG_MAX; } bytes_out += t; t = strtod( p, &p ) - ns->pkts_out; if ( t < 0. ) { t += ULONG_MAX; } pkts_out += t; /* Update the hash for this measurement */ ns->bytes_in = temp; } p = index (p, '\n') + 1; // skips a line } val.f = 0.; if ( bytes_in >= 1. ) { t = proc_net_dev.last_read - stamp; val.f = bytes_in / t; } stamp = proc_net_dev.last_read; } debug_msg(" ********** BYTES_IN RETURN: %f", val.f); return val; } g_val_t cpu_num_func ( void ) { static int cpu_num = 0; g_val_t val; /* Only need to do this once */ if (! cpu_num) { /* We'll use _SC_NPROCESSORS_ONLN to get operating cpus */ cpu_num = get_nprocs(); } val.uint16 = cpu_num; return val; } g_val_t cpu_speed_func ( void ) { char *p; static g_val_t val = {0}; /* we'll use scaling_max_freq before we fallback on proc_cpuinfo */ if(cpufreq && ! val.uint32) { p = sys_devices_system_cpu; val.uint32 = (uint32_t)(strtol( p, (char **)NULL , 10 ) / 1000 ); } /* i386, ia64, x86_64 and hppa all report MHz in the same format */ #if defined (__i386__) || defined(__ia64__) || defined(__hppa__) || defined(__x86_64__) if (! val.uint32 ) { p = proc_cpuinfo; p = strstr( p, "cpu MHz" ); if(p) { p = strchr( p, ':' ); p++; p = skip_whitespace(p); val.uint32 = (uint32_t)strtol( p, (char **)NULL , 10 ); } else { val.uint32 = 0; } } #endif #if defined (__alpha__) if (! val.uint32 ) { int num; p = proc_cpuinfo; p = strstr( p, "cycle frequency [Hz]" ); if(p) { p = strchr( p, ':' ); p++; p = skip_whitespace(p); sscanf(p, "%d", &num); num = num / 1000000; /* Convert to Mhz */ val.uint32 = (uint32_t)num; } else { val.uint32 = 0; } } #endif #if defined (__powerpc__) if (! val.uint32 ) { p = proc_cpuinfo; p = strstr( p, "clock" ); if(p) { p = strchr( p, ':' ); p++; p = skip_whitespace(p); val.uint32 = (uint32_t)strtol( p, (char **)NULL , 10 ); } else { val.uint32 = 0; } } #endif return val; } g_val_t mem_total_func ( void ) { char *p; g_val_t val; p = strstr( update_file(&proc_meminfo), "MemTotal:"); if(p) { p = skip_token(p); val.uint32 = strtol( p, (char **)NULL, 10 ); } else { val.uint32 = 0; } return val; } g_val_t swap_total_func ( void ) { char *p; g_val_t val; p = strstr( update_file(&proc_meminfo), "SwapTotal:" ); if(p) { p = skip_token(p); val.uint32 = strtol( p, (char **)NULL, 10 ); } else { val.uint32 = 0; } return val; } g_val_t boottime_func ( void ) { char *p; g_val_t val; p = update_file(&proc_stat); p = strstr ( p, "btime" ); if(p) { p = skip_token ( p ); val.uint32 = strtod ( p, (char **)NULL ); } else { val.uint32 = 0; } return val; } g_val_t sys_clock_func ( void ) { g_val_t val; val.uint32 = time(NULL); return val; } g_val_t machine_type_func ( void ) { g_val_t val; #ifdef __i386__ snprintf(val.str, MAX_G_STRING_SIZE, "x86"); #endif #ifdef __x86_64__ snprintf(val.str, MAX_G_STRING_SIZE, "x86_64"); #endif #ifdef __ia64__ snprintf(val.str, MAX_G_STRING_SIZE, "ia64"); #endif #ifdef __sparc__ snprintf(val.str, MAX_G_STRING_SIZE, "sparc"); #endif #ifdef __alpha__ snprintf(val.str, MAX_G_STRING_SIZE, "alpha"); #endif #ifdef __powerpc__ snprintf(val.str, MAX_G_STRING_SIZE, "powerpc"); #endif #ifdef __m68k__ snprintf(val.str, MAX_G_STRING_SIZE, "m68k"); #endif #ifdef __mips__ snprintf(val.str, MAX_G_STRING_SIZE, "mips"); #endif #ifdef __arm__ snprintf(val.str, MAX_G_STRING_SIZE, "arm"); #endif #ifdef __hppa__ snprintf(val.str, MAX_G_STRING_SIZE, "hppa"); #endif #ifdef __s390__ snprintf(val.str, MAX_G_STRING_SIZE, "s390"); #endif return val; } g_val_t os_name_func ( void ) { g_val_t val; snprintf(val.str, MAX_G_STRING_SIZE, "Linux"); return val; } g_val_t os_release_func ( void ) { g_val_t val; snprintf(val.str, MAX_G_STRING_SIZE, "%s", proc_sys_kernel_osrelease); return val; } /* * A helper function to return the total number of cpu jiffies */ unsigned long total_jiffies_func ( void ) { char *p; unsigned long user_jiffies, nice_jiffies, system_jiffies, idle_jiffies, wio_jiffies, irq_jiffies, sirq_jiffies; p = update_file(&proc_stat); p = skip_token(p); p = skip_whitespace(p); user_jiffies = strtod( p, &p ); p = skip_whitespace(p); nice_jiffies = strtod( p, &p ); p = skip_whitespace(p); system_jiffies = strtod( p , &p ); p = skip_whitespace(p); idle_jiffies = strtod( p , &p ); if(num_cpustates == NUM_CPUSTATES_24X) return user_jiffies + nice_jiffies + system_jiffies + idle_jiffies; p = skip_whitespace(p); wio_jiffies = strtod( p , &p ); p = skip_whitespace(p); irq_jiffies = strtod( p , &p ); p = skip_whitespace(p); sirq_jiffies = strtod( p , &p ); return user_jiffies + nice_jiffies + system_jiffies + idle_jiffies + wio_jiffies + irq_jiffies + sirq_jiffies; } g_val_t cpu_user_func ( void ) { char *p; static g_val_t val; static int stamp; static double last_user_jiffies, user_jiffies, last_total_jiffies, total_jiffies, diff; p = update_file(&proc_stat); if(proc_stat.last_read != stamp) { stamp = proc_stat.last_read; p = skip_token(p); user_jiffies = strtod( p , (char **)NULL ); total_jiffies = total_jiffies_func(); diff = user_jiffies - last_user_jiffies; if ( diff ) val.f = (diff/(total_jiffies - last_total_jiffies))*100; else val.f = 0.0; last_user_jiffies = user_jiffies; last_total_jiffies = total_jiffies; } return val; } g_val_t cpu_nice_func ( void ) { char *p; static g_val_t val; static int stamp; static double last_nice_jiffies, nice_jiffies, last_total_jiffies, total_jiffies, diff; p = update_file(&proc_stat); if(proc_stat.last_read != stamp) { stamp = proc_stat.last_read; p = skip_token(p); p = skip_token(p); nice_jiffies = strtod( p , (char **)NULL ); total_jiffies = total_jiffies_func(); diff = (nice_jiffies - last_nice_jiffies); if ( diff ) val.f = (diff/(total_jiffies - last_total_jiffies))*100; else val.f = 0.0; last_nice_jiffies = nice_jiffies; last_total_jiffies = total_jiffies; } return val; } g_val_t cpu_system_func ( void ) { char *p; static g_val_t val; static int stamp; static double last_system_jiffies, system_jiffies, last_total_jiffies, total_jiffies, diff; p = update_file(&proc_stat); if(proc_stat.last_read != stamp) { stamp = proc_stat.last_read; p = skip_token(p); p = skip_token(p); p = skip_token(p); system_jiffies = strtod( p , (char **)NULL ); if (num_cpustates > NUM_CPUSTATES_24X) { p = skip_token(p); p = skip_token(p); p = skip_token(p); system_jiffies += strtod( p , (char **)NULL ); /* "intr" counted in system */ p = skip_token(p); system_jiffies += strtod( p , (char **)NULL ); /* "sintr" counted in system */ } total_jiffies = total_jiffies_func(); diff = system_jiffies - last_system_jiffies; if ( diff ) val.f = (diff/(total_jiffies - last_total_jiffies))*100; else val.f = 0.0; last_system_jiffies = system_jiffies; last_total_jiffies = total_jiffies; } return val; } g_val_t cpu_idle_func ( void ) { char *p; static g_val_t val; static int stamp; static double last_idle_jiffies, idle_jiffies, last_total_jiffies, total_jiffies, diff; p = update_file(&proc_stat); if(proc_stat.last_read != stamp) { stamp = proc_stat.last_read; p = skip_token(p); p = skip_token(p); p = skip_token(p); p = skip_token(p); idle_jiffies = strtod( p , (char **)NULL ); total_jiffies = total_jiffies_func(); diff = idle_jiffies - last_idle_jiffies; if ( diff ) val.f = (diff/(total_jiffies - last_total_jiffies))*100; else val.f = 0.0; last_idle_jiffies = idle_jiffies; last_total_jiffies = total_jiffies; } return val; } g_val_t cpu_aidle_func ( void ) { char *p; g_val_t val; double idle_jiffies, total_jiffies; p = update_file(&proc_stat); p = skip_token(p); p = skip_token(p); p = skip_token(p); p = skip_token(p); idle_jiffies = strtod( p , (char **)NULL ); total_jiffies = total_jiffies_func(); val.f = (idle_jiffies/total_jiffies)*100; return val; } g_val_t cpu_wio_func ( void ) { char *p; static g_val_t val; static int stamp; static double last_wio_jiffies, wio_jiffies, last_total_jiffies, total_jiffies, diff; if (num_cpustates == NUM_CPUSTATES_24X) { val.f = 0.; return val; } p = update_file(&proc_stat); if(proc_stat.last_read != stamp) { stamp = proc_stat.last_read; p = skip_token(p); p = skip_token(p); p = skip_token(p); p = skip_token(p); p = skip_token(p); wio_jiffies = strtod( p , (char **)NULL ); total_jiffies = total_jiffies_func(); diff = wio_jiffies - last_wio_jiffies; if ( diff ) val.f = (diff/(total_jiffies - last_total_jiffies))*100; else val.f = 0.0; last_wio_jiffies = wio_jiffies; last_total_jiffies = total_jiffies; } return val; } g_val_t cpu_intr_func ( void ) { char *p; static g_val_t val; static int stamp; static double last_intr_jiffies, intr_jiffies, last_total_jiffies, total_jiffies, diff; if (num_cpustates == NUM_CPUSTATES_24X) { val.f = 0.; return val; } p = update_file(&proc_stat); if(proc_stat.last_read != stamp) { stamp = proc_stat.last_read; p = skip_token(p); p = skip_token(p); p = skip_token(p); p = skip_token(p); p = skip_token(p); p = skip_token(p); intr_jiffies = strtod( p , (char **)NULL ); total_jiffies = total_jiffies_func(); diff = intr_jiffies - last_intr_jiffies; if ( diff ) val.f = (diff/(total_jiffies - last_total_jiffies))*100; else val.f = 0.0; last_intr_jiffies = intr_jiffies; last_total_jiffies = total_jiffies; } return val; } g_val_t cpu_sintr_func ( void ) { char *p; static g_val_t val; static int stamp; static double last_sintr_jiffies, sintr_jiffies, last_total_jiffies, total_jiffies, diff; if (num_cpustates == NUM_CPUSTATES_24X) { val.f = 0.; return val; } p = update_file(&proc_stat); if(proc_stat.last_read != stamp) { stamp = proc_stat.last_read; p = skip_token(p); p = skip_token(p); p = skip_token(p); p = skip_token(p); p = skip_token(p); p = skip_token(p); p = skip_token(p); sintr_jiffies = strtod( p , (char **)NULL ); total_jiffies = total_jiffies_func(); diff = sintr_jiffies - last_sintr_jiffies; if ( diff ) val.f = (diff/(total_jiffies - last_total_jiffies))*100; else val.f = 0.0; last_sintr_jiffies = sintr_jiffies; last_total_jiffies = total_jiffies; } return val; } g_val_t load_one_func ( void ) { g_val_t val; val.f = strtod( update_file(&proc_loadavg), (char **)NULL); return val; } g_val_t load_five_func ( void ) { char *p; g_val_t val; p = update_file(&proc_loadavg); p = skip_token(p); val.f = strtod( p, (char **)NULL); return val; } g_val_t load_fifteen_func ( void ) { char *p; g_val_t val; p = update_file(&proc_loadavg); p = skip_token(p); p = skip_token(p); val.f = strtod( p, (char **)NULL); return val; } g_val_t proc_run_func( void ) { char *p; g_val_t val; p = update_file(&proc_loadavg); p = skip_token(p); p = skip_token(p); p = skip_token(p); val.uint32 = strtol( p, (char **)NULL, 10 ); val.uint32--; /* This shouldn't happen.. but it might */ if (val.uint32 <0) val.uint32 = 0; return val; } g_val_t proc_total_func ( void ) { char *p; g_val_t val; p = update_file(&proc_loadavg); p = skip_token(p); p = skip_token(p); p = skip_token(p); p = skip_whitespace(p); while ( isdigit(*p) ) p++; p++; /* skip the slash-/ */ val.uint32 = strtol( p, (char **)NULL, 10 ); return val; } g_val_t mem_free_func ( void ) { char *p; g_val_t val; p = strstr( update_file(&proc_meminfo), "MemFree:" ); if(p) { p = skip_token(p); val.uint32 = strtol( p, (char **)NULL, 10 ); } else { val.uint32 = 0; } return val; } g_val_t mem_shared_func ( void ) { char *p; g_val_t val; /* ** Broken since linux-2.5.52 when Memshared was removed !! */ p = strstr( update_file(&proc_meminfo), "MemShared:" ); if (p) { p = skip_token(p); val.uint32 = strtol( p, (char **)NULL, 10 ); } else { val.uint32 = 0; } return val; } g_val_t mem_buffers_func ( void ) { char *p; g_val_t val; p = strstr( update_file(&proc_meminfo), "Buffers:" ); if(p) { p = skip_token(p); val.uint32 = strtol( p, (char **)NULL, 10 ); } else { val.uint32 = 0; } return val; } g_val_t mem_cached_func ( void ) { char *p; g_val_t val; p = strstr( update_file(&proc_meminfo), "Cached:"); if(p) { p = skip_token(p); val.uint32 = strtol( p, (char **)NULL, 10 ); } else { val.uint32 = 0; } return val; } g_val_t swap_free_func ( void ) { char *p; g_val_t val; p = strstr( update_file(&proc_meminfo), "SwapFree:" ); if(p) { p = skip_token(p); val.uint32 = strtol( p, (char **)NULL, 10 ); } else { val.uint32 = 0; } return val; } /* --------------------------------------------------------------------------- */ g_val_t mtu_func ( void ) { /* We want to find the minimum MTU (Max packet size) over all UP interfaces. */ g_val_t val; val.uint32 = get_min_mtu(); /* A val of 0 means there are no UP interfaces. Shouldn't happen. */ return val; } /* ===================================================== */ /* Disk Usage. Using fsusage.c from the GNU fileutils-4.1.5 package. */ #include /* Linux Specific, but we are in the Linux machine file. */ #define MOUNTS "/proc/mounts" struct nlist { struct nlist *next; char *name; }; #define DFHASHSIZE 101 static struct nlist *DFhashvector[DFHASHSIZE]; /* --------------------------------------------------------------------------- */ unsigned int DFhash(const char *s) { unsigned int hashval; for (hashval=0; *s != '\0'; s++) hashval = *s + 31 * hashval; return hashval % DFHASHSIZE; } /* --------------------------------------------------------------------------- */ /* From K&R C book, pp. 144-145 */ struct nlist * seen_before(const char *name) { struct nlist *found=0, *np; unsigned int hashval; /* lookup */ hashval=DFhash(name); for (np=DFhashvector[hashval]; np; np=np->next) { if (!strcmp(name,np->name)) { found=np; break; } } if (!found) { /* not found */ np = (struct nlist *) malloc(sizeof(*np)); if (!np || !(np->name = (char *) strdup(name))) return NULL; np->next = DFhashvector[hashval]; DFhashvector[hashval] = np; return NULL; } else /* found name */ return found; } /* --------------------------------------------------------------------------- */ void DFcleanup() { struct nlist *np, *next; int i; for (i=0; inext; free(np->name); free(np); } DFhashvector[i] = 0; } } /* --------------------------------------------------------------------------- */ int remote_mount(const char *device, const char *type) { /* From ME_REMOTE macro in mountlist.h: A file system is `remote' if its Fs_name contains a `:' or if (it is of type smbfs and its Fs_name starts with `//'). */ return ((strchr(device,':') != 0) || (!strcmp(type, "smbfs") && device[0]=='/' && device[1]=='/') || (!strncmp(type, "nfs", 3)) || (!strcmp(type, "autofs")) || (!strcmp(type,"gfs")) || (!strcmp(type,"none")) ); } /* --------------------------------------------------------------------------- */ float device_space(char *mount, char *device, double *total_size, double *total_free) { struct statvfs svfs; uint32_t blocksize; uint32_t free; uint32_t size; /* The percent used: used/total * 100 */ float pct=0.0; /* Avoid multiply-mounted disks - not done in df. */ if (seen_before(device)) return pct; if (statvfs(mount, &svfs)) { /* Ignore funky devices... */ return pct; } free = svfs.f_bavail; size = svfs.f_blocks; blocksize = svfs.f_bsize; /* Keep running sum of total used, free local disk space. */ *total_size += size * (double) blocksize; *total_free += free * (double) blocksize; /* The percentage of space used on this partition. */ pct = size ? ((size - free) / (float) size) * 100 : 0.0; return pct; } /* --------------------------------------------------------------------------- */ float find_disk_space(double *total_size, double *total_free) { FILE *mounts; char procline[256]; char mount[128], device[128], type[32], mode[128]; /* We report in GB = 1e9 bytes. */ double reported_units = 1e9; /* Track the most full disk partition, report with a percentage. */ float thispct, max=0.0; int rc; /* Read all currently mounted filesystems. */ mounts=fopen(MOUNTS,"r"); if (!mounts) { debug_msg("Df Error: could not open mounts file %s. Are we on the right OS?\n", MOUNTS); return max; } while ( fgets(procline, sizeof(procline), mounts) ) { rc=sscanf(procline, "%s %s %s %s ", device, mount, type, mode); if (!rc) continue; if (!strncmp(mode, "ro", 2)) continue; if (remote_mount(device, type)) continue; if (strncmp(device, "/dev/", 5) != 0 && strncmp(device, "/dev2/", 6) != 0) continue; thispct = device_space(mount, device, total_size, total_free); debug_msg("Counting device %s (%.2f %%)", device, thispct); if (!max || max