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