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