1 /*
2 * Rewrite of AIX metrics using libperfstat API
3 *
4 * Libperfstat can deal with a 32-bit and a 64-bit Kernel and does not require root authority.
5 *
6 * The code is tested with AIX 5.2 (32Bit- and 64Bit-Kernel), but 5.1 and 5.3 shoud be OK too
7 *
8 * by Andreas Schoenfeld, TU Darmstadt, Germany (4/2005)
9 * E-Mail: Schoenfeld@hrz.tu-darmstadt.de
10 *
11 * Its based on the
12 * First stab at support for metrics in AIX
13 * by Preston Smith <psmith@physics.purdue.edu>
14 * Wed Feb 27 14:55:33 EST 2002
15 *
16 * AIX V5 support, bugfixes added by Davide Tacchella <tack@cscs.ch>
17 * May 10, 2002
18 *
19 * you may still find some code (like "int bos_level(..)" ) and the basic structure of this version.
20 *
21 * Some code fragments of the network statistics are "borowed" from
22 * the Solaris Metrics
23 *
24 * Fix proc_total, proc_run, swap_free and swap_total. Implement mem_cached (MKN, 16-Jan-2006)
25 *
26 */
27
28 #include "interface.h"
29 #include <stdlib.h>
30 #include <utmp.h>
31 #include <stdio.h>
32 #include <procinfo.h>
33 #include <strings.h>
34 #include <signal.h>
35 #include <odmi.h>
36 #include <cf.h>
37 #include <sys/utsname.h>
38 #include <sys/proc.h>
39 #include <sys/types.h>
40 #include <time.h>
41
42 #include <libperfstat.h>
43
44 #include "libmetrics.h"
45
46
47
48
49 struct Class *My_CLASS;
50
51 struct product {
52 char filler[12];
53 char lpp_name[145]; /* offset: 0xc ( 12) */
54 char comp_id[20]; /* offset: 0x9d ( 157) */
55 short update; /* offset: 0xb2 ( 178) */
56 long cp_flag; /* offset: 0xb4 ( 180) */
57 char fesn[10]; /* offset: 0xb8 ( 184) */
58 char *name; /*[42] offset: 0xc4 ( 196) */
59 short state; /* offset: 0xc8 ( 200) */
60 short ver; /* offset: 0xca ( 202) */
61 short rel; /* offset: 0xcc ( 204) */
62 short mod; /* offset: 0xce ( 206) */
63 short fix; /* offset: 0xd0 ( 208) */
64 char ptf[10]; /* offset: 0xd2 ( 210) */
65 short media; /* offset: 0xdc ( 220) */
66 char sceded_by[10]; /* offset: 0xde ( 222) */
67 char *fixinfo; /* [1024] offset: 0xe8 ( 232) */
68 char *prereq; /* [1024] offset: 0xec ( 236) */
69 char *description; /* [1024] offset: 0xf0 ( 240) */
70 char *supersedes; /* [512] offset: 0xf4 ( 244) */
71 };
72
73 #if defined(_AIX43)
74 #ifndef SBITS
75 /*
76 * For multiplication of fractions that are stored as integers, including
77 * p_pctcpu. Not allowed to do floating point arithmetic in the kernel.
78 */
79 #define SBITS 16
80 #endif
81 #endif
82
83 #define MAX_CPUS 64
84
85 #define INFO_TIMEOUT 10
86 #define CPU_INFO_TIMEOUT INFO_TIMEOUT
87
88 #define MEM_KB_PER_PAGE (4096/1024)
89
90
91 struct cpu_info {
92 time_t timestamp;
93 u_longlong_t total_ticks;
94 u_longlong_t user; /* raw total number of clock ticks spent in user mode */
95 u_longlong_t sys; /* raw total number of clock ticks spent in system mode */
96 u_longlong_t idle; /* raw total number of clock ticks spent idle */
97 u_longlong_t wait; /* raw total number of clock ticks spent waiting for I/O */
98 };
99
100 struct net_stat{
101 double ipackets;
102 double opackets;
103 double ibytes;
104 double obytes;
105 } cur_net_stat;
106
107
108
109
110
111
112 int ci_flag=0;
113 int ni_flag=0;
114
115 perfstat_cpu_total_t cpu_total_buffer;
116 perfstat_netinterface_total_t ninfo[2],*last_ninfo, *cur_ninfo ;
117
118
119 struct cpu_info cpu_info[2],
120 *last_cpu_info,
121 *cur_cpu_info;
122
123
124
125
126 int aixver, aixrel, aixlev, aixfix;
127 static time_t boottime;
128
129 static int isVIOserver;
130
131 /* Prototypes
132 */
133 void update_ifdata(void);
134 void get_cpuinfo(void);
135 int bos_level(int *aix_version, int *aix_release, int *aix_level, int *aix_fix);
136
137
138
139
140
141 /*
142 * This function is called only once by the gmond. Use to
143 * initialize data structures, etc or just return SYNAPSE_SUCCESS;
144 */
145 g_val_t
metric_init(void)146 metric_init(void)
147 {
148 g_val_t val;
149 FILE *f;
150
151
152 /* find out if we are running on a VIO server */
153
154 f = fopen( "/usr/ios/cli/ioscli", "r" );
155
156 if (f)
157 {
158 isVIOserver = 1;
159 fclose( f );
160 }
161 else
162 isVIOserver = 0;
163
164
165 last_cpu_info = &cpu_info[ci_flag];
166 ci_flag^=1;
167 cur_cpu_info = &cpu_info[ci_flag];
168 cur_cpu_info->total_ticks = 0;
169
170 update_ifdata();
171
172 get_cpuinfo();
173 sleep(CPU_INFO_TIMEOUT+1);
174 get_cpuinfo();
175
176 update_ifdata();
177
178 bos_level(&aixver, &aixrel, &aixlev, &aixfix);
179
180 val.int32 = SYNAPSE_SUCCESS;
181 return val;
182 }
183
184 g_val_t
cpu_speed_func(void)185 cpu_speed_func ( void )
186 {
187 g_val_t val;
188 perfstat_cpu_total_t c;
189
190 if (perfstat_cpu_total(NULL, &c, sizeof(perfstat_cpu_total_t), 1) == -1)
191 val.uint32 = 0;
192 else
193 val.uint32 = c.processorHZ/1000000;
194
195 return val;
196 }
197
198 g_val_t
boottime_func(void)199 boottime_func ( void )
200 {
201 g_val_t val;
202 struct utmp buf;
203 FILE *utmp;
204
205 if (!boottime) {
206 utmp = fopen(UTMP_FILE, "r");
207
208 if (utmp == NULL) {
209 /* Can't open utmp, use current time as boottime */
210 boottime = time(NULL);
211 } else {
212 while (fread((char *) &buf, sizeof(buf), 1, utmp) == 1) {
213 if (buf.ut_type == BOOT_TIME) {
214 boottime = buf.ut_time;
215 break;
216 }
217 }
218 fclose (utmp);
219 }
220 }
221 val.uint32 = boottime;
222
223 return val;
224 }
225
226 g_val_t
sys_clock_func(void)227 sys_clock_func ( void )
228 {
229 g_val_t val;
230
231 val.uint32 = time(NULL);
232 return val;
233 }
234
235 g_val_t
machine_type_func(void)236 machine_type_func ( void )
237 {
238 g_val_t val;
239 perfstat_cpu_total_t c;
240
241 if (perfstat_cpu_total (NULL, &c, sizeof( perfstat_cpu_total_t), 1) == -1)
242 strcpy (val.str, "unknown");
243 else
244 strncpy( val.str, c.description, MAX_G_STRING_SIZE );
245
246 return val;
247 }
248
249 g_val_t
os_name_func(void)250 os_name_func ( void )
251 {
252 g_val_t val;
253 struct utsname uts;
254
255 if (isVIOserver)
256 strcpy( val.str, "Virtual I/O Server" );
257 else
258 {
259 uname( &uts );
260 strncpy( val.str, uts.sysname, MAX_G_STRING_SIZE );
261 }
262
263 return val;
264 }
265
266
267 g_val_t
os_release_func(void)268 os_release_func ( void )
269 {
270 g_val_t val;
271 char oslevel[MAX_G_STRING_SIZE];
272
273 sprintf(oslevel, "%d.%d.%d.%d", aixver, aixrel, aixlev, aixfix);
274 strncpy( val.str, oslevel, MAX_G_STRING_SIZE );
275
276 return val;
277 }
278
279
280 /* AIX defines
281 CPU_IDLE, CPU_USER, CPU_SYS(CPU_KERNEL), CPU_WAIT
282 so no metrics for cpu_nice, or cpu_aidle
283 */
284
285
286 #define CALC_CPUINFO(type) ((100.0*(cur_cpu_info->type - last_cpu_info->type))/(1.0*(cur_cpu_info->total_ticks - last_cpu_info->total_ticks)))
287
288 g_val_t
cpu_user_func(void)289 cpu_user_func ( void )
290 {
291 g_val_t val;
292
293
294 get_cpuinfo();
295
296 val.f = CALC_CPUINFO(user);
297
298 if(val.f < 0) val.f = 0.0;
299 return val;
300 }
301
302
303 /*
304 ** AIX does not have this
305 ** FIXME --
306 */
307 g_val_t
cpu_nice_func(void)308 cpu_nice_func ( void )
309 {
310 g_val_t val;
311 val.f = 0;
312 return val;
313 }
314
315 g_val_t
cpu_system_func(void)316 cpu_system_func ( void )
317 {
318 g_val_t val;
319
320 get_cpuinfo();
321 val.f = CALC_CPUINFO(sys) ;
322 if(val.f < 0) val.f = 0.0;
323 return val;
324 }
325 g_val_t
326
cpu_wio_func(void)327 cpu_wio_func ( void )
328 {
329 g_val_t val;
330
331 get_cpuinfo();
332 val.f = CALC_CPUINFO(wait);
333
334
335 if(val.f < 0) val.f = 0.0;
336 return val;
337 }
338
339 g_val_t
cpu_idle_func(void)340 cpu_idle_func ( void )
341 {
342 g_val_t val;
343
344
345 get_cpuinfo();
346 val.f = CALC_CPUINFO(idle);
347
348
349 if(val.f < 0) val.f = 0.0;
350 return val;
351 }
352
353 /*
354 ** AIX does not have this
355 ** FIXME --
356 */
357 g_val_t
cpu_aidle_func(void)358 cpu_aidle_func ( void )
359 {
360 g_val_t val;
361 val.f = 0.0;
362 return val;
363 }
364
365 /*
366 ** Don't know what it is
367 ** FIXME --
368 */
369 g_val_t
cpu_intr_func(void)370 cpu_intr_func ( void )
371 {
372 g_val_t val;
373 val.f = 0.0;
374 return val;
375 }
376
377 /* Don't know what it is
378 ** FIXME --
379 */
380 g_val_t
cpu_sintr_func(void)381 cpu_sintr_func ( void )
382 {
383 g_val_t val;
384 val.f = 0.0;
385 return val;
386 }
387
388
389 g_val_t
bytes_in_func(void)390 bytes_in_func ( void )
391 {
392 g_val_t val;
393 update_ifdata();
394 val.f = cur_net_stat.ibytes;
395 return val;
396 }
397
398
399 g_val_t
bytes_out_func(void)400 bytes_out_func ( void )
401 {
402 g_val_t val;
403
404 update_ifdata();
405 val.f = cur_net_stat.obytes;
406
407 return val;
408 }
409
410
411 g_val_t
pkts_in_func(void)412 pkts_in_func ( void )
413 {
414 g_val_t val;
415
416 update_ifdata();
417 val.f = cur_net_stat.ipackets;
418
419 return val;
420 }
421
422
423 g_val_t
pkts_out_func(void)424 pkts_out_func ( void )
425 {
426 g_val_t val;
427
428
429 update_ifdata();
430 val.f = cur_net_stat.opackets;
431
432 return val;
433 }
434
435 g_val_t
disk_free_func(void)436 disk_free_func ( void )
437 {
438 g_val_t val;
439 perfstat_disk_total_t d;
440
441 if (perfstat_disk_total(NULL, &d, sizeof(perfstat_disk_total_t), 1) == -1)
442 val.d = 0.0;
443 else
444 val.d = (double)d.free / 1024;
445
446 return val;
447 }
448
449 g_val_t
disk_total_func(void)450 disk_total_func ( void )
451 {
452 g_val_t val;
453 perfstat_disk_total_t d;
454
455 if (perfstat_disk_total(NULL, &d, sizeof(perfstat_disk_total_t), 1) == -1)
456 val.d = 0.0;
457 else
458 val.d = (double)d.size / 1024;
459
460 return val;
461 }
462
463 /* FIXME */
464 g_val_t
part_max_used_func(void)465 part_max_used_func ( void )
466 {
467 g_val_t val;
468 val.f = 0.0;
469 return val;
470 }
471
472 g_val_t
load_one_func(void)473 load_one_func ( void )
474 {
475 g_val_t val;
476 perfstat_cpu_total_t c;
477
478 if (perfstat_cpu_total(NULL, &c, sizeof(perfstat_cpu_total_t), 1) == -1)
479 val.f = 0.0;
480 else
481 val.f = (float)c.loadavg[0]/(float)(1<<SBITS);
482 return val;
483 }
484
485 g_val_t
load_five_func(void)486 load_five_func ( void )
487 {
488 g_val_t val;
489 perfstat_cpu_total_t c;
490
491 if (perfstat_cpu_total(NULL, &c, sizeof(perfstat_cpu_total_t), 1) == -1)
492 val.f = 0.0;
493 else
494 val.f = (float)c.loadavg[1]/(float)(1<<SBITS);
495 return val;
496 }
497
498 g_val_t
load_fifteen_func(void)499 load_fifteen_func ( void )
500 {
501 g_val_t val;
502 perfstat_cpu_total_t c;
503
504 if (perfstat_cpu_total(NULL, &c, sizeof(perfstat_cpu_total_t), 1) == -1)
505 val.f = 0.0;
506 else
507 val.f = (float)c.loadavg[2]/(float)(1<<SBITS);
508
509 return val;
510 }
511
512 g_val_t
cpu_num_func(void)513 cpu_num_func ( void )
514 {
515 g_val_t val;
516 perfstat_cpu_total_t c;
517
518 if (perfstat_cpu_total(NULL, &c, sizeof(perfstat_cpu_total_t), 1) == -1)
519 val.uint16 = 0;
520 else
521 val.uint16 = c.ncpus;
522
523 return val;
524 }
525
526 #define MAXPROCS 20
527
528 #if !defined(_AIX61)
529 /*
530 ** These missing prototypes have caused me an afternoon of real grief !!!
531 */
532 int getprocs64 (struct procentry64 *ProcessBuffer, int ProcessSize,
533 struct fdsinfo64 *FileBuffer, int FileSize,
534 pid_t *IndexPointer, int Count);
535 int getthrds64 (pid_t ProcessIdentifier, struct thrdentry64 *ThreadBuffer,
536 int ThreadSize, tid64_t *IndexPointer, int Count);
537 #endif
538
539 /*
540 ** count_threads(pid) finds all runnable threads belonging to
541 ** process==pid. We do not count threads with the TFUNNELLED
542 ** flag set, as they do not seem to count against the load
543 ** averages (pure WOODOO, also known as "heuristics" :-)
544 */
count_threads(pid_t pid)545 int count_threads(pid_t pid) {
546
547 struct thrdentry64 ThreadsBuffer[MAXPROCS];
548 tid64_t IndexPointer = 0;
549 int stat_val;
550 int nth = 0;
551 int i;
552
553 while ((stat_val = getthrds64(pid,
554 ThreadsBuffer,
555 sizeof(struct thrdentry64),
556 &IndexPointer,
557 MAXPROCS )) > 0 )
558
559 {
560 for ( i=0; i<stat_val; i++) {
561 /*
562 ** Do not count FUNNELED threads, as they do not seem to
563 ** be counted in loadavg.
564 */
565 if (ThreadsBuffer[i].ti_flag & TFUNNELLED) continue;
566 if(ThreadsBuffer[i].ti_state == TSRUN) {
567 /*fprintf(stderr,"i=%d pid=%d tid=%lld state=%x flags=%x\n",i,ThreadsBuffer[i].ti_pid,
568 ThreadsBuffer[i].ti_tid,ThreadsBuffer[i].ti_state,
569 ThreadsBuffer[i].ti_flag);*/
570 nth++;
571 }
572 }
573 if (stat_val < MAXPROCS) break;
574 }
575 return nth;
576 }
577
578 /*
579 ** count_procs() computes the number of processes as shown in "ps -A".
580 ** Pass 0 as flag if you want to get a list of all processes.
581 ** Pass 1 if you want to get a list of all processes with
582 ** runnable threads.
583 */
count_procs(int flag)584 int count_procs(int flag) {
585
586 struct procentry64 ProcessBuffer[MAXPROCS];
587 pid_t IndexPointer = 0;
588 int np = 0;
589 int stat_val;
590 int i;
591
592 while ((stat_val = getprocs64(
593 &ProcessBuffer[0],
594 sizeof(struct procentry64),
595 NULL,
596 sizeof(struct fdsinfo64),
597 &IndexPointer,
598 MAXPROCS )) > 0 )
599
600 {
601 for ( i=0; i<stat_val; i++) {
602 if(flag != 0) {
603 /*fprintf(stderr,"i=%d pid=%d state=%x flags=%x flags2=%x thcount=%d\n",i,
604 ProcessBuffer[i].pi_pid,ProcessBuffer[i].pi_state,
605 ProcessBuffer[i].pi_flags,ProcessBuffer[i].pi_flags2,
606 ProcessBuffer[i].pi_thcount);*/
607 np += count_threads(ProcessBuffer[i].pi_pid);
608 }
609 else {
610 np++;
611 }
612 }
613 if (stat_val < MAXPROCS) break;
614 }
615
616 /*
617 ** Reduce by one to make proc_run more Linux "compliant".
618 */
619 if ((flag != 0) && (np > 0)) np--;
620
621 return np;
622 }
623
624
625 g_val_t
proc_total_func(void)626 proc_total_func ( void )
627 {
628 g_val_t foo;
629
630 foo.uint32 = count_procs(0);
631
632 return foo;
633 }
634
635
636 g_val_t
proc_run_func(void)637 proc_run_func( void )
638 {
639 g_val_t val;
640
641 val.uint32 = count_procs(1);
642
643 return val;
644 }
645
646 g_val_t
mem_total_func(void)647 mem_total_func ( void )
648 {
649 g_val_t val;
650 perfstat_memory_total_t m;
651
652 if (perfstat_memory_total(NULL, &m, sizeof(perfstat_memory_total_t), 1) == -1)
653 val.f = 0;
654 else
655 val.f = m.real_total * MEM_KB_PER_PAGE;
656
657 return val;
658 }
659
660 g_val_t
mem_free_func(void)661 mem_free_func ( void )
662 {
663 g_val_t val;
664 perfstat_memory_total_t m;
665
666 if (perfstat_memory_total(NULL, &m, sizeof(perfstat_memory_total_t), 1) == -1)
667 val.f = 0;
668 else
669 val.f = m.real_free * MEM_KB_PER_PAGE;
670
671 return val;
672 }
673
674 /* FIXME? */
675 g_val_t
mem_shared_func(void)676 mem_shared_func ( void )
677 {
678 g_val_t val;
679
680 val.f = 0;
681
682 return val;
683 }
684
685 /* FIXME? */
686 g_val_t
mem_buffers_func(void)687 mem_buffers_func ( void )
688 {
689 g_val_t val;
690
691 val.f = 0;
692
693 return val;
694 }
695
696 g_val_t
mem_cached_func(void)697 mem_cached_func ( void )
698 {
699 g_val_t val;
700 perfstat_memory_total_t m;
701
702 if (perfstat_memory_total(NULL, &m, sizeof(perfstat_memory_total_t), 1) == -1)
703 val.f = 0;
704 else
705 val.f = m.numperm * MEM_KB_PER_PAGE;
706
707 return val;
708 }
709
710 g_val_t
swap_total_func(void)711 swap_total_func ( void )
712 {
713 g_val_t val;
714 perfstat_memory_total_t m;
715
716 if (perfstat_memory_total(NULL, &m, sizeof(perfstat_memory_total_t), 1) == -1)
717 val.f = 0;
718 else
719 val.f = m.pgsp_total * MEM_KB_PER_PAGE;
720
721 return val;
722
723 }
724
725 g_val_t
swap_free_func(void)726 swap_free_func ( void )
727 {
728 g_val_t val;
729 perfstat_memory_total_t m;
730
731 if (perfstat_memory_total(NULL, &m, sizeof(perfstat_memory_total_t), 1) == -1)
732 val.f = 0;
733 else
734 val.f =m.pgsp_free * MEM_KB_PER_PAGE;
735
736 return val;
737 }
738
739 g_val_t
mtu_func(void)740 mtu_func ( void )
741 {
742 /* We want to find the minimum MTU (Max packet size) over all UP interfaces.
743 */
744 unsigned int min=0;
745 g_val_t val;
746 val.uint32 = get_min_mtu();
747 /* A val of 0 means there are no UP interfaces. Shouldn't happen. */
748 return val;
749 }
750
751
752
753
754
755
756
757
get_cpuinfo()758 void get_cpuinfo()
759 {
760 u_longlong_t cpu_total;
761 time_t new_time;
762
763
764 new_time = time(NULL);
765
766 if (new_time - CPU_INFO_TIMEOUT > cur_cpu_info->timestamp )
767 {
768
769 perfstat_cpu_total(NULL, &cpu_total_buffer, sizeof(perfstat_cpu_total_t), 1);
770
771
772 cpu_total = cpu_total_buffer.user + cpu_total_buffer.sys
773 + cpu_total_buffer.idle + cpu_total_buffer.wait;
774
775
776 last_cpu_info=&cpu_info[ci_flag];
777 ci_flag^=1;
778 cur_cpu_info=&cpu_info[ci_flag];
779
780 cur_cpu_info->timestamp = new_time;
781 cur_cpu_info->total_ticks = cpu_total;
782 cur_cpu_info->user = cpu_total_buffer.user;
783 cur_cpu_info->sys = cpu_total_buffer.sys;
784 cur_cpu_info->idle = cpu_total_buffer.idle;
785 cur_cpu_info->wait = cpu_total_buffer.wait;
786 }
787 } /* get_cpuinfo */
788
789
790
791 /* int bos_level(int *aix_version, int *aix_release, int *aix_level, int *aix_fix)
792 * is copied form
793 *
794 * First stab at support for metrics in AIX
795 * by Preston Smith <psmith@physics.purdue.edu>
796 * Wed Feb 27 14:55:33 EST 2002
797 *
798 * AIX V5 support, bugfixes added by Davide Tacchella <tack@cscs.ch>
799 * May 10, 2002
800 *
801 */
802
bos_level(int * aix_version,int * aix_release,int * aix_level,int * aix_fix)803 int bos_level(int *aix_version, int *aix_release, int *aix_level, int *aix_fix)
804 {
805 struct Class *my_cl; /* customized devices class ptr */
806 struct product productobj; /* customized device object storage */
807 int rc, getit, found = 0;
808 char *path;
809
810 /*
811 * start up odm
812 */
813 if (odm_initialize() == -1)
814 return E_ODMINIT;
815
816 /*
817 * Make sure we take the right database
818 */
819 if ((path = odm_set_path("/usr/lib/objrepos")) == (char *) -1)
820 return odmerrno;
821
822 /*
823 * Mount the lpp class
824 */
825 if ((My_CLASS = odm_mount_class("product")) == (CLASS_SYMBOL) -1)
826 return odmerrno;
827
828 /*
829 * open customized devices object class
830 */
831 if ((int)(my_cl = odm_open_class(My_CLASS)) == -1)
832 return E_ODMOPEN;
833
834 /*
835 * Loop trough all entries for the lpp name, ASSUMING the last
836 * one denotes the up to date number!!!
837 */
838 /*
839 * AIX > 4.2 uses bos.mp or bos.up
840 * AIX >= 6.1 uses bos.mp64
841 */
842 getit = ODM_FIRST;
843 while ((rc = (int)odm_get_obj(my_cl, "name like bos.?p*",
844 &productobj, getit)) != 0) {
845 getit = ODM_NEXT;
846 if (rc == -1) {
847 /* ODM failure */
848 break;
849 }
850 else {
851 *aix_version = productobj.ver;
852 *aix_release = productobj.rel;
853 *aix_level = productobj.mod;
854 *aix_fix = productobj.fix;
855 found++;
856 }
857 }
858 /*
859 * AIX < 4.2 uses bos.rte.mp or bos.rte.up
860 */
861 if (!found) {
862 getit = ODM_FIRST;
863 while ((rc = (int)odm_get_obj(my_cl, "name like bos.rte.?p",
864 &productobj, getit)) != 0) {
865 getit = ODM_NEXT;
866 if (rc == -1) {
867 /* ODM failure */
868 break;
869 }
870 else {
871 *aix_version = productobj.ver;
872 *aix_release = productobj.rel;
873 *aix_level = productobj.mod;
874 *aix_fix = productobj.fix;
875 found++;
876 }
877 }
878 }
879
880
881
882 /*
883 * close lpp object class
884 */
885 odm_close_class(my_cl);
886
887 odm_terminate();
888
889 free(path);
890 return (found ? 0 : -1);
891
892 } /* bos_level */
893
894
895
896
897 #define CALC_NETSTAT(type) (double) ((cur_ninfo->type<last_ninfo->type)?-1:(cur_ninfo->type - last_ninfo->type)/timediff)
898 void
update_ifdata(void)899 update_ifdata(void){
900
901 static int init_done = 0;
902 static struct timeval lasttime={0,0};
903 struct timeval thistime;
904 double timediff;
905
906
907 /*
908 ** Compute time between calls
909 */
910 gettimeofday (&thistime, NULL);
911 if (lasttime.tv_sec)
912 timediff = ((double) thistime.tv_sec * 1.0e6 +
913 (double) thistime.tv_usec -
914 (double) lasttime.tv_sec * 1.0e6 -
915 (double) lasttime.tv_usec) / 1.0e6;
916 else
917 timediff = 1.0;
918
919 /*
920 ** Do nothing if we are called to soon after the last call
921 */
922 if (init_done && (timediff < INFO_TIMEOUT)) return;
923
924 lasttime = thistime;
925
926 last_ninfo = &ninfo[ni_flag];
927
928 ni_flag^=1;
929
930 cur_ninfo = &ninfo[ni_flag];
931
932 perfstat_netinterface_total(NULL, cur_ninfo, sizeof(perfstat_netinterface_total_t), 1);
933
934 if (init_done) {
935 cur_net_stat.ipackets = (CALC_NETSTAT(ipackets)<0)?cur_net_stat.ipackets:CALC_NETSTAT(ipackets);
936 cur_net_stat.opackets = (CALC_NETSTAT(opackets)<0)?cur_net_stat.opackets:CALC_NETSTAT(opackets);
937 cur_net_stat.ibytes = (CALC_NETSTAT(ibytes ) <0)?cur_net_stat.ibytes:CALC_NETSTAT(ibytes );
938 cur_net_stat.obytes = (CALC_NETSTAT(obytes )<0)?cur_net_stat.obytes:CALC_NETSTAT(obytes );
939 }
940 else
941 {
942 init_done = 1;
943
944 cur_net_stat.ipackets = 0;
945 cur_net_stat.opackets = 0;
946 cur_net_stat.ibytes = 0;
947 cur_net_stat.obytes = 0;
948 }
949
950 } /* update_ifdata */
951
952
953