csigar 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/NOTICE +117 -0
  4. data/README +8 -0
  5. data/Rakefile +105 -0
  6. data/bindings/SigarBuild.pm +301 -0
  7. data/bindings/SigarWrapper.pm +2978 -0
  8. data/bindings/ruby/examples/arp.rb +24 -0
  9. data/bindings/ruby/examples/cpu_info.rb +35 -0
  10. data/bindings/ruby/examples/df.rb +49 -0
  11. data/bindings/ruby/examples/free.rb +36 -0
  12. data/bindings/ruby/examples/ifconfig.rb +101 -0
  13. data/bindings/ruby/examples/logging.rb +58 -0
  14. data/bindings/ruby/examples/net_info.rb +31 -0
  15. data/bindings/ruby/examples/netstat.rb +71 -0
  16. data/bindings/ruby/examples/pargs.rb +35 -0
  17. data/bindings/ruby/examples/penv.rb +31 -0
  18. data/bindings/ruby/examples/route.rb +48 -0
  19. data/bindings/ruby/examples/version.rb +40 -0
  20. data/bindings/ruby/examples/who.rb +30 -0
  21. data/bindings/ruby/extconf.rb +131 -0
  22. data/bindings/ruby/rbsigar.c +938 -0
  23. data/bindings/ruby/test/cpu_test.rb +40 -0
  24. data/bindings/ruby/test/file_system_test.rb +43 -0
  25. data/bindings/ruby/test/helper.rb +57 -0
  26. data/bindings/ruby/test/loadavg_test.rb +30 -0
  27. data/bindings/ruby/test/mem_test.rb +45 -0
  28. data/bindings/ruby/test/swap_test.rb +36 -0
  29. data/bindings/ruby/test/uptime_test.rb +26 -0
  30. data/include/sigar.h +943 -0
  31. data/include/sigar_fileinfo.h +157 -0
  32. data/include/sigar_format.h +65 -0
  33. data/include/sigar_getline.h +18 -0
  34. data/include/sigar_log.h +80 -0
  35. data/include/sigar_private.h +422 -0
  36. data/include/sigar_ptql.h +53 -0
  37. data/include/sigar_util.h +191 -0
  38. data/src/os/aix/aix_sigar.c +2151 -0
  39. data/src/os/aix/sigar_os.h +73 -0
  40. data/src/os/darwin/Info.plist.in +27 -0
  41. data/src/os/darwin/darwin_sigar.c +3711 -0
  42. data/src/os/darwin/sigar_os.h +80 -0
  43. data/src/os/hpux/hpux_sigar.c +1342 -0
  44. data/src/os/hpux/sigar_os.h +49 -0
  45. data/src/os/linux/linux_sigar.c +2782 -0
  46. data/src/os/linux/sigar_os.h +82 -0
  47. data/src/os/solaris/get_mib2.c +321 -0
  48. data/src/os/solaris/get_mib2.h +127 -0
  49. data/src/os/solaris/kstats.c +181 -0
  50. data/src/os/solaris/procfs.c +97 -0
  51. data/src/os/solaris/sigar_os.h +224 -0
  52. data/src/os/solaris/solaris_sigar.c +2717 -0
  53. data/src/os/win32/peb.c +212 -0
  54. data/src/os/win32/sigar.rc.in +40 -0
  55. data/src/os/win32/sigar_os.h +676 -0
  56. data/src/os/win32/sigar_pdh.h +47 -0
  57. data/src/os/win32/win32_sigar.c +3992 -0
  58. data/src/sigar.c +2428 -0
  59. data/src/sigar_cache.c +179 -0
  60. data/src/sigar_fileinfo.c +815 -0
  61. data/src/sigar_format.c +696 -0
  62. data/src/sigar_getline.c +1849 -0
  63. data/src/sigar_ptql.c +1967 -0
  64. data/src/sigar_signal.c +216 -0
  65. data/src/sigar_util.c +1060 -0
  66. data/src/sigar_version.c.in +22 -0
  67. data/src/sigar_version_autoconf.c.in +22 -0
  68. data/version.properties +11 -0
  69. metadata +112 -0
@@ -0,0 +1,73 @@
1
+ /*
2
+ * Copyright (c) 2004-2007, 2009 Hyperic, Inc.
3
+ * Copyright (c) 2009 SpringSource, Inc.
4
+ * Copyright (c) 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
+ #ifndef SIGAR_OS_H
20
+ #define SIGAR_OS_H
21
+
22
+ #include <fcntl.h>
23
+ #include <errno.h>
24
+ #include <dlfcn.h>
25
+ #include <procinfo.h>
26
+ #include <sys/resource.h>
27
+
28
+ enum {
29
+ KOFFSET_LOADAVG,
30
+ KOFFSET_VAR,
31
+ KOFFSET_SYSINFO,
32
+ KOFFSET_IFNET,
33
+ KOFFSET_VMINFO,
34
+ KOFFSET_CPUINFO,
35
+ KOFFSET_TCB,
36
+ KOFFSET_ARPTABSIZE,
37
+ KOFFSET_ARPTABP,
38
+ KOFFSET_MAX
39
+ };
40
+
41
+ typedef struct {
42
+ time_t mtime;
43
+ int num;
44
+ char **devs;
45
+ } swaps_t;
46
+
47
+ typedef int (*proc_fd_func_t) (sigar_t *, sigar_pid_t, sigar_proc_fd_t *);
48
+
49
+ struct sigar_t {
50
+ SIGAR_T_BASE;
51
+ int kmem;
52
+ /* offsets for seeking on kmem */
53
+ long koffsets[KOFFSET_MAX];
54
+ proc_fd_func_t getprocfd;
55
+ int pagesize;
56
+ swaps_t swaps;
57
+ time_t last_getprocs;
58
+ sigar_pid_t last_pid;
59
+ struct procsinfo64 *pinfo;
60
+ struct cpuinfo *cpuinfo;
61
+ int cpuinfo_size;
62
+ int cpu_mhz;
63
+ char model[128];
64
+ int aix_version;
65
+ int thrusage;
66
+ sigar_cache_t *diskmap;
67
+ };
68
+
69
+ #define HAVE_STRERROR_R
70
+
71
+ #define SIGAR_EPERM_KMEM (SIGAR_OS_START_ERROR+EACCES)
72
+
73
+ #endif /* SIGAR_OS_H */
@@ -0,0 +1,27 @@
1
+ <plist version="1.0">
2
+
3
+ <dict>
4
+
5
+ <key>CFBundleDevelopmentRegion</key>
6
+
7
+ <string>English</string>
8
+
9
+ <key>CFBundleIdentifier</key>
10
+
11
+ <string>org.hyperic.sigar</string>
12
+
13
+ <key>CFBundleInfoDictionaryVersion</key>
14
+
15
+ <string>6.0</string>
16
+
17
+ <key>CFBundleName</key>
18
+
19
+ <string>sigar</string>
20
+
21
+ <key>CFBundleVersion</key>
22
+
23
+ <string>@@VERSION_STRING@@</string>
24
+
25
+ </dict>
26
+
27
+ </plist>
@@ -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 <sys/param.h>
20
+ #include <sys/mount.h>
21
+ #if !(defined(__FreeBSD__) && (__FreeBSD_version >= 800000))
22
+ #include <nfs/rpcv2.h>
23
+ #endif
24
+ #include <nfs/nfsproto.h>
25
+
26
+ #ifdef DARWIN
27
+ #include <dlfcn.h>
28
+ #include <mach/mach_init.h>
29
+ #include <mach/message.h>
30
+ #include <mach/kern_return.h>
31
+ #include <mach/mach_host.h>
32
+ #include <mach/mach_traps.h>
33
+ #include <mach/mach_port.h>
34
+ #include <mach/task.h>
35
+ #include <mach/thread_act.h>
36
+ #include <mach/thread_info.h>
37
+ #include <mach/vm_map.h>
38
+ #if !defined(HAVE_SHARED_REGION_H) && defined(__MAC_10_5) /* see Availability.h */
39
+ # define HAVE_SHARED_REGION_H /* suckit autoconf */
40
+ #endif
41
+ #ifdef HAVE_SHARED_REGION_H
42
+ #include <mach/shared_region.h> /* does not exist in 10.4 SDK */
43
+ #else
44
+ #include <mach/shared_memory_server.h> /* deprecated in Leopard */
45
+ #endif
46
+ #include <mach-o/dyld.h>
47
+ #define __OPENTRANSPORTPROVIDERS__
48
+ #include <CoreServices/CoreServices.h>
49
+ #include <CoreFoundation/CoreFoundation.h>
50
+ #include <IOKit/IOBSD.h>
51
+ #include <IOKit/IOKitLib.h>
52
+ #include <IOKit/IOTypes.h>
53
+ #include <IOKit/storage/IOBlockStorageDriver.h>
54
+ #else
55
+ #include <sys/dkstat.h>
56
+ #include <sys/types.h>
57
+ #include <sys/param.h>
58
+ #include <sys/user.h>
59
+ #include <sys/vmmeter.h>
60
+ #include <fcntl.h>
61
+ #include <stdio.h>
62
+ #endif
63
+
64
+ #if defined(__FreeBSD__) && (__FreeBSD_version >= 500013)
65
+ #define SIGAR_FREEBSD5_NFSSTAT
66
+ #include <nfsclient/nfs.h>
67
+ #include <nfsserver/nfs.h>
68
+ #else
69
+ #include <nfs/nfs.h>
70
+ #endif
71
+
72
+ #include <sys/ioctl.h>
73
+ #include <sys/mount.h>
74
+ #include <sys/resource.h>
75
+ #include <sys/stat.h>
76
+ #include <sys/socket.h>
77
+ #include <sys/sockio.h>
78
+
79
+ #include <net/if.h>
80
+ #include <net/if_dl.h>
81
+ #include <net/if_types.h>
82
+ #include <net/route.h>
83
+ #include <netinet/in.h>
84
+ #include <netinet/if_ether.h>
85
+
86
+ #include <dirent.h>
87
+ #include <errno.h>
88
+
89
+ #include <sys/socketvar.h>
90
+ #include <netinet/in.h>
91
+ #include <netinet/in_systm.h>
92
+ #include <netinet/ip.h>
93
+ #include <netinet/in_pcb.h>
94
+ #include <netinet/tcp.h>
95
+ #include <netinet/tcp_timer.h>
96
+ #ifdef __NetBSD__
97
+ #include <netinet/ip_var.h>
98
+ #include <sys/lwp.h>
99
+ #include <sys/mount.h>
100
+ #define SRUN LSRUN
101
+ #define SSLEEP LSSLEEP
102
+ #define SDEAD LSDEAD
103
+ #define SONPROC LSONPROC
104
+ #define SSUSPENDED LSSUSPENDED
105
+ #include <sys/sched.h>
106
+ #endif
107
+ #include <netinet/tcp_var.h>
108
+ #include <netinet/tcp_fsm.h>
109
+
110
+ #include "sigar.h"
111
+ #include "sigar_private.h"
112
+ #include "sigar_util.h"
113
+ #include "sigar_os.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
+ }