1 /*
2  * This file contains all the metrics gathering code from Windows using cygwin
3  * or native Windows calls when possible.
4  *
5  * Tested in Windows XP Home SP3 (i386)
6  * Tested in Windows Vista Home SP1 (i386)
7  * Tested in Windows Advanced Server 2000 (i386)
8  */
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <time.h>
14 #include <unistd.h>
15 #include <ctype.h>
16 #define _WIN32_WINNT 0x0500
17 #include <windows.h>
18 #include <iphlpapi.h>
19 #include <sys/types.h>
20 #include <sys/utsname.h>
21 #include <sys/time.h>
22 #include <sys/timeb.h>
23 #include <mntent.h>
24 #include <sys/vfs.h>
25 #include <psapi.h>
26 
27 /* From old ganglia 2.5.x... */
28 #include "gm_file.h"
29 #include "libmetrics.h"
30 /* End old ganglia 2.5.x headers */
31 #undef min
32 #undef max
33 #include "interface.h"
34 
35 char *proc_cpuinfo = NULL;
36 
37 char sys_osname[MAX_G_STRING_SIZE];
38 char sys_osrelease[MAX_G_STRING_SIZE];
39 
40 timely_file proc_stat = { {0, 0}, 1., "/proc/stat", NULL, BUFFSIZE };
41 
42 static time_t
get_netbw(double * in_bytes,double * out_bytes,double * in_pkts,double * out_pkts)43 get_netbw(double *in_bytes, double *out_bytes,
44     double *in_pkts, double *out_pkts)
45 {
46   PMIB_IFTABLE iftable;
47   double bytes_in = 0, bytes_out = 0, pkts_in = 0, pkts_out = 0;
48   static DWORD dwSize;
49   DWORD ret, dwInterface;
50   struct timeb timebuffer;
51   PMIB_IFROW ifrow;
52 
53   dwSize = sizeof(MIB_IFTABLE);
54 
55   iftable = (PMIB_IFTABLE) malloc (dwSize);
56   while ((ret = GetIfTable(iftable, &dwSize, 1)) == ERROR_INSUFFICIENT_BUFFER) {
57      iftable = (PMIB_IFTABLE) realloc (iftable, dwSize);
58   }
59 
60   if (ret == NO_ERROR) {
61 
62     ftime ( &timebuffer );
63 
64     /* scan the interface table */
65     for (dwInterface = 0; dwInterface < (iftable -> dwNumEntries); dwInterface++) {
66       ifrow = &(iftable -> table[dwInterface]);
67 
68     /* exclude loopback */
69       if ( (ifrow -> dwType != MIB_IF_TYPE_LOOPBACK ) && (ifrow -> dwOperStatus ==MIB_IF_OPER_STATUS_OPERATIONAL ) ) {
70         bytes_in += ifrow -> dwInOctets;
71         bytes_out += ifrow -> dwOutOctets;
72 
73         /* does not include multicast traffic (dw{In,Out}NUcastPkts) */
74         pkts_in += ifrow -> dwInUcastPkts;
75         pkts_out += ifrow -> dwOutUcastPkts;
76       }
77     }
78     free (iftable);
79   } else {
80     err_msg("get_netbw() got an error from GetIfTable()");
81   }
82 
83   if (in_bytes) *in_bytes = bytes_in;
84   if (out_bytes) *out_bytes = bytes_out;
85   if (in_pkts) *in_pkts = pkts_in;
86   if (out_pkts) *out_pkts = pkts_out;
87 
88   return timebuffer.time;
89 }
90 
91 /*
92  * A helper function to determine the number of cpustates in /proc/stat (MKN)
93  */
94 #define NUM_CPUSTATES_24X 4
95 #define NUM_CPUSTATES_26X 7
96 static unsigned int num_cpustates;
97 
98 unsigned int
num_cpustates_func(void)99 num_cpustates_func ( void )
100 {
101    char *p;
102    unsigned int i=0;
103 
104    proc_stat.last_read.tv_sec = 0;
105    proc_stat.last_read.tv_usec = 0;
106    p = update_file(&proc_stat);
107    proc_stat.last_read.tv_sec = 0;
108    proc_stat.last_read.tv_usec = 0;
109 
110 /*
111 ** Skip initial "cpu" token
112 */
113    p = skip_token(p);
114    p = skip_whitespace(p);
115 /*
116 ** Loop over file until next "cpu" token is found.
117 ** i=4 : Cygwin
118 */
119    while (strncmp(p,"cpu",3)) {
120      p = skip_token(p);
121      p = skip_whitespace(p);
122      i++;
123      }
124 
125    return i;
126 }
127 /*
128  * This function is called only once by the gmond.  Use to
129  * initialize data structures, etc or just return SYNAPSE_SUCCESS;
130  */
131 g_val_t
metric_init(void)132 metric_init(void)
133 {
134    struct utsname u;
135    g_val_t rval;
136    char *bp;
137 
138    num_cpustates = num_cpustates_func();
139 
140    bp = proc_cpuinfo;
141    rval.int32 = slurpfile("/proc/cpuinfo", &bp, BUFFSIZE);
142    if (proc_cpuinfo == NULL)
143       proc_cpuinfo = bp;
144 
145    if ( rval.int32 == SLURP_FAILURE ) {
146          err_msg("metric_init() got an error from slurpfile() /proc/cpuinfo");
147          rval.int32 = SYNAPSE_FAILURE;
148          return rval;
149    }
150 
151    if (uname(&u) == -1) {
152       strncpy(sys_osname, "unknown", MAX_G_STRING_SIZE);
153       strncpy(sys_osrelease, "unknown", MAX_G_STRING_SIZE);
154    } else {
155       strncpy(sys_osname, u.sysname, MAX_G_STRING_SIZE);
156       sys_osname[MAX_G_STRING_SIZE - 1] = '\0';
157       strncpy(sys_osrelease, u.release, MAX_G_STRING_SIZE);
158       sys_osrelease[MAX_G_STRING_SIZE - 1] = '\0';
159    }
160    rval.int32 = SYNAPSE_SUCCESS;
161 
162    return rval;
163 }
164 
165 g_val_t
pkts_in_func(void)166 pkts_in_func ( void )
167 {
168    double in_pkts=0, t=0;
169    time_t stamp;
170    static time_t last_stamp;
171    static double last_pkts_in;
172    g_val_t val;
173    unsigned long diff;
174 
175    stamp = get_netbw(NULL, NULL, &in_pkts, NULL);
176    diff = (unsigned long)(in_pkts - last_pkts_in);
177    if ( diff && last_stamp ) {
178      t = stamp - last_stamp;
179      t = diff / t;
180      debug_msg("Returning value: %f\n", t);
181    } else
182      t = 0;
183 
184    val.f = t;
185    last_pkts_in = in_pkts;
186    last_stamp = stamp;
187 
188    return val;
189 }
190 
191 g_val_t
pkts_out_func(void)192 pkts_out_func ( void )
193 {
194    double out_pkts=0, t=0;
195    time_t stamp;
196    static time_t last_stamp;
197    static double last_pkts_out;
198    g_val_t val;
199    unsigned long diff;
200 
201    stamp = get_netbw(NULL, NULL, NULL, &out_pkts);
202    diff = (unsigned long)(out_pkts - last_pkts_out);
203    if ( diff && last_stamp ) {
204      t = stamp - last_stamp;
205      t = diff / t;
206      debug_msg("Returning value: %f\n", t);
207    } else
208      t = 0;
209 
210    val.f = t;
211    last_pkts_out = out_pkts;
212    last_stamp = stamp;
213 
214    return val;
215 }
216 
217 g_val_t
bytes_out_func(void)218 bytes_out_func ( void )
219 {
220    double out_bytes=0, t=0;
221    time_t stamp;
222    static time_t last_stamp;
223    static double last_bytes_out;
224    g_val_t val;
225    unsigned long diff;
226 
227    stamp = get_netbw(NULL, &out_bytes, NULL, NULL);
228    diff = (unsigned long)(out_bytes - last_bytes_out);
229    if ( diff && last_stamp ) {
230      t = stamp - last_stamp;
231      t = diff / t;
232      debug_msg("Returning value: %f\n", t);
233    } else
234      t = 0;
235 
236    val.f = t;
237    last_bytes_out = out_bytes;
238    last_stamp = stamp;
239 
240    return val;
241 }
242 
243 g_val_t
bytes_in_func(void)244 bytes_in_func ( void )
245 {
246    double in_bytes=0, t=0;
247    time_t stamp;
248    static time_t last_stamp;
249    static double last_bytes_in;
250    g_val_t val;
251    unsigned long diff;
252 
253    stamp = get_netbw(&in_bytes, NULL, NULL, NULL);
254    diff = (unsigned long)(in_bytes - last_bytes_in);
255    if ( diff && last_stamp ) {
256      t = stamp - last_stamp;
257      t = diff / t;
258      debug_msg("Returning value: %f\n", t);
259    } else
260      t = 0;
261 
262    val.f = t;
263    last_bytes_in = in_bytes;
264    last_stamp = stamp;
265 
266    return val;
267 }
268 
269 g_val_t
cpu_num_func(void)270 cpu_num_func ( void )
271 {
272    static DWORD cpu_num = 0;
273    SYSTEM_INFO siSysInfo;
274    g_val_t val;
275 
276    /* Only need to do this once */
277    if (!cpu_num) {
278       GetSystemInfo(&siSysInfo);
279       cpu_num = siSysInfo.dwNumberOfProcessors;
280    }
281    val.uint16 = cpu_num;
282 
283    return val;
284 }
285 
286 g_val_t
cpu_speed_func(void)287 cpu_speed_func ( void )
288 {
289    char *p;
290    static g_val_t val = {0};
291 
292 /* i386, ia64, x86_64 and hppa all report MHz in the same format */
293 #if defined (__i386__) || defined(__ia64__) || defined(__hppa__) || defined(__x86_64__)
294    if (! val.uint32 )
295       {
296          p = proc_cpuinfo;
297          p = strstr( p, "cpu MHz" );
298          if (p) {
299            p = strchr( p, ':' );
300            p++;
301            p = skip_whitespace(p);
302            val.uint32 = (uint32_t)strtol( p, (char **)NULL , 10 );
303          } else {
304            val.uint32 = 0;
305          }
306       }
307 #endif
308 #if defined (__alpha__)
309    if (! val.uint32 ) {
310          int num;
311          p = proc_cpuinfo;
312          p = strstr( p, "cycle frequency [Hz]" );
313          if (p) {
314            p = strchr( p, ':' );
315            p++;
316            p = skip_whitespace(p);
317            sscanf(p, "%d", &num);
318            num = num / 1000000;  /* Convert to Mhz */
319            val.uint32 = (uint32_t)num;
320          } else {
321            val.uint32 = 0;
322          }
323       }
324 #endif
325 #if defined (__powerpc__)
326    if (! val.uint32 )
327       {
328          p = proc_cpuinfo;
329          p = strstr( p, "clock" );
330          if (p) {
331            p = strchr( p, ':' );
332            p++;
333            p = skip_whitespace(p);
334            val.uint32 = (uint32_t)strtol( p, (char **)NULL , 10 );
335         } else {
336            val.uint32 = 0;
337         }
338       }
339 #endif
340    return val;
341 }
342 
343 g_val_t
mem_total_func(void)344 mem_total_func ( void )
345 {
346    MEMORYSTATUSEX stat;
347    DWORDLONG size;
348    g_val_t val;
349 
350    stat.dwLength = sizeof(stat);
351 
352    if (GlobalMemoryStatusEx(&stat)) {
353       size = stat.ullTotalPhys;
354       /* get the value in kB */
355       val.f =  size / 1024;
356    } else {
357       val.f = 0;
358    }
359 
360    return val;
361 }
362 
363 /* FIXME?: should be using PERFORMANCE_INFORMATION.CommitLimit */
364 g_val_t
swap_total_func(void)365 swap_total_func ( void )
366 {
367    MEMORYSTATUSEX stat;
368    DWORDLONG size;
369    g_val_t val;
370 
371    stat.dwLength = sizeof(stat);
372 
373    if (GlobalMemoryStatusEx(&stat)) {
374       size = stat.ullTotalPageFile;
375       /* get the value in kB */
376       val.f =  size / 1024;
377    } else {
378       val.f = 0;
379    }
380 
381    return val;
382 }
383 
384 g_val_t
boottime_func(void)385 boottime_func ( void )
386 {
387    char *p;
388    g_val_t val;
389 
390    p = update_file(&proc_stat);
391 
392    p = strstr ( p, "btime" );
393    if (p) {
394      p = skip_token ( p );
395      val.uint32 = atoi ( p );
396    } else {
397      val.uint32 = 0;
398    }
399 
400    return val;
401 }
402 
403 g_val_t
sys_clock_func(void)404 sys_clock_func ( void )
405 {
406    g_val_t val;
407 
408    val.uint32 = time(NULL);
409 
410    return val;
411 }
412 
413 g_val_t
machine_type_func(void)414 machine_type_func ( void )
415 {
416    SYSTEM_INFO siSysInfo;
417    g_val_t val;
418 
419    GetSystemInfo(&siSysInfo);
420 
421    switch (siSysInfo.wProcessorArchitecture) {
422       case PROCESSOR_ARCHITECTURE_AMD64:
423          snprintf(val.str, MAX_G_STRING_SIZE, "x86_64");
424          break;
425       case PROCESSOR_ARCHITECTURE_IA64:
426          snprintf(val.str, MAX_G_STRING_SIZE, "ia64");
427          break;
428       case PROCESSOR_ARCHITECTURE_INTEL:
429          snprintf(val.str, MAX_G_STRING_SIZE, "x86");
430          break;
431       case PROCESSOR_ARCHITECTURE_ALPHA:
432       case PROCESSOR_ARCHITECTURE_ALPHA64:
433          snprintf(val.str, MAX_G_STRING_SIZE, "alpha");
434          break;
435       case PROCESSOR_ARCHITECTURE_PPC:
436          snprintf(val.str, MAX_G_STRING_SIZE, "powerpc");
437          break;
438       case PROCESSOR_ARCHITECTURE_MIPS:
439          snprintf(val.str, MAX_G_STRING_SIZE, "mips");
440          break;
441       case PROCESSOR_ARCHITECTURE_ARM:
442          snprintf(val.str, MAX_G_STRING_SIZE, "arm");
443          break;
444       default:
445          snprintf(val.str, MAX_G_STRING_SIZE, "unknown");
446    }
447 
448    return val;
449 }
450 
451 g_val_t
os_name_func(void)452 os_name_func ( void )
453 {
454    g_val_t val;
455 
456    snprintf(val.str, MAX_G_STRING_SIZE, "%s", sys_osname);
457 
458    return val;
459 }
460 
461 g_val_t
os_release_func(void)462 os_release_func ( void )
463 {
464    g_val_t val;
465 
466    snprintf(val.str, MAX_G_STRING_SIZE, "%s", sys_osrelease);
467 
468    return val;
469 }
470 
471 /*
472  * A helper function to return the total number of cpu jiffies
473  */
474 unsigned long
total_jiffies_func(void)475 total_jiffies_func ( void )
476 {
477    char *p;
478    unsigned long user_jiffies, nice_jiffies, system_jiffies, idle_jiffies;
479 
480    p = update_file(&proc_stat);
481    p = skip_token(p);
482    p = skip_whitespace(p);
483    user_jiffies = strtod( p, &p );
484    p = skip_whitespace(p);
485    nice_jiffies = strtod( p, &p );
486    p = skip_whitespace(p);
487    system_jiffies = strtod( p , &p );
488    p = skip_whitespace(p);
489    idle_jiffies = strtod( p , &p );
490 
491    return (user_jiffies + nice_jiffies + system_jiffies + idle_jiffies);
492 }
493 
494 g_val_t
cpu_user_func(void)495 cpu_user_func ( void )
496 {
497    char *p;
498    static g_val_t val;
499    static struct timeval stamp = {0, 0};
500    static double last_user_jiffies,  user_jiffies,
501                  last_total_jiffies, total_jiffies, diff;
502 
503    p = update_file(&proc_stat);
504    if ((proc_stat.last_read.tv_sec != stamp.tv_sec) &&
505        (proc_stat.last_read.tv_usec != stamp.tv_usec)) {
506      stamp = proc_stat.last_read;
507 
508      p = skip_token(p);
509      user_jiffies  = strtod( p , (char **)NULL );
510      total_jiffies = total_jiffies_func();
511 
512      diff = user_jiffies - last_user_jiffies;
513 
514      if ( diff )
515        val.f = (diff/(total_jiffies - last_total_jiffies))*100;
516      else
517        val.f = 0.0;
518 
519      last_user_jiffies  = user_jiffies;
520      last_total_jiffies = total_jiffies;
521    }
522 
523    return val;
524 }
525 
526 g_val_t
cpu_nice_func(void)527 cpu_nice_func ( void )
528 {
529    char *p;
530    static g_val_t val;
531    static struct timeval stamp = {0, 0};
532    static double last_nice_jiffies,  nice_jiffies,
533                  last_total_jiffies, total_jiffies, diff;
534 
535    p = update_file(&proc_stat);
536    if ((proc_stat.last_read.tv_sec != stamp.tv_sec) &&
537        (proc_stat.last_read.tv_usec != stamp.tv_usec)) {
538      stamp = proc_stat.last_read;
539 
540      p = skip_token(p);
541      p = skip_token(p);
542      nice_jiffies  = strtod( p , (char **)NULL );
543      total_jiffies = total_jiffies_func();
544 
545      diff = (nice_jiffies  - last_nice_jiffies);
546 
547      if ( diff )
548        val.f = (diff/(total_jiffies - last_total_jiffies))*100;
549      else
550        val.f = 0.0;
551 
552      last_nice_jiffies  = nice_jiffies;
553      last_total_jiffies = total_jiffies;
554    }
555 
556    return val;
557 }
558 
559 g_val_t
cpu_system_func(void)560 cpu_system_func ( void )
561 {
562    char *p;
563    static g_val_t val;
564    static struct timeval stamp = {0, 0};
565    static double last_system_jiffies,  system_jiffies,
566                  last_total_jiffies, total_jiffies, diff;
567 
568    p = update_file(&proc_stat);
569    if ((proc_stat.last_read.tv_sec != stamp.tv_sec) &&
570        (proc_stat.last_read.tv_usec != stamp.tv_usec)) {
571      stamp = proc_stat.last_read;
572 
573      p = skip_token(p);
574      p = skip_token(p);
575      p = skip_token(p);
576      system_jiffies = strtod( p , (char **)NULL );
577      if (num_cpustates > NUM_CPUSTATES_24X) {
578        p = skip_token(p);
579        p = skip_token(p);
580        p = skip_token(p);
581        system_jiffies += strtod( p , (char **)NULL );
582        p = skip_token(p);
583        system_jiffies += strtod( p , (char **)NULL );
584        }
585      total_jiffies  = total_jiffies_func();
586 
587      diff = system_jiffies  - last_system_jiffies;
588 
589      if ( diff )
590        val.f = (diff/(total_jiffies - last_total_jiffies))*100;
591      else
592        val.f = 0.0;
593 
594      last_system_jiffies  = system_jiffies;
595      last_total_jiffies = total_jiffies;
596    }
597 
598    return val;
599 }
600 
601 g_val_t
cpu_idle_func(void)602 cpu_idle_func ( void )
603 {
604    char *p;
605    static g_val_t val;
606    static struct timeval stamp = {0, 0};
607    static double last_idle_jiffies,  idle_jiffies,
608                  last_total_jiffies, total_jiffies, diff;
609 
610    p = update_file(&proc_stat);
611    if ((proc_stat.last_read.tv_sec != stamp.tv_sec) &&
612        (proc_stat.last_read.tv_usec != stamp.tv_usec)) {
613      stamp = proc_stat.last_read;
614 
615      p = skip_token(p);
616      p = skip_token(p);
617      p = skip_token(p);
618      p = skip_token(p);
619      idle_jiffies  = strtod( p , (char **)NULL );
620      total_jiffies = total_jiffies_func();
621 
622      diff = idle_jiffies - last_idle_jiffies;
623 
624      if ( diff )
625        val.f = (diff/(total_jiffies - last_total_jiffies))*100;
626      else
627        val.f = 0.0;
628 
629      last_idle_jiffies  = idle_jiffies;
630      last_total_jiffies = total_jiffies;
631    }
632 
633    return val;
634 }
635 
636 /* FIXME? */
637 g_val_t
cpu_aidle_func(void)638 cpu_aidle_func ( void )
639 {
640    g_val_t val;
641 
642    val.f = 0.0;
643 
644    return val;
645 }
646 
647 /* FIXME? */
648 g_val_t
cpu_wio_func(void)649 cpu_wio_func ( void )
650 {
651    g_val_t val;
652 
653    val.f = 0.0;
654 
655    return val;
656 }
657 
658 /* FIXME? */
659 g_val_t
cpu_intr_func(void)660 cpu_intr_func ( void )
661 {
662    g_val_t val;
663 
664    val.f = 0.0;
665 
666    return val;
667 }
668 
669 /* FIXME? */
670 g_val_t
cpu_sintr_func(void)671 cpu_sintr_func ( void )
672 {
673    g_val_t val;
674 
675    val.f = 0.0;
676 
677    return val;
678 }
679 
680 /* FIXME? */
681 g_val_t
load_one_func(void)682 load_one_func ( void )
683 {
684    g_val_t val;
685 
686    val.f = 0.0;
687 
688    return val;
689 }
690 
691 /* FIXME? */
692 g_val_t
load_five_func(void)693 load_five_func ( void )
694 {
695    g_val_t val;
696 
697    val.f = 0.0;
698 
699    return val;
700 }
701 
702 /* FIXME? */
703 g_val_t
load_fifteen_func(void)704 load_fifteen_func ( void )
705 {
706    g_val_t val;
707 
708    val.f = 0.0;
709 
710    return val;
711 }
712 
713 /* FIXME: fixed number of processes */
714 #define MAXPROCESSES 1024
715 
716 /* FIXME */
717 g_val_t
proc_run_func(void)718 proc_run_func( void )
719 {
720    DWORD aProcesses[MAXPROCESSES], cbNeeded, cProcesses;
721    unsigned int running = 0;
722    g_val_t val;
723 
724    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
725       cProcesses = 0;
726    } else {
727       cProcesses = cbNeeded / sizeof(DWORD);
728    }
729 #if (_WIN32_WINNT >= 0x0501)
730    /* Only for XP or newer */
731    unsigned int i;
732    HANDLE hProcess;
733    BOOL bResult;
734 
735    for (i = 0; i < cProcesses; i++)
736       if (aProcesses[i] != 0) {
737          hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,
738                                 FALSE, aProcesses[i]);
739          if (hProcess != NULL) {
740             if (IsProcessInJob(hProcess, NULL, &bResult)) {
741                if (bResult)
742                   running++;
743             }
744             CloseHandle(hProcess);
745          }
746       }
747 #endif
748 
749    val.uint32 = running;
750 
751    return val;
752 }
753 
754 /* FIXME */
755 g_val_t
proc_total_func(void)756 proc_total_func ( void )
757 {
758    DWORD aProcesses[MAXPROCESSES], cbNeeded, cProcesses;
759    g_val_t val;
760 
761    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
762       cProcesses = 0;
763    } else {
764       cProcesses = cbNeeded / sizeof(DWORD);
765    }
766    val.uint32 = cProcesses;
767 
768    return val;
769 }
770 
771 g_val_t
mem_free_func(void)772 mem_free_func ( void )
773 {
774    MEMORYSTATUSEX stat;
775    DWORDLONG size;
776    g_val_t val;
777 
778    stat.dwLength = sizeof(stat);
779 
780    if (GlobalMemoryStatusEx(&stat)) {
781       size = stat.ullAvailPhys;
782       /* get the value in kB */
783       val.f =  size / 1024;
784    } else {
785       val.f = 0;
786    }
787 
788    return val;
789 }
790 
791 /* FIXME */
792 g_val_t
mem_shared_func(void)793 mem_shared_func ( void )
794 {
795    g_val_t val;
796 
797    val.f = 0;
798 
799    return val;
800 }
801 
802 /* FIXME */
803 g_val_t
mem_buffers_func(void)804 mem_buffers_func ( void )
805 {
806    g_val_t val;
807 
808    val.f = 0;
809 
810    return val;
811 }
812 
813 /* FIXME */
814 g_val_t
mem_cached_func(void)815 mem_cached_func ( void )
816 {
817    g_val_t val;
818 
819    val.f = 0;
820 
821    return val;
822 }
823 
824 /* FIXME: should be using PERFORMANCE_INFORMATION.CommitTotal */
825 g_val_t
swap_free_func(void)826 swap_free_func ( void )
827 {
828    MEMORYSTATUSEX stat;
829    DWORDLONG size;
830    g_val_t val;
831 
832    stat.dwLength = sizeof(stat);
833 
834    if (GlobalMemoryStatusEx(&stat)) {
835       size = stat.ullAvailPageFile;
836       /* get the value in kB */
837       val.f =  size / 1024;
838    } else {
839       val.f = 0;
840    }
841 
842    return val;
843 }
844 
845 g_val_t
mtu_func(void)846 mtu_func ( void )
847 {
848    /*
849     * We want to find the minimum MTU (Max packet size) over all UP
850     * interfaces.
851     */
852    g_val_t val;
853 
854    val.uint32 = get_min_mtu();
855 
856    /* A val of 0 means there are no UP interfaces. Shouldn't happen. */
857    return val;
858 }
859 
860 /* FIXME: hardcoded max number of disks */
861 #define MAXDRIVES 4
862 
863 typedef struct {
864    double total;
865    double avail;
866 } disk_t;
867 
868 static float
find_disk_space(double * total,double * avail)869 find_disk_space(double *total, double *avail)
870 {
871    FILE *mnttab;
872    disk_t drives[MAXDRIVES];
873    struct mntent *ent;
874    struct statfs fs;
875    const double reported_units = 1e9;
876    int drive;
877    float pct;
878    float most_full = 0.0;
879 
880    *total = 0.0;
881    *avail = 0.0;
882    bzero(drives, sizeof(disk_t) * MAXDRIVES);
883 
884    mnttab = setmntent(MOUNTED, "r");
885    while ((ent = getmntent(mnttab)) != NULL) {
886       if (islower((int)ent->mnt_fsname[0])) {
887          drive = ent->mnt_fsname[0] - 'a';
888          if (drives[drive].total == 0.0) {
889             statfs(ent->mnt_fsname, &fs);
890 
891             drives[drive].total = (double)fs.f_blocks * fs.f_bsize;
892             drives[drive].avail = (double)fs.f_bavail * fs.f_bsize;
893 
894             pct = (drives[drive].avail == 0) ? 100.0 :
895                ((drives[drive].total -
896                drives[drive].avail)/drives[drive].total) * 100.0;
897 
898             if (pct > most_full)
899                most_full = pct;
900 
901             *total += (drives[drive].total / reported_units);
902             *avail += (drives[drive].avail / reported_units);
903          }
904       }
905    }
906    endmntent(mnttab);
907 
908    return most_full;
909 }
910 
911 g_val_t
disk_free_func(void)912 disk_free_func( void )
913 {
914    double total_free = 0.0;
915    double total_size = 0.0;
916    g_val_t val;
917 
918    find_disk_space(&total_size, &total_free);
919 
920    val.d = total_free;
921    return val;
922 }
923 
924 g_val_t
disk_total_func(void)925 disk_total_func( void )
926 {
927    double total_free = 0.0;
928    double total_size = 0.0;
929    g_val_t val;
930 
931    find_disk_space(&total_size, &total_free);
932 
933    val.d = total_size;
934    return val;
935 }
936 
937 g_val_t
part_max_used_func(void)938 part_max_used_func( void )
939 {
940    double total_free = 0.0;
941    double total_size = 0.0;
942    float most_full;
943    g_val_t val;
944 
945    most_full = find_disk_space(&total_size, &total_free);
946 
947    val.f = most_full;
948    return val;
949 }
950