xref: /6.6.0/sigar/src/os/darwin/darwin_sigar.c (revision 79ee0635)
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#include "sigar.h"
20#include "sigar_private.h"
21#include "sigar_util.h"
22#include "sigar_os.h"
23
24#include <sys/param.h>
25#include <sys/mount.h>
26#if !(defined(__FreeBSD__) && (__FreeBSD_version >= 800000))
27#include <nfs/rpcv2.h>
28#endif
29#include <nfs/nfsproto.h>
30
31#ifdef DARWIN
32#include <dlfcn.h>
33#include <mach/mach_init.h>
34#include <mach/message.h>
35#include <mach/kern_return.h>
36#include <mach/mach_host.h>
37#include <mach/mach_traps.h>
38#include <mach/mach_port.h>
39#include <mach/task.h>
40#include <mach/thread_act.h>
41#include <mach/thread_info.h>
42#include <mach/vm_map.h>
43#if !defined(HAVE_SHARED_REGION_H) && defined(__MAC_10_5) /* see Availability.h */
44#  define HAVE_SHARED_REGION_H /* suckit autoconf */
45#endif
46#ifdef HAVE_SHARED_REGION_H
47#include <mach/shared_region.h> /* does not exist in 10.4 SDK */
48#else
49#include <mach/shared_memory_server.h> /* deprecated in Leopard */
50#endif
51#include <mach-o/dyld.h>
52#define __OPENTRANSPORTPROVIDERS__
53#include <CoreFoundation/CoreFoundation.h>
54#include <CoreServices/CoreServices.h>
55#include <IOKit/IOBSD.h>
56#include <IOKit/IOKitLib.h>
57#include <IOKit/IOTypes.h>
58#include <IOKit/storage/IOBlockStorageDriver.h>
59#else
60#include <sys/dkstat.h>
61#include <sys/types.h>
62#include <sys/param.h>
63#include <sys/user.h>
64#include <sys/vmmeter.h>
65#include <fcntl.h>
66#include <stdio.h>
67#endif
68
69#if defined(__FreeBSD__) && (__FreeBSD_version >= 500013)
70#define SIGAR_FREEBSD5_NFSSTAT
71#include <nfsclient/nfs.h>
72#include <nfsserver/nfs.h>
73#else
74#include <nfs/nfs.h>
75#endif
76
77#include <sys/ioctl.h>
78#include <sys/mount.h>
79#include <sys/resource.h>
80#include <sys/stat.h>
81#include <sys/socket.h>
82#include <sys/sockio.h>
83
84#include <net/if.h>
85#include <net/if_dl.h>
86#include <net/if_types.h>
87#include <net/route.h>
88#include <netinet/in.h>
89#include <netinet/if_ether.h>
90
91#include <dirent.h>
92#include <errno.h>
93
94#include <sys/socketvar.h>
95#include <netinet/in.h>
96#include <netinet/in_systm.h>
97#include <netinet/ip.h>
98#include <netinet/in_pcb.h>
99#include <netinet/tcp.h>
100#include <netinet/tcp_timer.h>
101#ifdef __NetBSD__
102#include <netinet/ip_var.h>
103#include <sys/lwp.h>
104#include <sys/mount.h>
105#define SRUN LSRUN
106#define SSLEEP LSSLEEP
107#define SDEAD LSDEAD
108#define SONPROC LSONPROC
109#define SSUSPENDED LSSUSPENDED
110#include <sys/sched.h>
111#endif
112#include <netinet/tcp_var.h>
113#include <netinet/tcp_fsm.h>
114
115#define NMIB(mib) (sizeof(mib)/sizeof(mib[0]))
116
117#ifdef __FreeBSD__
118#  if (__FreeBSD_version >= 500013)
119#    define SIGAR_FREEBSD5
120#  else
121#    define SIGAR_FREEBSD4
122#  endif
123#endif
124
125#if defined(SIGAR_FREEBSD5)
126
127#define KI_FD   ki_fd
128#define KI_PID  ki_pid
129#define KI_PPID ki_ppid
130#define KI_PRI  ki_pri.pri_user
131#define KI_NICE ki_nice
132#define KI_COMM ki_comm
133#define KI_STAT ki_stat
134#define KI_UID  ki_ruid
135#define KI_GID  ki_rgid
136#define KI_EUID ki_svuid
137#define KI_EGID ki_svgid
138#define KI_SIZE ki_size
139#define KI_RSS  ki_rssize
140#define KI_TSZ  ki_tsize
141#define KI_DSZ  ki_dsize
142#define KI_SSZ  ki_ssize
143#define KI_FLAG ki_flag
144#define KI_START ki_start
145
146#elif defined(DARWIN) || defined(SIGAR_FREEBSD4) || defined(__OpenBSD__) || defined(__NetBSD__)
147
148#define KI_FD   kp_proc.p_fd
149#define KI_PID  kp_proc.p_pid
150#define KI_PPID kp_eproc.e_ppid
151#define KI_PRI  kp_proc.p_priority
152#define KI_NICE kp_proc.p_nice
153#define KI_COMM kp_proc.p_comm
154#define KI_STAT kp_proc.p_stat
155#define KI_UID  kp_eproc.e_pcred.p_ruid
156#define KI_GID  kp_eproc.e_pcred.p_rgid
157#define KI_EUID kp_eproc.e_pcred.p_svuid
158#define KI_EGID kp_eproc.e_pcred.p_svgid
159#define KI_SIZE XXX
160#define KI_RSS  kp_eproc.e_vm.vm_rssize
161#define KI_TSZ  kp_eproc.e_vm.vm_tsize
162#define KI_DSZ  kp_eproc.e_vm.vm_dsize
163#define KI_SSZ  kp_eproc.e_vm.vm_ssize
164#define KI_FLAG kp_eproc.e_flag
165#define KI_START kp_proc.p_starttime
166
167#endif
168
169#ifndef DARWIN
170
171#define PROCFS_STATUS(status) \
172    ((((status) != SIGAR_OK) && !sigar->proc_mounted) ? \
173     SIGAR_ENOTIMPL : status)
174
175static int get_koffsets(sigar_t *sigar)
176{
177    int i;
178    struct nlist klist[] = {
179        { "_cp_time" },
180        { "_cnt" },
181#if defined(__OpenBSD__) || defined(__NetBSD__)
182        { "_tcpstat" },
183        { "_tcbtable" },
184#endif
185        { NULL }
186    };
187
188    if (!sigar->kmem) {
189        return SIGAR_EPERM_KMEM;
190    }
191
192    kvm_nlist(sigar->kmem, klist);
193
194    for (i=0; i<KOFFSET_MAX; i++) {
195        sigar->koffsets[i] = klist[i].n_value;
196    }
197
198    return SIGAR_OK;
199}
200
201static int kread(sigar_t *sigar, void *data, int size, long offset)
202{
203    if (!sigar->kmem) {
204        return SIGAR_EPERM_KMEM;
205    }
206
207    if (kvm_read(sigar->kmem, offset, data, size) != size) {
208        return errno;
209    }
210
211    return SIGAR_OK;
212}
213#endif
214
215int sigar_os_open(sigar_t **sigar)
216{
217    int mib[2];
218    int ncpu;
219    size_t len;
220    struct timeval boottime;
221#ifndef DARWIN
222    struct stat sb;
223#endif
224
225    len = sizeof(ncpu);
226    mib[0] = CTL_HW;
227    mib[1] = HW_NCPU;
228    if (sysctl(mib, NMIB(mib), &ncpu,  &len, NULL, 0) < 0) {
229        return errno;
230    }
231
232    len = sizeof(boottime);
233    mib[0] = CTL_KERN;
234    mib[1] = KERN_BOOTTIME;
235    if (sysctl(mib, NMIB(mib), &boottime, &len, NULL, 0) < 0) {
236        return errno;
237    }
238
239    *sigar = malloc(sizeof(**sigar));
240
241#ifdef DARWIN
242    (*sigar)->mach_port = mach_host_self();
243#  ifdef DARWIN_HAS_LIBPROC_H
244    if (((*sigar)->libproc = dlopen("/usr/lib/libproc.dylib", 0))) {
245        (*sigar)->proc_pidinfo = dlsym((*sigar)->libproc, "proc_pidinfo");
246        (*sigar)->proc_pidfdinfo = dlsym((*sigar)->libproc, "proc_pidfdinfo");
247    }
248#  endif
249#else
250    (*sigar)->kmem = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
251    if (stat("/proc/curproc", &sb) < 0) {
252        (*sigar)->proc_mounted = 0;
253    }
254    else {
255        (*sigar)->proc_mounted = 1;
256    }
257#endif
258
259#ifndef DARWIN
260    get_koffsets(*sigar);
261#endif
262
263    (*sigar)->ncpu = ncpu;
264    (*sigar)->lcpu = -1;
265    (*sigar)->argmax = 0;
266    (*sigar)->boot_time = boottime.tv_sec; /* XXX seems off a bit */
267
268    (*sigar)->pagesize = getpagesize();
269#ifdef __FreeBSD__
270    (*sigar)->ticks = 100; /* sysconf(_SC_CLK_TCK) == 128 !? */
271#else
272    (*sigar)->ticks = sysconf(_SC_CLK_TCK);
273#endif
274    (*sigar)->last_pid = -1;
275
276    (*sigar)->pinfo = NULL;
277
278    return SIGAR_OK;
279}
280
281int sigar_os_close(sigar_t *sigar)
282{
283    if (sigar->pinfo) {
284        free(sigar->pinfo);
285    }
286#ifndef DARWIN
287    if (sigar->kmem) {
288        kvm_close(sigar->kmem);
289    }
290#endif
291    free(sigar);
292    return SIGAR_OK;
293}
294
295char *sigar_os_error_string(sigar_t *sigar, int err)
296{
297    switch (err) {
298      case SIGAR_EPERM_KMEM:
299        return "Failed to open /dev/kmem for reading";
300      case SIGAR_EPROC_NOENT:
301        return "/proc filesystem is not mounted";
302      default:
303        return NULL;
304    }
305}
306
307#if defined(DARWIN)
308static int sigar_vmstat(sigar_t *sigar, vm_statistics_data_t *vmstat)
309{
310    kern_return_t status;
311    mach_msg_type_number_t count = sizeof(*vmstat) / sizeof(integer_t);
312
313    status = host_statistics(sigar->mach_port, HOST_VM_INFO,
314                             (host_info_t)vmstat, &count);
315
316    if (status == KERN_SUCCESS) {
317        return SIGAR_OK;
318    }
319    else {
320        return errno;
321    }
322}
323#elif defined(__FreeBSD__)
324static int sigar_vmstat(sigar_t *sigar, struct vmmeter *vmstat)
325{
326    int status;
327    size_t size = sizeof(unsigned int);
328
329    status = kread(sigar, vmstat, sizeof(*vmstat),
330                   sigar->koffsets[KOFFSET_VMMETER]);
331
332    if (status == SIGAR_OK) {
333        return SIGAR_OK;
334    }
335
336    SIGAR_ZERO(vmstat);
337
338    /* derived from src/usr.bin/vmstat/vmstat.c */
339    /* only collect the ones we actually use */
340#define GET_VM_STATS(cat, name, used) \
341    if (used) sysctlbyname("vm.stats." #cat "." #name, &vmstat->name, &size, NULL, 0)
342
343    /* sys */
344    GET_VM_STATS(sys, v_swtch, 0);
345    GET_VM_STATS(sys, v_trap, 0);
346    GET_VM_STATS(sys, v_syscall, 0);
347    GET_VM_STATS(sys, v_intr, 0);
348    GET_VM_STATS(sys, v_soft, 0);
349
350    /* vm */
351    GET_VM_STATS(vm, v_vm_faults, 0);
352    GET_VM_STATS(vm, v_cow_faults, 0);
353    GET_VM_STATS(vm, v_cow_optim, 0);
354    GET_VM_STATS(vm, v_zfod, 0);
355    GET_VM_STATS(vm, v_ozfod, 0);
356    GET_VM_STATS(vm, v_swapin, 1);
357    GET_VM_STATS(vm, v_swapout, 1);
358    GET_VM_STATS(vm, v_swappgsin, 0);
359    GET_VM_STATS(vm, v_swappgsout, 0);
360    GET_VM_STATS(vm, v_vnodein, 1);
361    GET_VM_STATS(vm, v_vnodeout, 1);
362    GET_VM_STATS(vm, v_vnodepgsin, 0);
363    GET_VM_STATS(vm, v_vnodepgsout, 0);
364    GET_VM_STATS(vm, v_intrans, 0);
365    GET_VM_STATS(vm, v_reactivated, 0);
366    GET_VM_STATS(vm, v_pdwakeups, 0);
367    GET_VM_STATS(vm, v_pdpages, 0);
368    GET_VM_STATS(vm, v_dfree, 0);
369    GET_VM_STATS(vm, v_pfree, 0);
370    GET_VM_STATS(vm, v_tfree, 0);
371    GET_VM_STATS(vm, v_page_size, 0);
372    GET_VM_STATS(vm, v_page_count, 0);
373    GET_VM_STATS(vm, v_free_reserved, 0);
374    GET_VM_STATS(vm, v_free_target, 0);
375    GET_VM_STATS(vm, v_free_min, 0);
376    GET_VM_STATS(vm, v_free_count, 1);
377    GET_VM_STATS(vm, v_wire_count, 0);
378    GET_VM_STATS(vm, v_active_count, 0);
379    GET_VM_STATS(vm, v_inactive_target, 0);
380    GET_VM_STATS(vm, v_inactive_count, 1);
381    GET_VM_STATS(vm, v_cache_count, 1);
382#if (__FreeBSD_version < 1100079 )
383    GET_VM_STATS(vm, v_cache_min, 0);
384    GET_VM_STATS(vm, v_cache_max, 0);
385#endif
386    GET_VM_STATS(vm, v_pageout_free_min, 0);
387    GET_VM_STATS(vm, v_interrupt_free_min, 0);
388    GET_VM_STATS(vm, v_forks, 0);
389    GET_VM_STATS(vm, v_vforks, 0);
390    GET_VM_STATS(vm, v_rforks, 0);
391    GET_VM_STATS(vm, v_kthreads, 0);
392    GET_VM_STATS(vm, v_forkpages, 0);
393    GET_VM_STATS(vm, v_vforkpages, 0);
394    GET_VM_STATS(vm, v_rforkpages, 0);
395    GET_VM_STATS(vm, v_kthreadpages, 0);
396#undef GET_VM_STATS
397
398    return SIGAR_OK;
399}
400#elif defined(__OpenBSD__) || defined(__NetBSD__)
401static int sigar_vmstat(sigar_t *sigar, struct uvmexp *vmstat)
402{
403    size_t size = sizeof(*vmstat);
404    int mib[] = { CTL_VM, VM_UVMEXP };
405    if (sysctl(mib, NMIB(mib), vmstat, &size, NULL, 0) < 0) {
406        return errno;
407    }
408    else {
409        return SIGAR_OK;
410    }
411}
412#endif
413
414int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
415{
416    sigar_uint64_t kern = 0;
417#ifdef DARWIN
418    vm_statistics_data_t vmstat;
419    uint64_t mem_total;
420#else
421    unsigned long mem_total;
422#endif
423#if defined(__FreeBSD__)
424    struct vmmeter vmstat;
425#elif defined(__OpenBSD__) || defined(__NetBSD__)
426    struct uvmexp vmstat;
427#endif
428    int mib[2];
429    size_t len;
430    int status;
431
432    mib[0] = CTL_HW;
433
434    mib[1] = HW_PAGESIZE;
435    len = sizeof(sigar->pagesize);
436    if (sysctl(mib, NMIB(mib), &sigar->pagesize, &len, NULL, 0) < 0) {
437        return errno;
438    }
439
440#ifdef DARWIN
441    mib[1] = HW_MEMSIZE;
442#else
443    mib[1] = HW_PHYSMEM;
444#endif
445    len = sizeof(mem_total);
446    if (sysctl(mib, NMIB(mib), &mem_total, &len, NULL, 0) < 0) {
447        return errno;
448    }
449
450    mem->total = mem_total;
451
452#if defined(DARWIN)
453    if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
454        return status;
455    }
456
457    mem->free = vmstat.free_count;
458    mem->free *= sigar->pagesize;
459    kern = vmstat.inactive_count;
460    kern *= sigar->pagesize;
461#elif defined(__FreeBSD__)
462    if ((status = sigar_vmstat(sigar, &vmstat)) == SIGAR_OK) {
463        kern = vmstat.v_cache_count + vmstat.v_inactive_count;
464        kern *= sigar->pagesize;
465        mem->free = vmstat.v_free_count;
466        mem->free *= sigar->pagesize;
467    }
468#elif defined(__OpenBSD__) || defined(__NetBSD__)
469    if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
470        return status;
471    }
472    mem->free = vmstat.free;
473    kern = vmstat.inactive;
474#  if defined(__OpenBSD__)
475    kern += vmstat.vnodepages + vmstat.vtextpages;
476# elif defined(__NetBSD__)
477    kern += vmstat.filepages + vmstat.execpages;
478#  endif
479    kern *= sigar->pagesize;
480#endif
481
482    mem->used = mem->total - mem->free;
483
484    mem->actual_free = mem->free + kern;
485    mem->actual_used = mem->used - kern;
486
487    sigar_mem_calc_ram(sigar, mem);
488
489    return SIGAR_OK;
490}
491
492#define SWI_MAXMIB 3
493
494#ifdef SIGAR_FREEBSD5
495/* code in this function is based on FreeBSD 5.3 kvm_getswapinfo.c */
496static int getswapinfo_sysctl(struct kvm_swap *swap_ary,
497                              int swap_max)
498{
499    int ti, ttl;
500    size_t mibi, len, size;
501    int soid[SWI_MAXMIB];
502    struct xswdev xsd;
503    struct kvm_swap tot;
504    int unswdev, dmmax;
505
506    /* XXX this can be optimized by using os_open */
507    size = sizeof(dmmax);
508    if (sysctlbyname("vm.dmmax", &dmmax, &size, NULL, 0) == -1) {
509        return errno;
510    }
511
512    mibi = SWI_MAXMIB - 1;
513    if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) {
514        return errno;
515    }
516
517    bzero(&tot, sizeof(tot));
518    for (unswdev = 0;; unswdev++) {
519        soid[mibi] = unswdev;
520        len = sizeof(xsd);
521        if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) {
522            if (errno == ENOENT) {
523                break;
524            }
525            return errno;
526        }
527#if 0
528        if (len != sizeof(xsd)) {
529            _kvm_err(kd, kd->program, "struct xswdev has unexpected "
530                     "size;  kernel and libkvm out of sync?");
531            return -1;
532        }
533        if (xsd.xsw_version != XSWDEV_VERSION) {
534            _kvm_err(kd, kd->program, "struct xswdev version "
535                     "mismatch; kernel and libkvm out of sync?");
536            return -1;
537        }
538#endif
539        ttl = xsd.xsw_nblks - dmmax;
540        if (unswdev < swap_max - 1) {
541            bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev]));
542            swap_ary[unswdev].ksw_total = ttl;
543            swap_ary[unswdev].ksw_used = xsd.xsw_used;
544            swap_ary[unswdev].ksw_flags = xsd.xsw_flags;
545        }
546        tot.ksw_total += ttl;
547        tot.ksw_used += xsd.xsw_used;
548    }
549
550    ti = unswdev;
551    if (ti >= swap_max) {
552        ti = swap_max - 1;
553    }
554    if (ti >= 0) {
555        swap_ary[ti] = tot;
556    }
557
558    return SIGAR_OK;
559}
560#else
561#define getswapinfo_sysctl(swap_ary, swap_max) SIGAR_ENOTIMPL
562#endif
563
564#define SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) ((val * bsize) >> 1)
565
566#ifdef DARWIN
567#define VM_DIR "/private/var/vm"
568#define SWAPFILE "swapfile"
569
570static int sigar_swap_fs_get(sigar_t *sigar, sigar_swap_t *swap) /* <= 10.3 */
571{
572    DIR *dirp;
573    struct dirent *ent;
574    char swapfile[SSTRLEN(VM_DIR) + SSTRLEN("/") + SSTRLEN(SWAPFILE) + 12];
575    struct stat swapstat;
576    struct statfs vmfs;
577    sigar_uint64_t val, bsize;
578
579    swap->used = swap->total = swap->free = 0;
580
581    if (!(dirp = opendir(VM_DIR))) {
582         return errno;
583     }
584
585    /* looking for "swapfile0", "swapfile1", etc. */
586    while ((ent = readdir(dirp))) {
587        char *ptr = swapfile;
588
589        if ((ent->d_namlen < SSTRLEN(SWAPFILE)+1) || /* n/a, see comment above */
590            (ent->d_namlen > SSTRLEN(SWAPFILE)+11)) /* ensure no overflow */
591        {
592            continue;
593        }
594
595        if (!strnEQ(ent->d_name, SWAPFILE, SSTRLEN(SWAPFILE))) {
596            continue;
597        }
598
599        /* sprintf(swapfile, "%s/%s", VM_DIR, ent->d_name) */
600
601        memcpy(ptr, VM_DIR, SSTRLEN(VM_DIR));
602        ptr += SSTRLEN(VM_DIR);
603
604        *ptr++ = '/';
605
606        memcpy(ptr, ent->d_name, ent->d_namlen+1);
607
608        if (stat(swapfile, &swapstat) < 0) {
609            continue;
610        }
611
612        swap->used += swapstat.st_size;
613    }
614
615    closedir(dirp);
616
617    if (statfs(VM_DIR, &vmfs) < 0) {
618        return errno;
619    }
620
621    bsize = vmfs.f_bsize / 512;
622    val = vmfs.f_bfree;
623    swap->total = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) + swap->used;
624
625    swap->free = swap->total - swap->used;
626
627    return SIGAR_OK;
628}
629
630static int sigar_swap_sysctl_get(sigar_t *sigar, sigar_swap_t *swap)
631
632{
633#ifdef VM_SWAPUSAGE /* => 10.4 */
634    struct xsw_usage sw_usage;
635    size_t size = sizeof(sw_usage);
636    int mib[] = { CTL_VM, VM_SWAPUSAGE };
637
638    if (sysctl(mib, NMIB(mib), &sw_usage, &size, NULL, 0) != 0) {
639        return errno;
640    }
641
642    swap->total = sw_usage.xsu_total;
643    swap->used = sw_usage.xsu_used;
644    swap->free = sw_usage.xsu_avail;
645
646    return SIGAR_OK;
647#else
648    return SIGAR_ENOTIMPL; /* <= 10.3 */
649#endif
650}
651#endif /* DARWIN */
652
653int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
654{
655    int status;
656#if defined(DARWIN)
657    vm_statistics_data_t vmstat;
658
659    if (sigar_swap_sysctl_get(sigar, swap) != SIGAR_OK) {
660        status = sigar_swap_fs_get(sigar, swap); /* <= 10.3 */
661        if (status != SIGAR_OK) {
662            return status;
663        }
664    }
665
666    if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
667        return status;
668    }
669    swap->page_in = vmstat.pageins;
670    swap->page_out = vmstat.pageouts;
671#elif defined(__FreeBSD__)
672    struct kvm_swap kswap[1];
673    struct vmmeter vmstat;
674
675    if (getswapinfo_sysctl(kswap, 1) != SIGAR_OK) {
676        if (!sigar->kmem) {
677            return SIGAR_EPERM_KMEM;
678        }
679
680        if (kvm_getswapinfo(sigar->kmem, kswap, 1, 0) < 0) {
681            return errno;
682        }
683    }
684
685    if (kswap[0].ksw_total == 0) {
686        swap->total = 0;
687        swap->used  = 0;
688        swap->free  = 0;
689        return SIGAR_OK;
690    }
691
692    swap->total = kswap[0].ksw_total * sigar->pagesize;
693    swap->used  = kswap[0].ksw_used * sigar->pagesize;
694    swap->free  = swap->total - swap->used;
695
696    if ((status = sigar_vmstat(sigar, &vmstat)) == SIGAR_OK) {
697        swap->page_in = vmstat.v_swapin + vmstat.v_vnodein;
698        swap->page_out = vmstat.v_swapout + vmstat.v_vnodeout;
699    }
700    else {
701        swap->page_in = swap->page_out = -1;
702    }
703#elif defined(__OpenBSD__) || defined(__NetBSD__)
704    struct uvmexp vmstat;
705
706    if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
707        return status;
708    }
709    swap->total = vmstat.swpages * sigar->pagesize;
710    swap->used = vmstat.swpginuse * sigar->pagesize;
711    swap->free  = swap->total - swap->used;
712    swap->page_in = vmstat.pageins;
713    swap->page_out = vmstat.pdpageouts;
714#endif
715
716    return SIGAR_OK;
717}
718
719#ifndef KERN_CPTIME
720#define KERN_CPTIME KERN_CP_TIME
721#endif
722
723#if defined(__NetBSD__)
724typedef uint64_t cp_time_t;
725#else
726typedef unsigned long cp_time_t;
727#endif
728
729int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
730{
731#if defined(DARWIN)
732    kern_return_t status;
733    mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
734    host_cpu_load_info_data_t cpuload;
735
736    status = host_statistics(sigar->mach_port, HOST_CPU_LOAD_INFO,
737                             (host_info_t)&cpuload, &count);
738
739    if (status != KERN_SUCCESS) {
740        return errno;
741    }
742
743    cpu->user = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_USER]);
744    cpu->sys  = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_SYSTEM]);
745    cpu->idle = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_IDLE]);
746    cpu->nice = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_NICE]);
747    cpu->wait = 0; /*N/A*/
748    cpu->irq = 0; /*N/A*/
749    cpu->soft_irq = 0; /*N/A*/
750    cpu->stolen = 0; /*N/A*/
751    cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle;
752
753#elif defined(__FreeBSD__) || (__OpenBSD__) || defined(__NetBSD__)
754    int status;
755    cp_time_t cp_time[CPUSTATES];
756    size_t size = sizeof(cp_time);
757
758#  if defined(__OpenBSD__) || defined(__NetBSD__)
759    int mib[] = { CTL_KERN, KERN_CPTIME };
760    if (sysctl(mib, NMIB(mib), &cp_time, &size, NULL, 0) == -1) {
761        status = errno;
762    }
763#  else
764    /* try sysctl first, does not require /dev/kmem perms */
765    if (sysctlbyname("kern.cp_time", &cp_time, &size, NULL, 0) == -1) {
766        status = kread(sigar, &cp_time, sizeof(cp_time),
767                       sigar->koffsets[KOFFSET_CPUINFO]);
768    }
769#  endif
770    else {
771        status = SIGAR_OK;
772    }
773
774    if (status != SIGAR_OK) {
775        return status;
776    }
777
778    cpu->user = SIGAR_TICK2MSEC(cp_time[CP_USER]);
779    cpu->nice = SIGAR_TICK2MSEC(cp_time[CP_NICE]);
780    cpu->sys  = SIGAR_TICK2MSEC(cp_time[CP_SYS]);
781    cpu->idle = SIGAR_TICK2MSEC(cp_time[CP_IDLE]);
782    cpu->wait = 0; /*N/A*/
783    cpu->irq = SIGAR_TICK2MSEC(cp_time[CP_INTR]);
784    cpu->soft_irq = 0; /*N/A*/
785    cpu->stolen = 0; /*N/A*/
786    cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle + cpu->irq;
787#endif
788
789    return SIGAR_OK;
790}
791
792#ifndef KERN_PROC_PROC
793/* freebsd 4.x */
794#define KERN_PROC_PROC KERN_PROC_ALL
795#endif
796
797int sigar_os_proc_list_get(sigar_t *sigar,
798                           sigar_proc_list_t *proclist)
799{
800#if defined(DARWIN) || defined(SIGAR_FREEBSD5) || defined(__OpenBSD__) || defined(__NetBSD__)
801    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 };
802    int i, num;
803    size_t len;
804    struct kinfo_proc *proc;
805
806    if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) {
807        return errno;
808    }
809
810    proc = malloc(len);
811
812    if (sysctl(mib, NMIB(mib), proc, &len, NULL, 0) < 0) {
813        free(proc);
814        return errno;
815    }
816
817    num = len/sizeof(*proc);
818
819    for (i=0; i<num; i++) {
820        if (proc[i].KI_FLAG & P_SYSTEM) {
821            continue;
822        }
823        if (proc[i].KI_PID == 0) {
824            continue;
825        }
826        SIGAR_PROC_LIST_GROW(proclist);
827        proclist->data[proclist->number++] = proc[i].KI_PID;
828    }
829
830    free(proc);
831
832    return SIGAR_OK;
833#else
834    int i, num;
835    struct kinfo_proc *proc;
836
837    if (!sigar->kmem) {
838        return SIGAR_EPERM_KMEM;
839    }
840
841    proc = kvm_getprocs(sigar->kmem, KERN_PROC_PROC, 0, &num);
842
843    for (i=0; i<num; i++) {
844        if (proc[i].KI_FLAG & P_SYSTEM) {
845            continue;
846        }
847        SIGAR_PROC_LIST_GROW(proclist);
848        proclist->data[proclist->number++] = proc[i].KI_PID;
849    }
850#endif
851
852    return SIGAR_OK;
853}
854
855static int sigar_get_pinfo(sigar_t *sigar, sigar_pid_t pid)
856{
857#if defined(__OpenBSD__) || defined(__NetBSD__)
858    int mib[] = { CTL_KERN, KERN_PROC2, KERN_PROC_PID, 0, sizeof(*sigar->pinfo), 1 };
859#else
860    int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
861#endif
862    size_t len = sizeof(*sigar->pinfo);
863    time_t timenow = time(NULL);
864    mib[3] = pid;
865
866    if (sigar->pinfo == NULL) {
867        sigar->pinfo = malloc(len);
868    }
869
870    if (sigar->last_pid == pid) {
871        if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) {
872            return SIGAR_OK;
873        }
874    }
875
876    sigar->last_pid = pid;
877    sigar->last_getprocs = timenow;
878
879    if (sysctl(mib, NMIB(mib), sigar->pinfo, &len, NULL, 0) < 0) {
880        return errno;
881    }
882
883    return SIGAR_OK;
884}
885
886#if defined(SHARED_TEXT_REGION_SIZE) && defined(SHARED_DATA_REGION_SIZE)
887#  define GLOBAL_SHARED_SIZE (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE) /* 10.4 SDK */
888#endif
889
890#if defined(DARWIN) && defined(DARWIN_HAS_LIBPROC_H) && !defined(GLOBAL_SHARED_SIZE)
891/* get the CPU type of the process for the given pid */
892static int sigar_proc_cpu_type(sigar_t *sigar, sigar_pid_t pid, cpu_type_t *type)
893{
894    int status;
895    int mib[CTL_MAXNAME];
896    size_t len, miblen = NMIB(mib);
897
898    status = sysctlnametomib("sysctl.proc_cputype", mib, &miblen);
899    if (status != SIGAR_OK) {
900        return status;
901    }
902
903    mib[miblen] = pid;
904    len = sizeof(*type);
905    return sysctl(mib, miblen + 1, type, &len, NULL, 0);
906}
907
908/* shared memory region size for the given cpu_type_t */
909static mach_vm_size_t sigar_shared_region_size(cpu_type_t type)
910{
911    switch (type) {
912      case CPU_TYPE_ARM:
913        return SHARED_REGION_SIZE_ARM;
914      case CPU_TYPE_POWERPC:
915        return SHARED_REGION_SIZE_PPC;
916      case CPU_TYPE_POWERPC64:
917        return SHARED_REGION_SIZE_PPC64;
918      case CPU_TYPE_I386:
919        return SHARED_REGION_SIZE_I386;
920      case CPU_TYPE_X86_64:
921        return SHARED_REGION_SIZE_X86_64;
922      default:
923        return SHARED_REGION_SIZE_I386; /* assume 32-bit x86|ppc */
924    }
925}
926#endif /* DARWIN */
927
928int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
929                       sigar_proc_mem_t *procmem)
930{
931#if defined(DARWIN)
932    mach_port_t task, self = mach_task_self();
933    kern_return_t status;
934    task_basic_info_data_t info;
935    task_events_info_data_t events;
936    mach_msg_type_number_t count;
937#  ifdef DARWIN_HAS_LIBPROC_H
938    struct proc_taskinfo pti;
939    struct proc_regioninfo pri;
940
941    if (sigar->libproc) {
942        int sz =
943            sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti));
944
945        if (sz == sizeof(pti)) {
946            procmem->size         = pti.pti_virtual_size;
947            procmem->resident     = pti.pti_resident_size;
948            procmem->page_faults  = pti.pti_faults;
949            procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
950            procmem->major_faults = SIGAR_FIELD_NOTIMPL;
951            procmem->share        = SIGAR_FIELD_NOTIMPL;
952
953            sz = sigar->proc_pidinfo(pid, PROC_PIDREGIONINFO, 0, &pri, sizeof(pri));
954            if (sz == sizeof(pri)) {
955                if (pri.pri_share_mode == SM_EMPTY) {
956                    mach_vm_size_t shared_size;
957#ifdef GLOBAL_SHARED_SIZE
958                    shared_size = GLOBAL_SHARED_SIZE; /* 10.4 SDK */
959#else
960                    cpu_type_t cpu_type;
961
962                    if (sigar_proc_cpu_type(sigar, pid, &cpu_type) == SIGAR_OK) {
963                        shared_size = sigar_shared_region_size(cpu_type);
964                    }
965                    else {
966                        shared_size = SHARED_REGION_SIZE_I386; /* assume 32-bit x86|ppc */
967                    }
968#endif
969                    if (procmem->size > shared_size) {
970                        procmem->size -= shared_size; /* SIGAR-123 */
971                    }
972                }
973            }
974            return SIGAR_OK;
975        }
976    }
977#  endif
978
979    status = task_for_pid(self, pid, &task);
980
981    if (status != KERN_SUCCESS) {
982        return errno;
983    }
984
985    count = TASK_BASIC_INFO_COUNT;
986    status = task_info(task, TASK_BASIC_INFO, (task_info_t)&info, &count);
987    if (status != KERN_SUCCESS) {
988        return errno;
989    }
990
991    count = TASK_EVENTS_INFO_COUNT;
992    status = task_info(task, TASK_EVENTS_INFO, (task_info_t)&events, &count);
993    if (status == KERN_SUCCESS) {
994        procmem->page_faults = events.faults;
995    }
996    else {
997        procmem->page_faults = SIGAR_FIELD_NOTIMPL;
998    }
999
1000    procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
1001    procmem->major_faults = SIGAR_FIELD_NOTIMPL;
1002
1003    if (task != self) {
1004        mach_port_deallocate(self, task);
1005    }
1006
1007    procmem->size     = info.virtual_size;
1008    procmem->resident = info.resident_size;
1009    procmem->share    = SIGAR_FIELD_NOTIMPL;
1010
1011    return SIGAR_OK;
1012#elif defined(__FreeBSD__)
1013    int status = sigar_get_pinfo(sigar, pid);
1014    bsd_pinfo_t *pinfo = sigar->pinfo;
1015
1016    if (status != SIGAR_OK) {
1017        return status;
1018    }
1019
1020    procmem->size =
1021        (pinfo->KI_TSZ + pinfo->KI_DSZ + pinfo->KI_SSZ) * sigar->pagesize;
1022
1023    procmem->resident = pinfo->KI_RSS * sigar->pagesize;
1024
1025    procmem->share = SIGAR_FIELD_NOTIMPL;
1026
1027    procmem->page_faults  = SIGAR_FIELD_NOTIMPL;
1028    procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
1029    procmem->major_faults = SIGAR_FIELD_NOTIMPL;
1030#elif defined(__OpenBSD__) || defined(__NetBSD__)
1031    int status = sigar_get_pinfo(sigar, pid);
1032    bsd_pinfo_t *pinfo = sigar->pinfo;
1033
1034    if (status != SIGAR_OK) {
1035        return status;
1036    }
1037
1038    procmem->size =
1039        (pinfo->p_vm_tsize + pinfo->p_vm_dsize + pinfo->p_vm_ssize) * sigar->pagesize;
1040
1041    procmem->resident = pinfo->p_vm_rssize * sigar->pagesize;
1042
1043    procmem->share = SIGAR_FIELD_NOTIMPL;
1044
1045    procmem->minor_faults = pinfo->p_uru_minflt;
1046    procmem->major_faults = pinfo->p_uru_majflt;
1047    procmem->page_faults  = procmem->minor_faults + procmem->major_faults;
1048#endif
1049    return SIGAR_OK;
1050}
1051
1052#define tv2msec(tv) \
1053   (((sigar_uint64_t)tv.tv_sec * SIGAR_MSEC) + (((sigar_uint64_t)tv.tv_usec) / 1000))
1054
1055#ifdef DARWIN
1056#define tval2msec(tval) \
1057   ((tval.seconds * SIGAR_MSEC) + (tval.microseconds / 1000))
1058
1059#define tval2nsec(tval) \
1060    (SIGAR_SEC2NANO((tval).seconds) + SIGAR_MICROSEC2NANO((tval).microseconds))
1061
1062static int get_proc_times(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *time)
1063{
1064    unsigned int count;
1065    time_value_t utime = {0, 0}, stime = {0, 0};
1066    task_basic_info_data_t ti;
1067    task_thread_times_info_data_t tti;
1068    task_port_t task, self;
1069    kern_return_t status;
1070#  ifdef DARWIN_HAS_LIBPROC_H
1071    if (sigar->libproc) {
1072        struct proc_taskinfo pti;
1073        int sz =
1074            sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti));
1075
1076        if (sz == sizeof(pti)) {
1077            time->user = SIGAR_NSEC2MSEC(pti.pti_total_user);
1078            time->sys  = SIGAR_NSEC2MSEC(pti.pti_total_system);
1079            time->total = time->user + time->sys;
1080            return SIGAR_OK;
1081        }
1082    }
1083#  endif
1084
1085    self = mach_task_self();
1086    status = task_for_pid(self, pid, &task);
1087    if (status != KERN_SUCCESS) {
1088        return errno;
1089    }
1090
1091    count = TASK_BASIC_INFO_COUNT;
1092    status = task_info(task, TASK_BASIC_INFO,
1093                       (task_info_t)&ti, &count);
1094    if (status != KERN_SUCCESS) {
1095        if (task != self) {
1096            mach_port_deallocate(self, task);
1097        }
1098        return errno;
1099    }
1100
1101    count = TASK_THREAD_TIMES_INFO_COUNT;
1102    status = task_info(task, TASK_THREAD_TIMES_INFO,
1103                       (task_info_t)&tti, &count);
1104    if (status != KERN_SUCCESS) {
1105        if (task != self) {
1106            mach_port_deallocate(self, task);
1107        }
1108        return errno;
1109    }
1110
1111    time_value_add(&utime, &ti.user_time);
1112    time_value_add(&stime, &ti.system_time);
1113    time_value_add(&utime, &tti.user_time);
1114    time_value_add(&stime, &tti.system_time);
1115
1116    time->user = tval2msec(utime);
1117    time->sys  = tval2msec(stime);
1118    time->total = time->user + time->sys;
1119
1120    return SIGAR_OK;
1121}
1122#endif
1123
1124int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
1125                        sigar_proc_time_t *proctime)
1126{
1127#ifdef SIGAR_FREEBSD4
1128    struct user user;
1129#endif
1130    int status = sigar_get_pinfo(sigar, pid);
1131    bsd_pinfo_t *pinfo = sigar->pinfo;
1132
1133    if (status != SIGAR_OK) {
1134        return status;
1135    }
1136
1137#if defined(DARWIN)
1138    if ((status = get_proc_times(sigar, pid, proctime)) != SIGAR_OK) {
1139        return status;
1140    }
1141    proctime->start_time = tv2msec(pinfo->KI_START);
1142#elif defined(SIGAR_FREEBSD5)
1143    proctime->user  = tv2msec(pinfo->ki_rusage.ru_utime);
1144    proctime->sys   = tv2msec(pinfo->ki_rusage.ru_stime);
1145    proctime->total = proctime->user + proctime->sys;
1146    proctime->start_time = tv2msec(pinfo->KI_START);
1147#elif defined(SIGAR_FREEBSD4)
1148    if (!sigar->kmem) {
1149        return SIGAR_EPERM_KMEM;
1150    }
1151
1152    status = kread(sigar, &user, sizeof(user),
1153                   (u_long)pinfo->kp_proc.p_addr);
1154    if (status != SIGAR_OK) {
1155        return status;
1156    }
1157
1158    proctime->user  = tv2msec(user.u_stats.p_ru.ru_utime);
1159    proctime->sys   = tv2msec(user.u_stats.p_ru.ru_stime);
1160    proctime->total = proctime->user + proctime->sys;
1161    proctime->start_time = tv2msec(user.u_stats.p_start);
1162#elif defined(__OpenBSD__) || defined(__NetBSD__)
1163    /* XXX *_usec */
1164    proctime->user  = pinfo->p_uutime_sec * SIGAR_MSEC;
1165    proctime->sys   = pinfo->p_ustime_sec * SIGAR_MSEC;
1166    proctime->total = proctime->user + proctime->sys;
1167    proctime->start_time = pinfo->p_ustart_sec * SIGAR_MSEC;
1168#endif
1169
1170    return SIGAR_OK;
1171}
1172
1173#ifdef DARWIN
1174/* thread state mapping derived from ps.tproj */
1175static const char thread_states[] = {
1176    /*0*/ '-',
1177    /*1*/ SIGAR_PROC_STATE_RUN,
1178    /*2*/ SIGAR_PROC_STATE_ZOMBIE,
1179    /*3*/ SIGAR_PROC_STATE_SLEEP,
1180    /*4*/ SIGAR_PROC_STATE_IDLE,
1181    /*5*/ SIGAR_PROC_STATE_STOP,
1182    /*6*/ SIGAR_PROC_STATE_STOP,
1183    /*7*/ '?'
1184};
1185
1186static int thread_state_get(thread_basic_info_data_t *info)
1187{
1188    switch (info->run_state) {
1189      case TH_STATE_RUNNING:
1190        return 1;
1191      case TH_STATE_UNINTERRUPTIBLE:
1192        return 2;
1193      case TH_STATE_WAITING:
1194        return (info->sleep_time > 20) ? 4 : 3;
1195      case TH_STATE_STOPPED:
1196        return 5;
1197      case TH_STATE_HALTED:
1198        return 6;
1199      default:
1200        return 7;
1201    }
1202}
1203
1204static int sigar_proc_threads_get(sigar_t *sigar, sigar_pid_t pid,
1205                                  sigar_proc_state_t *procstate)
1206{
1207    mach_port_t task, self = mach_task_self();
1208    kern_return_t status;
1209    thread_array_t threads;
1210    mach_msg_type_number_t count, i;
1211    int state = TH_STATE_HALTED + 1;
1212
1213    status = task_for_pid(self, pid, &task);
1214    if (status != KERN_SUCCESS) {
1215        return errno;
1216    }
1217
1218    status = task_threads(task, &threads, &count);
1219    if (status != KERN_SUCCESS) {
1220        return errno;
1221    }
1222
1223    procstate->threads = count;
1224
1225    for (i=0; i<count; i++) {
1226        mach_msg_type_number_t info_count = THREAD_BASIC_INFO_COUNT;
1227        thread_basic_info_data_t info;
1228
1229        status = thread_info(threads[i], THREAD_BASIC_INFO,
1230                             (thread_info_t)&info, &info_count);
1231        if (status == KERN_SUCCESS) {
1232            int tstate = thread_state_get(&info);
1233            if (tstate < state) {
1234                state = tstate;
1235            }
1236        }
1237    }
1238
1239    vm_deallocate(self, (vm_address_t)threads, sizeof(thread_t) * count);
1240
1241    procstate->state = thread_states[state];
1242
1243    return SIGAR_OK;
1244}
1245#endif
1246
1247int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
1248                         sigar_proc_state_t *procstate)
1249{
1250    int status = sigar_get_pinfo(sigar, pid);
1251    bsd_pinfo_t *pinfo = sigar->pinfo;
1252#if defined(__OpenBSD__) || defined(__NetBSD__)
1253    int state = pinfo->p_stat;
1254#else
1255    int state = pinfo->KI_STAT;
1256#endif
1257
1258    if (status != SIGAR_OK) {
1259        return status;
1260    }
1261
1262#if defined(__OpenBSD__) || defined(__NetBSD__)
1263    SIGAR_SSTRCPY(procstate->name, pinfo->p_comm);
1264    procstate->ppid     = pinfo->p_ppid;
1265    procstate->priority = pinfo->p_priority;
1266    procstate->nice     = pinfo->p_nice;
1267    procstate->tty      = pinfo->p_tdev;
1268    procstate->threads  = SIGAR_FIELD_NOTIMPL;
1269    procstate->processor = pinfo->p_cpuid;
1270#else
1271    SIGAR_SSTRCPY(procstate->name, pinfo->KI_COMM);
1272    procstate->ppid     = pinfo->KI_PPID;
1273    procstate->priority = pinfo->KI_PRI;
1274    procstate->nice     = pinfo->KI_NICE;
1275    procstate->tty      = SIGAR_FIELD_NOTIMPL; /*XXX*/
1276    procstate->threads  = SIGAR_FIELD_NOTIMPL;
1277    procstate->processor = SIGAR_FIELD_NOTIMPL;
1278#endif
1279
1280#ifdef DARWIN
1281    status = sigar_proc_threads_get(sigar, pid, procstate);
1282    if (status == SIGAR_OK) {
1283        return status;
1284    }
1285#endif
1286
1287    switch (state) {
1288      case SIDL:
1289        procstate->state = 'D';
1290        break;
1291      case SRUN:
1292#ifdef SONPROC
1293      case SONPROC:
1294#endif
1295        procstate->state = 'R';
1296        break;
1297      case SSLEEP:
1298        procstate->state = 'S';
1299        break;
1300      case SSTOP:
1301        procstate->state = 'T';
1302        break;
1303      case SZOMB:
1304        procstate->state = 'Z';
1305        break;
1306      default:
1307        procstate->state = '?';
1308        break;
1309    }
1310
1311    return SIGAR_OK;
1312}
1313
1314#define SIGAR_MICROSEC2NANO(s) \
1315    ((sigar_uint64_t)(s) * (sigar_uint64_t)1000)
1316
1317#define TIME_NSEC(t) \
1318    (SIGAR_SEC2NANO((t).tv_sec) + SIGAR_MICROSEC2NANO((t).tv_usec))
1319
1320
1321int sigar_os_fs_type_get(sigar_file_system_t *fsp)
1322{
1323    char *type = fsp->sys_type_name;
1324
1325    /* see sys/disklabel.h */
1326    switch (*type) {
1327      case 'f':
1328        if (strEQ(type, "ffs")) {
1329            fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1330        }
1331        break;
1332      case 'h':
1333        if (strEQ(type, "hfs")) {
1334            fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1335        }
1336        break;
1337      case 'u':
1338        if (strEQ(type, "ufs")) {
1339            fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1340        }
1341        break;
1342    }
1343
1344    return fsp->type;
1345}
1346
1347static void get_fs_options(char *opts, int osize, long flags)
1348{
1349    *opts = '\0';
1350    if (flags & MNT_RDONLY)         strncat(opts, "ro", osize);
1351    else                            strncat(opts, "rw", osize);
1352    if (flags & MNT_SYNCHRONOUS)    strncat(opts, ",sync", osize);
1353    if (flags & MNT_NOEXEC)         strncat(opts, ",noexec", osize);
1354    if (flags & MNT_NOSUID)         strncat(opts, ",nosuid", osize);
1355#ifdef MNT_NODEV
1356    if (flags & MNT_NODEV)          strncat(opts, ",nodev", osize);
1357#endif
1358#ifdef MNT_UNION
1359    if (flags & MNT_UNION)          strncat(opts, ",union", osize);
1360#endif
1361    if (flags & MNT_ASYNC)          strncat(opts, ",async", osize);
1362#ifdef MNT_NOATIME
1363    if (flags & MNT_NOATIME)        strncat(opts, ",noatime", osize);
1364#endif
1365#ifdef MNT_NOCLUSTERR
1366    if (flags & MNT_NOCLUSTERR)     strncat(opts, ",noclusterr", osize);
1367#endif
1368#ifdef MNT_NOCLUSTERW
1369    if (flags & MNT_NOCLUSTERW)     strncat(opts, ",noclusterw", osize);
1370#endif
1371#ifdef MNT_NOSYMFOLLOW
1372    if (flags & MNT_NOSYMFOLLOW)    strncat(opts, ",nosymfollow", osize);
1373#endif
1374#ifdef MNT_SUIDDIR
1375    if (flags & MNT_SUIDDIR)        strncat(opts, ",suiddir", osize);
1376#endif
1377#ifdef MNT_SOFTDEP
1378    if (flags & MNT_SOFTDEP)        strncat(opts, ",soft-updates", osize);
1379#endif
1380    if (flags & MNT_LOCAL)          strncat(opts, ",local", osize);
1381    if (flags & MNT_QUOTA)          strncat(opts, ",quota", osize);
1382    if (flags & MNT_ROOTFS)         strncat(opts, ",rootfs", osize);
1383#ifdef MNT_USER
1384    if (flags & MNT_USER)           strncat(opts, ",user", osize);
1385#endif
1386#ifdef MNT_IGNORE
1387    if (flags & MNT_IGNORE)         strncat(opts, ",ignore", osize);
1388#endif
1389    if (flags & MNT_EXPORTED)       strncat(opts, ",nfs", osize);
1390}
1391
1392#ifdef __NetBSD__
1393#define sigar_statfs statvfs
1394#define sigar_getfsstat getvfsstat
1395#define sigar_f_flags f_flag
1396#else
1397#define sigar_statfs statfs
1398#define sigar_getfsstat getfsstat
1399#define sigar_f_flags f_flags
1400#endif
1401
1402int sigar_file_system_list_get(sigar_t *sigar,
1403                               sigar_file_system_list_t *fslist)
1404{
1405    struct sigar_statfs *fs;
1406    int num, i;
1407    int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
1408    long len;
1409
1410    if ((num = sigar_getfsstat(NULL, 0, MNT_NOWAIT)) < 0) {
1411        return errno;
1412    }
1413
1414    len = sizeof(*fs) * num;
1415    fs = malloc(len);
1416
1417    if ((num = sigar_getfsstat(fs, len, MNT_NOWAIT)) < 0) {
1418        free(fs);
1419        return errno;
1420    }
1421
1422    sigar_file_system_list_create(fslist);
1423
1424    for (i=0; i<num; i++) {
1425        sigar_file_system_t *fsp;
1426
1427#ifdef MNT_AUTOMOUNTED
1428        if (fs[i].sigar_f_flags & MNT_AUTOMOUNTED) {
1429            if (is_debug) {
1430                sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1431                                 "[file_system_list] skipping automounted %s: %s",
1432                                 fs[i].f_fstypename, fs[i].f_mntonname);
1433            }
1434            continue;
1435        }
1436#endif
1437
1438#ifdef MNT_RDONLY
1439        if (fs[i].sigar_f_flags & MNT_RDONLY) {
1440            /* e.g. ftp mount or .dmg image */
1441            if (is_debug) {
1442                sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1443                                 "[file_system_list] skipping readonly %s: %s",
1444                                 fs[i].f_fstypename, fs[i].f_mntonname);
1445            }
1446            continue;
1447        }
1448#endif
1449
1450        SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
1451
1452        fsp = &fslist->data[fslist->number++];
1453
1454        SIGAR_SSTRCPY(fsp->dir_name, fs[i].f_mntonname);
1455        SIGAR_SSTRCPY(fsp->dev_name, fs[i].f_mntfromname);
1456        SIGAR_SSTRCPY(fsp->sys_type_name, fs[i].f_fstypename);
1457        get_fs_options(fsp->options, sizeof(fsp->options)-1, fs[i].sigar_f_flags);
1458
1459        sigar_fs_type_init(fsp);
1460    }
1461
1462    free(fs);
1463    return SIGAR_OK;
1464}
1465
1466#ifdef DARWIN
1467#define IoStatGetValue(key, val) \
1468    if ((number = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatistics##key)))) \
1469        CFNumberGetValue(number, kCFNumberSInt64Type, &val)
1470#endif
1471
1472
1473#ifdef DARWIN
1474#define CTL_HW_FREQ_MAX "hw.cpufrequency_max"
1475#define CTL_HW_FREQ_MIN "hw.cpufrequency_min"
1476#else
1477/* XXX FreeBSD 5.x+ only? */
1478#define CTL_HW_FREQ "machdep.tsc_freq"
1479#endif
1480
1481
1482#define rt_s_addr(sa) ((struct sockaddr_in *)(sa))->sin_addr.s_addr
1483
1484#ifndef SA_SIZE
1485#define SA_SIZE(sa)                                             \
1486    (  (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?      \
1487        sizeof(long)            :                               \
1488        1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
1489#endif
1490
1491typedef enum {
1492    IFMSG_ITER_LIST,
1493    IFMSG_ITER_GET
1494} ifmsg_iter_e;
1495
1496typedef struct {
1497    const char *name;
1498    ifmsg_iter_e type;
1499    union {
1500        sigar_net_interface_list_t *iflist;
1501        struct if_msghdr *ifm;
1502    } data;
1503} ifmsg_iter_t;
1504
1505static int sigar_ifmsg_init(sigar_t *sigar)
1506{
1507    int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, 0 };
1508    size_t len;
1509
1510    if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) {
1511        return errno;
1512    }
1513
1514    if (sigar->ifconf_len < len) {
1515        sigar->ifconf_buf = realloc(sigar->ifconf_buf, len);
1516        sigar->ifconf_len = len;
1517    }
1518
1519    if (sysctl(mib, NMIB(mib), sigar->ifconf_buf, &len, NULL, 0) < 0) {
1520        return errno;
1521    }
1522
1523    return SIGAR_OK;
1524}
1525
1526/**
1527 * @param name name of the interface
1528 * @param name_len length of name (w/o \0)
1529 */
1530static int has_ifaddr(char *name, size_t name_len)
1531{
1532    int sock, status;
1533    struct ifreq ifr;
1534
1535    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1536        return errno;
1537    }
1538    strncpy(ifr.ifr_name, name, MIN(sizeof(ifr.ifr_name) - 1, name_len));
1539    ifr.ifr_name[MIN(sizeof(ifr.ifr_name) - 1, name_len)] = '\0';
1540    if (ioctl(sock, SIOCGIFADDR, &ifr) == 0) {
1541        status = SIGAR_OK;
1542    }
1543    else {
1544        status = errno;
1545    }
1546
1547    close(sock);
1548    return status;
1549}
1550
1551static int sigar_ifmsg_iter(sigar_t *sigar, ifmsg_iter_t *iter)
1552{
1553    char *end = sigar->ifconf_buf + sigar->ifconf_len;
1554    char *ptr = sigar->ifconf_buf;
1555
1556    if (iter->type == IFMSG_ITER_LIST) {
1557        sigar_net_interface_list_create(iter->data.iflist);
1558    }
1559
1560    while (ptr < end) {
1561        char *name;
1562        struct sockaddr_dl *sdl;
1563        struct if_msghdr *ifm = (struct if_msghdr *)ptr;
1564
1565        if (ifm->ifm_type != RTM_IFINFO) {
1566            break;
1567        }
1568
1569        ptr += ifm->ifm_msglen;
1570
1571        while (ptr < end) {
1572            struct if_msghdr *next = (struct if_msghdr *)ptr;
1573
1574            if (next->ifm_type != RTM_NEWADDR) {
1575                break;
1576            }
1577
1578            ptr += next->ifm_msglen;
1579        }
1580
1581        sdl = (struct sockaddr_dl *)(ifm + 1);
1582        if (sdl->sdl_family != AF_LINK) {
1583            continue;
1584        }
1585
1586        switch (iter->type) {
1587          case IFMSG_ITER_LIST:
1588            if (sdl->sdl_type == IFT_OTHER) {
1589                if (has_ifaddr(sdl->sdl_data, sdl->sdl_nlen) != SIGAR_OK) {
1590                    break;
1591                }
1592            }
1593            else if (!((sdl->sdl_type == IFT_ETHER) ||
1594                       (sdl->sdl_type == IFT_LOOP)))
1595            {
1596                break; /* XXX deal w/ other weirdo interfaces */
1597            }
1598
1599            SIGAR_NET_IFLIST_GROW(iter->data.iflist);
1600
1601            /* sdl_data doesn't include a trailing \0, it is only sdl_nlen long */
1602            name = malloc(sdl->sdl_nlen+1);
1603            memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
1604            name[sdl->sdl_nlen] = '\0'; /* add the missing \0 */
1605
1606            iter->data.iflist->data[iter->data.iflist->number++] = name;
1607            break;
1608
1609          case IFMSG_ITER_GET:
1610            if (strlen(iter->name) == sdl->sdl_nlen && 0 == memcmp(iter->name, sdl->sdl_data, sdl->sdl_nlen)) {
1611                iter->data.ifm = ifm;
1612                return SIGAR_OK;
1613            }
1614        }
1615    }
1616
1617    switch (iter->type) {
1618      case IFMSG_ITER_LIST:
1619        return SIGAR_OK;
1620
1621      case IFMSG_ITER_GET:
1622      default:
1623        return ENXIO;
1624    }
1625}
1626
1627int sigar_net_interface_list_get(sigar_t *sigar,
1628                                 sigar_net_interface_list_t *iflist)
1629{
1630    int status;
1631    ifmsg_iter_t iter;
1632
1633    if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) {
1634        return status;
1635    }
1636
1637    iter.type = IFMSG_ITER_LIST;
1638    iter.data.iflist = iflist;
1639
1640    return sigar_ifmsg_iter(sigar, &iter);
1641}
1642
1643#include <ifaddrs.h>
1644
1645/* in6_prefixlen derived from freebsd/sbin/ifconfig/af_inet6.c */
1646static int sigar_in6_prefixlen(struct sockaddr *netmask)
1647{
1648    struct in6_addr *addr = SIGAR_SIN6_ADDR(netmask);
1649    u_char *name = (u_char *)addr;
1650    int size = sizeof(*addr);
1651    int byte, bit, plen = 0;
1652
1653    for (byte = 0; byte < size; byte++, plen += 8) {
1654        if (name[byte] != 0xff) {
1655            break;
1656        }
1657    }
1658    if (byte == size) {
1659        return plen;
1660    }
1661    for (bit = 7; bit != 0; bit--, plen++) {
1662        if (!(name[byte] & (1 << bit))) {
1663            break;
1664        }
1665    }
1666    for (; bit != 0; bit--) {
1667        if (name[byte] & (1 << bit)) {
1668            return 0;
1669        }
1670    }
1671    byte++;
1672    for (; byte < size; byte++) {
1673        if (name[byte]) {
1674            return 0;
1675        }
1676    }
1677    return plen;
1678}
1679
1680int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name,
1681                                        sigar_net_interface_config_t *ifconfig)
1682{
1683    int status = SIGAR_ENOENT;
1684    struct ifaddrs *addrs, *ifa;
1685
1686    if (getifaddrs(&addrs) != 0) {
1687        return errno;
1688    }
1689
1690    for (ifa=addrs; ifa; ifa=ifa->ifa_next) {
1691        if (ifa->ifa_addr &&
1692            (ifa->ifa_addr->sa_family == AF_INET6) &&
1693            strEQ(ifa->ifa_name, name))
1694        {
1695            status = SIGAR_OK;
1696            break;
1697        }
1698    }
1699
1700    if (status == SIGAR_OK) {
1701        struct in6_addr *addr = SIGAR_SIN6_ADDR(ifa->ifa_addr);
1702
1703        sigar_net_address6_set(ifconfig->address6, addr);
1704        sigar_net_interface_scope6_set(ifconfig, addr);
1705        ifconfig->prefix6_length = sigar_in6_prefixlen(ifa->ifa_netmask);
1706    }
1707
1708    freeifaddrs(addrs);
1709
1710    return status;
1711}
1712
1713int sigar_net_interface_config_get(sigar_t *sigar, const char *name,
1714                                   sigar_net_interface_config_t *ifconfig)
1715{
1716    int sock;
1717    int status;
1718    ifmsg_iter_t iter;
1719    struct if_msghdr *ifm;
1720    struct sockaddr_dl *sdl;
1721    struct ifreq ifr;
1722
1723    if (!name) {
1724        return sigar_net_interface_config_primary_get(sigar, ifconfig);
1725    }
1726
1727    if (sigar->ifconf_len == 0) {
1728        if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) {
1729            return status;
1730        }
1731    }
1732
1733    SIGAR_ZERO(ifconfig);
1734
1735    iter.type = IFMSG_ITER_GET;
1736    iter.name = name;
1737
1738    if ((status = sigar_ifmsg_iter(sigar, &iter)) != SIGAR_OK) {
1739        return status;
1740    }
1741
1742    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1743        return errno;
1744    }
1745
1746    ifm = iter.data.ifm;
1747
1748    SIGAR_SSTRCPY(ifconfig->name, name);
1749
1750    sdl = (struct sockaddr_dl *)(ifm + 1);
1751
1752    sigar_net_address_mac_set(ifconfig->hwaddr,
1753                              LLADDR(sdl),
1754                              sdl->sdl_alen);
1755
1756    ifconfig->flags = ifm->ifm_flags;
1757    ifconfig->mtu = ifm->ifm_data.ifi_mtu;
1758    ifconfig->metric = ifm->ifm_data.ifi_metric;
1759
1760    SIGAR_SSTRCPY(ifr.ifr_name, name);
1761
1762#define ifr_s_addr(ifr) \
1763    ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr
1764
1765    if (!ioctl(sock, SIOCGIFADDR, &ifr)) {
1766        sigar_net_address_set(ifconfig->address,
1767                              ifr_s_addr(ifr));
1768    }
1769
1770    if (!ioctl(sock, SIOCGIFNETMASK, &ifr)) {
1771        sigar_net_address_set(ifconfig->netmask,
1772                              ifr_s_addr(ifr));
1773    }
1774
1775    if (ifconfig->flags & IFF_LOOPBACK) {
1776        sigar_net_address_set(ifconfig->destination,
1777                              ifconfig->address.addr.in);
1778        sigar_net_address_set(ifconfig->broadcast, 0);
1779        SIGAR_SSTRCPY(ifconfig->type,
1780                      SIGAR_NIC_LOOPBACK);
1781    }
1782    else {
1783        if (!ioctl(sock, SIOCGIFDSTADDR, &ifr)) {
1784            sigar_net_address_set(ifconfig->destination,
1785                                  ifr_s_addr(ifr));
1786        }
1787
1788        if (!ioctl(sock, SIOCGIFBRDADDR, &ifr)) {
1789            sigar_net_address_set(ifconfig->broadcast,
1790                                  ifr_s_addr(ifr));
1791        }
1792        SIGAR_SSTRCPY(ifconfig->type,
1793                      SIGAR_NIC_ETHERNET);
1794    }
1795
1796    close(sock);
1797
1798    /* XXX can we get a better description like win32? */
1799    SIGAR_SSTRCPY(ifconfig->description,
1800                  ifconfig->name);
1801
1802    sigar_net_interface_ipv6_config_init(ifconfig);
1803    sigar_net_interface_ipv6_config_get(sigar, name, ifconfig);
1804
1805    return SIGAR_OK;
1806}
1807
1808
1809static int net_connection_state_get(int state)
1810{
1811    switch (state) {
1812      case TCPS_CLOSED:
1813        return SIGAR_TCP_CLOSE;
1814      case TCPS_LISTEN:
1815        return SIGAR_TCP_LISTEN;
1816      case TCPS_SYN_SENT:
1817        return SIGAR_TCP_SYN_SENT;
1818      case TCPS_SYN_RECEIVED:
1819        return SIGAR_TCP_SYN_RECV;
1820      case TCPS_ESTABLISHED:
1821        return SIGAR_TCP_ESTABLISHED;
1822      case TCPS_CLOSE_WAIT:
1823        return SIGAR_TCP_CLOSE_WAIT;
1824      case TCPS_FIN_WAIT_1:
1825        return SIGAR_TCP_FIN_WAIT1;
1826      case TCPS_CLOSING:
1827        return SIGAR_TCP_CLOSING;
1828      case TCPS_LAST_ACK:
1829        return SIGAR_TCP_LAST_ACK;
1830      case TCPS_FIN_WAIT_2:
1831        return SIGAR_TCP_FIN_WAIT2;
1832      case TCPS_TIME_WAIT:
1833        return SIGAR_TCP_TIME_WAIT;
1834      default:
1835        return SIGAR_TCP_UNKNOWN;
1836    }
1837}
1838
1839#if defined(__OpenBSD__) || defined(__NetBSD__)
1840static int net_connection_get(sigar_net_connection_walker_t *walker, int proto)
1841{
1842    int status;
1843    int istcp = 0, type;
1844    int flags = walker->flags;
1845    struct inpcbtable table;
1846    struct inpcb *head, *next, *prev;
1847    sigar_t *sigar = walker->sigar;
1848    u_long offset;
1849
1850    switch (proto) {
1851      case IPPROTO_TCP:
1852        offset = sigar->koffsets[KOFFSET_TCBTABLE];
1853        istcp = 1;
1854        type = SIGAR_NETCONN_TCP;
1855        break;
1856      case IPPROTO_UDP:
1857      default:
1858        return SIGAR_ENOTIMPL;
1859    }
1860
1861
1862    status = kread(sigar, &table, sizeof(table), offset);
1863
1864    if (status != SIGAR_OK) {
1865        return status;
1866    }
1867
1868    prev = head =
1869        (struct inpcb *)&CIRCLEQ_FIRST(&((struct inpcbtable *)offset)->inpt_queue);
1870
1871    next = (struct inpcb *)CIRCLEQ_FIRST(&table.inpt_queue);
1872
1873    while (next != head) {
1874        struct inpcb inpcb;
1875        struct tcpcb tcpcb;
1876        struct socket socket;
1877
1878        status = kread(sigar, &inpcb, sizeof(inpcb), (long)next);
1879        prev = next;
1880        next = (struct inpcb *)CIRCLEQ_NEXT(&inpcb, inp_queue);
1881
1882        kread(sigar, &socket, sizeof(socket), (u_long)inpcb.inp_socket);
1883
1884        if ((((flags & SIGAR_NETCONN_SERVER) && socket.so_qlimit) ||
1885            ((flags & SIGAR_NETCONN_CLIENT) && !socket.so_qlimit)))
1886        {
1887            sigar_net_connection_t conn;
1888
1889            SIGAR_ZERO(&conn);
1890
1891            if (istcp) {
1892                kread(sigar, &tcpcb, sizeof(tcpcb), (u_long)inpcb.inp_ppcb);
1893            }
1894
1895#ifdef __NetBSD__
1896            if (inpcb.inp_af == AF_INET6) {
1897                /*XXX*/
1898                continue;
1899            }
1900#else
1901            if (inpcb.inp_flags & INP_IPV6) {
1902                sigar_net_address6_set(conn.local_address,
1903                                       &inpcb.inp_laddr6.s6_addr);
1904
1905                sigar_net_address6_set(conn.remote_address,
1906                                       &inpcb.inp_faddr6.s6_addr);
1907            }
1908#endif
1909            else {
1910                sigar_net_address_set(conn.local_address,
1911                                      inpcb.inp_laddr.s_addr);
1912
1913                sigar_net_address_set(conn.remote_address,
1914                                      inpcb.inp_faddr.s_addr);
1915            }
1916
1917            conn.local_port  = ntohs(inpcb.inp_lport);
1918            conn.remote_port = ntohs(inpcb.inp_fport);
1919            conn.receive_queue = socket.so_rcv.sb_cc;
1920            conn.send_queue    = socket.so_snd.sb_cc;
1921            conn.uid           = socket.so_pgid;
1922            conn.type = type;
1923
1924            if (!istcp) {
1925                conn.state = SIGAR_TCP_UNKNOWN;
1926                if (walker->add_connection(walker, &conn) != SIGAR_OK) {
1927                    break;
1928                }
1929                continue;
1930            }
1931
1932            conn.state = net_connection_state_get(tcpcb.t_state);
1933
1934            if (walker->add_connection(walker, &conn) != SIGAR_OK) {
1935                break;
1936            }
1937        }
1938    }
1939
1940    return SIGAR_OK;
1941}
1942#else
1943static int net_connection_get(sigar_net_connection_walker_t *walker, int proto)
1944{
1945    int flags = walker->flags;
1946    int type, istcp = 0;
1947    char *buf;
1948    const char *mibvar;
1949    struct tcpcb *tp = NULL;
1950    struct inpcb *inp;
1951    struct xinpgen *xig, *oxig;
1952    struct xsocket *so;
1953    size_t len;
1954
1955    switch (proto) {
1956      case IPPROTO_TCP:
1957        mibvar = "net.inet.tcp.pcblist";
1958        istcp = 1;
1959        type = SIGAR_NETCONN_TCP;
1960        break;
1961      case IPPROTO_UDP:
1962        mibvar = "net.inet.udp.pcblist";
1963        type = SIGAR_NETCONN_UDP;
1964        break;
1965      default:
1966        mibvar = "net.inet.raw.pcblist";
1967        type = SIGAR_NETCONN_RAW;
1968        break;
1969    }
1970
1971    len = 0;
1972    if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
1973        return errno;
1974    }
1975    if ((buf = malloc(len)) == 0) {
1976        return errno;
1977    }
1978    if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
1979        free(buf);
1980        return errno;
1981    }
1982
1983    oxig = xig = (struct xinpgen *)buf;
1984    for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
1985         xig->xig_len > sizeof(struct xinpgen);
1986         xig = (struct xinpgen *)((char *)xig + xig->xig_len))
1987    {
1988        if (istcp) {
1989            struct xtcpcb *cb = (struct xtcpcb *)xig;
1990            tp = &cb->xt_tp;
1991            inp = &cb->xt_inp;
1992            so = &cb->xt_socket;
1993        }
1994        else {
1995            struct xinpcb *cb = (struct xinpcb *)xig;
1996            inp = &cb->xi_inp;
1997            so = &cb->xi_socket;
1998        }
1999
2000        if (so->xso_protocol != proto) {
2001            continue;
2002        }
2003
2004        if (inp->inp_gencnt > oxig->xig_gen) {
2005            continue;
2006        }
2007
2008        if ((((flags & SIGAR_NETCONN_SERVER) && so->so_qlimit) ||
2009            ((flags & SIGAR_NETCONN_CLIENT) && !so->so_qlimit)))
2010        {
2011            sigar_net_connection_t conn;
2012
2013            SIGAR_ZERO(&conn);
2014
2015            if (inp->inp_vflag & INP_IPV6) {
2016                sigar_net_address6_set(conn.local_address,
2017                                       &inp->in6p_laddr.s6_addr);
2018
2019                sigar_net_address6_set(conn.remote_address,
2020                                       &inp->in6p_faddr.s6_addr);
2021            }
2022            else {
2023                sigar_net_address_set(conn.local_address,
2024                                      inp->inp_laddr.s_addr);
2025
2026                sigar_net_address_set(conn.remote_address,
2027                                      inp->inp_faddr.s_addr);
2028            }
2029
2030            conn.local_port  = ntohs(inp->inp_lport);
2031            conn.remote_port = ntohs(inp->inp_fport);
2032            conn.receive_queue = so->so_rcv.sb_cc;
2033            conn.send_queue    = so->so_snd.sb_cc;
2034            conn.uid           = so->so_pgid;
2035            conn.type = type;
2036
2037            if (!istcp) {
2038                conn.state = SIGAR_TCP_UNKNOWN;
2039                if (walker->add_connection(walker, &conn) != SIGAR_OK) {
2040                    break;
2041                }
2042                continue;
2043            }
2044
2045            conn.state = net_connection_state_get(tp->t_state);
2046
2047            if (walker->add_connection(walker, &conn) != SIGAR_OK) {
2048                break;
2049            }
2050        }
2051    }
2052
2053    free(buf);
2054
2055    return SIGAR_OK;
2056}
2057#endif
2058
2059int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
2060{
2061    int flags = walker->flags;
2062    int status;
2063
2064    if (flags & SIGAR_NETCONN_TCP) {
2065        status = net_connection_get(walker, IPPROTO_TCP);
2066        if (status != SIGAR_OK) {
2067            return status;
2068        }
2069    }
2070    if (flags & SIGAR_NETCONN_UDP) {
2071        status = net_connection_get(walker, IPPROTO_UDP);
2072        if (status != SIGAR_OK) {
2073            return status;
2074        }
2075    }
2076
2077    return SIGAR_OK;
2078}
2079