sigar 0.7.0

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