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 
get_koffsets(sigar_t *sigar)175 static 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 
kread(sigar_t *sigar, void *data, int size, long offset)201 static 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 
sigar_os_open(sigar_t **sigar)215 int 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 
sigar_os_close(sigar_t *sigar)281 int 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 
sigar_os_error_string(sigar_t *sigar, int err)295 char *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)
sigar_vmstat(sigar_t *sigar, vm_statistics_data_t *vmstat)308 static 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__)
sigar_vmstat(sigar_t *sigar, struct vmmeter *vmstat)324 static 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__)
sigar_vmstat(sigar_t *sigar, struct uvmexp *vmstat)401 static 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 
sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)414 int 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 */
getswapinfo_sysctl(struct kvm_swap *swap_ary, int swap_max)496 static 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 
sigar_swap_fs_get(sigar_t *sigar, sigar_swap_t *swap)570 static 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 
sigar_swap_sysctl_get(sigar_t *sigar, sigar_swap_t *swap)630 static 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 
sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)653 int 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__)
724 typedef uint64_t cp_time_t;
725 #else
726 typedef unsigned long cp_time_t;
727 #endif
728 
sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)729 int 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 
sigar_os_proc_list_get(sigar_t *sigar, sigar_proc_list_t *proclist)797 int 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 
sigar_get_pinfo(sigar_t *sigar, sigar_pid_t pid)855 static 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 */
sigar_proc_cpu_type(sigar_t *sigar, sigar_pid_t pid, cpu_type_t *type)892 static 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 */
sigar_shared_region_size(cpu_type_t type)909 static 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 
sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_mem_t *procmem)928 int 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 
get_proc_times(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *time)1062 static 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 
sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *proctime)1124 int 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 */
1175 static 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 
thread_state_get(thread_basic_info_data_t *info)1186 static 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 
sigar_proc_threads_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_state_t *procstate)1204 static 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 
sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_state_t *procstate)1247 int 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 
sigar_os_fs_type_get(sigar_file_system_t *fsp)1321 int 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 
get_fs_options(char *opts, int osize, long flags)1347 static 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 
sigar_file_system_list_get(sigar_t *sigar, sigar_file_system_list_t *fslist)1402 int 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 
1491 typedef enum {
1492     IFMSG_ITER_LIST,
1493     IFMSG_ITER_GET
1494 } ifmsg_iter_e;
1495 
1496 typedef 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 
sigar_ifmsg_init(sigar_t *sigar)1505 static 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  */
has_ifaddr(char *name, size_t name_len)1530 static 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 
sigar_ifmsg_iter(sigar_t *sigar, ifmsg_iter_t *iter)1551 static 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 
sigar_net_interface_list_get(sigar_t *sigar, sigar_net_interface_list_t *iflist)1627 int 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 */
sigar_in6_prefixlen(struct sockaddr *netmask)1646 static 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 
sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, sigar_net_interface_config_t *ifconfig)1680 int 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 
sigar_net_interface_config_get(sigar_t *sigar, const char *name, sigar_net_interface_config_t *ifconfig)1713 int 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 
net_connection_state_get(int state)1809 static 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__)
net_connection_get(sigar_net_connection_walker_t *walker, int proto)1840 static 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
net_connection_get(sigar_net_connection_walker_t *walker, int proto)1943 static 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 
sigar_net_connection_walk(sigar_net_connection_walker_t *walker)2059 int 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