1 /*
2  * Copyright (c) 2004-2009 Hyperic, Inc.
3  * Copyright (c) 2009 SpringSource, Inc.
4  * Copyright (c) 2009-2010 VMware, Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 /* pull in time.h before resource.h does w/ _KERNEL */
20 #include <sys/time.h>
21 #define _KERNEL 1
22 #include <sys/file.h>     /* for struct file */
23 #include <sys/resource.h> /* for rlimit32 in 64-bit mode */
24 #undef  _KERNEL
25 
26 #include "sigar.h"
27 #include "sigar_private.h"
28 #include "sigar_util.h"
29 #include "sigar_os.h"
30 
31 #include <dlfcn.h>
32 #include <nlist.h>
33 #include <pthread.h>
34 #include <stdio.h>
35 #include <utmp.h>
36 #include <libperfstat.h>
37 #include <pthread.h>
38 
39 #include <sys/statfs.h>
40 #include <sys/systemcfg.h>
41 #include <sys/sysinfo.h>
42 #include <sys/var.h>
43 #include <sys/vminfo.h>
44 #include <sys/mntctl.h>
45 #include <sys/stat.h>
46 #include <sys/user.h>
47 #include <sys/utsname.h>
48 #include <sys/vmount.h>
49 #include <sys/proc.h>
50 
51 #include <sys/socket.h>
52 #include <arpa/inet.h>
53 #include <net/if.h>
54 
55 /* for proc_port */
56 #include <netinet/in_pcb.h>
57 #include <sys/domain.h>
58 #include <sys/protosw.h>
59 #include <sys/socketvar.h>
60 
61 /* for net_connection_list */
62 #include <netinet/ip_var.h>
63 #include <netinet/tcp_timer.h>
64 #include <netinet/tcp_var.h>
65 #include <netinet/tcp_fsm.h>
66 
67 /* for odm api */
68 #include <sys/cfgodm.h>
69 #include <sys/cfgdb.h>
70 #include <cf.h>
71 
72 #include <sys/ldr.h>
73 
74 /* for net_interface_config ipv6 */
75 #include <sys/ioctl.h>
76 #include <netinet/in6_var.h>
77 
78 /* for getkerninfo */
79 #include <sys/kinfo.h>
80 
81 /* not defined in aix 4.3 */
82 #ifndef SBITS
83 #define SBITS 16
84 #endif
85 
86 #ifndef PTHRDSINFO_RUSAGE_START
87 #define PTHRDSINFO_RUSAGE_START   0x00000001
88 #define PTHRDSINFO_RUSAGE_STOP    0x00000002
89 #define PTHRDSINFO_RUSAGE_COLLECT 0x00000004
90 #endif
91 
92 /*
93  * from libperfstat.h:
94  * "To calculate the load average, divide the numbers by (1<<SBITS).
95  *  SBITS is defined in <sys/proc.h>."
96  */
97 #define FIXED_TO_DOUBLE(x) (((double)x) / (1<<SBITS))
98 
99 /* these offsets wont change so just lookup them up during open */
get_koffsets(sigar_t *sigar)100 static int get_koffsets(sigar_t *sigar)
101 {
102     int i;
103     /* see man knlist and nlist.h */
104     struct nlist klist[] = {
105         {"avenrun", 0, 0, 0, 0, 0}, /* KOFFSET_LOADAVG */
106         {"v", 0, 0, 0, 0, 0}, /* KOFFSET_VAR */
107         {"sysinfo", 0, 0, 0, 0, 0}, /* KOFFSET_SYSINFO */
108         {"ifnet", 0, 0, 0, 0, 0}, /* KOFFSET_IFNET */
109         {"vmminfo", 0, 0, 0, 0, 0}, /* KOFFSET_VMINFO */
110         {"cpuinfo", 0, 0, 0, 0, 0}, /* KOFFSET_CPUINFO */
111         {"tcb", 0, 0, 0, 0, 0}, /* KOFFSET_TCB */
112         {"arptabsize", 0, 0, 0, 0, 0}, /* KOFFSET_ARPTABSIZE */
113         {"arptabp", 0, 0, 0, 0, 0}, /* KOFFSET_ARPTABP */
114         {NULL, 0, 0, 0, 0, 0}
115     };
116 
117     if (knlist(klist,
118                sizeof(klist) / sizeof(klist[0]),
119                sizeof(klist[0])) != 0)
120     {
121         return errno;
122     }
123 
124     for (i=0; i<KOFFSET_MAX; i++) {
125         sigar->koffsets[i] = klist[i].n_value;
126     }
127 
128     return SIGAR_OK;
129 }
130 
kread(sigar_t *sigar, void *data, int size, long offset)131 static int kread(sigar_t *sigar, void *data, int size, long offset)
132 {
133     if (sigar->kmem < 0) {
134         return SIGAR_EPERM_KMEM;
135     }
136 
137     if (lseek(sigar->kmem, offset, SEEK_SET) != offset) {
138         return errno;
139     }
140 
141     if (read(sigar->kmem, data, size) != size) {
142         return errno;
143     }
144 
145     return SIGAR_OK;
146 }
147 
sigar_thread_rusage(struct rusage *usage, int mode)148 static int sigar_thread_rusage(struct rusage *usage, int mode)
149 {
150     return pthread_getrusage_np(pthread_self(), usage, mode);
151 }
152 
sigar_perfstat_memory(perfstat_memory_total_t *memory)153 static int sigar_perfstat_memory(perfstat_memory_total_t *memory)
154 {
155     return perfstat_memory_total(NULL, memory, sizeof(*memory), 1);
156 }
157 
sigar_perfstat_cpu(perfstat_cpu_total_t *cpu_total)158 static int sigar_perfstat_cpu(perfstat_cpu_total_t *cpu_total)
159 {
160     return perfstat_cpu_total(NULL, cpu_total, sizeof(*cpu_total), 1);
161 }
162 
sigar_os_open(sigar_t **sigar)163 int sigar_os_open(sigar_t **sigar)
164 {
165     int status, i;
166     int kmem = -1;
167     struct utsname name;
168 
169     kmem = open("/dev/kmem", O_RDONLY);
170 
171     *sigar = malloc(sizeof(**sigar));
172 
173     (*sigar)->getprocfd = NULL; /*XXX*/
174     (*sigar)->kmem = kmem;
175     (*sigar)->pagesize = 0;
176     (*sigar)->ticks = sysconf(_SC_CLK_TCK);
177     (*sigar)->boot_time = 0;
178     (*sigar)->last_pid = -1;
179     (*sigar)->pinfo = NULL;
180     (*sigar)->cpuinfo = NULL;
181     (*sigar)->cpuinfo_size = 0;
182     SIGAR_ZERO(&(*sigar)->swaps);
183 
184     i = getpagesize();
185     while ((i >>= 1) > 0) {
186         (*sigar)->pagesize++;
187     }
188 
189     if (kmem > 0) {
190         if ((status = get_koffsets(*sigar)) != SIGAR_OK) {
191             /* libperfstat only mode (aix 6) */
192             close((*sigar)->kmem);
193             (*sigar)->kmem = -1;
194         }
195     }
196 
197     (*sigar)->cpu_mhz = -1;
198 
199     (*sigar)->model[0] = '\0';
200 
201     uname(&name);
202 
203     (*sigar)->aix_version = atoi(name.version);
204 
205     (*sigar)->thrusage = PTHRDSINFO_RUSAGE_STOP;
206 
207     (*sigar)->diskmap = NULL;
208 
209     return SIGAR_OK;
210 }
211 
212 static void swaps_free(swaps_t *swaps);
213 
sigar_os_close(sigar_t *sigar)214 int sigar_os_close(sigar_t *sigar)
215 {
216     swaps_free(&sigar->swaps);
217     if (sigar->kmem > 0) {
218         close(sigar->kmem);
219     }
220     if (sigar->pinfo) {
221         free(sigar->pinfo);
222     }
223     if (sigar->cpuinfo) {
224         free(sigar->cpuinfo);
225     }
226     if (sigar->diskmap) {
227         sigar_cache_destroy(sigar->diskmap);
228     }
229     if (sigar->thrusage == PTHRDSINFO_RUSAGE_START) {
230         struct rusage usage;
231         sigar_thread_rusage(&usage,
232                             PTHRDSINFO_RUSAGE_STOP);
233     }
234     free(sigar);
235     return SIGAR_OK;
236 }
237 
sigar_os_error_string(sigar_t *sigar, int err)238 char *sigar_os_error_string(sigar_t *sigar, int err)
239 {
240     switch (err) {
241       case SIGAR_EPERM_KMEM:
242         return "Failed to open /dev/kmem for reading";
243       default:
244         return NULL;
245     }
246 }
247 
248 #define PAGESHIFT(v) \
249     ((v) << sigar->pagesize)
250 
sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)251 int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
252 {
253     int status;
254     perfstat_memory_total_t minfo;
255     sigar_uint64_t kern;
256 
257     if (sigar_perfstat_memory(&minfo) == 1) {
258         mem->total = PAGESHIFT(minfo.real_total);
259         mem->free  = PAGESHIFT(minfo.real_free);
260         kern = PAGESHIFT(minfo.numperm); /* number of pages in file cache */
261     }
262     else {
263         return errno;
264     }
265 
266     mem->used = mem->total - mem->free;
267     mem->actual_used = mem->used - kern;
268     mem->actual_free = mem->free + kern;
269 
270     sigar_mem_calc_ram(sigar, mem);
271 
272     return SIGAR_OK;
273 }
274 
swaps_free(swaps_t *swaps)275 static void swaps_free(swaps_t *swaps)
276 {
277     if (swaps->num) {
278         int i;
279 
280         for (i=0; i<swaps->num; i++) {
281             free(swaps->devs[i]);
282         }
283 
284         free(swaps->devs);
285 
286         swaps->num = 0;
287     }
288 }
289 
290 /*
291  * there is no public api for parsing this file.
292  * well, there is something, but its super ugly and requires
293  * linking 2 static libraries (libodm and something else)
294  * maybe will switch to that if it can add value elsewhere too.
295  */
296 #define SWAPSPACES "/etc/swapspaces"
297 
swaps_get(swaps_t *swaps)298 static int swaps_get(swaps_t *swaps)
299 {
300     FILE *fp;
301     char buf[512];
302     char *ptr;
303     struct stat statbuf;
304 
305     if (stat(SWAPSPACES, &statbuf) < 0) {
306         return errno;
307     }
308 
309     /* only re-parse if file has changed */
310     if (swaps->mtime == statbuf.st_mtime) {
311         return 0;
312     }
313 
314     swaps->mtime = statbuf.st_mtime;
315 
316     /* easier to just start from scratch */
317     swaps_free(swaps);
318 
319     if (!(fp = fopen(SWAPSPACES, "r"))) {
320         return errno;
321     }
322 
323     while ((ptr = fgets(buf, sizeof(buf), fp))) {
324         if (!isalpha(*ptr)) {
325             continue;
326         }
327 
328         if (strchr(ptr, ':')) {
329             int len;
330 
331             ptr = fgets(buf, sizeof(buf), fp);
332 
333             while (isspace(*ptr)) {
334                 ++ptr;
335             }
336 
337             if (strncmp(ptr, "dev", 3)) {
338                 continue;
339             }
340             ptr += 3;
341             while (isspace(*ptr) || (*ptr == '=')) {
342                 ++ptr;
343             }
344 
345             len = strlen(ptr);
346             ptr[len-1] = '\0'; /* -1 == chomp \n */
347 
348             swaps->devs = realloc(swaps->devs, swaps->num+1 * sizeof(char *));
349             swaps->devs[swaps->num] = malloc(len);
350             memcpy(swaps->devs[swaps->num], ptr, len);
351 
352             swaps->num++;
353         }
354     }
355 
356     fclose(fp);
357 
358     return 0;
359 }
360 
361 /*
362  * documented in aix tech ref,
363  * but this prototype is not in any friggin header file.
364  * struct pginfo is in sys/vminfo.h
365  */
366 
367 int swapqry(char *path, struct pginfo *info);
368 
sigar_swap_get_swapqry(sigar_t *sigar, sigar_swap_t *swap)369 static int sigar_swap_get_swapqry(sigar_t *sigar, sigar_swap_t *swap)
370 {
371     int status, i;
372 
373     if ((status = swaps_get(&sigar->swaps)) != SIGAR_OK) {
374         return status;
375     }
376 
377     if (SIGAR_LOG_IS_DEBUG(sigar)) {
378         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
379                          "[swap] pagesize=%d, shift=%d",
380                          getpagesize(), sigar->pagesize);
381     }
382 
383     swap->total = swap->free = 0;
384 
385     for (i=0; i<sigar->swaps.num; i++) {
386         struct pginfo info;
387 
388         status = swapqry(sigar->swaps.devs[i], &info);
389 
390         if (status != 0) {
391             if (SIGAR_LOG_IS_DEBUG(sigar)) {
392                 sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
393                                  "[swap] swapqry(%s) failed: %s",
394                                  sigar->swaps.devs[i],
395                                  sigar_strerror(sigar, errno));
396             }
397             continue;
398         }
399 
400         if (SIGAR_LOG_IS_DEBUG(sigar)) {
401             sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
402                              "[swap] %s total=%d/%d, free=%d/%d",
403                              sigar->swaps.devs[i],
404                              info.size, PAGESHIFT(info.size),
405                              info.free, PAGESHIFT(info.free));
406         }
407 
408         swap->total += PAGESHIFT(info.size); /* lsps -a */
409         swap->free  += PAGESHIFT(info.free);
410     }
411 
412     swap->used = swap->total - swap->free;
413 
414     return SIGAR_OK;
415 }
416 
417 #define SWAP_DEV(ps) \
418    ((ps.type == LV_PAGING) ? \
419      ps.u.lv_paging.vgname : \
420      ps.u.nfs_paging.filename)
421 
422 #define SWAP_MB_TO_BYTES(v) ((v) * (1024 * 1024))
423 
sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)424 int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
425 {
426     perfstat_memory_total_t minfo;
427     perfstat_pagingspace_t ps;
428     perfstat_id_t id;
429 
430     id.name[0] = '\0';
431 
432     SIGAR_ZERO(swap);
433 
434     do {
435         if (perfstat_pagingspace(&id, &ps, sizeof(ps), 1) != 1) {
436             if (SIGAR_LOG_IS_DEBUG(sigar)) {
437                 sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
438                                  "[swap] dev=%s query failed: %s",
439                                  SWAP_DEV(ps),
440                                  sigar_strerror(sigar, errno));
441             }
442             continue;
443         }
444         if (SIGAR_LOG_IS_DEBUG(sigar)) {
445             sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
446                              "[swap] dev=%s: active=%s, "
447                              "total=%lluMb, used=%lluMb",
448                              SWAP_DEV(ps),
449                              ((ps.active == 1) ? "yes" : "no"),
450                              ps.mb_size, ps.mb_used);
451         }
452         if (ps.active != 1) {
453             continue;
454         }
455         /* convert MB sizes to bytes */
456         swap->total += SWAP_MB_TO_BYTES(ps.mb_size);
457         swap->used  += SWAP_MB_TO_BYTES(ps.mb_used);
458     } while (id.name[0] != '\0');
459 
460     swap->free = swap->total - swap->used;
461 
462     if (sigar_perfstat_memory(&minfo) == 1) {
463         swap->page_in = minfo.pgins;
464         swap->page_out = minfo.pgouts;
465     }
466     else {
467         swap->page_in = swap->page_out = -1;
468     }
469 
470     swap->allocstall = -1;
471     swap->allocstall_dma = -1;
472     swap->allocstall_dma32 = -1;
473     swap->allocstall_normal = -1;
474     swap->allocstall_movable = -1;
475 
476     return SIGAR_OK;
477 }
478 
sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)479 int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
480 {
481     int i, status;
482     struct sysinfo data;
483     perfstat_cpu_total_t cpu_data;
484 
485     if (sigar_perfstat_cpu(&cpu_data) == 1) {
486         cpu->user  = SIGAR_TICK2MSEC(cpu_data.user);
487         cpu->nice  = SIGAR_FIELD_NOTIMPL; /* N/A */
488         cpu->sys   = SIGAR_TICK2MSEC(cpu_data.sys);
489         cpu->idle  = SIGAR_TICK2MSEC(cpu_data.idle);
490         cpu->wait  = SIGAR_TICK2MSEC(cpu_data.wait);
491         cpu->irq = 0; /*N/A*/
492         cpu->soft_irq = 0; /*N/A*/
493         cpu->stolen = 0; /*N/A*/
494         cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait;
495         return SIGAR_OK;
496     }
497     else {
498         return errno;
499     }
500 }
501 
502 /*
503  * other possible metrics we could add:
504  * struct cpuinfo {
505  *       long    cpu[CPU_NTIMES];
506  *       long    pswitch;
507  *       long    syscall;
508  *       long    sysread;
509  *       long    syswrite;
510  *       long    sysfork;
511  *       long    sysexec;
512  *       long    readch;
513  *       long    writech;
514  *       long    iget;
515  *       long    namei;
516  *       long    dirblk;
517  *       long    msg;
518  *       long    sema;
519  *       long    bread;
520  *       long    bwrite;
521  *       long    lread;
522  *       long    lwrite;
523  *       long    phread;
524  *       long    phwrite;
525  * };
526  */
527 
528 
boot_time(sigar_t *sigar, time_t *time)529 static int boot_time(sigar_t *sigar, time_t *time)
530 {
531     int fd;
532     struct utmp data;
533 
534     if ((fd = open(UTMP_FILE, O_RDONLY)) < 0) {
535         return errno;
536     }
537 
538     do {
539         if (read(fd, &data, sizeof(data)) != sizeof(data)) {
540             int status = errno;
541             close(fd);
542             return status;
543         }
544     } while (data.ut_type != BOOT_TIME);
545 
546     *time = data.ut_time;
547 
548     close(fd);
549 
550     return SIGAR_OK;
551 }
552 
553 #define WHOCPY(dest, src) \
554     SIGAR_SSTRCPY(dest, src); \
555     if (sizeof(src) < sizeof(dest)) \
556         dest[sizeof(dest)-1] = '\0'
557 
sigar_who_utmp(sigar_t *sigar, sigar_who_list_t *wholist)558 static int sigar_who_utmp(sigar_t *sigar,
559                           sigar_who_list_t *wholist)
560 {
561     struct utmp ut;
562     FILE *fp;
563 
564     if (!(fp = fopen(UTMP_FILE, "r"))) {
565         return errno;
566     }
567 
568     while (fread(&ut, sizeof(ut), 1, fp) == 1) {
569         sigar_who_t *who;
570 
571         if (*ut.ut_name == '\0') {
572             continue;
573         }
574 
575         if (ut.ut_type != USER_PROCESS) {
576             continue;
577         }
578 
579         SIGAR_WHO_LIST_GROW(wholist);
580         who = &wholist->data[wholist->number++];
581 
582         WHOCPY(who->user, ut.ut_user);
583         WHOCPY(who->device, ut.ut_line);
584         WHOCPY(who->host, ut.ut_host);
585 
586         who->time = ut.ut_time;
587     }
588 
589     fclose(fp);
590 
591     return SIGAR_OK;
592 }
593 
sigar_os_proc_list_get(sigar_t *sigar, sigar_proc_list_t *proclist)594 int sigar_os_proc_list_get(sigar_t *sigar,
595                            sigar_proc_list_t *proclist)
596 {
597     pid_t pid = 0;
598     struct procsinfo info;
599 
600     for (;;) {
601         int num = getprocs(&info, sizeof(info),
602                            NULL, 0, &pid, 1);
603 
604         if (num == 0) {
605             break;
606         }
607 
608         SIGAR_PROC_LIST_GROW(proclist);
609 
610         proclist->data[proclist->number++] = info.pi_pid;
611     }
612 
613     return SIGAR_OK;
614 }
615 
sigar_getprocs(sigar_t *sigar, sigar_pid_t pid)616 static int sigar_getprocs(sigar_t *sigar, sigar_pid_t pid)
617 {
618     int status, num;
619     time_t timenow = time(NULL);
620 
621     if (sigar->pinfo == NULL) {
622         sigar->pinfo = malloc(sizeof(*sigar->pinfo));
623     }
624 
625     if (sigar->last_pid == pid) {
626         if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) {
627             return SIGAR_OK;
628         }
629     }
630 
631     sigar->last_pid = pid;
632     sigar->last_getprocs = timenow;
633 
634     num = getprocs(sigar->pinfo, sizeof(*sigar->pinfo),
635                    NULL, 0, &pid, 1);
636 
637     if (num != 1) {
638         return ESRCH;
639     }
640 
641     return SIGAR_OK;
642 }
643 
sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_mem_t *procmem)644 int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
645                        sigar_proc_mem_t *procmem)
646 {
647     int status = sigar_getprocs(sigar, pid);
648     struct procsinfo64 *pinfo = sigar->pinfo;
649 
650     if (status != SIGAR_OK) {
651         return status;
652     }
653 
654     procmem->size  = PAGESHIFT(pinfo->pi_size); /* XXX fold in pi_dvm ? */
655     procmem->share = PAGESHIFT(pinfo->pi_sdsize);
656     procmem->resident = PAGESHIFT(pinfo->pi_drss + pinfo->pi_trss);
657 
658     procmem->minor_faults = pinfo->pi_minflt;
659     procmem->major_faults = pinfo->pi_majflt;
660     procmem->page_faults =
661         procmem->minor_faults +
662         procmem->major_faults;
663 
664     return SIGAR_OK;
665 }
666 
sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *proctime)667 int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
668                         sigar_proc_time_t *proctime)
669 {
670     int status = sigar_getprocs(sigar, pid);
671     struct procsinfo64 *pinfo = sigar->pinfo;
672 
673     if (status != SIGAR_OK) {
674         return status;
675     }
676 
677     proctime->start_time = pinfo->pi_start;
678     proctime->start_time *= SIGAR_MSEC; /* convert to ms */
679     proctime->user = pinfo->pi_utime * SIGAR_MSEC;
680     proctime->sys  = pinfo->pi_stime * SIGAR_MSEC;
681     proctime->total = proctime->user + proctime->sys;
682 
683     return SIGAR_OK;
684 }
685 
sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_state_t *procstate)686 int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
687                          sigar_proc_state_t *procstate)
688 {
689     int status = sigar_getprocs(sigar, pid);
690     struct procsinfo64 *pinfo = sigar->pinfo;
691     tid_t tid = 0;
692     struct thrdsinfo64 thrinfo;
693 
694     if (status != SIGAR_OK) {
695         return status;
696     }
697 
698     if (getthrds(pid, &thrinfo, sizeof(thrinfo), &tid, 1) == 1) {
699         procstate->processor = thrinfo.ti_affinity;
700     }
701     else {
702         procstate->processor = SIGAR_FIELD_NOTIMPL;
703     }
704 
705     SIGAR_SSTRCPY(procstate->name, pinfo->pi_comm);
706     procstate->ppid = pinfo->pi_ppid;
707     procstate->nice = pinfo->pi_nice;
708     procstate->tty  = pinfo->pi_ttyd;
709     procstate->priority = pinfo->pi_pri;
710     procstate->threads = pinfo->pi_thcount;
711 
712     switch (pinfo->pi_state) {
713       case SACTIVE:
714         procstate->state = 'R';
715         break;
716       case SIDL:
717         procstate->state = 'D';
718         break;
719       case SSTOP:
720         procstate->state = 'S';
721         break;
722       case SZOMB:
723         procstate->state = 'Z';
724         break;
725       case SSWAP:
726         procstate->state = 'S';
727         break;
728     }
729 
730     return SIGAR_OK;
731 }
732 
sigar_proc_modules_local_get(sigar_t *sigar, sigar_proc_modules_t *procmods)733 static int sigar_proc_modules_local_get(sigar_t *sigar,
734                                         sigar_proc_modules_t *procmods)
735 {
736     struct ld_info *info;
737     char *buffer;
738     int size = 2048, status;
739     unsigned int offset;
740 
741     buffer = malloc(size);
742     while ((loadquery(L_GETINFO, buffer, size) == -1) &&
743            (errno == ENOMEM))
744     {
745         size += 2048;
746         buffer = realloc(buffer, size);
747     }
748 
749     info = (struct ld_info *)buffer;
750 
751     do {
752         char *name = info->ldinfo_filename;
753 
754         status =
755             procmods->module_getter(procmods->data, name, strlen(name));
756 
757         if (status != SIGAR_OK) {
758             /* not an error; just stop iterating */
759             free(buffer);
760             return status;
761         }
762 
763         offset = info->ldinfo_next;
764         info = (struct ld_info *)((char*)info + offset);
765     } while(offset);
766 
767     free(buffer);
768 
769     return SIGAR_OK;
770 }
771 
772 
773 #define SIGAR_MICROSEC2NANO(s) \
774     ((sigar_uint64_t)(s) * (sigar_uint64_t)1000)
775 
776 #define TIME_NSEC(t) \
777     (SIGAR_SEC2NANO((t).tv_sec) + SIGAR_MICROSEC2NANO((t).tv_usec))
778 
779 
sigar_os_fs_type_get(sigar_file_system_t *fsp)780 int sigar_os_fs_type_get(sigar_file_system_t *fsp)
781 {
782     return fsp->type;
783 }
784 
785 #ifndef MNT_NFS4
786 /* another one documented in aix tech ref
787  * with no friggin prototype in any header file...
788  * ...but added in 5.2
789  */
790 int mntctl(int command, int size, char *buffer);
791 #endif
792 
sigar_file_system_list_get(sigar_t *sigar, sigar_file_system_list_t *fslist)793 int sigar_file_system_list_get(sigar_t *sigar,
794                                sigar_file_system_list_t *fslist)
795 {
796     int i, size, num;
797     char *buf, *mntlist;
798 
799     /* get required size */
800     if (mntctl(MCTL_QUERY, sizeof(size), (char *)&size) < 0) {
801         return errno;
802     }
803 
804     mntlist = buf = malloc(size);
805 
806     if ((num = mntctl(MCTL_QUERY, size, buf)) < 0) {
807         free(buf);
808         return errno;
809     }
810 
811     sigar_file_system_list_create(fslist);
812 
813     for (i=0; i<num; i++) {
814         char *devname;
815         const char *typename = NULL;
816         sigar_file_system_t *fsp;
817         struct vmount *ent = (struct vmount *)mntlist;
818 
819         mntlist += ent->vmt_length;
820 
821         SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
822 
823         fsp = &fslist->data[fslist->number++];
824 
825         switch (ent->vmt_gfstype) {
826           case MNT_AIX:
827             typename = "aix";
828             fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
829             break;
830           case MNT_JFS:
831             typename = "jfs";
832             fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
833             break;
834           case MNT_NFS:
835           case MNT_NFS3:
836             typename = "nfs";
837             fsp->type = SIGAR_FSTYPE_NETWORK;
838             break;
839           case MNT_CDROM:
840             fsp->type = SIGAR_FSTYPE_CDROM;
841             break;
842           case MNT_SFS:
843           case MNT_CACHEFS:
844           case MNT_AUTOFS:
845           default:
846             if (ent->vmt_flags & MNT_REMOTE) {
847                 fsp->type = SIGAR_FSTYPE_NETWORK;
848             }
849             else {
850                 fsp->type = SIGAR_FSTYPE_NONE;
851             }
852         }
853 
854         SIGAR_SSTRCPY(fsp->dir_name, vmt2dataptr(ent, VMT_STUB));
855         SIGAR_SSTRCPY(fsp->options, vmt2dataptr(ent, VMT_ARGS));
856 
857         devname = vmt2dataptr(ent, VMT_OBJECT);
858 
859         if (fsp->type == SIGAR_FSTYPE_NETWORK) {
860             char *hostname   = vmt2dataptr(ent, VMT_HOSTNAME);
861 #if 0
862             /* XXX: these do not seem reliable */
863             int hostname_len = vmt2datasize(ent, VMT_HOSTNAME)-1; /* -1 == skip '\0' */
864             int devname_len  = vmt2datasize(ent, VMT_OBJECT);     /* includes '\0' */
865 #else
866             int hostname_len = strlen(hostname);
867             int devname_len = strlen(devname) + 1;
868 #endif
869             int total_len    = hostname_len + devname_len + 1;    /* 1 == strlen(":") */
870 
871             if (total_len > sizeof(fsp->dev_name)) {
872                 /* justincase - prevent overflow.  chances: slim..none */
873                 SIGAR_SSTRCPY(fsp->dev_name, devname);
874             }
875             else {
876                 /* sprintf(fsp->devname, "%s:%s", hostname, devname) */
877                 char *ptr = fsp->dev_name;
878 
879                 memcpy(ptr, hostname, hostname_len);
880                 ptr += hostname_len;
881 
882                 *ptr++ = ':';
883 
884                 memcpy(ptr, devname, devname_len);
885             }
886         }
887         else {
888             SIGAR_SSTRCPY(fsp->dev_name, devname);
889         }
890 
891         /* we set fsp->type, just looking up sigar.c:fstype_names[type] */
892         sigar_fs_type_get(fsp);
893 
894         if (typename == NULL) {
895             typename = fsp->type_name;
896         }
897 
898         SIGAR_SSTRCPY(fsp->sys_type_name, typename);
899     }
900 
901     free(buf);
902 
903     return SIGAR_OK;
904 }
905 
906 typedef struct {
907     char name[IDENTIFIER_LENGTH];
908     long addr;
909 } aix_diskio_t;
910 
create_diskmap(sigar_t *sigar)911 static int create_diskmap(sigar_t *sigar)
912 {
913     int i, total, num;
914     perfstat_disk_t *disk;
915     perfstat_id_t id;
916 
917     total = perfstat_disk(NULL, NULL, sizeof(*disk), 0);
918     if (total < 1) {
919         return ENOENT;
920     }
921 
922     disk = malloc(total * sizeof(*disk));
923     id.name[0] = '\0';
924 
925     num = perfstat_disk(&id, disk, sizeof(*disk), total);
926     if (num < 1) {
927         free(disk);
928         return ENOENT;
929     }
930 
931     sigar->diskmap = sigar_cache_new(25);
932 
933     odm_initialize();
934 
935     for (i=0; i<num; i++) {
936         char query[256];
937         struct CuDv *dv, *ptr;
938         struct listinfo info;
939         sigar_cache_entry_t *ent;
940         int j;
941 
942         snprintf(query, sizeof(query),
943                  "parent = '%s'", disk[i].vgname);
944 
945         ptr = dv = odm_get_list(CuDv_CLASS, query, &info, 256, 1);
946         if ((int)dv == -1) {
947             continue; /* XXX */
948         }
949 
950         for (j=0; j<info.num; j++, ptr++) {
951             struct CuAt *attr;
952             int num, retval;
953             struct stat sb;
954 
955             if ((attr = getattr(ptr->name, "label", 0, &num))) {
956                 retval = stat(attr->value, &sb);
957 
958                 if (retval == 0) {
959                     aix_diskio_t *diskio = malloc(sizeof(*diskio));
960                     SIGAR_SSTRCPY(diskio->name, disk[i].name);
961                     diskio->addr = -1;
962                     ent = sigar_cache_get(sigar->diskmap, SIGAR_FSDEV_ID(sb));
963                     ent->value = diskio;
964                 }
965 
966                 free(attr);
967             }
968         }
969 
970         odm_free_list(dv, &info);
971     }
972 
973     free(disk);
974     odm_terminate();
975 
976     return SIGAR_OK;
977 }
978 
979 
980 /* from sys/systemcfg.h, not defined in 4.3 headers */
981 #ifndef POWER_4
982 #define POWER_4		0x0800
983 #endif
984 #ifndef POWER_MPC7450
985 #define POWER_MPC7450	0x1000
986 #endif
987 #ifndef POWER_5
988 #define POWER_5		0x2000
989 #endif
990 
sigar_get_odm_model(sigar_t *sigar)991 static char *sigar_get_odm_model(sigar_t *sigar)
992 {
993     if (sigar->model[0] == '\0') {
994         struct CuAt *odm_obj;
995         int num;
996 
997         odm_initialize();
998 
999         if ((odm_obj = getattr("proc0", "type", 0, &num))) {
1000             SIGAR_SSTRCPY(sigar->model, odm_obj->value);
1001             free(odm_obj);
1002         }
1003 
1004         odm_terminate();
1005     }
1006 
1007     return sigar->model;
1008 }
1009 
1010 #define SIGAR_CPU_CACHE_SIZE \
1011   (_system_configuration.L2_cache_size / 1024)
1012 
sigar_get_cpu_mhz(sigar_t *sigar)1013 static int sigar_get_cpu_mhz(sigar_t *sigar)
1014 {
1015     if (sigar->cpu_mhz == SIGAR_FIELD_NOTIMPL) {
1016         perfstat_cpu_total_t data;
1017 
1018         if (sigar_perfstat_cpu(&data) == 1) {
1019             sigar->cpu_mhz = data.processorHZ / 1000000;
1020         }
1021         else {
1022             sigar_log_printf(sigar, SIGAR_LOG_ERROR,
1023                              "perfstat_cpu_total failed: %s",
1024                              sigar_strerror(sigar, errno));
1025         }
1026     }
1027 
1028     return sigar->cpu_mhz;
1029 }
1030 
get_cpu_arch(void)1031 static char *get_cpu_arch(void)
1032 {
1033     switch (_system_configuration.architecture) {
1034         case POWER_RS:
1035             return "Power Classic";
1036         case POWER_PC:
1037             return "PowerPC";
1038         case IA64:
1039             return "IA64";
1040         default:
1041             return "PowerPC"; /* what else could it be */
1042     }
1043 }
1044 
get_ppc_cpu_model(void)1045 static char *get_ppc_cpu_model(void)
1046 {
1047     switch (_system_configuration.implementation) {
1048         case POWER_RS1:
1049             return "RS1";
1050         case POWER_RSC:
1051             return "RSC";
1052         case POWER_RS2:
1053             return "RS2";
1054         case POWER_601:
1055             return "601";
1056         case POWER_603:
1057             return "603";
1058         case POWER_604:
1059             return "604";
1060         case POWER_620:
1061             return "620";
1062         case POWER_630:
1063             return "630";
1064         case POWER_A35:
1065             return "A35";
1066         case POWER_RS64II:
1067             return "RS64-II";
1068         case POWER_RS64III:
1069             return "RS64-III";
1070         case POWER_4:
1071             return "POWER4";
1072         case POWER_MPC7450:
1073             return "MPC7450";
1074         case POWER_5:
1075             return "POWER5";
1076         default:
1077             return "Unknown";
1078     }
1079 }
1080 
get_ia64_cpu_model(void)1081 static char *get_ia64_cpu_model(void)
1082 {
1083     switch (_system_configuration.implementation) {
1084         case IA64_M1:
1085             return "M1";
1086         case IA64_M2:
1087             return "M2";
1088         default:
1089             return "Unknown";
1090     }
1091 }
1092 
get_cpu_model(void)1093 static char *get_cpu_model(void)
1094 {
1095     if (_system_configuration.architecture == IA64) {
1096         return get_ia64_cpu_model();
1097     }
1098     else {
1099         return get_ppc_cpu_model();
1100     }
1101 }
1102 
1103 /* XXX net_route_list copy-n-pasted from darwin_sigar.c; only diff is getkerninfo instead of sysctl */
1104 #define rt_s_addr(sa) ((struct sockaddr_in *)(sa))->sin_addr.s_addr
1105 
1106 #ifndef SA_SIZE
1107 #define SA_SIZE(sa)                                             \
1108     (  (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?      \
1109         sizeof(long)            :                               \
1110         1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
1111 #endif
1112 
1113 
sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, sigar_net_interface_config_t *ifconfig)1114 int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name,
1115                                         sigar_net_interface_config_t *ifconfig)
1116 {
1117     int sock;
1118     struct in6_ifreq ifr;
1119 
1120     if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1121         return errno;
1122     }
1123 
1124     SIGAR_SSTRCPY(ifr.ifr_name, name);
1125 
1126     if (ioctl(sock, SIOCGIFADDR6, &ifr) == 0) {
1127         struct in6_addr *addr = SIGAR_SIN6_ADDR(&ifr.ifr_Addr);
1128 
1129         sigar_net_address6_set(ifconfig->address6, addr);
1130         sigar_net_interface_scope6_set(ifconfig, addr);
1131 
1132         if (ioctl(sock, SIOCGIFNETMASK6, &ifr) == 0) {
1133             addr = SIGAR_SIN6_ADDR(&ifr.ifr_Addr);
1134             ifconfig->prefix6_length = SIGAR_SIN6(&ifr.ifr_Addr)->sin6_len; /*XXX*/
1135         }
1136     }
1137 
1138     close(sock);
1139     return SIGAR_OK;
1140 }
1141 
1142 #define IS_TCP_SERVER(state, flags) \
1143     ((flags & SIGAR_NETCONN_SERVER) && (state == TCPS_LISTEN))
1144 
1145 #define IS_TCP_CLIENT(state, flags) \
1146     ((flags & SIGAR_NETCONN_CLIENT) && (state != TCPS_LISTEN))
1147 
net_conn_get_tcp(sigar_net_connection_walker_t *walker)1148 static int net_conn_get_tcp(sigar_net_connection_walker_t *walker)
1149 {
1150     sigar_t *sigar = walker->sigar;
1151     int flags = walker->flags;
1152     int status;
1153     struct inpcb tcp_inpcb;
1154     struct tcpcb tcpcb;
1155     struct inpcb *entry;
1156 
1157     status = kread(sigar, &tcp_inpcb, sizeof(tcp_inpcb),
1158                    sigar->koffsets[KOFFSET_TCB]);
1159 
1160     if (status != SIGAR_OK) {
1161         return status;
1162     }
1163 
1164     entry = tcp_inpcb.inp_next;
1165     while (entry) {
1166         struct inpcb pcb;
1167         int state;
1168 
1169         status = kread(sigar, &pcb, sizeof(pcb), (long)entry);
1170         if (status != SIGAR_OK) {
1171             return status;
1172         }
1173         status = kread(sigar, &tcpcb, sizeof(tcpcb), (long)pcb.inp_ppcb);
1174         if (status != SIGAR_OK) {
1175             return status;
1176         }
1177 
1178         state = tcpcb.t_state;
1179         if ((IS_TCP_SERVER(state, flags) ||
1180              IS_TCP_CLIENT(state, flags)))
1181         {
1182             sigar_net_connection_t conn;
1183 
1184             SIGAR_ZERO(&conn);
1185 
1186             conn.type = SIGAR_NETCONN_TCP;
1187 
1188             sigar_net_address_set(conn.local_address,
1189                                   pcb.inp_laddr.s_addr);
1190 
1191             sigar_net_address_set(conn.remote_address,
1192                                   pcb.inp_faddr.s_addr);
1193 
1194             conn.local_port  = ntohs(pcb.inp_lport);
1195             conn.remote_port = ntohs(pcb.inp_fport);
1196 
1197             conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
1198 
1199             switch (state) {
1200               case TCPS_CLOSED:
1201                 conn.state = SIGAR_TCP_CLOSE;
1202                 break;
1203               case TCPS_LISTEN:
1204                 conn.state = SIGAR_TCP_LISTEN;
1205                 break;
1206               case TCPS_SYN_SENT:
1207                 conn.state = SIGAR_TCP_SYN_SENT;
1208                 break;
1209               case TCPS_SYN_RECEIVED:
1210                 conn.state = SIGAR_TCP_SYN_RECV;
1211                 break;
1212               case TCPS_ESTABLISHED:
1213                 conn.state = SIGAR_TCP_ESTABLISHED;
1214                 break;
1215               case TCPS_CLOSE_WAIT:
1216                 conn.state = SIGAR_TCP_CLOSE_WAIT;
1217                 break;
1218               case TCPS_FIN_WAIT_1:
1219                 conn.state = SIGAR_TCP_FIN_WAIT1;
1220                 break;
1221               case TCPS_CLOSING:
1222                 conn.state = SIGAR_TCP_CLOSING;
1223                 break;
1224               case TCPS_LAST_ACK:
1225                 conn.state = SIGAR_TCP_LAST_ACK;
1226                 break;
1227               case TCPS_FIN_WAIT_2:
1228                 conn.state = SIGAR_TCP_FIN_WAIT2;
1229                 break;
1230               case TCPS_TIME_WAIT:
1231                 conn.state = SIGAR_TCP_TIME_WAIT;
1232                 break;
1233               default:
1234                 conn.state = SIGAR_TCP_UNKNOWN;
1235                 break;
1236             }
1237 
1238             if (walker->add_connection(walker, &conn) != SIGAR_OK) {
1239                 break;
1240             }
1241         }
1242 
1243         entry = pcb.inp_next;
1244         if (entry == tcp_inpcb.inp_next) {
1245             break;
1246         }
1247     }
1248 
1249     return SIGAR_OK;
1250 }
1251 
sigar_net_connection_walk(sigar_net_connection_walker_t *walker)1252 int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
1253 {
1254     int status;
1255 
1256     if (walker->flags & SIGAR_NETCONN_TCP) {
1257         status = net_conn_get_tcp(walker);
1258 
1259         if (status != SIGAR_OK) {
1260             return status;
1261         }
1262     }
1263 #if 0
1264     if (walker->flags & SIGAR_NETCONN_UDP) {
1265         status = net_conn_get_udp(walker);
1266 
1267         if (status != SIGAR_OK) {
1268             return status;
1269         }
1270     }
1271 #endif
1272     return SIGAR_OK;
1273 }
1274