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