sigar 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3711 @@
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 <CoreServices/CoreServices.h>
54
+ #include <CoreFoundation/CoreFoundation.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
+
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
+
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
+
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
+
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
+
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
+ /* ARG_MAX in FreeBSD 6.0 == 262144, which blows up the stack */
308
+ #define SIGAR_ARG_MAX 65536
309
+
310
+ #ifdef DARWIN
311
+ static size_t sigar_argmax_get(sigar_t *sigar)
312
+ {
313
+ #ifdef KERN_ARGMAX
314
+ int mib[] = { CTL_KERN, KERN_ARGMAX };
315
+ size_t size = sizeof(sigar->argmax);
316
+
317
+ if (sigar->argmax != 0) {
318
+ return sigar->argmax;
319
+ }
320
+ if (sysctl(mib, NMIB(mib), &sigar->argmax, &size, NULL, 0) == 0) {
321
+ return sigar->argmax;
322
+ }
323
+ #endif
324
+ return SIGAR_ARG_MAX;
325
+ }
326
+ #endif /* DARWIN */
327
+
328
+ #if defined(DARWIN)
329
+ static int sigar_vmstat(sigar_t *sigar, vm_statistics_data_t *vmstat)
330
+ {
331
+ kern_return_t status;
332
+ mach_msg_type_number_t count = sizeof(*vmstat) / sizeof(integer_t);
333
+
334
+ status = host_statistics(sigar->mach_port, HOST_VM_INFO,
335
+ (host_info_t)vmstat, &count);
336
+
337
+ if (status == KERN_SUCCESS) {
338
+ return SIGAR_OK;
339
+ }
340
+ else {
341
+ return errno;
342
+ }
343
+ }
344
+ #elif defined(__FreeBSD__)
345
+ static int sigar_vmstat(sigar_t *sigar, struct vmmeter *vmstat)
346
+ {
347
+ int status;
348
+ size_t size = sizeof(unsigned int);
349
+
350
+ status = kread(sigar, vmstat, sizeof(*vmstat),
351
+ sigar->koffsets[KOFFSET_VMMETER]);
352
+
353
+ if (status == SIGAR_OK) {
354
+ return SIGAR_OK;
355
+ }
356
+
357
+ SIGAR_ZERO(vmstat);
358
+
359
+ /* derived from src/usr.bin/vmstat/vmstat.c */
360
+ /* only collect the ones we actually use */
361
+ #define GET_VM_STATS(cat, name, used) \
362
+ if (used) sysctlbyname("vm.stats." #cat "." #name, &vmstat->name, &size, NULL, 0)
363
+
364
+ /* sys */
365
+ GET_VM_STATS(sys, v_swtch, 0);
366
+ GET_VM_STATS(sys, v_trap, 0);
367
+ GET_VM_STATS(sys, v_syscall, 0);
368
+ GET_VM_STATS(sys, v_intr, 0);
369
+ GET_VM_STATS(sys, v_soft, 0);
370
+
371
+ /* vm */
372
+ GET_VM_STATS(vm, v_vm_faults, 0);
373
+ GET_VM_STATS(vm, v_cow_faults, 0);
374
+ GET_VM_STATS(vm, v_cow_optim, 0);
375
+ GET_VM_STATS(vm, v_zfod, 0);
376
+ GET_VM_STATS(vm, v_ozfod, 0);
377
+ GET_VM_STATS(vm, v_swapin, 1);
378
+ GET_VM_STATS(vm, v_swapout, 1);
379
+ GET_VM_STATS(vm, v_swappgsin, 0);
380
+ GET_VM_STATS(vm, v_swappgsout, 0);
381
+ GET_VM_STATS(vm, v_vnodein, 1);
382
+ GET_VM_STATS(vm, v_vnodeout, 1);
383
+ GET_VM_STATS(vm, v_vnodepgsin, 0);
384
+ GET_VM_STATS(vm, v_vnodepgsout, 0);
385
+ GET_VM_STATS(vm, v_intrans, 0);
386
+ GET_VM_STATS(vm, v_reactivated, 0);
387
+ GET_VM_STATS(vm, v_pdwakeups, 0);
388
+ GET_VM_STATS(vm, v_pdpages, 0);
389
+ GET_VM_STATS(vm, v_dfree, 0);
390
+ GET_VM_STATS(vm, v_pfree, 0);
391
+ GET_VM_STATS(vm, v_tfree, 0);
392
+ GET_VM_STATS(vm, v_page_size, 0);
393
+ GET_VM_STATS(vm, v_page_count, 0);
394
+ GET_VM_STATS(vm, v_free_reserved, 0);
395
+ GET_VM_STATS(vm, v_free_target, 0);
396
+ GET_VM_STATS(vm, v_free_min, 0);
397
+ GET_VM_STATS(vm, v_free_count, 1);
398
+ GET_VM_STATS(vm, v_wire_count, 0);
399
+ GET_VM_STATS(vm, v_active_count, 0);
400
+ GET_VM_STATS(vm, v_inactive_target, 0);
401
+ GET_VM_STATS(vm, v_inactive_count, 1);
402
+ GET_VM_STATS(vm, v_cache_count, 1);
403
+ GET_VM_STATS(vm, v_cache_min, 0);
404
+ GET_VM_STATS(vm, v_cache_max, 0);
405
+ GET_VM_STATS(vm, v_pageout_free_min, 0);
406
+ GET_VM_STATS(vm, v_interrupt_free_min, 0);
407
+ GET_VM_STATS(vm, v_forks, 0);
408
+ GET_VM_STATS(vm, v_vforks, 0);
409
+ GET_VM_STATS(vm, v_rforks, 0);
410
+ GET_VM_STATS(vm, v_kthreads, 0);
411
+ GET_VM_STATS(vm, v_forkpages, 0);
412
+ GET_VM_STATS(vm, v_vforkpages, 0);
413
+ GET_VM_STATS(vm, v_rforkpages, 0);
414
+ GET_VM_STATS(vm, v_kthreadpages, 0);
415
+ #undef GET_VM_STATS
416
+
417
+ return SIGAR_OK;
418
+ }
419
+ #elif defined(__OpenBSD__) || defined(__NetBSD__)
420
+ static int sigar_vmstat(sigar_t *sigar, struct uvmexp *vmstat)
421
+ {
422
+ size_t size = sizeof(*vmstat);
423
+ int mib[] = { CTL_VM, VM_UVMEXP };
424
+ if (sysctl(mib, NMIB(mib), vmstat, &size, NULL, 0) < 0) {
425
+ return errno;
426
+ }
427
+ else {
428
+ return SIGAR_OK;
429
+ }
430
+ }
431
+ #endif
432
+
433
+ int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
434
+ {
435
+ sigar_uint64_t kern = 0;
436
+ #ifdef DARWIN
437
+ vm_statistics_data_t vmstat;
438
+ uint64_t mem_total;
439
+ #else
440
+ unsigned long mem_total;
441
+ #endif
442
+ #if defined(__FreeBSD__)
443
+ struct vmmeter vmstat;
444
+ #elif defined(__OpenBSD__) || defined(__NetBSD__)
445
+ struct uvmexp vmstat;
446
+ #endif
447
+ int mib[2];
448
+ size_t len;
449
+ int status;
450
+
451
+ mib[0] = CTL_HW;
452
+
453
+ mib[1] = HW_PAGESIZE;
454
+ len = sizeof(sigar->pagesize);
455
+ if (sysctl(mib, NMIB(mib), &sigar->pagesize, &len, NULL, 0) < 0) {
456
+ return errno;
457
+ }
458
+
459
+ #ifdef DARWIN
460
+ mib[1] = HW_MEMSIZE;
461
+ #else
462
+ mib[1] = HW_PHYSMEM;
463
+ #endif
464
+ len = sizeof(mem_total);
465
+ if (sysctl(mib, NMIB(mib), &mem_total, &len, NULL, 0) < 0) {
466
+ return errno;
467
+ }
468
+
469
+ mem->total = mem_total;
470
+
471
+ #if defined(DARWIN)
472
+ if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
473
+ return status;
474
+ }
475
+
476
+ mem->free = vmstat.free_count;
477
+ mem->free *= sigar->pagesize;
478
+ kern = vmstat.inactive_count;
479
+ kern *= sigar->pagesize;
480
+ #elif defined(__FreeBSD__)
481
+ if ((status = sigar_vmstat(sigar, &vmstat)) == SIGAR_OK) {
482
+ kern = vmstat.v_cache_count + vmstat.v_inactive_count;
483
+ kern *= sigar->pagesize;
484
+ mem->free = vmstat.v_free_count;
485
+ mem->free *= sigar->pagesize;
486
+ }
487
+ #elif defined(__OpenBSD__) || defined(__NetBSD__)
488
+ if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
489
+ return status;
490
+ }
491
+ mem->free = vmstat.free;
492
+ kern = vmstat.inactive;
493
+ # if defined(__OpenBSD__)
494
+ kern += vmstat.vnodepages + vmstat.vtextpages;
495
+ # elif defined(__NetBSD__)
496
+ kern += vmstat.filepages + vmstat.execpages;
497
+ # endif
498
+ kern *= sigar->pagesize;
499
+ #endif
500
+
501
+ mem->used = mem->total - mem->free;
502
+
503
+ mem->actual_free = mem->free + kern;
504
+ mem->actual_used = mem->used - kern;
505
+
506
+ sigar_mem_calc_ram(sigar, mem);
507
+
508
+ return SIGAR_OK;
509
+ }
510
+
511
+ #define SWI_MAXMIB 3
512
+
513
+ #ifdef SIGAR_FREEBSD5
514
+ /* code in this function is based on FreeBSD 5.3 kvm_getswapinfo.c */
515
+ static int getswapinfo_sysctl(struct kvm_swap *swap_ary,
516
+ int swap_max)
517
+ {
518
+ int ti, ttl;
519
+ size_t mibi, len, size;
520
+ int soid[SWI_MAXMIB];
521
+ struct xswdev xsd;
522
+ struct kvm_swap tot;
523
+ int unswdev, dmmax;
524
+
525
+ /* XXX this can be optimized by using os_open */
526
+ size = sizeof(dmmax);
527
+ if (sysctlbyname("vm.dmmax", &dmmax, &size, NULL, 0) == -1) {
528
+ return errno;
529
+ }
530
+
531
+ mibi = SWI_MAXMIB - 1;
532
+ if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) {
533
+ return errno;
534
+ }
535
+
536
+ bzero(&tot, sizeof(tot));
537
+ for (unswdev = 0;; unswdev++) {
538
+ soid[mibi] = unswdev;
539
+ len = sizeof(xsd);
540
+ if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) {
541
+ if (errno == ENOENT) {
542
+ break;
543
+ }
544
+ return errno;
545
+ }
546
+ #if 0
547
+ if (len != sizeof(xsd)) {
548
+ _kvm_err(kd, kd->program, "struct xswdev has unexpected "
549
+ "size; kernel and libkvm out of sync?");
550
+ return -1;
551
+ }
552
+ if (xsd.xsw_version != XSWDEV_VERSION) {
553
+ _kvm_err(kd, kd->program, "struct xswdev version "
554
+ "mismatch; kernel and libkvm out of sync?");
555
+ return -1;
556
+ }
557
+ #endif
558
+ ttl = xsd.xsw_nblks - dmmax;
559
+ if (unswdev < swap_max - 1) {
560
+ bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev]));
561
+ swap_ary[unswdev].ksw_total = ttl;
562
+ swap_ary[unswdev].ksw_used = xsd.xsw_used;
563
+ swap_ary[unswdev].ksw_flags = xsd.xsw_flags;
564
+ }
565
+ tot.ksw_total += ttl;
566
+ tot.ksw_used += xsd.xsw_used;
567
+ }
568
+
569
+ ti = unswdev;
570
+ if (ti >= swap_max) {
571
+ ti = swap_max - 1;
572
+ }
573
+ if (ti >= 0) {
574
+ swap_ary[ti] = tot;
575
+ }
576
+
577
+ return SIGAR_OK;
578
+ }
579
+ #else
580
+ #define getswapinfo_sysctl(swap_ary, swap_max) SIGAR_ENOTIMPL
581
+ #endif
582
+
583
+ #define SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) ((val * bsize) >> 1)
584
+
585
+ #ifdef DARWIN
586
+ #define VM_DIR "/private/var/vm"
587
+ #define SWAPFILE "swapfile"
588
+
589
+ static int sigar_swap_fs_get(sigar_t *sigar, sigar_swap_t *swap) /* <= 10.3 */
590
+ {
591
+ DIR *dirp;
592
+ struct dirent *ent;
593
+ char swapfile[SSTRLEN(VM_DIR) + SSTRLEN("/") + SSTRLEN(SWAPFILE) + 12];
594
+ struct stat swapstat;
595
+ struct statfs vmfs;
596
+ sigar_uint64_t val, bsize;
597
+
598
+ swap->used = swap->total = swap->free = 0;
599
+
600
+ if (!(dirp = opendir(VM_DIR))) {
601
+ return errno;
602
+ }
603
+
604
+ /* looking for "swapfile0", "swapfile1", etc. */
605
+ while ((ent = readdir(dirp))) {
606
+ char *ptr = swapfile;
607
+
608
+ if ((ent->d_namlen < SSTRLEN(SWAPFILE)+1) || /* n/a, see comment above */
609
+ (ent->d_namlen > SSTRLEN(SWAPFILE)+11)) /* ensure no overflow */
610
+ {
611
+ continue;
612
+ }
613
+
614
+ if (!strnEQ(ent->d_name, SWAPFILE, SSTRLEN(SWAPFILE))) {
615
+ continue;
616
+ }
617
+
618
+ /* sprintf(swapfile, "%s/%s", VM_DIR, ent->d_name) */
619
+
620
+ memcpy(ptr, VM_DIR, SSTRLEN(VM_DIR));
621
+ ptr += SSTRLEN(VM_DIR);
622
+
623
+ *ptr++ = '/';
624
+
625
+ memcpy(ptr, ent->d_name, ent->d_namlen+1);
626
+
627
+ if (stat(swapfile, &swapstat) < 0) {
628
+ continue;
629
+ }
630
+
631
+ swap->used += swapstat.st_size;
632
+ }
633
+
634
+ closedir(dirp);
635
+
636
+ if (statfs(VM_DIR, &vmfs) < 0) {
637
+ return errno;
638
+ }
639
+
640
+ bsize = vmfs.f_bsize / 512;
641
+ val = vmfs.f_bfree;
642
+ swap->total = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) + swap->used;
643
+
644
+ swap->free = swap->total - swap->used;
645
+
646
+ return SIGAR_OK;
647
+ }
648
+
649
+ static int sigar_swap_sysctl_get(sigar_t *sigar, sigar_swap_t *swap)
650
+
651
+ {
652
+ #ifdef VM_SWAPUSAGE /* => 10.4 */
653
+ struct xsw_usage sw_usage;
654
+ size_t size = sizeof(sw_usage);
655
+ int mib[] = { CTL_VM, VM_SWAPUSAGE };
656
+
657
+ if (sysctl(mib, NMIB(mib), &sw_usage, &size, NULL, 0) != 0) {
658
+ return errno;
659
+ }
660
+
661
+ swap->total = sw_usage.xsu_total;
662
+ swap->used = sw_usage.xsu_used;
663
+ swap->free = sw_usage.xsu_avail;
664
+
665
+ return SIGAR_OK;
666
+ #else
667
+ return SIGAR_ENOTIMPL; /* <= 10.3 */
668
+ #endif
669
+ }
670
+ #endif /* DARWIN */
671
+
672
+ int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
673
+ {
674
+ int status;
675
+ #if defined(DARWIN)
676
+ vm_statistics_data_t vmstat;
677
+
678
+ if (sigar_swap_sysctl_get(sigar, swap) != SIGAR_OK) {
679
+ status = sigar_swap_fs_get(sigar, swap); /* <= 10.3 */
680
+ if (status != SIGAR_OK) {
681
+ return status;
682
+ }
683
+ }
684
+
685
+ if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
686
+ return status;
687
+ }
688
+ swap->page_in = vmstat.pageins;
689
+ swap->page_out = vmstat.pageouts;
690
+ #elif defined(__FreeBSD__)
691
+ struct kvm_swap kswap[1];
692
+ struct vmmeter vmstat;
693
+
694
+ if (getswapinfo_sysctl(kswap, 1) != SIGAR_OK) {
695
+ if (!sigar->kmem) {
696
+ return SIGAR_EPERM_KMEM;
697
+ }
698
+
699
+ if (kvm_getswapinfo(sigar->kmem, kswap, 1, 0) < 0) {
700
+ return errno;
701
+ }
702
+ }
703
+
704
+ if (kswap[0].ksw_total == 0) {
705
+ swap->total = 0;
706
+ swap->used = 0;
707
+ swap->free = 0;
708
+ return SIGAR_OK;
709
+ }
710
+
711
+ swap->total = kswap[0].ksw_total * sigar->pagesize;
712
+ swap->used = kswap[0].ksw_used * sigar->pagesize;
713
+ swap->free = swap->total - swap->used;
714
+
715
+ if ((status = sigar_vmstat(sigar, &vmstat)) == SIGAR_OK) {
716
+ swap->page_in = vmstat.v_swapin + vmstat.v_vnodein;
717
+ swap->page_out = vmstat.v_swapout + vmstat.v_vnodeout;
718
+ }
719
+ else {
720
+ swap->page_in = swap->page_out = -1;
721
+ }
722
+ #elif defined(__OpenBSD__) || defined(__NetBSD__)
723
+ struct uvmexp vmstat;
724
+
725
+ if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
726
+ return status;
727
+ }
728
+ swap->total = vmstat.swpages * sigar->pagesize;
729
+ swap->used = vmstat.swpginuse * sigar->pagesize;
730
+ swap->free = swap->total - swap->used;
731
+ swap->page_in = vmstat.pageins;
732
+ swap->page_out = vmstat.pdpageouts;
733
+ #endif
734
+
735
+ return SIGAR_OK;
736
+ }
737
+
738
+ #ifndef KERN_CPTIME
739
+ #define KERN_CPTIME KERN_CP_TIME
740
+ #endif
741
+
742
+ #if defined(__NetBSD__)
743
+ typedef uint64_t cp_time_t;
744
+ #else
745
+ typedef unsigned long cp_time_t;
746
+ #endif
747
+
748
+ int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
749
+ {
750
+ #if defined(DARWIN)
751
+ kern_return_t status;
752
+ mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
753
+ host_cpu_load_info_data_t cpuload;
754
+
755
+ status = host_statistics(sigar->mach_port, HOST_CPU_LOAD_INFO,
756
+ (host_info_t)&cpuload, &count);
757
+
758
+ if (status != KERN_SUCCESS) {
759
+ return errno;
760
+ }
761
+
762
+ cpu->user = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_USER]);
763
+ cpu->sys = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_SYSTEM]);
764
+ cpu->idle = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_IDLE]);
765
+ cpu->nice = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_NICE]);
766
+ cpu->wait = 0; /*N/A*/
767
+ cpu->irq = 0; /*N/A*/
768
+ cpu->soft_irq = 0; /*N/A*/
769
+ cpu->stolen = 0; /*N/A*/
770
+ cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle;
771
+
772
+ #elif defined(__FreeBSD__) || (__OpenBSD__) || defined(__NetBSD__)
773
+ int status;
774
+ cp_time_t cp_time[CPUSTATES];
775
+ size_t size = sizeof(cp_time);
776
+
777
+ # if defined(__OpenBSD__) || defined(__NetBSD__)
778
+ int mib[] = { CTL_KERN, KERN_CPTIME };
779
+ if (sysctl(mib, NMIB(mib), &cp_time, &size, NULL, 0) == -1) {
780
+ status = errno;
781
+ }
782
+ # else
783
+ /* try sysctl first, does not require /dev/kmem perms */
784
+ if (sysctlbyname("kern.cp_time", &cp_time, &size, NULL, 0) == -1) {
785
+ status = kread(sigar, &cp_time, sizeof(cp_time),
786
+ sigar->koffsets[KOFFSET_CPUINFO]);
787
+ }
788
+ # endif
789
+ else {
790
+ status = SIGAR_OK;
791
+ }
792
+
793
+ if (status != SIGAR_OK) {
794
+ return status;
795
+ }
796
+
797
+ cpu->user = SIGAR_TICK2MSEC(cp_time[CP_USER]);
798
+ cpu->nice = SIGAR_TICK2MSEC(cp_time[CP_NICE]);
799
+ cpu->sys = SIGAR_TICK2MSEC(cp_time[CP_SYS]);
800
+ cpu->idle = SIGAR_TICK2MSEC(cp_time[CP_IDLE]);
801
+ cpu->wait = 0; /*N/A*/
802
+ cpu->irq = SIGAR_TICK2MSEC(cp_time[CP_INTR]);
803
+ cpu->soft_irq = 0; /*N/A*/
804
+ cpu->stolen = 0; /*N/A*/
805
+ cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle + cpu->irq;
806
+ #endif
807
+
808
+ return SIGAR_OK;
809
+ }
810
+
811
+ #if defined(__FreeBSD__) && (__FreeBSD_version >= 700000)
812
+ #define HAVE_KERN_CP_TIMES /* kern.cp_times came later than 7.0, not sure exactly when */
813
+ static int sigar_cp_times_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
814
+ {
815
+ int maxcpu, status;
816
+ size_t len = sizeof(maxcpu), size;
817
+ long *times;
818
+
819
+ if (sysctlbyname("kern.smp.maxcpus", &maxcpu, &len, NULL, 0) == -1) {
820
+ return errno;
821
+ }
822
+
823
+ size = sizeof(long) * maxcpu * CPUSTATES;
824
+ times = malloc(size);
825
+ if (sysctlbyname("kern.cp_times", times, &size, NULL, 0) == -1) {
826
+ status = errno;
827
+ }
828
+ else {
829
+ int i, maxid = (size / CPUSTATES / sizeof(long));
830
+ long *cp_time = times;
831
+ status = SIGAR_OK;
832
+
833
+ for (i=0; i<maxid; i++) {
834
+ sigar_cpu_t *cpu;
835
+
836
+ SIGAR_CPU_LIST_GROW(cpulist);
837
+
838
+ cpu = &cpulist->data[cpulist->number++];
839
+ cpu->user = SIGAR_TICK2MSEC(cp_time[CP_USER]);
840
+ cpu->nice = SIGAR_TICK2MSEC(cp_time[CP_NICE]);
841
+ cpu->sys = SIGAR_TICK2MSEC(cp_time[CP_SYS]);
842
+ cpu->idle = SIGAR_TICK2MSEC(cp_time[CP_IDLE]);
843
+ cpu->wait = 0; /*N/A*/
844
+ cpu->irq = SIGAR_TICK2MSEC(cp_time[CP_INTR]);
845
+ cpu->soft_irq = 0; /*N/A*/
846
+ cpu->stolen = 0; /*N/A*/
847
+ cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle + cpu->irq;
848
+ cp_time += CPUSTATES;
849
+ }
850
+ }
851
+
852
+ free(times);
853
+ return status;
854
+ }
855
+ #endif
856
+
857
+ int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
858
+ {
859
+ #ifdef DARWIN
860
+ kern_return_t status;
861
+ mach_msg_type_number_t count;
862
+ processor_cpu_load_info_data_t *cpuload;
863
+ natural_t i, ncpu;
864
+
865
+ status = host_processor_info(sigar->mach_port,
866
+ PROCESSOR_CPU_LOAD_INFO,
867
+ &ncpu,
868
+ (processor_info_array_t*)&cpuload,
869
+ &count);
870
+
871
+ if (status != KERN_SUCCESS) {
872
+ return errno;
873
+ }
874
+
875
+ sigar_cpu_list_create(cpulist);
876
+
877
+ for (i=0; i<ncpu; i++) {
878
+ sigar_cpu_t *cpu;
879
+
880
+ SIGAR_CPU_LIST_GROW(cpulist);
881
+
882
+ cpu = &cpulist->data[cpulist->number++];
883
+
884
+ cpu->user = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_USER]);
885
+ cpu->sys = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_SYSTEM]);
886
+ cpu->idle = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_IDLE]);
887
+ cpu->nice = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_NICE]);
888
+ cpu->wait = 0; /*N/A*/
889
+ cpu->irq = 0; /*N/A*/
890
+ cpu->soft_irq = 0; /*N/A*/
891
+ cpu->stolen = 0; /*N/A*/
892
+ cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle;
893
+ }
894
+
895
+ vm_deallocate(mach_task_self(), (vm_address_t)cpuload, count);
896
+
897
+ return SIGAR_OK;
898
+ #else
899
+ int status, i;
900
+ sigar_cpu_t *cpu;
901
+
902
+ sigar_cpu_list_create(cpulist);
903
+
904
+ #ifdef HAVE_KERN_CP_TIMES
905
+ if ((status = sigar_cp_times_get(sigar, cpulist)) == SIGAR_OK) {
906
+ return SIGAR_OK;
907
+ }
908
+ #endif
909
+ /* XXX no multi cpu in freebsd < 7.0, howbout others?
910
+ * for now just report all metrics on the 1st cpu
911
+ * 0's for the rest
912
+ */
913
+ cpu = &cpulist->data[cpulist->number++];
914
+
915
+ status = sigar_cpu_get(sigar, cpu);
916
+ if (status != SIGAR_OK) {
917
+ return status;
918
+ }
919
+
920
+ for (i=1; i<sigar->ncpu; i++) {
921
+ SIGAR_CPU_LIST_GROW(cpulist);
922
+
923
+ cpu = &cpulist->data[cpulist->number++];
924
+ SIGAR_ZERO(cpu);
925
+ }
926
+
927
+ return SIGAR_OK;
928
+ #endif
929
+ }
930
+
931
+ int sigar_uptime_get(sigar_t *sigar,
932
+ sigar_uptime_t *uptime)
933
+ {
934
+ uptime->uptime = time(NULL) - sigar->boot_time;
935
+
936
+ return SIGAR_OK;
937
+ }
938
+
939
+ int sigar_loadavg_get(sigar_t *sigar,
940
+ sigar_loadavg_t *loadavg)
941
+ {
942
+ getloadavg(loadavg->loadavg, 3);
943
+
944
+ return SIGAR_OK;
945
+ }
946
+
947
+ #if defined(DARWIN) && defined(DARWIN_HAS_LIBPROC_H)
948
+
949
+ static int proc_fdinfo_get(sigar_t *sigar, sigar_pid_t pid, int *num)
950
+ {
951
+ int rsize;
952
+ const int init_size = PROC_PIDLISTFD_SIZE * 32;
953
+
954
+ if (!sigar->libproc) {
955
+ return SIGAR_ENOTIMPL;
956
+ }
957
+
958
+ if (sigar->ifconf_len == 0) {
959
+ sigar->ifconf_len = init_size;
960
+ sigar->ifconf_buf = malloc(sigar->ifconf_len);
961
+ }
962
+
963
+ while (1) {
964
+ rsize = sigar->proc_pidinfo(pid, PROC_PIDLISTFDS, 0,
965
+ sigar->ifconf_buf, sigar->ifconf_len);
966
+ if (rsize <= 0) {
967
+ return errno;
968
+ }
969
+ if ((rsize + PROC_PIDLISTFD_SIZE) < sigar->ifconf_len) {
970
+ break;
971
+ }
972
+
973
+ sigar->ifconf_len += init_size;
974
+ sigar->ifconf_buf = realloc(sigar->ifconf_buf, sigar->ifconf_len);
975
+ }
976
+
977
+ *num = rsize / PROC_PIDLISTFD_SIZE;
978
+
979
+ return SIGAR_OK;
980
+ }
981
+
982
+ #endif
983
+
984
+ #ifndef KERN_PROC_PROC
985
+ /* freebsd 4.x */
986
+ #define KERN_PROC_PROC KERN_PROC_ALL
987
+ #endif
988
+
989
+ int sigar_os_proc_list_get(sigar_t *sigar,
990
+ sigar_proc_list_t *proclist)
991
+ {
992
+ #if defined(DARWIN) || defined(SIGAR_FREEBSD5) || defined(__OpenBSD__) || defined(__NetBSD__)
993
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 };
994
+ int i, num;
995
+ size_t len;
996
+ struct kinfo_proc *proc;
997
+
998
+ if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) {
999
+ return errno;
1000
+ }
1001
+
1002
+ proc = malloc(len);
1003
+
1004
+ if (sysctl(mib, NMIB(mib), proc, &len, NULL, 0) < 0) {
1005
+ free(proc);
1006
+ return errno;
1007
+ }
1008
+
1009
+ num = len/sizeof(*proc);
1010
+
1011
+ for (i=0; i<num; i++) {
1012
+ if (proc[i].KI_FLAG & P_SYSTEM) {
1013
+ continue;
1014
+ }
1015
+ if (proc[i].KI_PID == 0) {
1016
+ continue;
1017
+ }
1018
+ SIGAR_PROC_LIST_GROW(proclist);
1019
+ proclist->data[proclist->number++] = proc[i].KI_PID;
1020
+ }
1021
+
1022
+ free(proc);
1023
+
1024
+ return SIGAR_OK;
1025
+ #else
1026
+ int i, num;
1027
+ struct kinfo_proc *proc;
1028
+
1029
+ if (!sigar->kmem) {
1030
+ return SIGAR_EPERM_KMEM;
1031
+ }
1032
+
1033
+ proc = kvm_getprocs(sigar->kmem, KERN_PROC_PROC, 0, &num);
1034
+
1035
+ for (i=0; i<num; i++) {
1036
+ if (proc[i].KI_FLAG & P_SYSTEM) {
1037
+ continue;
1038
+ }
1039
+ SIGAR_PROC_LIST_GROW(proclist);
1040
+ proclist->data[proclist->number++] = proc[i].KI_PID;
1041
+ }
1042
+ #endif
1043
+
1044
+ return SIGAR_OK;
1045
+ }
1046
+
1047
+ static int sigar_get_pinfo(sigar_t *sigar, sigar_pid_t pid)
1048
+ {
1049
+ #if defined(__OpenBSD__) || defined(__NetBSD__)
1050
+ int mib[] = { CTL_KERN, KERN_PROC2, KERN_PROC_PID, 0, sizeof(*sigar->pinfo), 1 };
1051
+ #else
1052
+ int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
1053
+ #endif
1054
+ size_t len = sizeof(*sigar->pinfo);
1055
+ time_t timenow = time(NULL);
1056
+ mib[3] = pid;
1057
+
1058
+ if (sigar->pinfo == NULL) {
1059
+ sigar->pinfo = malloc(len);
1060
+ }
1061
+
1062
+ if (sigar->last_pid == pid) {
1063
+ if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) {
1064
+ return SIGAR_OK;
1065
+ }
1066
+ }
1067
+
1068
+ sigar->last_pid = pid;
1069
+ sigar->last_getprocs = timenow;
1070
+
1071
+ if (sysctl(mib, NMIB(mib), sigar->pinfo, &len, NULL, 0) < 0) {
1072
+ return errno;
1073
+ }
1074
+
1075
+ return SIGAR_OK;
1076
+ }
1077
+
1078
+ #if defined(SHARED_TEXT_REGION_SIZE) && defined(SHARED_DATA_REGION_SIZE)
1079
+ # define GLOBAL_SHARED_SIZE (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE) /* 10.4 SDK */
1080
+ #endif
1081
+
1082
+ #if defined(DARWIN) && defined(DARWIN_HAS_LIBPROC_H) && !defined(GLOBAL_SHARED_SIZE)
1083
+ /* get the CPU type of the process for the given pid */
1084
+ static int sigar_proc_cpu_type(sigar_t *sigar, sigar_pid_t pid, cpu_type_t *type)
1085
+ {
1086
+ int status;
1087
+ int mib[CTL_MAXNAME];
1088
+ size_t len, miblen = NMIB(mib);
1089
+
1090
+ status = sysctlnametomib("sysctl.proc_cputype", mib, &miblen);
1091
+ if (status != SIGAR_OK) {
1092
+ return status;
1093
+ }
1094
+
1095
+ mib[miblen] = pid;
1096
+ len = sizeof(*type);
1097
+ return sysctl(mib, miblen + 1, type, &len, NULL, 0);
1098
+ }
1099
+
1100
+ /* shared memory region size for the given cpu_type_t */
1101
+ static mach_vm_size_t sigar_shared_region_size(cpu_type_t type)
1102
+ {
1103
+ switch (type) {
1104
+ case CPU_TYPE_ARM:
1105
+ return SHARED_REGION_SIZE_ARM;
1106
+ case CPU_TYPE_POWERPC:
1107
+ return SHARED_REGION_SIZE_PPC;
1108
+ case CPU_TYPE_POWERPC64:
1109
+ return SHARED_REGION_SIZE_PPC64;
1110
+ case CPU_TYPE_I386:
1111
+ return SHARED_REGION_SIZE_I386;
1112
+ case CPU_TYPE_X86_64:
1113
+ return SHARED_REGION_SIZE_X86_64;
1114
+ default:
1115
+ return SHARED_REGION_SIZE_I386; /* assume 32-bit x86|ppc */
1116
+ }
1117
+ }
1118
+ #endif /* DARWIN */
1119
+
1120
+ int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
1121
+ sigar_proc_mem_t *procmem)
1122
+ {
1123
+ #if defined(DARWIN)
1124
+ mach_port_t task, self = mach_task_self();
1125
+ kern_return_t status;
1126
+ task_basic_info_data_t info;
1127
+ task_events_info_data_t events;
1128
+ mach_msg_type_number_t count;
1129
+ # ifdef DARWIN_HAS_LIBPROC_H
1130
+ struct proc_taskinfo pti;
1131
+ struct proc_regioninfo pri;
1132
+
1133
+ if (sigar->libproc) {
1134
+ int sz =
1135
+ sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti));
1136
+
1137
+ if (sz == sizeof(pti)) {
1138
+ procmem->size = pti.pti_virtual_size;
1139
+ procmem->resident = pti.pti_resident_size;
1140
+ procmem->page_faults = pti.pti_faults;
1141
+ procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
1142
+ procmem->major_faults = SIGAR_FIELD_NOTIMPL;
1143
+ procmem->share = SIGAR_FIELD_NOTIMPL;
1144
+
1145
+ sz = sigar->proc_pidinfo(pid, PROC_PIDREGIONINFO, 0, &pri, sizeof(pri));
1146
+ if (sz == sizeof(pri)) {
1147
+ if (pri.pri_share_mode == SM_EMPTY) {
1148
+ mach_vm_size_t shared_size;
1149
+ #ifdef GLOBAL_SHARED_SIZE
1150
+ shared_size = GLOBAL_SHARED_SIZE; /* 10.4 SDK */
1151
+ #else
1152
+ cpu_type_t cpu_type;
1153
+
1154
+ if (sigar_proc_cpu_type(sigar, pid, &cpu_type) == SIGAR_OK) {
1155
+ shared_size = sigar_shared_region_size(cpu_type);
1156
+ }
1157
+ else {
1158
+ shared_size = SHARED_REGION_SIZE_I386; /* assume 32-bit x86|ppc */
1159
+ }
1160
+ #endif
1161
+ if (procmem->size > shared_size) {
1162
+ procmem->size -= shared_size; /* SIGAR-123 */
1163
+ }
1164
+ }
1165
+ }
1166
+ return SIGAR_OK;
1167
+ }
1168
+ }
1169
+ # endif
1170
+
1171
+ status = task_for_pid(self, pid, &task);
1172
+
1173
+ if (status != KERN_SUCCESS) {
1174
+ return errno;
1175
+ }
1176
+
1177
+ count = TASK_BASIC_INFO_COUNT;
1178
+ status = task_info(task, TASK_BASIC_INFO, (task_info_t)&info, &count);
1179
+ if (status != KERN_SUCCESS) {
1180
+ return errno;
1181
+ }
1182
+
1183
+ count = TASK_EVENTS_INFO_COUNT;
1184
+ status = task_info(task, TASK_EVENTS_INFO, (task_info_t)&events, &count);
1185
+ if (status == KERN_SUCCESS) {
1186
+ procmem->page_faults = events.faults;
1187
+ }
1188
+ else {
1189
+ procmem->page_faults = SIGAR_FIELD_NOTIMPL;
1190
+ }
1191
+
1192
+ procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
1193
+ procmem->major_faults = SIGAR_FIELD_NOTIMPL;
1194
+
1195
+ if (task != self) {
1196
+ mach_port_deallocate(self, task);
1197
+ }
1198
+
1199
+ procmem->size = info.virtual_size;
1200
+ procmem->resident = info.resident_size;
1201
+ procmem->share = SIGAR_FIELD_NOTIMPL;
1202
+
1203
+ return SIGAR_OK;
1204
+ #elif defined(__FreeBSD__)
1205
+ int status = sigar_get_pinfo(sigar, pid);
1206
+ bsd_pinfo_t *pinfo = sigar->pinfo;
1207
+
1208
+ if (status != SIGAR_OK) {
1209
+ return status;
1210
+ }
1211
+
1212
+ procmem->size =
1213
+ (pinfo->KI_TSZ + pinfo->KI_DSZ + pinfo->KI_SSZ) * sigar->pagesize;
1214
+
1215
+ procmem->resident = pinfo->KI_RSS * sigar->pagesize;
1216
+
1217
+ procmem->share = SIGAR_FIELD_NOTIMPL;
1218
+
1219
+ procmem->page_faults = SIGAR_FIELD_NOTIMPL;
1220
+ procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
1221
+ procmem->major_faults = SIGAR_FIELD_NOTIMPL;
1222
+ #elif defined(__OpenBSD__) || defined(__NetBSD__)
1223
+ int status = sigar_get_pinfo(sigar, pid);
1224
+ bsd_pinfo_t *pinfo = sigar->pinfo;
1225
+
1226
+ if (status != SIGAR_OK) {
1227
+ return status;
1228
+ }
1229
+
1230
+ procmem->size =
1231
+ (pinfo->p_vm_tsize + pinfo->p_vm_dsize + pinfo->p_vm_ssize) * sigar->pagesize;
1232
+
1233
+ procmem->resident = pinfo->p_vm_rssize * sigar->pagesize;
1234
+
1235
+ procmem->share = SIGAR_FIELD_NOTIMPL;
1236
+
1237
+ procmem->minor_faults = pinfo->p_uru_minflt;
1238
+ procmem->major_faults = pinfo->p_uru_majflt;
1239
+ procmem->page_faults = procmem->minor_faults + procmem->major_faults;
1240
+ #endif
1241
+ return SIGAR_OK;
1242
+ }
1243
+
1244
+ int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
1245
+ sigar_proc_cred_t *proccred)
1246
+ {
1247
+ int status = sigar_get_pinfo(sigar, pid);
1248
+ bsd_pinfo_t *pinfo = sigar->pinfo;
1249
+
1250
+ if (status != SIGAR_OK) {
1251
+ return status;
1252
+ }
1253
+
1254
+ #if defined(__OpenBSD__) || defined(__NetBSD__)
1255
+ proccred->uid = pinfo->p_ruid;
1256
+ proccred->gid = pinfo->p_rgid;
1257
+ proccred->euid = pinfo->p_uid;
1258
+ proccred->egid = pinfo->p_gid;
1259
+ #else
1260
+ proccred->uid = pinfo->KI_UID;
1261
+ proccred->gid = pinfo->KI_GID;
1262
+ proccred->euid = pinfo->KI_EUID;
1263
+ proccred->egid = pinfo->KI_EGID;
1264
+ #endif
1265
+
1266
+ return SIGAR_OK;
1267
+ }
1268
+
1269
+ #define tv2msec(tv) \
1270
+ (((sigar_uint64_t)tv.tv_sec * SIGAR_MSEC) + (((sigar_uint64_t)tv.tv_usec) / 1000))
1271
+
1272
+ #ifdef DARWIN
1273
+ #define tval2msec(tval) \
1274
+ ((tval.seconds * SIGAR_MSEC) + (tval.microseconds / 1000))
1275
+
1276
+ #define tval2nsec(tval) \
1277
+ (SIGAR_SEC2NANO((tval).seconds) + SIGAR_MICROSEC2NANO((tval).microseconds))
1278
+
1279
+ static int get_proc_times(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *time)
1280
+ {
1281
+ unsigned int count;
1282
+ time_value_t utime = {0, 0}, stime = {0, 0};
1283
+ task_basic_info_data_t ti;
1284
+ task_thread_times_info_data_t tti;
1285
+ task_port_t task, self;
1286
+ kern_return_t status;
1287
+ # ifdef DARWIN_HAS_LIBPROC_H
1288
+ if (sigar->libproc) {
1289
+ struct proc_taskinfo pti;
1290
+ int sz =
1291
+ sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti));
1292
+
1293
+ if (sz == sizeof(pti)) {
1294
+ time->user = SIGAR_NSEC2MSEC(pti.pti_total_user);
1295
+ time->sys = SIGAR_NSEC2MSEC(pti.pti_total_system);
1296
+ time->total = time->user + time->sys;
1297
+ return SIGAR_OK;
1298
+ }
1299
+ }
1300
+ # endif
1301
+
1302
+ self = mach_task_self();
1303
+ status = task_for_pid(self, pid, &task);
1304
+ if (status != KERN_SUCCESS) {
1305
+ return errno;
1306
+ }
1307
+
1308
+ count = TASK_BASIC_INFO_COUNT;
1309
+ status = task_info(task, TASK_BASIC_INFO,
1310
+ (task_info_t)&ti, &count);
1311
+ if (status != KERN_SUCCESS) {
1312
+ if (task != self) {
1313
+ mach_port_deallocate(self, task);
1314
+ }
1315
+ return errno;
1316
+ }
1317
+
1318
+ count = TASK_THREAD_TIMES_INFO_COUNT;
1319
+ status = task_info(task, TASK_THREAD_TIMES_INFO,
1320
+ (task_info_t)&tti, &count);
1321
+ if (status != KERN_SUCCESS) {
1322
+ if (task != self) {
1323
+ mach_port_deallocate(self, task);
1324
+ }
1325
+ return errno;
1326
+ }
1327
+
1328
+ time_value_add(&utime, &ti.user_time);
1329
+ time_value_add(&stime, &ti.system_time);
1330
+ time_value_add(&utime, &tti.user_time);
1331
+ time_value_add(&stime, &tti.system_time);
1332
+
1333
+ time->user = tval2msec(utime);
1334
+ time->sys = tval2msec(stime);
1335
+ time->total = time->user + time->sys;
1336
+
1337
+ return SIGAR_OK;
1338
+ }
1339
+ #endif
1340
+
1341
+ int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
1342
+ sigar_proc_time_t *proctime)
1343
+ {
1344
+ #ifdef SIGAR_FREEBSD4
1345
+ struct user user;
1346
+ #endif
1347
+ int status = sigar_get_pinfo(sigar, pid);
1348
+ bsd_pinfo_t *pinfo = sigar->pinfo;
1349
+
1350
+ if (status != SIGAR_OK) {
1351
+ return status;
1352
+ }
1353
+
1354
+ #if defined(DARWIN)
1355
+ if ((status = get_proc_times(sigar, pid, proctime)) != SIGAR_OK) {
1356
+ return status;
1357
+ }
1358
+ proctime->start_time = tv2msec(pinfo->KI_START);
1359
+ #elif defined(SIGAR_FREEBSD5)
1360
+ proctime->user = tv2msec(pinfo->ki_rusage.ru_utime);
1361
+ proctime->sys = tv2msec(pinfo->ki_rusage.ru_stime);
1362
+ proctime->total = proctime->user + proctime->sys;
1363
+ proctime->start_time = tv2msec(pinfo->KI_START);
1364
+ #elif defined(SIGAR_FREEBSD4)
1365
+ if (!sigar->kmem) {
1366
+ return SIGAR_EPERM_KMEM;
1367
+ }
1368
+
1369
+ status = kread(sigar, &user, sizeof(user),
1370
+ (u_long)pinfo->kp_proc.p_addr);
1371
+ if (status != SIGAR_OK) {
1372
+ return status;
1373
+ }
1374
+
1375
+ proctime->user = tv2msec(user.u_stats.p_ru.ru_utime);
1376
+ proctime->sys = tv2msec(user.u_stats.p_ru.ru_stime);
1377
+ proctime->total = proctime->user + proctime->sys;
1378
+ proctime->start_time = tv2msec(user.u_stats.p_start);
1379
+ #elif defined(__OpenBSD__) || defined(__NetBSD__)
1380
+ /* XXX *_usec */
1381
+ proctime->user = pinfo->p_uutime_sec * SIGAR_MSEC;
1382
+ proctime->sys = pinfo->p_ustime_sec * SIGAR_MSEC;
1383
+ proctime->total = proctime->user + proctime->sys;
1384
+ proctime->start_time = pinfo->p_ustart_sec * SIGAR_MSEC;
1385
+ #endif
1386
+
1387
+ return SIGAR_OK;
1388
+ }
1389
+
1390
+ #ifdef DARWIN
1391
+ /* thread state mapping derived from ps.tproj */
1392
+ static const char const thread_states[] = {
1393
+ /*0*/ '-',
1394
+ /*1*/ SIGAR_PROC_STATE_RUN,
1395
+ /*2*/ SIGAR_PROC_STATE_ZOMBIE,
1396
+ /*3*/ SIGAR_PROC_STATE_SLEEP,
1397
+ /*4*/ SIGAR_PROC_STATE_IDLE,
1398
+ /*5*/ SIGAR_PROC_STATE_STOP,
1399
+ /*6*/ SIGAR_PROC_STATE_STOP,
1400
+ /*7*/ '?'
1401
+ };
1402
+
1403
+ static int thread_state_get(thread_basic_info_data_t *info)
1404
+ {
1405
+ switch (info->run_state) {
1406
+ case TH_STATE_RUNNING:
1407
+ return 1;
1408
+ case TH_STATE_UNINTERRUPTIBLE:
1409
+ return 2;
1410
+ case TH_STATE_WAITING:
1411
+ return (info->sleep_time > 20) ? 4 : 3;
1412
+ case TH_STATE_STOPPED:
1413
+ return 5;
1414
+ case TH_STATE_HALTED:
1415
+ return 6;
1416
+ default:
1417
+ return 7;
1418
+ }
1419
+ }
1420
+
1421
+ static int sigar_proc_threads_get(sigar_t *sigar, sigar_pid_t pid,
1422
+ sigar_proc_state_t *procstate)
1423
+ {
1424
+ mach_port_t task, self = mach_task_self();
1425
+ kern_return_t status;
1426
+ thread_array_t threads;
1427
+ mach_msg_type_number_t count, i;
1428
+ int state = TH_STATE_HALTED + 1;
1429
+
1430
+ status = task_for_pid(self, pid, &task);
1431
+ if (status != KERN_SUCCESS) {
1432
+ return errno;
1433
+ }
1434
+
1435
+ status = task_threads(task, &threads, &count);
1436
+ if (status != KERN_SUCCESS) {
1437
+ return errno;
1438
+ }
1439
+
1440
+ procstate->threads = count;
1441
+
1442
+ for (i=0; i<count; i++) {
1443
+ mach_msg_type_number_t info_count = THREAD_BASIC_INFO_COUNT;
1444
+ thread_basic_info_data_t info;
1445
+
1446
+ status = thread_info(threads[i], THREAD_BASIC_INFO,
1447
+ (thread_info_t)&info, &info_count);
1448
+ if (status == KERN_SUCCESS) {
1449
+ int tstate = thread_state_get(&info);
1450
+ if (tstate < state) {
1451
+ state = tstate;
1452
+ }
1453
+ }
1454
+ }
1455
+
1456
+ vm_deallocate(self, (vm_address_t)threads, sizeof(thread_t) * count);
1457
+
1458
+ procstate->state = thread_states[state];
1459
+
1460
+ return SIGAR_OK;
1461
+ }
1462
+ #endif
1463
+
1464
+ int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
1465
+ sigar_proc_state_t *procstate)
1466
+ {
1467
+ int status = sigar_get_pinfo(sigar, pid);
1468
+ bsd_pinfo_t *pinfo = sigar->pinfo;
1469
+ #if defined(__OpenBSD__) || defined(__NetBSD__)
1470
+ int state = pinfo->p_stat;
1471
+ #else
1472
+ int state = pinfo->KI_STAT;
1473
+ #endif
1474
+
1475
+ if (status != SIGAR_OK) {
1476
+ return status;
1477
+ }
1478
+
1479
+ #if defined(__OpenBSD__) || defined(__NetBSD__)
1480
+ SIGAR_SSTRCPY(procstate->name, pinfo->p_comm);
1481
+ procstate->ppid = pinfo->p_ppid;
1482
+ procstate->priority = pinfo->p_priority;
1483
+ procstate->nice = pinfo->p_nice;
1484
+ procstate->tty = pinfo->p_tdev;
1485
+ procstate->threads = SIGAR_FIELD_NOTIMPL;
1486
+ procstate->processor = pinfo->p_cpuid;
1487
+ #else
1488
+ SIGAR_SSTRCPY(procstate->name, pinfo->KI_COMM);
1489
+ procstate->ppid = pinfo->KI_PPID;
1490
+ procstate->priority = pinfo->KI_PRI;
1491
+ procstate->nice = pinfo->KI_NICE;
1492
+ procstate->tty = SIGAR_FIELD_NOTIMPL; /*XXX*/
1493
+ procstate->threads = SIGAR_FIELD_NOTIMPL;
1494
+ procstate->processor = SIGAR_FIELD_NOTIMPL;
1495
+ #endif
1496
+
1497
+ #ifdef DARWIN
1498
+ status = sigar_proc_threads_get(sigar, pid, procstate);
1499
+ if (status == SIGAR_OK) {
1500
+ return status;
1501
+ }
1502
+ #endif
1503
+
1504
+ switch (state) {
1505
+ case SIDL:
1506
+ procstate->state = 'D';
1507
+ break;
1508
+ case SRUN:
1509
+ #ifdef SONPROC
1510
+ case SONPROC:
1511
+ #endif
1512
+ procstate->state = 'R';
1513
+ break;
1514
+ case SSLEEP:
1515
+ procstate->state = 'S';
1516
+ break;
1517
+ case SSTOP:
1518
+ procstate->state = 'T';
1519
+ break;
1520
+ case SZOMB:
1521
+ procstate->state = 'Z';
1522
+ break;
1523
+ default:
1524
+ procstate->state = '?';
1525
+ break;
1526
+ }
1527
+
1528
+ return SIGAR_OK;
1529
+ }
1530
+
1531
+ #if defined(DARWIN)
1532
+ typedef struct {
1533
+ char *buf, *ptr, *end;
1534
+ int count;
1535
+ } sigar_kern_proc_args_t;
1536
+
1537
+ static void sigar_kern_proc_args_destroy(sigar_kern_proc_args_t *kargs)
1538
+ {
1539
+ if (kargs->buf) {
1540
+ free(kargs->buf);
1541
+ kargs->buf = NULL;
1542
+ }
1543
+ }
1544
+
1545
+ /* re-usable hack for use by proc_args and proc_env */
1546
+ static int sigar_kern_proc_args_get(sigar_t *sigar,
1547
+ sigar_pid_t pid,
1548
+ char *exe,
1549
+ sigar_kern_proc_args_t *kargs)
1550
+ {
1551
+ /*
1552
+ * derived from:
1553
+ * http://darwinsource.opendarwin.org/10.4.1/adv_cmds-79.1/ps.tproj/print.c
1554
+ */
1555
+ int mib[3], len;
1556
+ size_t size = sigar_argmax_get(sigar);
1557
+
1558
+ kargs->buf = malloc(size);
1559
+
1560
+ mib[0] = CTL_KERN;
1561
+ mib[1] = KERN_PROCARGS2;
1562
+ mib[2] = pid;
1563
+
1564
+ if (sysctl(mib, NMIB(mib), kargs->buf, &size, NULL, 0) < 0) {
1565
+ sigar_kern_proc_args_destroy(kargs);
1566
+ return errno;
1567
+ }
1568
+
1569
+ kargs->end = &kargs->buf[size];
1570
+
1571
+ memcpy(&kargs->count, kargs->buf, sizeof(kargs->count));
1572
+ kargs->ptr = kargs->buf + sizeof(kargs->count);
1573
+
1574
+ len = strlen(kargs->ptr);
1575
+ if (exe) {
1576
+ memcpy(exe, kargs->ptr, len+1);
1577
+ }
1578
+ kargs->ptr += len+1;
1579
+
1580
+ if (kargs->ptr == kargs->end) {
1581
+ sigar_kern_proc_args_destroy(kargs);
1582
+ return exe ? SIGAR_OK : ENOENT;
1583
+ }
1584
+
1585
+ for (; kargs->ptr < kargs->end; kargs->ptr++) {
1586
+ if (*kargs->ptr != '\0') {
1587
+ break; /* start of argv[0] */
1588
+ }
1589
+ }
1590
+
1591
+ if (kargs->ptr == kargs->end) {
1592
+ sigar_kern_proc_args_destroy(kargs);
1593
+ return exe ? SIGAR_OK : ENOENT;
1594
+ }
1595
+
1596
+ return SIGAR_OK;
1597
+ }
1598
+
1599
+ static int kern_proc_args_skip_argv(sigar_kern_proc_args_t *kargs)
1600
+ {
1601
+ char *ptr = kargs->ptr;
1602
+ char *end = kargs->end;
1603
+ int count = kargs->count;
1604
+
1605
+ /* skip over argv */
1606
+ while ((ptr < end) && (count-- > 0)) {
1607
+ int alen = strlen(ptr)+1;
1608
+
1609
+ ptr += alen;
1610
+ }
1611
+
1612
+ kargs->ptr = ptr;
1613
+ kargs->end = end;
1614
+ kargs->count = 0;
1615
+
1616
+ if (ptr >= end) {
1617
+ return ENOENT;
1618
+ }
1619
+
1620
+ return SIGAR_OK;
1621
+ }
1622
+ #endif
1623
+
1624
+ int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
1625
+ sigar_proc_args_t *procargs)
1626
+ {
1627
+ #if defined(DARWIN)
1628
+ int status, count;
1629
+ sigar_kern_proc_args_t kargs;
1630
+ char *ptr, *end;
1631
+
1632
+ status = sigar_kern_proc_args_get(sigar, pid, NULL, &kargs);
1633
+ if (status != SIGAR_OK) {
1634
+ return status;
1635
+ }
1636
+
1637
+ count = kargs.count;
1638
+ ptr = kargs.ptr;
1639
+ end = kargs.end;
1640
+
1641
+ while ((ptr < end) && (count-- > 0)) {
1642
+ int slen = strlen(ptr);
1643
+ int alen = slen+1;
1644
+ char *arg;
1645
+
1646
+ /*
1647
+ * trim trailing whitespace.
1648
+ * seen w/ postgresql, probably related
1649
+ * to messing with argv[0]
1650
+ */
1651
+ while (*(ptr + (slen-1)) == ' ') {
1652
+ if (--slen <= 0) {
1653
+ break;
1654
+ }
1655
+ }
1656
+
1657
+ arg = malloc(slen+1);
1658
+
1659
+ SIGAR_PROC_ARGS_GROW(procargs);
1660
+ memcpy(arg, ptr, slen);
1661
+ *(arg+slen) = '\0';
1662
+
1663
+ procargs->data[procargs->number++] = arg;
1664
+
1665
+ ptr += alen;
1666
+ }
1667
+
1668
+ sigar_kern_proc_args_destroy(&kargs);
1669
+ return SIGAR_OK;
1670
+ #elif defined(__FreeBSD__) || defined(__NetBSD__)
1671
+ char buffer[SIGAR_ARG_MAX+1], *ptr=buffer;
1672
+ size_t len = sizeof(buffer);
1673
+ # ifdef __NetBSD__
1674
+ int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ARGV };
1675
+ mib[2] = pid;
1676
+ # else
1677
+ int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, 0 };
1678
+ mib[3] = pid;
1679
+ # endif
1680
+
1681
+ if (sysctl(mib, NMIB(mib), buffer, &len, NULL, 0) < 0) {
1682
+ return errno;
1683
+ }
1684
+
1685
+ if (len == 0) {
1686
+ procargs->number = 0;
1687
+ return SIGAR_OK;
1688
+ }
1689
+
1690
+ buffer[len] = '\0';
1691
+
1692
+ while (len > 0) {
1693
+ int alen = strlen(ptr)+1;
1694
+ char *arg = malloc(alen);
1695
+
1696
+ SIGAR_PROC_ARGS_GROW(procargs);
1697
+ memcpy(arg, ptr, alen);
1698
+
1699
+ procargs->data[procargs->number++] = arg;
1700
+
1701
+ len -= alen;
1702
+ if (len > 0) {
1703
+ ptr += alen;
1704
+ }
1705
+ }
1706
+
1707
+ return SIGAR_OK;
1708
+ #elif defined(__OpenBSD__)
1709
+ char buffer[SIGAR_ARG_MAX+1], **ptr=(char **)buffer;
1710
+ size_t len = sizeof(buffer);
1711
+ int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ARGV };
1712
+ mib[2] = pid;
1713
+
1714
+ if (sysctl(mib, NMIB(mib), buffer, &len, NULL, 0) < 0) {
1715
+ return errno;
1716
+ }
1717
+
1718
+ if (len == 0) {
1719
+ procargs->number = 0;
1720
+ return SIGAR_OK;
1721
+ }
1722
+
1723
+ for (; *ptr; ptr++) {
1724
+ int alen = strlen(*ptr)+1;
1725
+ char *arg = malloc(alen);
1726
+
1727
+ SIGAR_PROC_ARGS_GROW(procargs);
1728
+ memcpy(arg, *ptr, alen);
1729
+
1730
+ procargs->data[procargs->number++] = arg;
1731
+ }
1732
+
1733
+ return SIGAR_OK;
1734
+ #else
1735
+ return SIGAR_ENOTIMPL;
1736
+ #endif
1737
+ }
1738
+
1739
+ int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
1740
+ sigar_proc_env_t *procenv)
1741
+ {
1742
+ #ifdef DARWIN
1743
+ int status, count;
1744
+ sigar_kern_proc_args_t kargs;
1745
+ char *ptr, *end;
1746
+
1747
+ status = sigar_kern_proc_args_get(sigar, pid, NULL, &kargs);
1748
+ if (status != SIGAR_OK) {
1749
+ return status;
1750
+ }
1751
+
1752
+ status = kern_proc_args_skip_argv(&kargs);
1753
+ if (status != SIGAR_OK) {
1754
+ sigar_kern_proc_args_destroy(&kargs);
1755
+ return status;
1756
+ }
1757
+
1758
+ count = kargs.count;
1759
+ ptr = kargs.ptr;
1760
+ end = kargs.end;
1761
+
1762
+ /* into environ */
1763
+ while (ptr < end) {
1764
+ char *val = strchr(ptr, '=');
1765
+ int klen, vlen, status;
1766
+ char key[256]; /* XXX is there a max key size? */
1767
+
1768
+ if (val == NULL) {
1769
+ /* not key=val format */
1770
+ break;
1771
+ }
1772
+
1773
+ klen = val - ptr;
1774
+ SIGAR_SSTRCPY(key, ptr);
1775
+ key[klen] = '\0';
1776
+ ++val;
1777
+
1778
+ vlen = strlen(val);
1779
+ status = procenv->env_getter(procenv->data,
1780
+ key, klen, val, vlen);
1781
+
1782
+ if (status != SIGAR_OK) {
1783
+ /* not an error; just stop iterating */
1784
+ break;
1785
+ }
1786
+
1787
+ ptr += (klen + 1 + vlen + 1);
1788
+
1789
+ if (*ptr == '\0') {
1790
+ break;
1791
+ }
1792
+ }
1793
+
1794
+ sigar_kern_proc_args_destroy(&kargs);
1795
+ return SIGAR_OK;
1796
+ #else
1797
+ char **env;
1798
+ struct kinfo_proc *pinfo;
1799
+ int num;
1800
+
1801
+ if (!sigar->kmem) {
1802
+ return SIGAR_EPERM_KMEM;
1803
+ }
1804
+
1805
+ pinfo = kvm_getprocs(sigar->kmem, KERN_PROC_PID, pid, &num);
1806
+ if (!pinfo || (num < 1)) {
1807
+ return errno;
1808
+ }
1809
+
1810
+ if (!(env = kvm_getenvv(sigar->kmem, pinfo, 9086))) {
1811
+ return errno;
1812
+ }
1813
+
1814
+ while (*env) {
1815
+ char *ptr = *env++;
1816
+ char *val = strchr(ptr, '=');
1817
+ int klen, vlen, status;
1818
+ char key[128]; /* XXX is there a max key size? */
1819
+
1820
+ if (val == NULL) {
1821
+ /* not key=val format */
1822
+ procenv->env_getter(procenv->data, ptr, strlen(ptr), NULL, 0);
1823
+ break;
1824
+ }
1825
+
1826
+ klen = val - ptr;
1827
+ SIGAR_SSTRCPY(key, ptr);
1828
+ key[klen] = '\0';
1829
+ ++val;
1830
+
1831
+ vlen = strlen(val);
1832
+ status = procenv->env_getter(procenv->data,
1833
+ key, klen, val, vlen);
1834
+
1835
+ if (status != SIGAR_OK) {
1836
+ /* not an error; just stop iterating */
1837
+ break;
1838
+ }
1839
+
1840
+ ptr += (klen + 1 + vlen + 1);
1841
+ }
1842
+
1843
+ return SIGAR_OK;
1844
+ #endif
1845
+ }
1846
+
1847
+ int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
1848
+ sigar_proc_fd_t *procfd)
1849
+ {
1850
+ #ifdef __FreeBSD__
1851
+ int status;
1852
+ bsd_pinfo_t *pinfo;
1853
+ struct filedesc filed;
1854
+ #if 0
1855
+ struct file **ofiles;
1856
+ int nfiles, i;
1857
+ size_t size;
1858
+ #endif
1859
+ if (!sigar->kmem) {
1860
+ return SIGAR_EPERM_KMEM;
1861
+ }
1862
+
1863
+ if ((status = sigar_get_pinfo(sigar, pid)) != SIGAR_OK) {
1864
+ return status;
1865
+ }
1866
+ pinfo = sigar->pinfo;
1867
+
1868
+ status = kread(sigar, &filed, sizeof(filed), (u_long)pinfo->KI_FD);
1869
+ if (status != SIGAR_OK) {
1870
+ return status;
1871
+ }
1872
+ #if 0
1873
+ nfiles = filed.fd_lastfile+1;
1874
+ size = sizeof(*ofiles) * nfiles;
1875
+ ofiles = malloc(size);
1876
+ status = kread(sigar, ofiles, size, (u_long)filed.fd_ofiles);
1877
+ if (status != SIGAR_OK) {
1878
+ free(ofiles);
1879
+ return status;
1880
+ }
1881
+
1882
+ procfd->total = 0;
1883
+ for (i=0; i<filed.fd_lastfile; i++) {
1884
+ if (!ofiles[i]) {
1885
+ continue;
1886
+ }
1887
+ procfd->total++;
1888
+ }
1889
+
1890
+ free(ofiles);
1891
+ #else
1892
+ /* seems the same as the above */
1893
+ procfd->total = filed.fd_lastfile;
1894
+ #endif
1895
+
1896
+ return SIGAR_OK;
1897
+ #else
1898
+ return SIGAR_ENOTIMPL;
1899
+ #endif
1900
+ }
1901
+
1902
+ int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
1903
+ sigar_proc_exe_t *procexe)
1904
+ {
1905
+ #ifdef DARWIN
1906
+ int status;
1907
+ sigar_kern_proc_args_t kargs;
1908
+
1909
+ status = sigar_kern_proc_args_get(sigar, pid, procexe->name, &kargs);
1910
+ if (status != SIGAR_OK) {
1911
+ return status;
1912
+ }
1913
+
1914
+ procexe->cwd[0] = '\0';
1915
+ procexe->root[0] = '\0';
1916
+
1917
+ /* attempt to determine cwd from $PWD */
1918
+ status = kern_proc_args_skip_argv(&kargs);
1919
+ if (status == SIGAR_OK) {
1920
+ char *ptr = kargs.ptr;
1921
+ char *end = kargs.end;
1922
+
1923
+ /* into environ */
1924
+ while (ptr < end) {
1925
+ int len = strlen(ptr);
1926
+
1927
+ if ((len > 4) &&
1928
+ (ptr[0] == 'P') &&
1929
+ (ptr[1] == 'W') &&
1930
+ (ptr[2] == 'D') &&
1931
+ (ptr[3] == '='))
1932
+ {
1933
+ memcpy(procexe->cwd, ptr+4, len-3);
1934
+ break;
1935
+ }
1936
+
1937
+ ptr += len+1;
1938
+ }
1939
+ }
1940
+
1941
+ sigar_kern_proc_args_destroy(&kargs);
1942
+
1943
+ return SIGAR_OK;
1944
+ #else
1945
+ int len;
1946
+ char name[1024];
1947
+
1948
+ procexe->cwd[0] = '\0';
1949
+ procexe->root[0] = '\0';
1950
+
1951
+ (void)SIGAR_PROC_FILENAME(name, pid, "/file");
1952
+
1953
+ if ((len = readlink(name, procexe->name,
1954
+ sizeof(procexe->name)-1)) < 0)
1955
+ {
1956
+ return PROCFS_STATUS(errno);
1957
+ }
1958
+
1959
+ procexe->name[len] = '\0';
1960
+
1961
+ return SIGAR_OK;
1962
+ #endif
1963
+ }
1964
+
1965
+ #ifdef DARWIN
1966
+ static int sigar_dlinfo_modules(sigar_t *sigar, sigar_proc_modules_t *procmods)
1967
+ {
1968
+ uint32_t i, count = _dyld_image_count();
1969
+
1970
+ for (i=0; i<count; i++) {
1971
+ int status;
1972
+ const char *name =
1973
+ _dyld_get_image_name(i);
1974
+
1975
+ if (name == NULL) {
1976
+ continue;
1977
+ }
1978
+ status =
1979
+ procmods->module_getter(procmods->data,
1980
+ (char *)name, strlen(name));
1981
+
1982
+ if (status != SIGAR_OK) {
1983
+ /* not an error; just stop iterating */
1984
+ break;
1985
+ }
1986
+ }
1987
+ return SIGAR_OK;
1988
+ }
1989
+ #endif /* DARWIN */
1990
+
1991
+ int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
1992
+ sigar_proc_modules_t *procmods)
1993
+ {
1994
+ #if defined(SIGAR_HAS_DLINFO_MODULES) || defined(DARWIN)
1995
+ if (pid == sigar_pid_get(sigar)) {
1996
+ return sigar_dlinfo_modules(sigar, procmods);
1997
+ }
1998
+ #endif
1999
+ return SIGAR_ENOTIMPL;
2000
+ }
2001
+
2002
+ #define SIGAR_MICROSEC2NANO(s) \
2003
+ ((sigar_uint64_t)(s) * (sigar_uint64_t)1000)
2004
+
2005
+ #define TIME_NSEC(t) \
2006
+ (SIGAR_SEC2NANO((t).tv_sec) + SIGAR_MICROSEC2NANO((t).tv_usec))
2007
+
2008
+ int sigar_thread_cpu_get(sigar_t *sigar,
2009
+ sigar_uint64_t id,
2010
+ sigar_thread_cpu_t *cpu)
2011
+ {
2012
+ #if defined(DARWIN)
2013
+ mach_port_t self = mach_thread_self();
2014
+ thread_basic_info_data_t info;
2015
+ mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
2016
+ kern_return_t status;
2017
+
2018
+ status = thread_info(self, THREAD_BASIC_INFO,
2019
+ (thread_info_t)&info, &count);
2020
+ if (status != KERN_SUCCESS) {
2021
+ return errno;
2022
+ }
2023
+
2024
+ mach_port_deallocate(mach_task_self(), self);
2025
+
2026
+ cpu->user = tval2nsec(info.user_time);
2027
+ cpu->sys = tval2nsec(info.system_time);
2028
+ cpu->total = cpu->user + cpu->sys;
2029
+ #elif defined(__NetBSD__)
2030
+ return SIGAR_ENOTIMPL; /* http://tinyurl.com/chbvln */
2031
+ #else
2032
+ /* XXX this is not per-thread, it is for the whole-process.
2033
+ * just want to use for the shell time command at the moment.
2034
+ */
2035
+ struct rusage usage;
2036
+ getrusage(RUSAGE_SELF, &usage);
2037
+
2038
+ cpu->user = TIME_NSEC(usage.ru_utime);
2039
+ cpu->sys = TIME_NSEC(usage.ru_stime);
2040
+ cpu->total = TIME_NSEC(usage.ru_utime) + TIME_NSEC(usage.ru_stime);
2041
+ #endif
2042
+
2043
+ return SIGAR_OK;
2044
+ }
2045
+
2046
+ int sigar_os_fs_type_get(sigar_file_system_t *fsp)
2047
+ {
2048
+ char *type = fsp->sys_type_name;
2049
+
2050
+ /* see sys/disklabel.h */
2051
+ switch (*type) {
2052
+ case 'f':
2053
+ if (strEQ(type, "ffs")) {
2054
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
2055
+ }
2056
+ break;
2057
+ case 'h':
2058
+ if (strEQ(type, "hfs")) {
2059
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
2060
+ }
2061
+ break;
2062
+ case 'u':
2063
+ if (strEQ(type, "ufs")) {
2064
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
2065
+ }
2066
+ break;
2067
+ }
2068
+
2069
+ return fsp->type;
2070
+ }
2071
+
2072
+ static void get_fs_options(char *opts, int osize, long flags)
2073
+ {
2074
+ *opts = '\0';
2075
+ if (flags & MNT_RDONLY) strncat(opts, "ro", osize);
2076
+ else strncat(opts, "rw", osize);
2077
+ if (flags & MNT_SYNCHRONOUS) strncat(opts, ",sync", osize);
2078
+ if (flags & MNT_NOEXEC) strncat(opts, ",noexec", osize);
2079
+ if (flags & MNT_NOSUID) strncat(opts, ",nosuid", osize);
2080
+ #ifdef MNT_NODEV
2081
+ if (flags & MNT_NODEV) strncat(opts, ",nodev", osize);
2082
+ #endif
2083
+ #ifdef MNT_UNION
2084
+ if (flags & MNT_UNION) strncat(opts, ",union", osize);
2085
+ #endif
2086
+ if (flags & MNT_ASYNC) strncat(opts, ",async", osize);
2087
+ #ifdef MNT_NOATIME
2088
+ if (flags & MNT_NOATIME) strncat(opts, ",noatime", osize);
2089
+ #endif
2090
+ #ifdef MNT_NOCLUSTERR
2091
+ if (flags & MNT_NOCLUSTERR) strncat(opts, ",noclusterr", osize);
2092
+ #endif
2093
+ #ifdef MNT_NOCLUSTERW
2094
+ if (flags & MNT_NOCLUSTERW) strncat(opts, ",noclusterw", osize);
2095
+ #endif
2096
+ #ifdef MNT_NOSYMFOLLOW
2097
+ if (flags & MNT_NOSYMFOLLOW) strncat(opts, ",nosymfollow", osize);
2098
+ #endif
2099
+ #ifdef MNT_SUIDDIR
2100
+ if (flags & MNT_SUIDDIR) strncat(opts, ",suiddir", osize);
2101
+ #endif
2102
+ #ifdef MNT_SOFTDEP
2103
+ if (flags & MNT_SOFTDEP) strncat(opts, ",soft-updates", osize);
2104
+ #endif
2105
+ if (flags & MNT_LOCAL) strncat(opts, ",local", osize);
2106
+ if (flags & MNT_QUOTA) strncat(opts, ",quota", osize);
2107
+ if (flags & MNT_ROOTFS) strncat(opts, ",rootfs", osize);
2108
+ #ifdef MNT_USER
2109
+ if (flags & MNT_USER) strncat(opts, ",user", osize);
2110
+ #endif
2111
+ #ifdef MNT_IGNORE
2112
+ if (flags & MNT_IGNORE) strncat(opts, ",ignore", osize);
2113
+ #endif
2114
+ if (flags & MNT_EXPORTED) strncat(opts, ",nfs", osize);
2115
+ }
2116
+
2117
+ #ifdef __NetBSD__
2118
+ #define sigar_statfs statvfs
2119
+ #define sigar_getfsstat getvfsstat
2120
+ #define sigar_f_flags f_flag
2121
+ #else
2122
+ #define sigar_statfs statfs
2123
+ #define sigar_getfsstat getfsstat
2124
+ #define sigar_f_flags f_flags
2125
+ #endif
2126
+
2127
+ int sigar_file_system_list_get(sigar_t *sigar,
2128
+ sigar_file_system_list_t *fslist)
2129
+ {
2130
+ struct sigar_statfs *fs;
2131
+ int num, i;
2132
+ int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
2133
+ long len;
2134
+
2135
+ if ((num = sigar_getfsstat(NULL, 0, MNT_NOWAIT)) < 0) {
2136
+ return errno;
2137
+ }
2138
+
2139
+ len = sizeof(*fs) * num;
2140
+ fs = malloc(len);
2141
+
2142
+ if ((num = sigar_getfsstat(fs, len, MNT_NOWAIT)) < 0) {
2143
+ free(fs);
2144
+ return errno;
2145
+ }
2146
+
2147
+ sigar_file_system_list_create(fslist);
2148
+
2149
+ for (i=0; i<num; i++) {
2150
+ sigar_file_system_t *fsp;
2151
+
2152
+ #ifdef MNT_AUTOMOUNTED
2153
+ if (fs[i].sigar_f_flags & MNT_AUTOMOUNTED) {
2154
+ if (is_debug) {
2155
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2156
+ "[file_system_list] skipping automounted %s: %s",
2157
+ fs[i].f_fstypename, fs[i].f_mntonname);
2158
+ }
2159
+ continue;
2160
+ }
2161
+ #endif
2162
+
2163
+ #ifdef MNT_RDONLY
2164
+ if (fs[i].sigar_f_flags & MNT_RDONLY) {
2165
+ /* e.g. ftp mount or .dmg image */
2166
+ if (is_debug) {
2167
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2168
+ "[file_system_list] skipping readonly %s: %s",
2169
+ fs[i].f_fstypename, fs[i].f_mntonname);
2170
+ }
2171
+ continue;
2172
+ }
2173
+ #endif
2174
+
2175
+ SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
2176
+
2177
+ fsp = &fslist->data[fslist->number++];
2178
+
2179
+ SIGAR_SSTRCPY(fsp->dir_name, fs[i].f_mntonname);
2180
+ SIGAR_SSTRCPY(fsp->dev_name, fs[i].f_mntfromname);
2181
+ SIGAR_SSTRCPY(fsp->sys_type_name, fs[i].f_fstypename);
2182
+ get_fs_options(fsp->options, sizeof(fsp->options)-1, fs[i].sigar_f_flags);
2183
+
2184
+ sigar_fs_type_init(fsp);
2185
+ }
2186
+
2187
+ free(fs);
2188
+ return SIGAR_OK;
2189
+ }
2190
+
2191
+ #ifdef DARWIN
2192
+ #define IoStatGetValue(key, val) \
2193
+ if ((number = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatistics##key)))) \
2194
+ CFNumberGetValue(number, kCFNumberSInt64Type, &val)
2195
+ #endif
2196
+
2197
+ int sigar_disk_usage_get(sigar_t *sigar, const char *name,
2198
+ sigar_disk_usage_t *disk)
2199
+ {
2200
+ #if defined(DARWIN)
2201
+ kern_return_t status;
2202
+ io_registry_entry_t parent;
2203
+ io_service_t service;
2204
+ CFDictionaryRef props;
2205
+ CFNumberRef number;
2206
+ sigar_iodev_t *iodev = sigar_iodev_get(sigar, name);
2207
+ char dname[256], *ptr;
2208
+
2209
+ SIGAR_DISK_STATS_INIT(disk);
2210
+
2211
+ if (!iodev) {
2212
+ return ENXIO;
2213
+ }
2214
+
2215
+ /* "/dev/disk0s1" -> "disk0" */ /* XXX better way? */
2216
+ ptr = &iodev->name[SSTRLEN(SIGAR_DEV_PREFIX)];
2217
+ SIGAR_SSTRCPY(dname, ptr);
2218
+ ptr = dname;
2219
+ if (strnEQ(ptr, "disk", 4)) {
2220
+ ptr += 4;
2221
+ if ((ptr = strchr(ptr, 's')) && isdigit(*(ptr+1))) {
2222
+ *ptr = '\0';
2223
+ }
2224
+ }
2225
+
2226
+ if (SIGAR_LOG_IS_DEBUG(sigar)) {
2227
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2228
+ "[disk_usage] map %s -> %s",
2229
+ iodev->name, dname);
2230
+ }
2231
+
2232
+ /* e.g. name == "disk0" */
2233
+ service = IOServiceGetMatchingService(kIOMasterPortDefault,
2234
+ IOBSDNameMatching(kIOMasterPortDefault, 0, dname));
2235
+
2236
+ if (!service) {
2237
+ return errno;
2238
+ }
2239
+
2240
+ status = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
2241
+ if (status != KERN_SUCCESS) {
2242
+ IOObjectRelease(service);
2243
+ return status;
2244
+ }
2245
+
2246
+ status = IORegistryEntryCreateCFProperties(parent,
2247
+ (CFMutableDictionaryRef *)&props,
2248
+ kCFAllocatorDefault,
2249
+ kNilOptions);
2250
+ if (props) {
2251
+ CFDictionaryRef stats =
2252
+ (CFDictionaryRef)CFDictionaryGetValue(props,
2253
+ CFSTR(kIOBlockStorageDriverStatisticsKey));
2254
+
2255
+ if (stats) {
2256
+ IoStatGetValue(ReadsKey, disk->reads);
2257
+ IoStatGetValue(BytesReadKey, disk->read_bytes);
2258
+ IoStatGetValue(TotalReadTimeKey, disk->rtime);
2259
+ IoStatGetValue(WritesKey, disk->writes);
2260
+ IoStatGetValue(BytesWrittenKey, disk->write_bytes);
2261
+ IoStatGetValue(TotalWriteTimeKey, disk->wtime);
2262
+ disk->time = disk->rtime + disk->wtime;
2263
+ }
2264
+
2265
+ CFRelease(props);
2266
+ }
2267
+
2268
+ IOObjectRelease(service);
2269
+ IOObjectRelease(parent);
2270
+
2271
+ return SIGAR_OK;
2272
+ #elif defined(__FreeBSD__)
2273
+ /* XXX incomplete */
2274
+ struct sigar_statfs buf;
2275
+
2276
+ if (sigar_statfs(name, &buf) < 0) {
2277
+ return errno;
2278
+ }
2279
+
2280
+ SIGAR_DISK_STATS_INIT(disk);
2281
+
2282
+ disk->reads = buf.f_syncreads + buf.f_asyncreads;
2283
+ disk->writes = buf.f_syncwrites + buf.f_asyncwrites;
2284
+ return SIGAR_OK;
2285
+ #else
2286
+ SIGAR_DISK_STATS_INIT(disk);
2287
+ return SIGAR_ENOTIMPL;
2288
+ #endif
2289
+ }
2290
+
2291
+ int sigar_file_system_usage_get(sigar_t *sigar,
2292
+ const char *dirname,
2293
+ sigar_file_system_usage_t *fsusage)
2294
+ {
2295
+ int status = sigar_statvfs(sigar, dirname, fsusage);
2296
+
2297
+ if (status != SIGAR_OK) {
2298
+ return status;
2299
+ }
2300
+
2301
+ fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
2302
+
2303
+ sigar_disk_usage_get(sigar, dirname, &fsusage->disk);
2304
+
2305
+ return SIGAR_OK;
2306
+ }
2307
+
2308
+ #ifdef DARWIN
2309
+ #define CTL_HW_FREQ_MAX "hw.cpufrequency_max"
2310
+ #define CTL_HW_FREQ_MIN "hw.cpufrequency_min"
2311
+ #else
2312
+ /* XXX FreeBSD 5.x+ only? */
2313
+ #define CTL_HW_FREQ "machdep.tsc_freq"
2314
+ #endif
2315
+
2316
+ int sigar_cpu_info_list_get(sigar_t *sigar,
2317
+ sigar_cpu_info_list_t *cpu_infos)
2318
+ {
2319
+ int i;
2320
+ unsigned int mhz, mhz_min, mhz_max;
2321
+ int cache_size=SIGAR_FIELD_NOTIMPL;
2322
+ size_t size;
2323
+ char model[128], vendor[128], *ptr;
2324
+
2325
+ size = sizeof(mhz);
2326
+
2327
+ (void)sigar_cpu_core_count(sigar);
2328
+
2329
+ #if defined(DARWIN)
2330
+ {
2331
+ int mib[] = { CTL_HW, HW_CPU_FREQ };
2332
+ size = sizeof(mhz);
2333
+ if (sysctl(mib, NMIB(mib), &mhz, &size, NULL, 0) < 0) {
2334
+ mhz = SIGAR_FIELD_NOTIMPL;
2335
+ }
2336
+ }
2337
+ if (sysctlbyname(CTL_HW_FREQ_MAX, &mhz_max, &size, NULL, 0) < 0) {
2338
+ mhz_max = SIGAR_FIELD_NOTIMPL;
2339
+ }
2340
+ if (sysctlbyname(CTL_HW_FREQ_MIN, &mhz_min, &size, NULL, 0) < 0) {
2341
+ mhz_min = SIGAR_FIELD_NOTIMPL;
2342
+ }
2343
+ #elif defined(__FreeBSD__)
2344
+ if (sysctlbyname(CTL_HW_FREQ, &mhz, &size, NULL, 0) < 0) {
2345
+ mhz = SIGAR_FIELD_NOTIMPL;
2346
+ }
2347
+ /* TODO */
2348
+ mhz_max = SIGAR_FIELD_NOTIMPL;
2349
+ mhz_min = SIGAR_FIELD_NOTIMPL;
2350
+ #else
2351
+ /*XXX OpenBSD*/
2352
+ mhz = SIGAR_FIELD_NOTIMPL;
2353
+ mhz_max = SIGAR_FIELD_NOTIMPL;
2354
+ mhz_min = SIGAR_FIELD_NOTIMPL;
2355
+ #endif
2356
+
2357
+ if (mhz != SIGAR_FIELD_NOTIMPL) {
2358
+ mhz /= 1000000;
2359
+ }
2360
+ if (mhz_max != SIGAR_FIELD_NOTIMPL) {
2361
+ mhz_max /= 1000000;
2362
+ }
2363
+ if (mhz_min != SIGAR_FIELD_NOTIMPL) {
2364
+ mhz_min /= 1000000;
2365
+ }
2366
+
2367
+ size = sizeof(model);
2368
+ #ifdef __OpenBSD__
2369
+ if (1) {
2370
+ #else
2371
+ if (sysctlbyname("hw.model", &model, &size, NULL, 0) < 0) {
2372
+ #endif
2373
+ int mib[] = { CTL_HW, HW_MODEL };
2374
+ size = sizeof(model);
2375
+ if (sysctl(mib, NMIB(mib), &model[0], &size, NULL, 0) < 0) {
2376
+ #ifdef DARWIN
2377
+ strcpy(model, "powerpc");
2378
+ #else
2379
+ strcpy(model, "Unknown");
2380
+ #endif
2381
+ }
2382
+ }
2383
+
2384
+ if (mhz == SIGAR_FIELD_NOTIMPL) {
2385
+ /* freebsd4 */
2386
+ mhz = sigar_cpu_mhz_from_model(model);
2387
+ }
2388
+ /* XXX not sure */
2389
+ if (mhz_max == SIGAR_FIELD_NOTIMPL) {
2390
+ mhz_max = 0;
2391
+ }
2392
+ if (mhz_min == SIGAR_FIELD_NOTIMPL) {
2393
+ mhz_min = 0;
2394
+ }
2395
+
2396
+
2397
+ #ifdef DARWIN
2398
+ size = sizeof(vendor);
2399
+ if (sysctlbyname("machdep.cpu.vendor", &vendor, &size, NULL, 0) < 0) {
2400
+ SIGAR_SSTRCPY(vendor, "Apple");
2401
+ }
2402
+ else {
2403
+ /* GenuineIntel -> Intel */
2404
+ if (strstr(vendor, "Intel")) {
2405
+ SIGAR_SSTRCPY(vendor, "Intel");
2406
+ }
2407
+ }
2408
+ #endif
2409
+
2410
+ if ((ptr = strchr(model, ' '))) {
2411
+ if (strstr(model, "Intel")) {
2412
+ SIGAR_SSTRCPY(vendor, "Intel");
2413
+ }
2414
+ else if (strstr(model, "AMD")) {
2415
+ SIGAR_SSTRCPY(vendor, "AMD");
2416
+ }
2417
+ else {
2418
+ SIGAR_SSTRCPY(vendor, "Unknown");
2419
+ }
2420
+ SIGAR_SSTRCPY(model, ptr+1);
2421
+ }
2422
+
2423
+ #ifdef DARWIN
2424
+ {
2425
+ int mib[] = { CTL_HW, HW_L2CACHESIZE }; /* in bytes */
2426
+ size = sizeof(cache_size);
2427
+ if (sysctl(mib, NMIB(mib), &cache_size, &size, NULL, 0) < 0) {
2428
+ cache_size = SIGAR_FIELD_NOTIMPL;
2429
+ }
2430
+ else {
2431
+ cache_size /= 1024; /* convert to KB */
2432
+ }
2433
+ }
2434
+ #endif
2435
+
2436
+ sigar_cpu_info_list_create(cpu_infos);
2437
+
2438
+ for (i=0; i<sigar->ncpu; i++) {
2439
+ sigar_cpu_info_t *info;
2440
+
2441
+ SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
2442
+
2443
+ info = &cpu_infos->data[cpu_infos->number++];
2444
+
2445
+ SIGAR_SSTRCPY(info->vendor, vendor);
2446
+ SIGAR_SSTRCPY(info->model, model);
2447
+ sigar_cpu_model_adjust(sigar, info);
2448
+
2449
+ info->mhz = mhz;
2450
+ info->mhz_max = mhz_max;
2451
+ info->mhz_min = mhz_min;
2452
+ info->cache_size = cache_size;
2453
+ info->total_cores = sigar->ncpu;
2454
+ info->cores_per_socket = sigar->lcpu;
2455
+ info->total_sockets = sigar_cpu_socket_count(sigar);
2456
+ }
2457
+
2458
+ return SIGAR_OK;
2459
+ }
2460
+
2461
+ #define rt_s_addr(sa) ((struct sockaddr_in *)(sa))->sin_addr.s_addr
2462
+
2463
+ #ifndef SA_SIZE
2464
+ #define SA_SIZE(sa) \
2465
+ ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
2466
+ sizeof(long) : \
2467
+ 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
2468
+ #endif
2469
+
2470
+ int sigar_net_route_list_get(sigar_t *sigar,
2471
+ sigar_net_route_list_t *routelist)
2472
+ {
2473
+ size_t needed;
2474
+ int bit;
2475
+ char *buf, *next, *lim;
2476
+ struct rt_msghdr *rtm;
2477
+ int mib[6] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 };
2478
+
2479
+ if (sysctl(mib, NMIB(mib), NULL, &needed, NULL, 0) < 0) {
2480
+ return errno;
2481
+ }
2482
+ #if __FreeBSD_version >= 800000
2483
+ if (needed == 0) {
2484
+ return SIGAR_ENOTIMPL; /*XXX hoping this is an 8.0beta bug*/
2485
+ }
2486
+ #endif
2487
+ buf = malloc(needed);
2488
+
2489
+ if (sysctl(mib, NMIB(mib), buf, &needed, NULL, 0) < 0) {
2490
+ free(buf);
2491
+ return errno;
2492
+ }
2493
+
2494
+ sigar_net_route_list_create(routelist);
2495
+
2496
+ lim = buf + needed;
2497
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
2498
+ struct sockaddr *sa;
2499
+ sigar_net_route_t *route;
2500
+ rtm = (struct rt_msghdr *)next;
2501
+
2502
+ if (rtm->rtm_type != RTM_GET) {
2503
+ continue;
2504
+ }
2505
+
2506
+ sa = (struct sockaddr *)(rtm + 1);
2507
+
2508
+ if (sa->sa_family != AF_INET) {
2509
+ continue;
2510
+ }
2511
+
2512
+ SIGAR_NET_ROUTE_LIST_GROW(routelist);
2513
+ route = &routelist->data[routelist->number++];
2514
+ SIGAR_ZERO(route);
2515
+
2516
+ route->flags = rtm->rtm_flags;
2517
+ if_indextoname(rtm->rtm_index, route->ifname);
2518
+
2519
+ for (bit=RTA_DST;
2520
+ bit && ((char *)sa < lim);
2521
+ bit <<= 1)
2522
+ {
2523
+ if ((rtm->rtm_addrs & bit) == 0) {
2524
+ continue;
2525
+ }
2526
+ switch (bit) {
2527
+ case RTA_DST:
2528
+ sigar_net_address_set(route->destination,
2529
+ rt_s_addr(sa));
2530
+ break;
2531
+ case RTA_GATEWAY:
2532
+ if (sa->sa_family == AF_INET) {
2533
+ sigar_net_address_set(route->gateway,
2534
+ rt_s_addr(sa));
2535
+ }
2536
+ break;
2537
+ case RTA_NETMASK:
2538
+ sigar_net_address_set(route->mask,
2539
+ rt_s_addr(sa));
2540
+ break;
2541
+ case RTA_IFA:
2542
+ break;
2543
+ }
2544
+
2545
+ sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
2546
+ }
2547
+ }
2548
+
2549
+ free(buf);
2550
+
2551
+ return SIGAR_OK;
2552
+ }
2553
+
2554
+ typedef enum {
2555
+ IFMSG_ITER_LIST,
2556
+ IFMSG_ITER_GET
2557
+ } ifmsg_iter_e;
2558
+
2559
+ typedef struct {
2560
+ const char *name;
2561
+ ifmsg_iter_e type;
2562
+ union {
2563
+ sigar_net_interface_list_t *iflist;
2564
+ struct if_msghdr *ifm;
2565
+ } data;
2566
+ } ifmsg_iter_t;
2567
+
2568
+ static int sigar_ifmsg_init(sigar_t *sigar)
2569
+ {
2570
+ int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, 0 };
2571
+ size_t len;
2572
+
2573
+ if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) {
2574
+ return errno;
2575
+ }
2576
+
2577
+ if (sigar->ifconf_len < len) {
2578
+ sigar->ifconf_buf = realloc(sigar->ifconf_buf, len);
2579
+ sigar->ifconf_len = len;
2580
+ }
2581
+
2582
+ if (sysctl(mib, NMIB(mib), sigar->ifconf_buf, &len, NULL, 0) < 0) {
2583
+ return errno;
2584
+ }
2585
+
2586
+ return SIGAR_OK;
2587
+ }
2588
+
2589
+ /**
2590
+ * @param name name of the interface
2591
+ * @param name_len length of name (w/o \0)
2592
+ */
2593
+ static int has_ifaddr(char *name, size_t name_len)
2594
+ {
2595
+ int sock, status;
2596
+ struct ifreq ifr;
2597
+
2598
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
2599
+ return errno;
2600
+ }
2601
+ strncpy(ifr.ifr_name, name, MIN(sizeof(ifr.ifr_name) - 1, name_len));
2602
+ ifr.ifr_name[MIN(sizeof(ifr.ifr_name) - 1, name_len)] = '\0';
2603
+ if (ioctl(sock, SIOCGIFADDR, &ifr) == 0) {
2604
+ status = SIGAR_OK;
2605
+ }
2606
+ else {
2607
+ status = errno;
2608
+ }
2609
+
2610
+ close(sock);
2611
+ return status;
2612
+ }
2613
+
2614
+ static int sigar_ifmsg_iter(sigar_t *sigar, ifmsg_iter_t *iter)
2615
+ {
2616
+ char *end = sigar->ifconf_buf + sigar->ifconf_len;
2617
+ char *ptr = sigar->ifconf_buf;
2618
+
2619
+ if (iter->type == IFMSG_ITER_LIST) {
2620
+ sigar_net_interface_list_create(iter->data.iflist);
2621
+ }
2622
+
2623
+ while (ptr < end) {
2624
+ char *name;
2625
+ struct sockaddr_dl *sdl;
2626
+ struct if_msghdr *ifm = (struct if_msghdr *)ptr;
2627
+
2628
+ if (ifm->ifm_type != RTM_IFINFO) {
2629
+ break;
2630
+ }
2631
+
2632
+ ptr += ifm->ifm_msglen;
2633
+
2634
+ while (ptr < end) {
2635
+ struct if_msghdr *next = (struct if_msghdr *)ptr;
2636
+
2637
+ if (next->ifm_type != RTM_NEWADDR) {
2638
+ break;
2639
+ }
2640
+
2641
+ ptr += next->ifm_msglen;
2642
+ }
2643
+
2644
+ sdl = (struct sockaddr_dl *)(ifm + 1);
2645
+ if (sdl->sdl_family != AF_LINK) {
2646
+ continue;
2647
+ }
2648
+
2649
+ switch (iter->type) {
2650
+ case IFMSG_ITER_LIST:
2651
+ if (sdl->sdl_type == IFT_OTHER) {
2652
+ if (has_ifaddr(sdl->sdl_data, sdl->sdl_nlen) != SIGAR_OK) {
2653
+ break;
2654
+ }
2655
+ }
2656
+ else if (!((sdl->sdl_type == IFT_ETHER) ||
2657
+ (sdl->sdl_type == IFT_LOOP)))
2658
+ {
2659
+ break; /* XXX deal w/ other weirdo interfaces */
2660
+ }
2661
+
2662
+ SIGAR_NET_IFLIST_GROW(iter->data.iflist);
2663
+
2664
+ /* sdl_data doesn't include a trailing \0, it is only sdl_nlen long */
2665
+ name = malloc(sdl->sdl_nlen+1);
2666
+ memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
2667
+ name[sdl->sdl_nlen] = '\0'; /* add the missing \0 */
2668
+
2669
+ iter->data.iflist->data[iter->data.iflist->number++] = name;
2670
+ break;
2671
+
2672
+ case IFMSG_ITER_GET:
2673
+ if (strlen(iter->name) == sdl->sdl_nlen && 0 == memcmp(iter->name, sdl->sdl_data, sdl->sdl_nlen)) {
2674
+ iter->data.ifm = ifm;
2675
+ return SIGAR_OK;
2676
+ }
2677
+ }
2678
+ }
2679
+
2680
+ switch (iter->type) {
2681
+ case IFMSG_ITER_LIST:
2682
+ return SIGAR_OK;
2683
+
2684
+ case IFMSG_ITER_GET:
2685
+ default:
2686
+ return ENXIO;
2687
+ }
2688
+ }
2689
+
2690
+ int sigar_net_interface_list_get(sigar_t *sigar,
2691
+ sigar_net_interface_list_t *iflist)
2692
+ {
2693
+ int status;
2694
+ ifmsg_iter_t iter;
2695
+
2696
+ if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) {
2697
+ return status;
2698
+ }
2699
+
2700
+ iter.type = IFMSG_ITER_LIST;
2701
+ iter.data.iflist = iflist;
2702
+
2703
+ return sigar_ifmsg_iter(sigar, &iter);
2704
+ }
2705
+
2706
+ #include <ifaddrs.h>
2707
+
2708
+ /* in6_prefixlen derived from freebsd/sbin/ifconfig/af_inet6.c */
2709
+ static int sigar_in6_prefixlen(struct sockaddr *netmask)
2710
+ {
2711
+ struct in6_addr *addr = SIGAR_SIN6_ADDR(netmask);
2712
+ u_char *name = (u_char *)addr;
2713
+ int size = sizeof(*addr);
2714
+ int byte, bit, plen = 0;
2715
+
2716
+ for (byte = 0; byte < size; byte++, plen += 8) {
2717
+ if (name[byte] != 0xff) {
2718
+ break;
2719
+ }
2720
+ }
2721
+ if (byte == size) {
2722
+ return plen;
2723
+ }
2724
+ for (bit = 7; bit != 0; bit--, plen++) {
2725
+ if (!(name[byte] & (1 << bit))) {
2726
+ break;
2727
+ }
2728
+ }
2729
+ for (; bit != 0; bit--) {
2730
+ if (name[byte] & (1 << bit)) {
2731
+ return 0;
2732
+ }
2733
+ }
2734
+ byte++;
2735
+ for (; byte < size; byte++) {
2736
+ if (name[byte]) {
2737
+ return 0;
2738
+ }
2739
+ }
2740
+ return plen;
2741
+ }
2742
+
2743
+ int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name,
2744
+ sigar_net_interface_config_t *ifconfig)
2745
+ {
2746
+ int status = SIGAR_ENOENT;
2747
+ struct ifaddrs *addrs, *ifa;
2748
+
2749
+ if (getifaddrs(&addrs) != 0) {
2750
+ return errno;
2751
+ }
2752
+
2753
+ for (ifa=addrs; ifa; ifa=ifa->ifa_next) {
2754
+ if (ifa->ifa_addr &&
2755
+ (ifa->ifa_addr->sa_family == AF_INET6) &&
2756
+ strEQ(ifa->ifa_name, name))
2757
+ {
2758
+ status = SIGAR_OK;
2759
+ break;
2760
+ }
2761
+ }
2762
+
2763
+ if (status == SIGAR_OK) {
2764
+ struct in6_addr *addr = SIGAR_SIN6_ADDR(ifa->ifa_addr);
2765
+
2766
+ sigar_net_address6_set(ifconfig->address6, addr);
2767
+ sigar_net_interface_scope6_set(ifconfig, addr);
2768
+ ifconfig->prefix6_length = sigar_in6_prefixlen(ifa->ifa_netmask);
2769
+ }
2770
+
2771
+ freeifaddrs(addrs);
2772
+
2773
+ return status;
2774
+ }
2775
+
2776
+ int sigar_net_interface_config_get(sigar_t *sigar, const char *name,
2777
+ sigar_net_interface_config_t *ifconfig)
2778
+ {
2779
+ int sock;
2780
+ int status;
2781
+ ifmsg_iter_t iter;
2782
+ struct if_msghdr *ifm;
2783
+ struct sockaddr_dl *sdl;
2784
+ struct ifreq ifr;
2785
+
2786
+ if (!name) {
2787
+ return sigar_net_interface_config_primary_get(sigar, ifconfig);
2788
+ }
2789
+
2790
+ if (sigar->ifconf_len == 0) {
2791
+ if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) {
2792
+ return status;
2793
+ }
2794
+ }
2795
+
2796
+ SIGAR_ZERO(ifconfig);
2797
+
2798
+ iter.type = IFMSG_ITER_GET;
2799
+ iter.name = name;
2800
+
2801
+ if ((status = sigar_ifmsg_iter(sigar, &iter)) != SIGAR_OK) {
2802
+ return status;
2803
+ }
2804
+
2805
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
2806
+ return errno;
2807
+ }
2808
+
2809
+ ifm = iter.data.ifm;
2810
+
2811
+ SIGAR_SSTRCPY(ifconfig->name, name);
2812
+
2813
+ sdl = (struct sockaddr_dl *)(ifm + 1);
2814
+
2815
+ sigar_net_address_mac_set(ifconfig->hwaddr,
2816
+ LLADDR(sdl),
2817
+ sdl->sdl_alen);
2818
+
2819
+ ifconfig->flags = ifm->ifm_flags;
2820
+ ifconfig->mtu = ifm->ifm_data.ifi_mtu;
2821
+ ifconfig->metric = ifm->ifm_data.ifi_metric;
2822
+
2823
+ SIGAR_SSTRCPY(ifr.ifr_name, name);
2824
+
2825
+ #define ifr_s_addr(ifr) \
2826
+ ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr
2827
+
2828
+ if (!ioctl(sock, SIOCGIFADDR, &ifr)) {
2829
+ sigar_net_address_set(ifconfig->address,
2830
+ ifr_s_addr(ifr));
2831
+ }
2832
+
2833
+ if (!ioctl(sock, SIOCGIFNETMASK, &ifr)) {
2834
+ sigar_net_address_set(ifconfig->netmask,
2835
+ ifr_s_addr(ifr));
2836
+ }
2837
+
2838
+ if (ifconfig->flags & IFF_LOOPBACK) {
2839
+ sigar_net_address_set(ifconfig->destination,
2840
+ ifconfig->address.addr.in);
2841
+ sigar_net_address_set(ifconfig->broadcast, 0);
2842
+ SIGAR_SSTRCPY(ifconfig->type,
2843
+ SIGAR_NIC_LOOPBACK);
2844
+ }
2845
+ else {
2846
+ if (!ioctl(sock, SIOCGIFDSTADDR, &ifr)) {
2847
+ sigar_net_address_set(ifconfig->destination,
2848
+ ifr_s_addr(ifr));
2849
+ }
2850
+
2851
+ if (!ioctl(sock, SIOCGIFBRDADDR, &ifr)) {
2852
+ sigar_net_address_set(ifconfig->broadcast,
2853
+ ifr_s_addr(ifr));
2854
+ }
2855
+ SIGAR_SSTRCPY(ifconfig->type,
2856
+ SIGAR_NIC_ETHERNET);
2857
+ }
2858
+
2859
+ close(sock);
2860
+
2861
+ /* XXX can we get a better description like win32? */
2862
+ SIGAR_SSTRCPY(ifconfig->description,
2863
+ ifconfig->name);
2864
+
2865
+ sigar_net_interface_ipv6_config_init(ifconfig);
2866
+ sigar_net_interface_ipv6_config_get(sigar, name, ifconfig);
2867
+
2868
+ return SIGAR_OK;
2869
+ }
2870
+
2871
+ int sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
2872
+ sigar_net_interface_stat_t *ifstat)
2873
+ {
2874
+ int status;
2875
+ ifmsg_iter_t iter;
2876
+ struct if_msghdr *ifm;
2877
+
2878
+ if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) {
2879
+ return status;
2880
+ }
2881
+
2882
+ iter.type = IFMSG_ITER_GET;
2883
+ iter.name = name;
2884
+
2885
+ if ((status = sigar_ifmsg_iter(sigar, &iter)) != SIGAR_OK) {
2886
+ return status;
2887
+ }
2888
+
2889
+ ifm = iter.data.ifm;
2890
+
2891
+ ifstat->rx_bytes = ifm->ifm_data.ifi_ibytes;
2892
+ ifstat->rx_packets = ifm->ifm_data.ifi_ipackets;
2893
+ ifstat->rx_errors = ifm->ifm_data.ifi_ierrors;
2894
+ ifstat->rx_dropped = ifm->ifm_data.ifi_iqdrops;
2895
+ ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL;
2896
+ ifstat->rx_frame = SIGAR_FIELD_NOTIMPL;
2897
+
2898
+ ifstat->tx_bytes = ifm->ifm_data.ifi_obytes;
2899
+ ifstat->tx_packets = ifm->ifm_data.ifi_opackets;
2900
+ ifstat->tx_errors = ifm->ifm_data.ifi_oerrors;
2901
+ ifstat->tx_collisions = ifm->ifm_data.ifi_collisions;
2902
+ ifstat->tx_dropped = SIGAR_FIELD_NOTIMPL;
2903
+ ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL;
2904
+ ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL;
2905
+
2906
+ ifstat->speed = ifm->ifm_data.ifi_baudrate;
2907
+
2908
+ return SIGAR_OK;
2909
+ }
2910
+
2911
+ static int net_connection_state_get(int state)
2912
+ {
2913
+ switch (state) {
2914
+ case TCPS_CLOSED:
2915
+ return SIGAR_TCP_CLOSE;
2916
+ case TCPS_LISTEN:
2917
+ return SIGAR_TCP_LISTEN;
2918
+ case TCPS_SYN_SENT:
2919
+ return SIGAR_TCP_SYN_SENT;
2920
+ case TCPS_SYN_RECEIVED:
2921
+ return SIGAR_TCP_SYN_RECV;
2922
+ case TCPS_ESTABLISHED:
2923
+ return SIGAR_TCP_ESTABLISHED;
2924
+ case TCPS_CLOSE_WAIT:
2925
+ return SIGAR_TCP_CLOSE_WAIT;
2926
+ case TCPS_FIN_WAIT_1:
2927
+ return SIGAR_TCP_FIN_WAIT1;
2928
+ case TCPS_CLOSING:
2929
+ return SIGAR_TCP_CLOSING;
2930
+ case TCPS_LAST_ACK:
2931
+ return SIGAR_TCP_LAST_ACK;
2932
+ case TCPS_FIN_WAIT_2:
2933
+ return SIGAR_TCP_FIN_WAIT2;
2934
+ case TCPS_TIME_WAIT:
2935
+ return SIGAR_TCP_TIME_WAIT;
2936
+ default:
2937
+ return SIGAR_TCP_UNKNOWN;
2938
+ }
2939
+ }
2940
+
2941
+ #if defined(__OpenBSD__) || defined(__NetBSD__)
2942
+ static int net_connection_get(sigar_net_connection_walker_t *walker, int proto)
2943
+ {
2944
+ int status;
2945
+ int istcp = 0, type;
2946
+ int flags = walker->flags;
2947
+ struct inpcbtable table;
2948
+ struct inpcb *head, *next, *prev;
2949
+ sigar_t *sigar = walker->sigar;
2950
+ u_long offset;
2951
+
2952
+ switch (proto) {
2953
+ case IPPROTO_TCP:
2954
+ offset = sigar->koffsets[KOFFSET_TCBTABLE];
2955
+ istcp = 1;
2956
+ type = SIGAR_NETCONN_TCP;
2957
+ break;
2958
+ case IPPROTO_UDP:
2959
+ default:
2960
+ return SIGAR_ENOTIMPL;
2961
+ }
2962
+
2963
+
2964
+ status = kread(sigar, &table, sizeof(table), offset);
2965
+
2966
+ if (status != SIGAR_OK) {
2967
+ return status;
2968
+ }
2969
+
2970
+ prev = head =
2971
+ (struct inpcb *)&CIRCLEQ_FIRST(&((struct inpcbtable *)offset)->inpt_queue);
2972
+
2973
+ next = (struct inpcb *)CIRCLEQ_FIRST(&table.inpt_queue);
2974
+
2975
+ while (next != head) {
2976
+ struct inpcb inpcb;
2977
+ struct tcpcb tcpcb;
2978
+ struct socket socket;
2979
+
2980
+ status = kread(sigar, &inpcb, sizeof(inpcb), (long)next);
2981
+ prev = next;
2982
+ next = (struct inpcb *)CIRCLEQ_NEXT(&inpcb, inp_queue);
2983
+
2984
+ kread(sigar, &socket, sizeof(socket), (u_long)inpcb.inp_socket);
2985
+
2986
+ if ((((flags & SIGAR_NETCONN_SERVER) && socket.so_qlimit) ||
2987
+ ((flags & SIGAR_NETCONN_CLIENT) && !socket.so_qlimit)))
2988
+ {
2989
+ sigar_net_connection_t conn;
2990
+
2991
+ SIGAR_ZERO(&conn);
2992
+
2993
+ if (istcp) {
2994
+ kread(sigar, &tcpcb, sizeof(tcpcb), (u_long)inpcb.inp_ppcb);
2995
+ }
2996
+
2997
+ #ifdef __NetBSD__
2998
+ if (inpcb.inp_af == AF_INET6) {
2999
+ /*XXX*/
3000
+ continue;
3001
+ }
3002
+ #else
3003
+ if (inpcb.inp_flags & INP_IPV6) {
3004
+ sigar_net_address6_set(conn.local_address,
3005
+ &inpcb.inp_laddr6.s6_addr);
3006
+
3007
+ sigar_net_address6_set(conn.remote_address,
3008
+ &inpcb.inp_faddr6.s6_addr);
3009
+ }
3010
+ #endif
3011
+ else {
3012
+ sigar_net_address_set(conn.local_address,
3013
+ inpcb.inp_laddr.s_addr);
3014
+
3015
+ sigar_net_address_set(conn.remote_address,
3016
+ inpcb.inp_faddr.s_addr);
3017
+ }
3018
+
3019
+ conn.local_port = ntohs(inpcb.inp_lport);
3020
+ conn.remote_port = ntohs(inpcb.inp_fport);
3021
+ conn.receive_queue = socket.so_rcv.sb_cc;
3022
+ conn.send_queue = socket.so_snd.sb_cc;
3023
+ conn.uid = socket.so_pgid;
3024
+ conn.type = type;
3025
+
3026
+ if (!istcp) {
3027
+ conn.state = SIGAR_TCP_UNKNOWN;
3028
+ if (walker->add_connection(walker, &conn) != SIGAR_OK) {
3029
+ break;
3030
+ }
3031
+ continue;
3032
+ }
3033
+
3034
+ conn.state = net_connection_state_get(tcpcb.t_state);
3035
+
3036
+ if (walker->add_connection(walker, &conn) != SIGAR_OK) {
3037
+ break;
3038
+ }
3039
+ }
3040
+ }
3041
+
3042
+ return SIGAR_OK;
3043
+ }
3044
+ #else
3045
+ static int net_connection_get(sigar_net_connection_walker_t *walker, int proto)
3046
+ {
3047
+ int flags = walker->flags;
3048
+ int type, istcp = 0;
3049
+ char *buf;
3050
+ const char *mibvar;
3051
+ struct tcpcb *tp = NULL;
3052
+ struct inpcb *inp;
3053
+ struct xinpgen *xig, *oxig;
3054
+ struct xsocket *so;
3055
+ size_t len;
3056
+
3057
+ switch (proto) {
3058
+ case IPPROTO_TCP:
3059
+ mibvar = "net.inet.tcp.pcblist";
3060
+ istcp = 1;
3061
+ type = SIGAR_NETCONN_TCP;
3062
+ break;
3063
+ case IPPROTO_UDP:
3064
+ mibvar = "net.inet.udp.pcblist";
3065
+ type = SIGAR_NETCONN_UDP;
3066
+ break;
3067
+ default:
3068
+ mibvar = "net.inet.raw.pcblist";
3069
+ type = SIGAR_NETCONN_RAW;
3070
+ break;
3071
+ }
3072
+
3073
+ len = 0;
3074
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
3075
+ return errno;
3076
+ }
3077
+ if ((buf = malloc(len)) == 0) {
3078
+ return errno;
3079
+ }
3080
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
3081
+ free(buf);
3082
+ return errno;
3083
+ }
3084
+
3085
+ oxig = xig = (struct xinpgen *)buf;
3086
+ for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
3087
+ xig->xig_len > sizeof(struct xinpgen);
3088
+ xig = (struct xinpgen *)((char *)xig + xig->xig_len))
3089
+ {
3090
+ if (istcp) {
3091
+ struct xtcpcb *cb = (struct xtcpcb *)xig;
3092
+ tp = &cb->xt_tp;
3093
+ inp = &cb->xt_inp;
3094
+ so = &cb->xt_socket;
3095
+ }
3096
+ else {
3097
+ struct xinpcb *cb = (struct xinpcb *)xig;
3098
+ inp = &cb->xi_inp;
3099
+ so = &cb->xi_socket;
3100
+ }
3101
+
3102
+ if (so->xso_protocol != proto) {
3103
+ continue;
3104
+ }
3105
+
3106
+ if (inp->inp_gencnt > oxig->xig_gen) {
3107
+ continue;
3108
+ }
3109
+
3110
+ if ((((flags & SIGAR_NETCONN_SERVER) && so->so_qlimit) ||
3111
+ ((flags & SIGAR_NETCONN_CLIENT) && !so->so_qlimit)))
3112
+ {
3113
+ sigar_net_connection_t conn;
3114
+
3115
+ SIGAR_ZERO(&conn);
3116
+
3117
+ if (inp->inp_vflag & INP_IPV6) {
3118
+ sigar_net_address6_set(conn.local_address,
3119
+ &inp->in6p_laddr.s6_addr);
3120
+
3121
+ sigar_net_address6_set(conn.remote_address,
3122
+ &inp->in6p_faddr.s6_addr);
3123
+ }
3124
+ else {
3125
+ sigar_net_address_set(conn.local_address,
3126
+ inp->inp_laddr.s_addr);
3127
+
3128
+ sigar_net_address_set(conn.remote_address,
3129
+ inp->inp_faddr.s_addr);
3130
+ }
3131
+
3132
+ conn.local_port = ntohs(inp->inp_lport);
3133
+ conn.remote_port = ntohs(inp->inp_fport);
3134
+ conn.receive_queue = so->so_rcv.sb_cc;
3135
+ conn.send_queue = so->so_snd.sb_cc;
3136
+ conn.uid = so->so_pgid;
3137
+ conn.type = type;
3138
+
3139
+ if (!istcp) {
3140
+ conn.state = SIGAR_TCP_UNKNOWN;
3141
+ if (walker->add_connection(walker, &conn) != SIGAR_OK) {
3142
+ break;
3143
+ }
3144
+ continue;
3145
+ }
3146
+
3147
+ conn.state = net_connection_state_get(tp->t_state);
3148
+
3149
+ if (walker->add_connection(walker, &conn) != SIGAR_OK) {
3150
+ break;
3151
+ }
3152
+ }
3153
+ }
3154
+
3155
+ free(buf);
3156
+
3157
+ return SIGAR_OK;
3158
+ }
3159
+ #endif
3160
+
3161
+ int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
3162
+ {
3163
+ int flags = walker->flags;
3164
+ int status;
3165
+
3166
+ if (flags & SIGAR_NETCONN_TCP) {
3167
+ status = net_connection_get(walker, IPPROTO_TCP);
3168
+ if (status != SIGAR_OK) {
3169
+ return status;
3170
+ }
3171
+ }
3172
+ if (flags & SIGAR_NETCONN_UDP) {
3173
+ status = net_connection_get(walker, IPPROTO_UDP);
3174
+ if (status != SIGAR_OK) {
3175
+ return status;
3176
+ }
3177
+ }
3178
+
3179
+ return SIGAR_OK;
3180
+ }
3181
+
3182
+ SIGAR_DECLARE(int)
3183
+ sigar_tcp_get(sigar_t *sigar,
3184
+ sigar_tcp_t *tcp)
3185
+ {
3186
+ struct tcpstat mib;
3187
+ #if !defined(TCPCTL_STATS) && (defined(__OpenBSD__) || defined(__NetBSD__))
3188
+ int status =
3189
+ kread(sigar, &mib, sizeof(mib),
3190
+ sigar->koffsets[KOFFSET_TCPSTAT]);
3191
+ if (status != SIGAR_OK) {
3192
+ return status;
3193
+ }
3194
+ #else
3195
+ int var[4] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS };
3196
+ size_t len = sizeof(mib);
3197
+
3198
+ if (sysctl(var, NMIB(var), &mib, &len, NULL, 0) < 0) {
3199
+ return errno;
3200
+ }
3201
+ #endif
3202
+
3203
+ tcp->active_opens = mib.tcps_connattempt;
3204
+ tcp->passive_opens = mib.tcps_accepts;
3205
+ tcp->attempt_fails = mib.tcps_conndrops;
3206
+ tcp->estab_resets = mib.tcps_drops;
3207
+ if (sigar_tcp_curr_estab(sigar, tcp) != SIGAR_OK) {
3208
+ tcp->curr_estab = -1;
3209
+ }
3210
+ tcp->in_segs = mib.tcps_rcvtotal;
3211
+ tcp->out_segs = mib.tcps_sndtotal - mib.tcps_sndrexmitpack;
3212
+ tcp->retrans_segs = mib.tcps_sndrexmitpack;
3213
+ tcp->in_errs =
3214
+ mib.tcps_rcvbadsum +
3215
+ mib.tcps_rcvbadoff +
3216
+ mib.tcps_rcvmemdrop +
3217
+ mib.tcps_rcvshort;
3218
+ tcp->out_rsts = -1; /* XXX mib.tcps_sndctrl - mib.tcps_closed; ? */
3219
+
3220
+ return SIGAR_OK;
3221
+ }
3222
+
3223
+ #ifndef SIGAR_FREEBSD5_NFSSTAT
3224
+ static int get_nfsstats(struct nfsstats *stats)
3225
+ {
3226
+ size_t len = sizeof(*stats);
3227
+ int mib[] = { CTL_VFS, 2, NFS_NFSSTATS };
3228
+
3229
+ if (sysctl(mib, NMIB(mib), stats, &len, NULL, 0) < 0) {
3230
+ return errno;
3231
+ }
3232
+ else {
3233
+ return SIGAR_OK;
3234
+ }
3235
+ }
3236
+ #endif
3237
+
3238
+ #if defined(__OpenBSD__)
3239
+ typedef uint64_t rpc_cnt_t;
3240
+ #else
3241
+ typedef int rpc_cnt_t;
3242
+ #endif
3243
+
3244
+ static void map_nfs_stats(sigar_nfs_v3_t *nfs, rpc_cnt_t *rpc)
3245
+ {
3246
+ nfs->null = rpc[NFSPROC_NULL];
3247
+ nfs->getattr = rpc[NFSPROC_GETATTR];
3248
+ nfs->setattr = rpc[NFSPROC_SETATTR];
3249
+ nfs->lookup = rpc[NFSPROC_LOOKUP];
3250
+ nfs->access = rpc[NFSPROC_ACCESS];
3251
+ nfs->readlink = rpc[NFSPROC_READLINK];
3252
+ nfs->read = rpc[NFSPROC_READ];
3253
+ nfs->write = rpc[NFSPROC_WRITE];
3254
+ nfs->create = rpc[NFSPROC_CREATE];
3255
+ nfs->mkdir = rpc[NFSPROC_MKDIR];
3256
+ nfs->symlink = rpc[NFSPROC_SYMLINK];
3257
+ nfs->mknod = rpc[NFSPROC_MKNOD];
3258
+ nfs->remove = rpc[NFSPROC_REMOVE];
3259
+ nfs->rmdir = rpc[NFSPROC_RMDIR];
3260
+ nfs->rename = rpc[NFSPROC_RENAME];
3261
+ nfs->link = rpc[NFSPROC_LINK];
3262
+ nfs->readdir = rpc[NFSPROC_READDIR];
3263
+ nfs->readdirplus = rpc[NFSPROC_READDIRPLUS];
3264
+ nfs->fsstat = rpc[NFSPROC_FSSTAT];
3265
+ nfs->fsinfo = rpc[NFSPROC_FSINFO];
3266
+ nfs->pathconf = rpc[NFSPROC_PATHCONF];
3267
+ nfs->commit = rpc[NFSPROC_COMMIT];
3268
+ }
3269
+
3270
+ int sigar_nfs_client_v2_get(sigar_t *sigar,
3271
+ sigar_nfs_client_v2_t *nfs)
3272
+ {
3273
+ return SIGAR_ENOTIMPL;
3274
+ }
3275
+
3276
+ int sigar_nfs_server_v2_get(sigar_t *sigar,
3277
+ sigar_nfs_server_v2_t *nfs)
3278
+ {
3279
+ return SIGAR_ENOTIMPL;
3280
+ }
3281
+
3282
+ int sigar_nfs_client_v3_get(sigar_t *sigar,
3283
+ sigar_nfs_client_v3_t *nfs)
3284
+ {
3285
+ #ifdef SIGAR_FREEBSD5_NFSSTAT
3286
+ struct nfsstats stats;
3287
+ size_t size = sizeof(stats);
3288
+
3289
+ if (sysctlbyname("vfs.nfs.nfsstats", &stats, &size, NULL, 0) == -1) {
3290
+ return errno;
3291
+ }
3292
+
3293
+ map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.rpccnt[0]);
3294
+ #else
3295
+ int status;
3296
+ struct nfsstats stats;
3297
+
3298
+ if ((status = get_nfsstats(&stats)) != SIGAR_OK) {
3299
+ return status;
3300
+ }
3301
+
3302
+ map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.rpccnt[0]);
3303
+ #endif
3304
+
3305
+ return SIGAR_OK;
3306
+ }
3307
+
3308
+ int sigar_nfs_server_v3_get(sigar_t *sigar,
3309
+ sigar_nfs_server_v3_t *nfs)
3310
+ {
3311
+ #ifdef SIGAR_FREEBSD5_NFSSTAT
3312
+ struct nfsrvstats stats;
3313
+ size_t size = sizeof(stats);
3314
+
3315
+ if (sysctlbyname("vfs.nfsrv.nfsrvstats", &stats, &size, NULL, 0) == -1) {
3316
+ return errno;
3317
+ }
3318
+
3319
+ map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.srvrpccnt[0]);
3320
+ #else
3321
+ int status;
3322
+ struct nfsstats stats;
3323
+
3324
+ if ((status = get_nfsstats(&stats)) != SIGAR_OK) {
3325
+ return status;
3326
+ }
3327
+
3328
+ map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.srvrpccnt[0]);
3329
+ #endif
3330
+
3331
+ return SIGAR_OK;
3332
+ }
3333
+
3334
+ static char *get_hw_type(int type)
3335
+ {
3336
+ switch (type) {
3337
+ case IFT_ETHER:
3338
+ return "ether";
3339
+ case IFT_ISO88025:
3340
+ return "tr";
3341
+ case IFT_FDDI:
3342
+ return "fddi";
3343
+ case IFT_ATM:
3344
+ return "atm";
3345
+ case IFT_L2VLAN:
3346
+ return "vlan";
3347
+ case IFT_IEEE1394:
3348
+ return "firewire";
3349
+ #ifdef IFT_BRIDGE
3350
+ case IFT_BRIDGE:
3351
+ return "bridge";
3352
+ #endif
3353
+ default:
3354
+ return "unknown";
3355
+ }
3356
+ }
3357
+
3358
+ int sigar_arp_list_get(sigar_t *sigar,
3359
+ sigar_arp_list_t *arplist)
3360
+ {
3361
+ size_t needed;
3362
+ char *lim, *buf, *next;
3363
+ struct rt_msghdr *rtm;
3364
+ struct sockaddr_inarp *sin;
3365
+ struct sockaddr_dl *sdl;
3366
+ int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO };
3367
+
3368
+ if (sysctl(mib, NMIB(mib), NULL, &needed, NULL, 0) < 0) {
3369
+ return errno;
3370
+ }
3371
+
3372
+ if (needed == 0) { /* empty cache */
3373
+ return 0;
3374
+ }
3375
+
3376
+ buf = malloc(needed);
3377
+
3378
+ if (sysctl(mib, NMIB(mib), buf, &needed, NULL, 0) < 0) {
3379
+ free(buf);
3380
+ return errno;
3381
+ }
3382
+
3383
+ sigar_arp_list_create(arplist);
3384
+
3385
+ lim = buf + needed;
3386
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
3387
+ sigar_arp_t *arp;
3388
+
3389
+ SIGAR_ARP_LIST_GROW(arplist);
3390
+ arp = &arplist->data[arplist->number++];
3391
+
3392
+ rtm = (struct rt_msghdr *)next;
3393
+ sin = (struct sockaddr_inarp *)(rtm + 1);
3394
+ sdl = (struct sockaddr_dl *)((char *)sin + SA_SIZE(sin));
3395
+
3396
+ sigar_net_address_set(arp->address, sin->sin_addr.s_addr);
3397
+ sigar_net_address_mac_set(arp->hwaddr, LLADDR(sdl), sdl->sdl_alen);
3398
+ if_indextoname(sdl->sdl_index, arp->ifname);
3399
+ arp->flags = rtm->rtm_flags;
3400
+
3401
+ SIGAR_SSTRCPY(arp->type, get_hw_type(sdl->sdl_type));
3402
+ }
3403
+
3404
+ free(buf);
3405
+
3406
+ return SIGAR_OK;
3407
+ }
3408
+
3409
+ #if defined(__FreeBSD__) && /*XXX*/ (__FreeBSD_version < 800000)
3410
+
3411
+ #define _KERNEL
3412
+ #include <sys/file.h>
3413
+ #undef _KERNEL
3414
+
3415
+ /* derived from
3416
+ * /usr/ports/security/pidentd/work/pidentd-3.0.16/src/k_freebsd2.c
3417
+ */
3418
+ int sigar_proc_port_get(sigar_t *sigar, int protocol,
3419
+ unsigned long port, sigar_pid_t *pid)
3420
+ {
3421
+ struct nlist nl[2];
3422
+ struct inpcbhead tcb;
3423
+ struct socket *sockp = NULL;
3424
+ struct kinfo_proc *pinfo;
3425
+ struct inpcb *head, pcbp;
3426
+ int i, nentries, status;
3427
+
3428
+ if (protocol != SIGAR_NETCONN_TCP) {
3429
+ return SIGAR_ENOTIMPL;
3430
+ }
3431
+
3432
+ if (!sigar->kmem) {
3433
+ return SIGAR_EPERM_KMEM;
3434
+ }
3435
+
3436
+ nl[0].n_name = "_tcb"; /* XXX cache */
3437
+ nl[1].n_name = "";
3438
+ if (kvm_nlist(sigar->kmem, nl) < 0) {
3439
+ return errno;
3440
+ }
3441
+
3442
+ status = kread(sigar, &tcb, sizeof(tcb), nl[0].n_value);
3443
+ if (status != SIGAR_OK) {
3444
+ return status;
3445
+ }
3446
+
3447
+ for (head = tcb.lh_first; head != NULL;
3448
+ head = pcbp.inp_list.le_next)
3449
+ {
3450
+ status = kread(sigar, &pcbp, sizeof(pcbp), (long)head);
3451
+ if (status != SIGAR_OK) {
3452
+ return status;
3453
+ }
3454
+ if (!(pcbp.inp_vflag & INP_IPV4)) {
3455
+ continue;
3456
+ }
3457
+ if (pcbp.inp_fport != 0) {
3458
+ continue;
3459
+ }
3460
+ if (ntohs(pcbp.inp_lport) == port) {
3461
+ sockp = pcbp.inp_socket;
3462
+ break;
3463
+ }
3464
+ }
3465
+
3466
+ if (!sockp) {
3467
+ return ENOENT;
3468
+ }
3469
+
3470
+ pinfo = kvm_getprocs(sigar->kmem, KERN_PROC_PROC, 0, &nentries);
3471
+ if (!pinfo) {
3472
+ return errno;
3473
+ }
3474
+
3475
+ for (i=0; i<nentries; i++) {
3476
+ if (pinfo[i].KI_FLAG & P_SYSTEM) {
3477
+ continue;
3478
+ }
3479
+ if (pinfo[i].KI_FD) {
3480
+ struct filedesc pfd;
3481
+ struct file **ofiles, ofile;
3482
+ int j, osize;
3483
+
3484
+ status = kread(sigar, &pfd, sizeof(pfd), (long)pinfo[i].KI_FD);
3485
+ if (status != SIGAR_OK) {
3486
+ return status;
3487
+ }
3488
+
3489
+ osize = pfd.fd_nfiles * sizeof(struct file *);
3490
+ ofiles = malloc(osize); /* XXX reuse */
3491
+ if (!ofiles) {
3492
+ return errno;
3493
+ }
3494
+
3495
+ status = kread(sigar, ofiles, osize, (long)pfd.fd_ofiles);
3496
+ if (status != SIGAR_OK) {
3497
+ free(ofiles);
3498
+ return status;
3499
+ }
3500
+
3501
+ for (j=0; j<pfd.fd_nfiles; j++) {
3502
+ if (!ofiles[j]) {
3503
+ continue;
3504
+ }
3505
+
3506
+ status = kread(sigar, &ofile, sizeof(ofile), (long)ofiles[j]);
3507
+ if (status != SIGAR_OK) {
3508
+ free(ofiles);
3509
+ return status;
3510
+ }
3511
+
3512
+ if (ofile.f_count == 0) {
3513
+ continue;
3514
+ }
3515
+
3516
+ if (ofile.f_type == DTYPE_SOCKET &&
3517
+ (struct socket *)ofile.f_data == sockp)
3518
+ {
3519
+ *pid = pinfo[i].KI_PID;
3520
+ free(ofiles);
3521
+ return SIGAR_OK;
3522
+ }
3523
+ }
3524
+
3525
+ free(ofiles);
3526
+ }
3527
+ }
3528
+
3529
+ return ENOENT;
3530
+ }
3531
+
3532
+ #elif defined(DARWIN) && defined(DARWIN_HAS_LIBPROC_H)
3533
+
3534
+ int sigar_proc_port_get(sigar_t *sigar, int protocol,
3535
+ unsigned long port, sigar_pid_t *pid)
3536
+ {
3537
+ sigar_proc_list_t pids;
3538
+ int i, status, found=0;
3539
+
3540
+ if (!sigar->libproc) {
3541
+ return SIGAR_ENOTIMPL;
3542
+ }
3543
+
3544
+ status = sigar_proc_list_get(sigar, &pids);
3545
+ if (status != SIGAR_OK) {
3546
+ return status;
3547
+ }
3548
+
3549
+ for (i=0; i<pids.number; i++) {
3550
+ int n, num=0;
3551
+ struct proc_fdinfo *fdinfo;
3552
+
3553
+ status = proc_fdinfo_get(sigar, pids.data[i], &num);
3554
+ if (status != SIGAR_OK) {
3555
+ continue;
3556
+ }
3557
+ fdinfo = (struct proc_fdinfo *)sigar->ifconf_buf;
3558
+
3559
+ for (n=0; n<num; n++) {
3560
+ struct proc_fdinfo *fdp = &fdinfo[n];
3561
+ struct socket_fdinfo si;
3562
+ int rsize, family;
3563
+ unsigned long lport;
3564
+
3565
+ if (fdp->proc_fdtype != PROX_FDTYPE_SOCKET) {
3566
+ continue;
3567
+ }
3568
+ rsize = sigar->proc_pidfdinfo(pids.data[i], fdp->proc_fd,
3569
+ PROC_PIDFDSOCKETINFO, &si, sizeof(si));
3570
+ if (rsize != sizeof(si)) {
3571
+ continue;
3572
+ }
3573
+ if (si.psi.soi_kind != SOCKINFO_TCP) {
3574
+ continue;
3575
+ }
3576
+ if (si.psi.soi_proto.pri_tcp.tcpsi_state != TSI_S_LISTEN) {
3577
+ continue;
3578
+ }
3579
+ family = si.psi.soi_family;
3580
+ if (!((family == AF_INET) || (family == AF_INET6))) {
3581
+ continue;
3582
+ }
3583
+ lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport);
3584
+ if (lport == port) {
3585
+ *pid = pids.data[i];
3586
+ found = 1;
3587
+ break;
3588
+ }
3589
+ }
3590
+ }
3591
+
3592
+ sigar_proc_list_destroy(sigar, &pids);
3593
+
3594
+ return found ? SIGAR_OK : ENOENT;
3595
+ }
3596
+
3597
+ #else
3598
+
3599
+ int sigar_proc_port_get(sigar_t *sigar, int protocol,
3600
+ unsigned long port, sigar_pid_t *pid)
3601
+ {
3602
+ return SIGAR_ENOTIMPL;
3603
+ }
3604
+
3605
+ #endif
3606
+
3607
+ int sigar_os_sys_info_get(sigar_t *sigar,
3608
+ sigar_sys_info_t *sysinfo)
3609
+ {
3610
+ #ifdef DARWIN
3611
+ char *codename = NULL;
3612
+ SInt32 version, version_major, version_minor, version_fix;
3613
+
3614
+ SIGAR_SSTRCPY(sysinfo->name, "MacOSX");
3615
+ SIGAR_SSTRCPY(sysinfo->vendor_name, "Mac OS X");
3616
+ SIGAR_SSTRCPY(sysinfo->vendor, "Apple");
3617
+
3618
+ if (Gestalt(gestaltSystemVersion, &version) == noErr) {
3619
+ if (version >= 0x00001040) {
3620
+ Gestalt('sys1' /*gestaltSystemVersionMajor*/, &version_major);
3621
+ Gestalt('sys2' /*gestaltSystemVersionMinor*/, &version_minor);
3622
+ Gestalt('sys3' /*gestaltSystemVersionBugFix*/, &version_fix);
3623
+ }
3624
+ else {
3625
+ version_fix = version & 0xf;
3626
+ version >>= 4;
3627
+ version_minor = version & 0xf;
3628
+ version >>= 4;
3629
+ version_major = version - (version >> 4) * 6;
3630
+ }
3631
+ }
3632
+ else {
3633
+ return SIGAR_ENOTIMPL;
3634
+ }
3635
+
3636
+ snprintf(sysinfo->vendor_version,
3637
+ sizeof(sysinfo->vendor_version),
3638
+ "%d.%d",
3639
+ (int)version_major, (int)version_minor);
3640
+
3641
+ snprintf(sysinfo->version,
3642
+ sizeof(sysinfo->version),
3643
+ "%s.%d",
3644
+ sysinfo->vendor_version, (int)version_fix);
3645
+
3646
+ if (version_major == 10) {
3647
+ switch (version_minor) {
3648
+ case 2:
3649
+ codename = "Jaguar";
3650
+ break;
3651
+ case 3:
3652
+ codename = "Panther";
3653
+ break;
3654
+ case 4:
3655
+ codename = "Tiger";
3656
+ break;
3657
+ case 5:
3658
+ codename = "Leopard";
3659
+ break;
3660
+ case 6:
3661
+ codename = "Snow Leopard";
3662
+ break;
3663
+ case 7:
3664
+ codename = "Lion";
3665
+ break;
3666
+ default:
3667
+ codename = "Unknown";
3668
+ break;
3669
+ }
3670
+ }
3671
+ else {
3672
+ return SIGAR_ENOTIMPL;
3673
+ }
3674
+
3675
+ SIGAR_SSTRCPY(sysinfo->vendor_code_name, codename);
3676
+
3677
+ snprintf(sysinfo->description,
3678
+ sizeof(sysinfo->description),
3679
+ "%s %s",
3680
+ sysinfo->vendor_name, sysinfo->vendor_code_name);
3681
+ #else
3682
+ char *ptr;
3683
+
3684
+ #if defined(__FreeBSD__)
3685
+ SIGAR_SSTRCPY(sysinfo->name, "FreeBSD");
3686
+ #elif defined(__OpenBSD__)
3687
+ SIGAR_SSTRCPY(sysinfo->name, "OpenBSD");
3688
+ #elif defined(__NetBSD__)
3689
+ SIGAR_SSTRCPY(sysinfo->name, "NetBSD");
3690
+ #else
3691
+ SIGAR_SSTRCPY(sysinfo->name, "Unknown");
3692
+ #endif
3693
+ SIGAR_SSTRCPY(sysinfo->vendor_name, sysinfo->name);
3694
+ SIGAR_SSTRCPY(sysinfo->vendor, sysinfo->name);
3695
+ SIGAR_SSTRCPY(sysinfo->vendor_version,
3696
+ sysinfo->version);
3697
+
3698
+ if ((ptr = strstr(sysinfo->vendor_version, "-"))) {
3699
+ /* STABLE, RELEASE, CURRENT */
3700
+ *ptr++ = '\0';
3701
+ SIGAR_SSTRCPY(sysinfo->vendor_code_name, ptr);
3702
+ }
3703
+
3704
+ snprintf(sysinfo->description,
3705
+ sizeof(sysinfo->description),
3706
+ "%s %s",
3707
+ sysinfo->name, sysinfo->version);
3708
+ #endif
3709
+
3710
+ return SIGAR_OK;
3711
+ }