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