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 
get_koffsets(sigar_t *sigar)176 static 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 
kread(sigar_t *sigar, void *data, int size, long offset)202 static 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 
sigar_os_open(sigar_t **sigar)216 int 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 
sigar_os_close(sigar_t *sigar)284 int 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 
sigar_os_error_string(sigar_t *sigar, int err)298 char *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)
sigar_vmstat(sigar_t *sigar, vm_statistics_data_t *vmstat)311 static 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__)
sigar_vmstat(sigar_t *sigar, struct vmmeter *vmstat)327 static 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__)
sigar_vmstat(sigar_t *sigar, struct uvmexp *vmstat)404 static 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 
sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)417 int 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 */
getswapinfo_sysctl(struct kvm_swap *swap_ary, int swap_max)499 static 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 
sigar_swap_fs_get(sigar_t *sigar, sigar_swap_t *swap)573 static 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 
sigar_swap_sysctl_get(sigar_t *sigar, sigar_swap_t *swap)633 static 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 
sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)656 int 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     swap->allocstall = -1;
720     swap->allocstall_dma = -1;
721     swap->allocstall_dma32 = -1;
722     swap->allocstall_normal = -1;
723     swap->allocstall_movable = -1;
724 
725     return SIGAR_OK;
726 }
727 
728 #ifndef KERN_CPTIME
729 #define KERN_CPTIME KERN_CP_TIME
730 #endif
731 
732 #if defined(__NetBSD__)
733 typedef uint64_t cp_time_t;
734 #else
735 typedef unsigned long cp_time_t;
736 #endif
737 
sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)738 int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
739 {
740 #if defined(DARWIN)
741     kern_return_t status;
742     mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
743     host_cpu_load_info_data_t cpuload;
744 
745     status = host_statistics(sigar->mach_port, HOST_CPU_LOAD_INFO,
746                              (host_info_t)&cpuload, &count);
747 
748     if (status != KERN_SUCCESS) {
749         return errno;
750     }
751 
752     cpu->user = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_USER]);
753     cpu->sys  = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_SYSTEM]);
754     cpu->idle = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_IDLE]);
755     cpu->nice = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_NICE]);
756     cpu->wait = 0; /*N/A*/
757     cpu->irq = 0; /*N/A*/
758     cpu->soft_irq = 0; /*N/A*/
759     cpu->stolen = 0; /*N/A*/
760     cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle;
761 
762 #elif defined(__FreeBSD__) || (__OpenBSD__) || defined(__NetBSD__)
763     int status;
764     cp_time_t cp_time[CPUSTATES];
765     size_t size = sizeof(cp_time);
766 
767 #  if defined(__OpenBSD__) || defined(__NetBSD__)
768     int mib[] = { CTL_KERN, KERN_CPTIME };
769     if (sysctl(mib, NMIB(mib), &cp_time, &size, NULL, 0) == -1) {
770         status = errno;
771     }
772 #  else
773     /* try sysctl first, does not require /dev/kmem perms */
774     if (sysctlbyname("kern.cp_time", &cp_time, &size, NULL, 0) == -1) {
775         status = kread(sigar, &cp_time, sizeof(cp_time),
776                        sigar->koffsets[KOFFSET_CPUINFO]);
777     }
778 #  endif
779     else {
780         status = SIGAR_OK;
781     }
782 
783     if (status != SIGAR_OK) {
784         return status;
785     }
786 
787     cpu->user = SIGAR_TICK2MSEC(cp_time[CP_USER]);
788     cpu->nice = SIGAR_TICK2MSEC(cp_time[CP_NICE]);
789     cpu->sys  = SIGAR_TICK2MSEC(cp_time[CP_SYS]);
790     cpu->idle = SIGAR_TICK2MSEC(cp_time[CP_IDLE]);
791     cpu->wait = 0; /*N/A*/
792     cpu->irq = SIGAR_TICK2MSEC(cp_time[CP_INTR]);
793     cpu->soft_irq = 0; /*N/A*/
794     cpu->stolen = 0; /*N/A*/
795     cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle + cpu->irq;
796 #endif
797 
798     return SIGAR_OK;
799 }
800 
801 #ifndef KERN_PROC_PROC
802 /* freebsd 4.x */
803 #define KERN_PROC_PROC KERN_PROC_ALL
804 #endif
805 
sigar_os_proc_list_get(sigar_t *sigar, sigar_proc_list_t *proclist)806 int sigar_os_proc_list_get(sigar_t *sigar,
807                            sigar_proc_list_t *proclist)
808 {
809 #if defined(DARWIN) || defined(SIGAR_FREEBSD5) || defined(__OpenBSD__) || defined(__NetBSD__)
810     int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 };
811     int i, num;
812     size_t len;
813     struct kinfo_proc *proc;
814 
815     if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) {
816         return errno;
817     }
818 
819     proc = malloc(len);
820 
821     if (sysctl(mib, NMIB(mib), proc, &len, NULL, 0) < 0) {
822         free(proc);
823         return errno;
824     }
825 
826     num = len/sizeof(*proc);
827 
828     sigar_uid_t me = getuid();
829 
830     for (i=0; i<num; i++) {
831         if (proc[i].KI_FLAG & P_SYSTEM) {
832             continue;
833         }
834         if (proc[i].KI_PID == 0) {
835             continue;
836         }
837 
838         if (proc[i].KI_UID != me) {
839             continue;
840         }
841 
842         SIGAR_PROC_LIST_GROW(proclist);
843         proclist->data[proclist->number++] = proc[i].KI_PID;
844     }
845 
846     free(proc);
847 
848     return SIGAR_OK;
849 #else
850     int i, num;
851     struct kinfo_proc *proc;
852 
853     if (!sigar->kmem) {
854         return SIGAR_EPERM_KMEM;
855     }
856 
857     proc = kvm_getprocs(sigar->kmem, KERN_PROC_PROC, 0, &num);
858 
859     for (i=0; i<num; i++) {
860         if (proc[i].KI_FLAG & P_SYSTEM) {
861             continue;
862         }
863         SIGAR_PROC_LIST_GROW(proclist);
864         proclist->data[proclist->number++] = proc[i].KI_PID;
865     }
866 #endif
867 
868     return SIGAR_OK;
869 }
870 
lookup_proc(const struct kinfo_proc* proc, int nproc, pid_t pid)871 static const struct kinfo_proc* lookup_proc(const struct kinfo_proc* proc,
872                                             int nproc,
873                                             pid_t pid) {
874     for (int  i = 0; i < nproc; i++) {
875         if (proc[i].KI_PID == pid) {
876             return proc + i;
877         }
878     }
879     return NULL;
880 }
881 
sigar_os_check_parents(const struct kinfo_proc* proc, int nproc, pid_t pid, pid_t ppid)882 static int sigar_os_check_parents(const struct kinfo_proc* proc,
883                                   int nproc,
884                                   pid_t pid,
885                                   pid_t ppid) {
886     const struct kinfo_proc* p;
887     do {
888         p = lookup_proc(proc, nproc, pid);
889         if (p == NULL) {
890             return -1;
891         }
892 
893         if (p->KI_PPID == ppid) {
894             return SIGAR_OK;
895         }
896         pid = p->KI_PPID;
897     } while (p->KI_PPID != 0);
898     return -1;
899 }
900 
sigar_os_proc_list_get_children(sigar_t* sigar, sigar_pid_t ppid, sigar_proc_list_t* proclist)901 int sigar_os_proc_list_get_children(sigar_t* sigar,
902                                     sigar_pid_t ppid,
903                                     sigar_proc_list_t* proclist) {
904     int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0};
905     int i, num;
906     size_t len;
907     struct kinfo_proc* proc;
908 
909     if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) {
910         return errno;
911     }
912 
913     proc = malloc(len);
914 
915     if (sysctl(mib, NMIB(mib), proc, &len, NULL, 0) < 0) {
916         free(proc);
917         return errno;
918     }
919 
920     num = len / sizeof(*proc);
921 
922     for (i = 0; i < num; i++) {
923         if (sigar_os_check_parents(proc, num, proc[i].KI_PID, ppid) ==
924             SIGAR_OK) {
925             SIGAR_PROC_LIST_GROW(proclist);
926             proclist->data[proclist->number++] = proc[i].KI_PID;
927         }
928     }
929 
930     free(proc);
931 
932     return SIGAR_OK;
933 }
934 
sigar_get_pinfo(sigar_t *sigar, sigar_pid_t pid)935 static int sigar_get_pinfo(sigar_t *sigar, sigar_pid_t pid)
936 {
937 #if defined(__OpenBSD__) || defined(__NetBSD__)
938     int mib[] = { CTL_KERN, KERN_PROC2, KERN_PROC_PID, 0, sizeof(*sigar->pinfo), 1 };
939 #else
940     int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
941 #endif
942     size_t len = sizeof(*sigar->pinfo);
943     time_t timenow = time(NULL);
944     mib[3] = pid;
945 
946     if (sigar->pinfo == NULL) {
947         sigar->pinfo = malloc(len);
948     }
949 
950     if (sigar->last_pid == pid) {
951         if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) {
952             return SIGAR_OK;
953         }
954     }
955 
956     sigar->last_pid = pid;
957     sigar->last_getprocs = timenow;
958 
959     if (sysctl(mib, NMIB(mib), sigar->pinfo, &len, NULL, 0) < 0) {
960         return errno;
961     }
962 
963     return SIGAR_OK;
964 }
965 
966 #if defined(SHARED_TEXT_REGION_SIZE) && defined(SHARED_DATA_REGION_SIZE)
967 #  define GLOBAL_SHARED_SIZE (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE) /* 10.4 SDK */
968 #endif
969 
970 #if defined(DARWIN) && defined(DARWIN_HAS_LIBPROC_H) && !defined(GLOBAL_SHARED_SIZE)
971 /* 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)972 static int sigar_proc_cpu_type(sigar_t *sigar, sigar_pid_t pid, cpu_type_t *type)
973 {
974     int status;
975     int mib[CTL_MAXNAME];
976     size_t len, miblen = NMIB(mib);
977 
978     status = sysctlnametomib("sysctl.proc_cputype", mib, &miblen);
979     if (status != SIGAR_OK) {
980         return status;
981     }
982 
983     mib[miblen] = pid;
984     len = sizeof(*type);
985     return sysctl(mib, miblen + 1, type, &len, NULL, 0);
986 }
987 
988 /* shared memory region size for the given cpu_type_t */
sigar_shared_region_size(cpu_type_t type)989 static mach_vm_size_t sigar_shared_region_size(cpu_type_t type)
990 {
991     switch (type) {
992       case CPU_TYPE_ARM:
993         return SHARED_REGION_SIZE_ARM;
994       case CPU_TYPE_POWERPC:
995         return SHARED_REGION_SIZE_PPC;
996       case CPU_TYPE_POWERPC64:
997         return SHARED_REGION_SIZE_PPC64;
998       case CPU_TYPE_I386:
999         return SHARED_REGION_SIZE_I386;
1000       case CPU_TYPE_X86_64:
1001         return SHARED_REGION_SIZE_X86_64;
1002       default:
1003         return SHARED_REGION_SIZE_I386; /* assume 32-bit x86|ppc */
1004     }
1005 }
1006 #endif /* DARWIN */
1007 
sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_mem_t *procmem)1008 int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
1009                        sigar_proc_mem_t *procmem)
1010 {
1011 #if defined(DARWIN)
1012     mach_port_t task, self = mach_task_self();
1013     kern_return_t status;
1014     task_basic_info_data_t info;
1015     task_events_info_data_t events;
1016     mach_msg_type_number_t count;
1017 #  ifdef DARWIN_HAS_LIBPROC_H
1018     struct proc_taskinfo pti;
1019     struct proc_regioninfo pri;
1020 
1021     if (sigar->libproc) {
1022         int sz =
1023             sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti));
1024 
1025         if (sz == sizeof(pti)) {
1026             procmem->size         = pti.pti_virtual_size;
1027             procmem->resident     = pti.pti_resident_size;
1028             procmem->page_faults  = pti.pti_faults;
1029             procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
1030             procmem->major_faults = SIGAR_FIELD_NOTIMPL;
1031             procmem->share        = SIGAR_FIELD_NOTIMPL;
1032 
1033             sz = sigar->proc_pidinfo(pid, PROC_PIDREGIONINFO, 0, &pri, sizeof(pri));
1034             if (sz == sizeof(pri)) {
1035                 if (pri.pri_share_mode == SM_EMPTY) {
1036                     mach_vm_size_t shared_size;
1037 #ifdef GLOBAL_SHARED_SIZE
1038                     shared_size = GLOBAL_SHARED_SIZE; /* 10.4 SDK */
1039 #else
1040                     cpu_type_t cpu_type;
1041 
1042                     if (sigar_proc_cpu_type(sigar, pid, &cpu_type) == SIGAR_OK) {
1043                         shared_size = sigar_shared_region_size(cpu_type);
1044                     }
1045                     else {
1046                         shared_size = SHARED_REGION_SIZE_I386; /* assume 32-bit x86|ppc */
1047                     }
1048 #endif
1049                     if (procmem->size > shared_size) {
1050                         procmem->size -= shared_size; /* SIGAR-123 */
1051                     }
1052                 }
1053             }
1054             return SIGAR_OK;
1055         }
1056     }
1057 #  endif
1058 
1059     status = task_for_pid(self, pid, &task);
1060 
1061     if (status != KERN_SUCCESS) {
1062         return errno;
1063     }
1064 
1065     count = TASK_BASIC_INFO_COUNT;
1066     status = task_info(task, TASK_BASIC_INFO, (task_info_t)&info, &count);
1067     if (status != KERN_SUCCESS) {
1068         return errno;
1069     }
1070 
1071     count = TASK_EVENTS_INFO_COUNT;
1072     status = task_info(task, TASK_EVENTS_INFO, (task_info_t)&events, &count);
1073     if (status == KERN_SUCCESS) {
1074         procmem->page_faults = events.faults;
1075     }
1076     else {
1077         procmem->page_faults = SIGAR_FIELD_NOTIMPL;
1078     }
1079 
1080     procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
1081     procmem->major_faults = SIGAR_FIELD_NOTIMPL;
1082 
1083     if (task != self) {
1084         mach_port_deallocate(self, task);
1085     }
1086 
1087     procmem->size     = info.virtual_size;
1088     procmem->resident = info.resident_size;
1089     procmem->share    = SIGAR_FIELD_NOTIMPL;
1090 
1091     return SIGAR_OK;
1092 #elif defined(__FreeBSD__)
1093     int status = sigar_get_pinfo(sigar, pid);
1094     bsd_pinfo_t *pinfo = sigar->pinfo;
1095 
1096     if (status != SIGAR_OK) {
1097         return status;
1098     }
1099 
1100     procmem->size =
1101         (pinfo->KI_TSZ + pinfo->KI_DSZ + pinfo->KI_SSZ) * sigar->pagesize;
1102 
1103     procmem->resident = pinfo->KI_RSS * sigar->pagesize;
1104 
1105     procmem->share = SIGAR_FIELD_NOTIMPL;
1106 
1107     procmem->page_faults  = SIGAR_FIELD_NOTIMPL;
1108     procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
1109     procmem->major_faults = SIGAR_FIELD_NOTIMPL;
1110 #elif defined(__OpenBSD__) || defined(__NetBSD__)
1111     int status = sigar_get_pinfo(sigar, pid);
1112     bsd_pinfo_t *pinfo = sigar->pinfo;
1113 
1114     if (status != SIGAR_OK) {
1115         return status;
1116     }
1117 
1118     procmem->size =
1119         (pinfo->p_vm_tsize + pinfo->p_vm_dsize + pinfo->p_vm_ssize) * sigar->pagesize;
1120 
1121     procmem->resident = pinfo->p_vm_rssize * sigar->pagesize;
1122 
1123     procmem->share = SIGAR_FIELD_NOTIMPL;
1124 
1125     procmem->minor_faults = pinfo->p_uru_minflt;
1126     procmem->major_faults = pinfo->p_uru_majflt;
1127     procmem->page_faults  = procmem->minor_faults + procmem->major_faults;
1128 #endif
1129     return SIGAR_OK;
1130 }
1131 
1132 #define tv2msec(tv) \
1133    (((sigar_uint64_t)tv.tv_sec * SIGAR_MSEC) + (((sigar_uint64_t)tv.tv_usec) / 1000))
1134 
1135 #ifdef DARWIN
1136 #define tval2msec(tval) \
1137    ((tval.seconds * SIGAR_MSEC) + (tval.microseconds / 1000))
1138 
1139 #define tval2nsec(tval) \
1140     (SIGAR_SEC2NANO((tval).seconds) + SIGAR_MICROSEC2NANO((tval).microseconds))
1141 
get_proc_times(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *time)1142 static int get_proc_times(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *time)
1143 {
1144     unsigned int count;
1145     time_value_t utime = {0, 0}, stime = {0, 0};
1146     task_basic_info_data_t ti;
1147     task_thread_times_info_data_t tti;
1148     task_port_t task, self;
1149     kern_return_t status;
1150 #  ifdef DARWIN_HAS_LIBPROC_H
1151     if (sigar->libproc) {
1152         struct proc_taskinfo pti;
1153         int sz =
1154             sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti));
1155 
1156         if (sz == sizeof(pti)) {
1157             time->user = SIGAR_NSEC2MSEC(pti.pti_total_user);
1158             time->sys  = SIGAR_NSEC2MSEC(pti.pti_total_system);
1159             time->total = time->user + time->sys;
1160             return SIGAR_OK;
1161         }
1162     }
1163 #  endif
1164 
1165     self = mach_task_self();
1166     status = task_for_pid(self, pid, &task);
1167     if (status != KERN_SUCCESS) {
1168         return errno;
1169     }
1170 
1171     count = TASK_BASIC_INFO_COUNT;
1172     status = task_info(task, TASK_BASIC_INFO,
1173                        (task_info_t)&ti, &count);
1174     if (status != KERN_SUCCESS) {
1175         if (task != self) {
1176             mach_port_deallocate(self, task);
1177         }
1178         return errno;
1179     }
1180 
1181     count = TASK_THREAD_TIMES_INFO_COUNT;
1182     status = task_info(task, TASK_THREAD_TIMES_INFO,
1183                        (task_info_t)&tti, &count);
1184     if (status != KERN_SUCCESS) {
1185         if (task != self) {
1186             mach_port_deallocate(self, task);
1187         }
1188         return errno;
1189     }
1190 
1191     time_value_add(&utime, &ti.user_time);
1192     time_value_add(&stime, &ti.system_time);
1193     time_value_add(&utime, &tti.user_time);
1194     time_value_add(&stime, &tti.system_time);
1195 
1196     time->user = tval2msec(utime);
1197     time->sys  = tval2msec(stime);
1198     time->total = time->user + time->sys;
1199 
1200     return SIGAR_OK;
1201 }
1202 #endif
1203 
sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *proctime)1204 int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
1205                         sigar_proc_time_t *proctime)
1206 {
1207 #ifdef SIGAR_FREEBSD4
1208     struct user user;
1209 #endif
1210     int status = sigar_get_pinfo(sigar, pid);
1211     bsd_pinfo_t *pinfo = sigar->pinfo;
1212 
1213     if (status != SIGAR_OK) {
1214         return status;
1215     }
1216 
1217 #if defined(DARWIN)
1218     if ((status = get_proc_times(sigar, pid, proctime)) != SIGAR_OK) {
1219         return status;
1220     }
1221     proctime->start_time = tv2msec(pinfo->KI_START);
1222 #elif defined(SIGAR_FREEBSD5)
1223     proctime->user  = tv2msec(pinfo->ki_rusage.ru_utime);
1224     proctime->sys   = tv2msec(pinfo->ki_rusage.ru_stime);
1225     proctime->total = proctime->user + proctime->sys;
1226     proctime->start_time = tv2msec(pinfo->KI_START);
1227 #elif defined(SIGAR_FREEBSD4)
1228     if (!sigar->kmem) {
1229         return SIGAR_EPERM_KMEM;
1230     }
1231 
1232     status = kread(sigar, &user, sizeof(user),
1233                    (u_long)pinfo->kp_proc.p_addr);
1234     if (status != SIGAR_OK) {
1235         return status;
1236     }
1237 
1238     proctime->user  = tv2msec(user.u_stats.p_ru.ru_utime);
1239     proctime->sys   = tv2msec(user.u_stats.p_ru.ru_stime);
1240     proctime->total = proctime->user + proctime->sys;
1241     proctime->start_time = tv2msec(user.u_stats.p_start);
1242 #elif defined(__OpenBSD__) || defined(__NetBSD__)
1243     /* XXX *_usec */
1244     proctime->user  = pinfo->p_uutime_sec * SIGAR_MSEC;
1245     proctime->sys   = pinfo->p_ustime_sec * SIGAR_MSEC;
1246     proctime->total = proctime->user + proctime->sys;
1247     proctime->start_time = pinfo->p_ustart_sec * SIGAR_MSEC;
1248 #endif
1249 
1250     return SIGAR_OK;
1251 }
1252 
1253 #ifdef DARWIN
1254 /* thread state mapping derived from ps.tproj */
1255 static const char thread_states[] = {
1256     /*0*/ '-',
1257     /*1*/ SIGAR_PROC_STATE_RUN,
1258     /*2*/ SIGAR_PROC_STATE_ZOMBIE,
1259     /*3*/ SIGAR_PROC_STATE_SLEEP,
1260     /*4*/ SIGAR_PROC_STATE_IDLE,
1261     /*5*/ SIGAR_PROC_STATE_STOP,
1262     /*6*/ SIGAR_PROC_STATE_STOP,
1263     /*7*/ '?'
1264 };
1265 
thread_state_get(thread_basic_info_data_t *info)1266 static int thread_state_get(thread_basic_info_data_t *info)
1267 {
1268     switch (info->run_state) {
1269       case TH_STATE_RUNNING:
1270         return 1;
1271       case TH_STATE_UNINTERRUPTIBLE:
1272         return 2;
1273       case TH_STATE_WAITING:
1274         return (info->sleep_time > 20) ? 4 : 3;
1275       case TH_STATE_STOPPED:
1276         return 5;
1277       case TH_STATE_HALTED:
1278         return 6;
1279       default:
1280         return 7;
1281     }
1282 }
1283 
sigar_proc_threads_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_state_t *procstate)1284 static int sigar_proc_threads_get(sigar_t *sigar, sigar_pid_t pid,
1285                                   sigar_proc_state_t *procstate)
1286 {
1287     mach_port_t task, self = mach_task_self();
1288     kern_return_t status;
1289     thread_array_t threads;
1290     mach_msg_type_number_t count, i;
1291     int state = TH_STATE_HALTED + 1;
1292 
1293     status = task_for_pid(self, pid, &task);
1294     if (status != KERN_SUCCESS) {
1295         return errno;
1296     }
1297 
1298     status = task_threads(task, &threads, &count);
1299     if (status != KERN_SUCCESS) {
1300         return errno;
1301     }
1302 
1303     procstate->threads = count;
1304 
1305     for (i=0; i<count; i++) {
1306         mach_msg_type_number_t info_count = THREAD_BASIC_INFO_COUNT;
1307         thread_basic_info_data_t info;
1308 
1309         status = thread_info(threads[i], THREAD_BASIC_INFO,
1310                              (thread_info_t)&info, &info_count);
1311         if (status == KERN_SUCCESS) {
1312             int tstate = thread_state_get(&info);
1313             if (tstate < state) {
1314                 state = tstate;
1315             }
1316         }
1317     }
1318 
1319     vm_deallocate(self, (vm_address_t)threads, sizeof(thread_t) * count);
1320 
1321     procstate->state = thread_states[state];
1322 
1323     return SIGAR_OK;
1324 }
1325 #endif
1326 
sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_state_t *procstate)1327 int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
1328                          sigar_proc_state_t *procstate)
1329 {
1330     int status = sigar_get_pinfo(sigar, pid);
1331     bsd_pinfo_t *pinfo = sigar->pinfo;
1332 #if defined(__OpenBSD__) || defined(__NetBSD__)
1333     int state = pinfo->p_stat;
1334 #else
1335     int state = pinfo->KI_STAT;
1336 #endif
1337 
1338     if (status != SIGAR_OK) {
1339         return status;
1340     }
1341 
1342 #if defined(__OpenBSD__) || defined(__NetBSD__)
1343     SIGAR_SSTRCPY(procstate->name, pinfo->p_comm);
1344     procstate->ppid     = pinfo->p_ppid;
1345     procstate->priority = pinfo->p_priority;
1346     procstate->nice     = pinfo->p_nice;
1347     procstate->tty      = pinfo->p_tdev;
1348     procstate->threads  = SIGAR_FIELD_NOTIMPL;
1349     procstate->processor = pinfo->p_cpuid;
1350 #else
1351     SIGAR_SSTRCPY(procstate->name, pinfo->KI_COMM);
1352     procstate->ppid     = pinfo->KI_PPID;
1353     procstate->priority = pinfo->KI_PRI;
1354     procstate->nice     = pinfo->KI_NICE;
1355     procstate->tty      = SIGAR_FIELD_NOTIMPL; /*XXX*/
1356     procstate->threads  = SIGAR_FIELD_NOTIMPL;
1357     procstate->processor = SIGAR_FIELD_NOTIMPL;
1358 #endif
1359 
1360 #ifdef DARWIN
1361     status = sigar_proc_threads_get(sigar, pid, procstate);
1362     if (status == SIGAR_OK) {
1363         return status;
1364     }
1365 #endif
1366 
1367     switch (state) {
1368       case SIDL:
1369         procstate->state = 'D';
1370         break;
1371       case SRUN:
1372 #ifdef SONPROC
1373       case SONPROC:
1374 #endif
1375         procstate->state = 'R';
1376         break;
1377       case SSLEEP:
1378         procstate->state = 'S';
1379         break;
1380       case SSTOP:
1381         procstate->state = 'T';
1382         break;
1383       case SZOMB:
1384         procstate->state = 'Z';
1385         break;
1386       default:
1387         procstate->state = '?';
1388         break;
1389     }
1390 
1391     return SIGAR_OK;
1392 }
1393 
1394 #define SIGAR_MICROSEC2NANO(s) \
1395     ((sigar_uint64_t)(s) * (sigar_uint64_t)1000)
1396 
1397 #define TIME_NSEC(t) \
1398     (SIGAR_SEC2NANO((t).tv_sec) + SIGAR_MICROSEC2NANO((t).tv_usec))
1399 
1400 
sigar_os_fs_type_get(sigar_file_system_t *fsp)1401 int sigar_os_fs_type_get(sigar_file_system_t *fsp)
1402 {
1403     char *type = fsp->sys_type_name;
1404 
1405     /* see sys/disklabel.h */
1406     switch (*type) {
1407       case 'f':
1408         if (strEQ(type, "ffs")) {
1409             fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1410         }
1411         break;
1412       case 'h':
1413         if (strEQ(type, "hfs")) {
1414             fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1415         }
1416         break;
1417       case 'u':
1418         if (strEQ(type, "ufs")) {
1419             fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1420         }
1421         break;
1422     }
1423 
1424     return fsp->type;
1425 }
1426 
get_fs_options(char *opts, int osize, long flags)1427 static void get_fs_options(char *opts, int osize, long flags)
1428 {
1429     *opts = '\0';
1430     if (flags & MNT_RDONLY)         strncat(opts, "ro", osize);
1431     else                            strncat(opts, "rw", osize);
1432     if (flags & MNT_SYNCHRONOUS)    strncat(opts, ",sync", osize);
1433     if (flags & MNT_NOEXEC)         strncat(opts, ",noexec", osize);
1434     if (flags & MNT_NOSUID)         strncat(opts, ",nosuid", osize);
1435 #ifdef MNT_NODEV
1436     if (flags & MNT_NODEV)          strncat(opts, ",nodev", osize);
1437 #endif
1438 #ifdef MNT_UNION
1439     if (flags & MNT_UNION)          strncat(opts, ",union", osize);
1440 #endif
1441     if (flags & MNT_ASYNC)          strncat(opts, ",async", osize);
1442 #ifdef MNT_NOATIME
1443     if (flags & MNT_NOATIME)        strncat(opts, ",noatime", osize);
1444 #endif
1445 #ifdef MNT_NOCLUSTERR
1446     if (flags & MNT_NOCLUSTERR)     strncat(opts, ",noclusterr", osize);
1447 #endif
1448 #ifdef MNT_NOCLUSTERW
1449     if (flags & MNT_NOCLUSTERW)     strncat(opts, ",noclusterw", osize);
1450 #endif
1451 #ifdef MNT_NOSYMFOLLOW
1452     if (flags & MNT_NOSYMFOLLOW)    strncat(opts, ",nosymfollow", osize);
1453 #endif
1454 #ifdef MNT_SUIDDIR
1455     if (flags & MNT_SUIDDIR)        strncat(opts, ",suiddir", osize);
1456 #endif
1457 #ifdef MNT_SOFTDEP
1458     if (flags & MNT_SOFTDEP)        strncat(opts, ",soft-updates", osize);
1459 #endif
1460     if (flags & MNT_LOCAL)          strncat(opts, ",local", osize);
1461     if (flags & MNT_QUOTA)          strncat(opts, ",quota", osize);
1462     if (flags & MNT_ROOTFS)         strncat(opts, ",rootfs", osize);
1463 #ifdef MNT_USER
1464     if (flags & MNT_USER)           strncat(opts, ",user", osize);
1465 #endif
1466 #ifdef MNT_IGNORE
1467     if (flags & MNT_IGNORE)         strncat(opts, ",ignore", osize);
1468 #endif
1469     if (flags & MNT_EXPORTED)       strncat(opts, ",nfs", osize);
1470 }
1471 
1472 #ifdef __NetBSD__
1473 #define sigar_statfs statvfs
1474 #define sigar_getfsstat getvfsstat
1475 #define sigar_f_flags f_flag
1476 #else
1477 #define sigar_statfs statfs
1478 #define sigar_getfsstat getfsstat
1479 #define sigar_f_flags f_flags
1480 #endif
1481 
sigar_file_system_list_get(sigar_t *sigar, sigar_file_system_list_t *fslist)1482 int sigar_file_system_list_get(sigar_t *sigar,
1483                                sigar_file_system_list_t *fslist)
1484 {
1485     struct sigar_statfs *fs;
1486     int num, i;
1487     int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
1488     long len;
1489 
1490     if ((num = sigar_getfsstat(NULL, 0, MNT_NOWAIT)) < 0) {
1491         return errno;
1492     }
1493 
1494     len = sizeof(*fs) * num;
1495     fs = malloc(len);
1496 
1497     if ((num = sigar_getfsstat(fs, len, MNT_NOWAIT)) < 0) {
1498         free(fs);
1499         return errno;
1500     }
1501 
1502     sigar_file_system_list_create(fslist);
1503 
1504     for (i=0; i<num; i++) {
1505         sigar_file_system_t *fsp;
1506 
1507 #ifdef MNT_AUTOMOUNTED
1508         if (fs[i].sigar_f_flags & MNT_AUTOMOUNTED) {
1509             if (is_debug) {
1510                 sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1511                                  "[file_system_list] skipping automounted %s: %s",
1512                                  fs[i].f_fstypename, fs[i].f_mntonname);
1513             }
1514             continue;
1515         }
1516 #endif
1517 
1518 #ifdef MNT_RDONLY
1519         if (fs[i].sigar_f_flags & MNT_RDONLY) {
1520             /* e.g. ftp mount or .dmg image */
1521             if (is_debug) {
1522                 sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1523                                  "[file_system_list] skipping readonly %s: %s",
1524                                  fs[i].f_fstypename, fs[i].f_mntonname);
1525             }
1526             continue;
1527         }
1528 #endif
1529 
1530         SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
1531 
1532         fsp = &fslist->data[fslist->number++];
1533 
1534         SIGAR_SSTRCPY(fsp->dir_name, fs[i].f_mntonname);
1535         SIGAR_SSTRCPY(fsp->dev_name, fs[i].f_mntfromname);
1536         SIGAR_SSTRCPY(fsp->sys_type_name, fs[i].f_fstypename);
1537         get_fs_options(fsp->options, sizeof(fsp->options)-1, fs[i].sigar_f_flags);
1538 
1539         sigar_fs_type_init(fsp);
1540     }
1541 
1542     free(fs);
1543     return SIGAR_OK;
1544 }
1545 
1546 #ifdef DARWIN
1547 #define IoStatGetValue(key, val) \
1548     if ((number = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatistics##key)))) \
1549         CFNumberGetValue(number, kCFNumberSInt64Type, &val)
1550 #endif
1551 
1552 
1553 #ifdef DARWIN
1554 #define CTL_HW_FREQ_MAX "hw.cpufrequency_max"
1555 #define CTL_HW_FREQ_MIN "hw.cpufrequency_min"
1556 #else
1557 /* XXX FreeBSD 5.x+ only? */
1558 #define CTL_HW_FREQ "machdep.tsc_freq"
1559 #endif
1560 
1561 
1562 #define rt_s_addr(sa) ((struct sockaddr_in *)(sa))->sin_addr.s_addr
1563 
1564 #ifndef SA_SIZE
1565 #define SA_SIZE(sa)                                             \
1566     (  (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?      \
1567         sizeof(long)            :                               \
1568         1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
1569 #endif
1570 
1571 typedef enum {
1572     IFMSG_ITER_LIST,
1573     IFMSG_ITER_GET
1574 } ifmsg_iter_e;
1575 
1576 typedef struct {
1577     const char *name;
1578     ifmsg_iter_e type;
1579     union {
1580         sigar_net_interface_list_t *iflist;
1581         struct if_msghdr *ifm;
1582     } data;
1583 } ifmsg_iter_t;
1584 
sigar_ifmsg_init(sigar_t *sigar)1585 static int sigar_ifmsg_init(sigar_t *sigar)
1586 {
1587     int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, 0 };
1588     size_t len;
1589 
1590     if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) {
1591         return errno;
1592     }
1593 
1594     if (sigar->ifconf_len < len) {
1595         sigar->ifconf_buf = realloc(sigar->ifconf_buf, len);
1596         sigar->ifconf_len = len;
1597     }
1598 
1599     if (sysctl(mib, NMIB(mib), sigar->ifconf_buf, &len, NULL, 0) < 0) {
1600         return errno;
1601     }
1602 
1603     return SIGAR_OK;
1604 }
1605 
1606 /**
1607  * @param name name of the interface
1608  * @param name_len length of name (w/o \0)
1609  */
has_ifaddr(char *name, size_t name_len)1610 static int has_ifaddr(char *name, size_t name_len)
1611 {
1612     int sock, status;
1613     struct ifreq ifr;
1614 
1615     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1616         return errno;
1617     }
1618     strncpy(ifr.ifr_name, name, MIN(sizeof(ifr.ifr_name) - 1, name_len));
1619     ifr.ifr_name[MIN(sizeof(ifr.ifr_name) - 1, name_len)] = '\0';
1620     if (ioctl(sock, SIOCGIFADDR, &ifr) == 0) {
1621         status = SIGAR_OK;
1622     }
1623     else {
1624         status = errno;
1625     }
1626 
1627     close(sock);
1628     return status;
1629 }
1630 
sigar_ifmsg_iter(sigar_t *sigar, ifmsg_iter_t *iter)1631 static int sigar_ifmsg_iter(sigar_t *sigar, ifmsg_iter_t *iter)
1632 {
1633     char *end = sigar->ifconf_buf + sigar->ifconf_len;
1634     char *ptr = sigar->ifconf_buf;
1635 
1636     if (iter->type == IFMSG_ITER_LIST) {
1637         sigar_net_interface_list_create(iter->data.iflist);
1638     }
1639 
1640     while (ptr < end) {
1641         char *name;
1642         struct sockaddr_dl *sdl;
1643         struct if_msghdr *ifm = (struct if_msghdr *)ptr;
1644 
1645         if (ifm->ifm_type != RTM_IFINFO) {
1646             break;
1647         }
1648 
1649         ptr += ifm->ifm_msglen;
1650 
1651         while (ptr < end) {
1652             struct if_msghdr *next = (struct if_msghdr *)ptr;
1653 
1654             if (next->ifm_type != RTM_NEWADDR) {
1655                 break;
1656             }
1657 
1658             ptr += next->ifm_msglen;
1659         }
1660 
1661         sdl = (struct sockaddr_dl *)(ifm + 1);
1662         if (sdl->sdl_family != AF_LINK) {
1663             continue;
1664         }
1665 
1666         switch (iter->type) {
1667           case IFMSG_ITER_LIST:
1668             if (sdl->sdl_type == IFT_OTHER) {
1669                 if (has_ifaddr(sdl->sdl_data, sdl->sdl_nlen) != SIGAR_OK) {
1670                     break;
1671                 }
1672             }
1673             else if (!((sdl->sdl_type == IFT_ETHER) ||
1674                        (sdl->sdl_type == IFT_LOOP)))
1675             {
1676                 break; /* XXX deal w/ other weirdo interfaces */
1677             }
1678 
1679             SIGAR_NET_IFLIST_GROW(iter->data.iflist);
1680 
1681             /* sdl_data doesn't include a trailing \0, it is only sdl_nlen long */
1682             name = malloc(sdl->sdl_nlen+1);
1683             memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
1684             name[sdl->sdl_nlen] = '\0'; /* add the missing \0 */
1685 
1686             iter->data.iflist->data[iter->data.iflist->number++] = name;
1687             break;
1688 
1689           case IFMSG_ITER_GET:
1690             if (strlen(iter->name) == sdl->sdl_nlen && 0 == memcmp(iter->name, sdl->sdl_data, sdl->sdl_nlen)) {
1691                 iter->data.ifm = ifm;
1692                 return SIGAR_OK;
1693             }
1694         }
1695     }
1696 
1697     switch (iter->type) {
1698       case IFMSG_ITER_LIST:
1699         return SIGAR_OK;
1700 
1701       case IFMSG_ITER_GET:
1702       default:
1703         return ENXIO;
1704     }
1705 }
1706 
sigar_net_interface_list_get(sigar_t *sigar, sigar_net_interface_list_t *iflist)1707 int sigar_net_interface_list_get(sigar_t *sigar,
1708                                  sigar_net_interface_list_t *iflist)
1709 {
1710     int status;
1711     ifmsg_iter_t iter;
1712 
1713     if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) {
1714         return status;
1715     }
1716 
1717     iter.type = IFMSG_ITER_LIST;
1718     iter.data.iflist = iflist;
1719 
1720     return sigar_ifmsg_iter(sigar, &iter);
1721 }
1722 
1723 #include <ifaddrs.h>
1724 
1725 /* in6_prefixlen derived from freebsd/sbin/ifconfig/af_inet6.c */
sigar_in6_prefixlen(struct sockaddr *netmask)1726 static int sigar_in6_prefixlen(struct sockaddr *netmask)
1727 {
1728     struct in6_addr *addr = SIGAR_SIN6_ADDR(netmask);
1729     u_char *name = (u_char *)addr;
1730     int size = sizeof(*addr);
1731     int byte, bit, plen = 0;
1732 
1733     for (byte = 0; byte < size; byte++, plen += 8) {
1734         if (name[byte] != 0xff) {
1735             break;
1736         }
1737     }
1738     if (byte == size) {
1739         return plen;
1740     }
1741     for (bit = 7; bit != 0; bit--, plen++) {
1742         if (!(name[byte] & (1 << bit))) {
1743             break;
1744         }
1745     }
1746     for (; bit != 0; bit--) {
1747         if (name[byte] & (1 << bit)) {
1748             return 0;
1749         }
1750     }
1751     byte++;
1752     for (; byte < size; byte++) {
1753         if (name[byte]) {
1754             return 0;
1755         }
1756     }
1757     return plen;
1758 }
1759 
sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, sigar_net_interface_config_t *ifconfig)1760 int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name,
1761                                         sigar_net_interface_config_t *ifconfig)
1762 {
1763     int status = SIGAR_ENOENT;
1764     struct ifaddrs *addrs, *ifa;
1765 
1766     if (getifaddrs(&addrs) != 0) {
1767         return errno;
1768     }
1769 
1770     for (ifa=addrs; ifa; ifa=ifa->ifa_next) {
1771         if (ifa->ifa_addr &&
1772             (ifa->ifa_addr->sa_family == AF_INET6) &&
1773             strEQ(ifa->ifa_name, name))
1774         {
1775             status = SIGAR_OK;
1776             break;
1777         }
1778     }
1779 
1780     if (status == SIGAR_OK) {
1781         struct in6_addr *addr = SIGAR_SIN6_ADDR(ifa->ifa_addr);
1782 
1783         sigar_net_address6_set(ifconfig->address6, addr);
1784         sigar_net_interface_scope6_set(ifconfig, addr);
1785         ifconfig->prefix6_length = sigar_in6_prefixlen(ifa->ifa_netmask);
1786     }
1787 
1788     freeifaddrs(addrs);
1789 
1790     return status;
1791 }
1792 
sigar_net_interface_config_get(sigar_t *sigar, const char *name, sigar_net_interface_config_t *ifconfig)1793 int sigar_net_interface_config_get(sigar_t *sigar, const char *name,
1794                                    sigar_net_interface_config_t *ifconfig)
1795 {
1796     int sock;
1797     int status;
1798     ifmsg_iter_t iter;
1799     struct if_msghdr *ifm;
1800     struct sockaddr_dl *sdl;
1801     struct ifreq ifr;
1802 
1803     if (!name) {
1804         return sigar_net_interface_config_primary_get(sigar, ifconfig);
1805     }
1806 
1807     if (sigar->ifconf_len == 0) {
1808         if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) {
1809             return status;
1810         }
1811     }
1812 
1813     SIGAR_ZERO(ifconfig);
1814 
1815     iter.type = IFMSG_ITER_GET;
1816     iter.name = name;
1817 
1818     if ((status = sigar_ifmsg_iter(sigar, &iter)) != SIGAR_OK) {
1819         return status;
1820     }
1821 
1822     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1823         return errno;
1824     }
1825 
1826     ifm = iter.data.ifm;
1827 
1828     SIGAR_SSTRCPY(ifconfig->name, name);
1829 
1830     sdl = (struct sockaddr_dl *)(ifm + 1);
1831 
1832     sigar_net_address_mac_set(ifconfig->hwaddr,
1833                               LLADDR(sdl),
1834                               sdl->sdl_alen);
1835 
1836     ifconfig->flags = ifm->ifm_flags;
1837     ifconfig->mtu = ifm->ifm_data.ifi_mtu;
1838     ifconfig->metric = ifm->ifm_data.ifi_metric;
1839 
1840     SIGAR_SSTRCPY(ifr.ifr_name, name);
1841 
1842 #define ifr_s_addr(ifr) \
1843     ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr
1844 
1845     if (!ioctl(sock, SIOCGIFADDR, &ifr)) {
1846         sigar_net_address_set(ifconfig->address,
1847                               ifr_s_addr(ifr));
1848     }
1849 
1850     if (!ioctl(sock, SIOCGIFNETMASK, &ifr)) {
1851         sigar_net_address_set(ifconfig->netmask,
1852                               ifr_s_addr(ifr));
1853     }
1854 
1855     if (ifconfig->flags & IFF_LOOPBACK) {
1856         sigar_net_address_set(ifconfig->destination,
1857                               ifconfig->address.addr.in);
1858         sigar_net_address_set(ifconfig->broadcast, 0);
1859         SIGAR_SSTRCPY(ifconfig->type,
1860                       SIGAR_NIC_LOOPBACK);
1861     }
1862     else {
1863         if (!ioctl(sock, SIOCGIFDSTADDR, &ifr)) {
1864             sigar_net_address_set(ifconfig->destination,
1865                                   ifr_s_addr(ifr));
1866         }
1867 
1868         if (!ioctl(sock, SIOCGIFBRDADDR, &ifr)) {
1869             sigar_net_address_set(ifconfig->broadcast,
1870                                   ifr_s_addr(ifr));
1871         }
1872         SIGAR_SSTRCPY(ifconfig->type,
1873                       SIGAR_NIC_ETHERNET);
1874     }
1875 
1876     close(sock);
1877 
1878     /* XXX can we get a better description like win32? */
1879     SIGAR_SSTRCPY(ifconfig->description,
1880                   ifconfig->name);
1881 
1882     sigar_net_interface_ipv6_config_init(ifconfig);
1883     sigar_net_interface_ipv6_config_get(sigar, name, ifconfig);
1884 
1885     return SIGAR_OK;
1886 }
1887 
1888 
net_connection_state_get(int state)1889 static int net_connection_state_get(int state)
1890 {
1891     switch (state) {
1892       case TCPS_CLOSED:
1893         return SIGAR_TCP_CLOSE;
1894       case TCPS_LISTEN:
1895         return SIGAR_TCP_LISTEN;
1896       case TCPS_SYN_SENT:
1897         return SIGAR_TCP_SYN_SENT;
1898       case TCPS_SYN_RECEIVED:
1899         return SIGAR_TCP_SYN_RECV;
1900       case TCPS_ESTABLISHED:
1901         return SIGAR_TCP_ESTABLISHED;
1902       case TCPS_CLOSE_WAIT:
1903         return SIGAR_TCP_CLOSE_WAIT;
1904       case TCPS_FIN_WAIT_1:
1905         return SIGAR_TCP_FIN_WAIT1;
1906       case TCPS_CLOSING:
1907         return SIGAR_TCP_CLOSING;
1908       case TCPS_LAST_ACK:
1909         return SIGAR_TCP_LAST_ACK;
1910       case TCPS_FIN_WAIT_2:
1911         return SIGAR_TCP_FIN_WAIT2;
1912       case TCPS_TIME_WAIT:
1913         return SIGAR_TCP_TIME_WAIT;
1914       default:
1915         return SIGAR_TCP_UNKNOWN;
1916     }
1917 }
1918 
1919 #if defined(__OpenBSD__) || defined(__NetBSD__)
net_connection_get(sigar_net_connection_walker_t *walker, int proto)1920 static int net_connection_get(sigar_net_connection_walker_t *walker, int proto)
1921 {
1922     int status;
1923     int istcp = 0, type;
1924     int flags = walker->flags;
1925     struct inpcbtable table;
1926     struct inpcb *head, *next, *prev;
1927     sigar_t *sigar = walker->sigar;
1928     u_long offset;
1929 
1930     switch (proto) {
1931       case IPPROTO_TCP:
1932         offset = sigar->koffsets[KOFFSET_TCBTABLE];
1933         istcp = 1;
1934         type = SIGAR_NETCONN_TCP;
1935         break;
1936       case IPPROTO_UDP:
1937       default:
1938         return SIGAR_ENOTIMPL;
1939     }
1940 
1941 
1942     status = kread(sigar, &table, sizeof(table), offset);
1943 
1944     if (status != SIGAR_OK) {
1945         return status;
1946     }
1947 
1948     prev = head =
1949         (struct inpcb *)&CIRCLEQ_FIRST(&((struct inpcbtable *)offset)->inpt_queue);
1950 
1951     next = (struct inpcb *)CIRCLEQ_FIRST(&table.inpt_queue);
1952 
1953     while (next != head) {
1954         struct inpcb inpcb;
1955         struct tcpcb tcpcb;
1956         struct socket socket;
1957 
1958         status = kread(sigar, &inpcb, sizeof(inpcb), (long)next);
1959         prev = next;
1960         next = (struct inpcb *)CIRCLEQ_NEXT(&inpcb, inp_queue);
1961 
1962         kread(sigar, &socket, sizeof(socket), (u_long)inpcb.inp_socket);
1963 
1964         if ((((flags & SIGAR_NETCONN_SERVER) && socket.so_qlimit) ||
1965             ((flags & SIGAR_NETCONN_CLIENT) && !socket.so_qlimit)))
1966         {
1967             sigar_net_connection_t conn;
1968 
1969             SIGAR_ZERO(&conn);
1970 
1971             if (istcp) {
1972                 kread(sigar, &tcpcb, sizeof(tcpcb), (u_long)inpcb.inp_ppcb);
1973             }
1974 
1975 #ifdef __NetBSD__
1976             if (inpcb.inp_af == AF_INET6) {
1977                 /*XXX*/
1978                 continue;
1979             }
1980 #else
1981             if (inpcb.inp_flags & INP_IPV6) {
1982                 sigar_net_address6_set(conn.local_address,
1983                                        &inpcb.inp_laddr6.s6_addr);
1984 
1985                 sigar_net_address6_set(conn.remote_address,
1986                                        &inpcb.inp_faddr6.s6_addr);
1987             }
1988 #endif
1989             else {
1990                 sigar_net_address_set(conn.local_address,
1991                                       inpcb.inp_laddr.s_addr);
1992 
1993                 sigar_net_address_set(conn.remote_address,
1994                                       inpcb.inp_faddr.s_addr);
1995             }
1996 
1997             conn.local_port  = ntohs(inpcb.inp_lport);
1998             conn.remote_port = ntohs(inpcb.inp_fport);
1999             conn.receive_queue = socket.so_rcv.sb_cc;
2000             conn.send_queue    = socket.so_snd.sb_cc;
2001             conn.uid           = socket.so_pgid;
2002             conn.type = type;
2003 
2004             if (!istcp) {
2005                 conn.state = SIGAR_TCP_UNKNOWN;
2006                 if (walker->add_connection(walker, &conn) != SIGAR_OK) {
2007                     break;
2008                 }
2009                 continue;
2010             }
2011 
2012             conn.state = net_connection_state_get(tcpcb.t_state);
2013 
2014             if (walker->add_connection(walker, &conn) != SIGAR_OK) {
2015                 break;
2016             }
2017         }
2018     }
2019 
2020     return SIGAR_OK;
2021 }
2022 #else
net_connection_get(sigar_net_connection_walker_t *walker, int proto)2023 static int net_connection_get(sigar_net_connection_walker_t *walker, int proto)
2024 {
2025     int flags = walker->flags;
2026     int type, istcp = 0;
2027     char *buf;
2028     const char *mibvar;
2029     struct tcpcb *tp = NULL;
2030     struct inpcb *inp;
2031     struct xinpgen *xig, *oxig;
2032     struct xsocket *so;
2033     size_t len;
2034 
2035     switch (proto) {
2036       case IPPROTO_TCP:
2037         mibvar = "net.inet.tcp.pcblist";
2038         istcp = 1;
2039         type = SIGAR_NETCONN_TCP;
2040         break;
2041       case IPPROTO_UDP:
2042         mibvar = "net.inet.udp.pcblist";
2043         type = SIGAR_NETCONN_UDP;
2044         break;
2045       default:
2046         mibvar = "net.inet.raw.pcblist";
2047         type = SIGAR_NETCONN_RAW;
2048         break;
2049     }
2050 
2051     len = 0;
2052     if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
2053         return errno;
2054     }
2055     if ((buf = malloc(len)) == 0) {
2056         return errno;
2057     }
2058     if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
2059         free(buf);
2060         return errno;
2061     }
2062 
2063     oxig = xig = (struct xinpgen *)buf;
2064     for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
2065          xig->xig_len > sizeof(struct xinpgen);
2066          xig = (struct xinpgen *)((char *)xig + xig->xig_len))
2067     {
2068         if (istcp) {
2069             struct xtcpcb *cb = (struct xtcpcb *)xig;
2070             tp = &cb->xt_tp;
2071             inp = &cb->xt_inp;
2072             so = &cb->xt_socket;
2073         }
2074         else {
2075             struct xinpcb *cb = (struct xinpcb *)xig;
2076             inp = &cb->xi_inp;
2077             so = &cb->xi_socket;
2078         }
2079 
2080         if (so->xso_protocol != proto) {
2081             continue;
2082         }
2083 
2084         if (inp->inp_gencnt > oxig->xig_gen) {
2085             continue;
2086         }
2087 
2088         if ((((flags & SIGAR_NETCONN_SERVER) && so->so_qlimit) ||
2089             ((flags & SIGAR_NETCONN_CLIENT) && !so->so_qlimit)))
2090         {
2091             sigar_net_connection_t conn;
2092 
2093             SIGAR_ZERO(&conn);
2094 
2095             if (inp->inp_vflag & INP_IPV6) {
2096                 sigar_net_address6_set(conn.local_address,
2097                                        &inp->in6p_laddr.s6_addr);
2098 
2099                 sigar_net_address6_set(conn.remote_address,
2100                                        &inp->in6p_faddr.s6_addr);
2101             }
2102             else {
2103                 sigar_net_address_set(conn.local_address,
2104                                       inp->inp_laddr.s_addr);
2105 
2106                 sigar_net_address_set(conn.remote_address,
2107                                       inp->inp_faddr.s_addr);
2108             }
2109 
2110             conn.local_port  = ntohs(inp->inp_lport);
2111             conn.remote_port = ntohs(inp->inp_fport);
2112             conn.receive_queue = so->so_rcv.sb_cc;
2113             conn.send_queue    = so->so_snd.sb_cc;
2114             conn.uid           = so->so_pgid;
2115             conn.type = type;
2116 
2117             if (!istcp) {
2118                 conn.state = SIGAR_TCP_UNKNOWN;
2119                 if (walker->add_connection(walker, &conn) != SIGAR_OK) {
2120                     break;
2121                 }
2122                 continue;
2123             }
2124 
2125             conn.state = net_connection_state_get(tp->t_state);
2126 
2127             if (walker->add_connection(walker, &conn) != SIGAR_OK) {
2128                 break;
2129             }
2130         }
2131     }
2132 
2133     free(buf);
2134 
2135     return SIGAR_OK;
2136 }
2137 #endif
2138 
sigar_net_connection_walk(sigar_net_connection_walker_t *walker)2139 int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
2140 {
2141     int flags = walker->flags;
2142     int status;
2143 
2144     if (flags & SIGAR_NETCONN_TCP) {
2145         status = net_connection_get(walker, IPPROTO_TCP);
2146         if (status != SIGAR_OK) {
2147             return status;
2148         }
2149     }
2150     if (flags & SIGAR_NETCONN_UDP) {
2151         status = net_connection_get(walker, IPPROTO_UDP);
2152         if (status != SIGAR_OK) {
2153             return status;
2154         }
2155     }
2156 
2157     return SIGAR_OK;
2158 }
2159