sigar 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/README +2 -0
  2. data/Rakefile +105 -0
  3. data/bindings/SigarBuild.pm +310 -0
  4. data/bindings/SigarWrapper.pm +2978 -0
  5. data/bindings/ruby/examples/arp.rb +24 -0
  6. data/bindings/ruby/examples/cpu_info.rb +35 -0
  7. data/bindings/ruby/examples/df.rb +49 -0
  8. data/bindings/ruby/examples/free.rb +36 -0
  9. data/bindings/ruby/examples/ifconfig.rb +101 -0
  10. data/bindings/ruby/examples/logging.rb +58 -0
  11. data/bindings/ruby/examples/net_info.rb +31 -0
  12. data/bindings/ruby/examples/netstat.rb +71 -0
  13. data/bindings/ruby/examples/pargs.rb +35 -0
  14. data/bindings/ruby/examples/penv.rb +31 -0
  15. data/bindings/ruby/examples/route.rb +48 -0
  16. data/bindings/ruby/examples/version.rb +40 -0
  17. data/bindings/ruby/examples/who.rb +30 -0
  18. data/bindings/ruby/extconf.rb +128 -0
  19. data/bindings/ruby/rbsigar.c +888 -0
  20. data/bindings/ruby/test/cpu_test.rb +40 -0
  21. data/bindings/ruby/test/file_system_test.rb +43 -0
  22. data/bindings/ruby/test/helper.rb +57 -0
  23. data/bindings/ruby/test/loadavg_test.rb +30 -0
  24. data/bindings/ruby/test/mem_test.rb +45 -0
  25. data/bindings/ruby/test/swap_test.rb +36 -0
  26. data/bindings/ruby/test/uptime_test.rb +26 -0
  27. data/include/sigar.h +939 -0
  28. data/include/sigar_fileinfo.h +157 -0
  29. data/include/sigar_format.h +65 -0
  30. data/include/sigar_getline.h +18 -0
  31. data/include/sigar_log.h +80 -0
  32. data/include/sigar_private.h +422 -0
  33. data/include/sigar_ptql.h +53 -0
  34. data/include/sigar_util.h +191 -0
  35. data/src/os/aix/aix_sigar.c +2151 -0
  36. data/src/os/aix/sigar_os.h +73 -0
  37. data/src/os/darwin/Info.plist.in +27 -0
  38. data/src/os/darwin/darwin_sigar.c +3709 -0
  39. data/src/os/darwin/sigar_os.h +80 -0
  40. data/src/os/hpux/hpux_sigar.c +1342 -0
  41. data/src/os/hpux/sigar_os.h +49 -0
  42. data/src/os/linux/linux_sigar.c +2782 -0
  43. data/src/os/linux/sigar_os.h +82 -0
  44. data/src/os/solaris/get_mib2.c +321 -0
  45. data/src/os/solaris/get_mib2.h +127 -0
  46. data/src/os/solaris/kstats.c +181 -0
  47. data/src/os/solaris/procfs.c +97 -0
  48. data/src/os/solaris/sigar_os.h +224 -0
  49. data/src/os/solaris/solaris_sigar.c +2717 -0
  50. data/src/os/win32/peb.c +212 -0
  51. data/src/os/win32/sigar.rc.in +40 -0
  52. data/src/os/win32/sigar_os.h +653 -0
  53. data/src/os/win32/sigar_pdh.h +47 -0
  54. data/src/os/win32/win32_sigar.c +3911 -0
  55. data/src/sigar.c +2428 -0
  56. data/src/sigar_cache.c +179 -0
  57. data/src/sigar_fileinfo.c +815 -0
  58. data/src/sigar_format.c +696 -0
  59. data/src/sigar_getline.c +1849 -0
  60. data/src/sigar_ptql.c +1967 -0
  61. data/src/sigar_signal.c +216 -0
  62. data/src/sigar_util.c +1060 -0
  63. data/src/sigar_version.c.in +22 -0
  64. data/src/sigar_version_autoconf.c.in +22 -0
  65. data/version.properties +11 -0
  66. metadata +131 -0
@@ -0,0 +1,49 @@
1
+ /*
2
+ * Copyright (c) 2004-2007 Hyperic, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #ifndef SIGAR_OS_H
18
+ #define SIGAR_OS_H
19
+
20
+ #if defined(__ia64) && !defined(__ia64__)
21
+ #define __ia64__
22
+ #endif
23
+
24
+ #ifdef __ia64__
25
+ #ifndef _LP64
26
+ #define _LP64
27
+ #endif
28
+ #endif
29
+
30
+ #define _PSTAT64
31
+
32
+ #include <sys/pstat.h>
33
+ #include <sys/mib.h>
34
+ #include <stdlib.h>
35
+ #include <fcntl.h>
36
+
37
+ struct sigar_t {
38
+ SIGAR_T_BASE;
39
+ struct pst_static pstatic;
40
+ time_t last_getprocs;
41
+ sigar_pid_t last_pid;
42
+ struct pst_status *pinfo;
43
+
44
+ int mib;
45
+ };
46
+
47
+ int hpux_get_mib_ifentry(int ppa, mib_ifEntry *mib);
48
+
49
+ #endif /* SIGAR_OS_H */
@@ -0,0 +1,2782 @@
1
+ /*
2
+ * Copyright (c) 2004-2009 Hyperic, Inc.
3
+ * Copyright (c) 2009 SpringSource, Inc.
4
+ * Copyright (c) 2009-2010 VMware, Inc.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ #include <dirent.h>
20
+ #include <stdio.h>
21
+ #include <stdlib.h>
22
+ #include <errno.h>
23
+ #include <sys/param.h>
24
+ #include <sys/stat.h>
25
+ #include <sys/times.h>
26
+ #include <sys/utsname.h>
27
+
28
+ #include "sigar.h"
29
+ #include "sigar_private.h"
30
+ #include "sigar_util.h"
31
+ #include "sigar_os.h"
32
+
33
+ #define pageshift(x) ((x) << sigar->pagesize)
34
+
35
+ #define PROC_MEMINFO PROC_FS_ROOT "meminfo"
36
+ #define PROC_VMSTAT PROC_FS_ROOT "vmstat"
37
+ #define PROC_MTRR PROC_FS_ROOT "mtrr"
38
+ #define PROC_STAT PROC_FS_ROOT "stat"
39
+ #define PROC_UPTIME PROC_FS_ROOT "uptime"
40
+ #define PROC_LOADAVG PROC_FS_ROOT "loadavg"
41
+
42
+ #define PROC_PSTAT "/stat"
43
+ #define PROC_PSTATUS "/status"
44
+
45
+ #define SYS_BLOCK "/sys/block"
46
+ #define PROC_PARTITIONS PROC_FS_ROOT "partitions"
47
+ #define PROC_DISKSTATS PROC_FS_ROOT "diskstats"
48
+
49
+ /*
50
+ * /proc/self/stat fields:
51
+ * 1 - pid
52
+ * 2 - comm
53
+ * 3 - state
54
+ * 4 - ppid
55
+ * 5 - pgrp
56
+ * 6 - session
57
+ * 7 - tty_nr
58
+ * 8 - tpgid
59
+ * 9 - flags
60
+ * 10 - minflt
61
+ * 11 - cminflt
62
+ * 12 - majflt
63
+ * 13 - cmajflt
64
+ * 14 - utime
65
+ * 15 - stime
66
+ * 16 - cutime
67
+ * 17 - cstime
68
+ * 18 - priority
69
+ * 19 - nice
70
+ * 20 - 0 (removed field)
71
+ * 21 - itrealvalue
72
+ * 22 - starttime
73
+ * 23 - vsize
74
+ * 24 - rss
75
+ * 25 - rlim
76
+ * 26 - startcode
77
+ * 27 - endcode
78
+ * 28 - startstack
79
+ * 29 - kstkesp
80
+ * 30 - kstkeip
81
+ * 31 - signal
82
+ * 32 - blocked
83
+ * 33 - sigignore
84
+ * 34 - sigcache
85
+ * 35 - wchan
86
+ * 36 - nswap
87
+ * 37 - cnswap
88
+ * 38 - exit_signal <-- looking for this.
89
+ * 39 - processor
90
+ * ... more for newer RH
91
+ */
92
+
93
+ #define PROC_SIGNAL_IX 38
94
+
95
+ static int get_proc_signal_offset(void)
96
+ {
97
+ char buffer[BUFSIZ], *ptr=buffer;
98
+ int fields = 0;
99
+ int status = sigar_file2str(PROCP_FS_ROOT "self/stat",
100
+ buffer, sizeof(buffer));
101
+
102
+ if (status != SIGAR_OK) {
103
+ return 1;
104
+ }
105
+
106
+ while (*ptr) {
107
+ if (*ptr++ == ' ') {
108
+ fields++;
109
+ }
110
+ }
111
+
112
+ return (fields - PROC_SIGNAL_IX) + 1;
113
+ }
114
+
115
+ sigar_pid_t sigar_pid_get(sigar_t *sigar)
116
+ {
117
+ /* XXX cannot safely cache getpid unless using nptl */
118
+ /* we can however, cache it for optimizations in the
119
+ * case of proc_env_get for example.
120
+ */
121
+ sigar->pid = getpid();
122
+ return sigar->pid;
123
+ }
124
+
125
+ static int sigar_boot_time_get(sigar_t *sigar)
126
+ {
127
+ FILE *fp;
128
+ char buffer[BUFSIZ], *ptr;
129
+ int found = 0;
130
+
131
+ if (!(fp = fopen(PROC_STAT, "r"))) {
132
+ return errno;
133
+ }
134
+
135
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
136
+ if (strnEQ(ptr, "btime", 5)) {
137
+ if ((ptr = sigar_skip_token(ptr))) {
138
+ sigar->boot_time = sigar_strtoul(ptr);
139
+ found = 1;
140
+ }
141
+ break;
142
+ }
143
+ }
144
+
145
+ fclose(fp);
146
+
147
+ if (!found) {
148
+ /* should never happen */
149
+ sigar->boot_time = time(NULL);
150
+ }
151
+
152
+ return SIGAR_OK;
153
+ }
154
+
155
+ int sigar_os_open(sigar_t **sigar)
156
+ {
157
+ int i, status;
158
+ int kernel_rev, has_nptl;
159
+ struct stat sb;
160
+ struct utsname name;
161
+
162
+ *sigar = malloc(sizeof(**sigar));
163
+
164
+ (*sigar)->pagesize = 0;
165
+ i = getpagesize();
166
+ while ((i >>= 1) > 0) {
167
+ (*sigar)->pagesize++;
168
+ }
169
+
170
+ status = sigar_boot_time_get(*sigar);
171
+ if (status != SIGAR_OK) {
172
+ return status;
173
+ }
174
+
175
+ (*sigar)->ticks = sysconf(_SC_CLK_TCK);
176
+
177
+ (*sigar)->ram = -1;
178
+
179
+ (*sigar)->proc_signal_offset = -1;
180
+
181
+ (*sigar)->last_proc_stat.pid = -1;
182
+
183
+ (*sigar)->lcpu = -1;
184
+
185
+ if (stat(PROC_DISKSTATS, &sb) == 0) {
186
+ (*sigar)->iostat = IOSTAT_DISKSTATS;
187
+ }
188
+ else if (stat(SYS_BLOCK, &sb) == 0) {
189
+ (*sigar)->iostat = IOSTAT_SYS;
190
+ }
191
+ else if (stat(PROC_PARTITIONS, &sb) == 0) {
192
+ /* XXX file exists does not mean is has the fields */
193
+ (*sigar)->iostat = IOSTAT_PARTITIONS;
194
+ }
195
+ else {
196
+ (*sigar)->iostat = IOSTAT_NONE;
197
+ }
198
+
199
+ /* hook for using mirrored /proc/net/tcp file */
200
+ (*sigar)->proc_net = getenv("SIGAR_PROC_NET");
201
+
202
+ uname(&name);
203
+ /* 2.X.y.z -> just need X (unless there is ever a kernel version 3!) */
204
+ kernel_rev = atoi(&name.release[2]);
205
+ if (kernel_rev >= 6) {
206
+ has_nptl = 1;
207
+ }
208
+ else {
209
+ has_nptl = getenv("SIGAR_HAS_NPTL") ? 1 : 0;
210
+ }
211
+ (*sigar)->has_nptl = has_nptl;
212
+
213
+ return SIGAR_OK;
214
+ }
215
+
216
+ int sigar_os_close(sigar_t *sigar)
217
+ {
218
+ free(sigar);
219
+ return SIGAR_OK;
220
+ }
221
+
222
+ char *sigar_os_error_string(sigar_t *sigar, int err)
223
+ {
224
+ return NULL;
225
+ }
226
+
227
+ static int sigar_cpu_total_count(sigar_t *sigar)
228
+ {
229
+ sigar->ncpu = (int)sysconf(_SC_NPROCESSORS_CONF);
230
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[cpu] ncpu=%d\n",
231
+ sigar->ncpu);
232
+ return sigar->ncpu;
233
+ }
234
+
235
+ static int get_ram(sigar_t *sigar, sigar_mem_t *mem)
236
+ {
237
+ char buffer[BUFSIZ], *ptr;
238
+ FILE *fp;
239
+ int total = 0;
240
+ sigar_uint64_t sys_total = (mem->total / (1024 * 1024));
241
+
242
+ if (sigar->ram > 0) {
243
+ /* return cached value */
244
+ mem->ram = sigar->ram;
245
+ return SIGAR_OK;
246
+ }
247
+
248
+ if (sigar->ram == 0) {
249
+ return ENOENT;
250
+ }
251
+
252
+ /*
253
+ * Memory Type Range Registers
254
+ * write-back registers add up to the total.
255
+ * Well, they are supposed to add up, but seen
256
+ * at least one configuration where that is not the
257
+ * case.
258
+ */
259
+ if (!(fp = fopen(PROC_MTRR, "r"))) {
260
+ return errno;
261
+ }
262
+
263
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
264
+ if (!(ptr = strstr(ptr, "size="))) {
265
+ continue;
266
+ }
267
+
268
+ if (!strstr(ptr, "write-back")) {
269
+ continue;
270
+ }
271
+
272
+ ptr += 5;
273
+ while (sigar_isspace(*ptr)) {
274
+ ++ptr;
275
+ }
276
+
277
+ total += atoi(ptr);
278
+ }
279
+
280
+ fclose(fp);
281
+
282
+ if ((total - sys_total) > 256) {
283
+ /* mtrr write-back registers are way off
284
+ * kernel should not be using more that 256MB of mem
285
+ */
286
+ total = 0; /* punt */
287
+ }
288
+
289
+ if (total == 0) {
290
+ return ENOENT;
291
+ }
292
+
293
+ mem->ram = sigar->ram = total;
294
+
295
+ return SIGAR_OK;
296
+ }
297
+
298
+ #define MEMINFO_PARAM(a) a ":", SSTRLEN(a ":")
299
+
300
+ static SIGAR_INLINE sigar_uint64_t sigar_meminfo(char *buffer,
301
+ char *attr, int len)
302
+ {
303
+ sigar_uint64_t val = 0;
304
+ char *ptr, *tok;
305
+
306
+ if ((ptr = strstr(buffer, attr))) {
307
+ ptr += len;
308
+ val = strtoull(ptr, &tok, 0);
309
+ while (*tok == ' ') {
310
+ ++tok;
311
+ }
312
+ if (*tok == 'k') {
313
+ val *= 1024;
314
+ }
315
+ else if (*tok == 'M') {
316
+ val *= (1024 * 1024);
317
+ }
318
+ }
319
+
320
+ return val;
321
+ }
322
+
323
+ int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
324
+ {
325
+ sigar_uint64_t buffers, cached, kern;
326
+ char buffer[BUFSIZ];
327
+
328
+ int status = sigar_file2str(PROC_MEMINFO,
329
+ buffer, sizeof(buffer));
330
+
331
+ if (status != SIGAR_OK) {
332
+ return status;
333
+ }
334
+
335
+ mem->total = sigar_meminfo(buffer, MEMINFO_PARAM("MemTotal"));
336
+ mem->free = sigar_meminfo(buffer, MEMINFO_PARAM("MemFree"));
337
+ mem->used = mem->total - mem->free;
338
+
339
+ buffers = sigar_meminfo(buffer, MEMINFO_PARAM("Buffers"));
340
+ cached = sigar_meminfo(buffer, MEMINFO_PARAM("Cached"));
341
+
342
+ kern = buffers + cached;
343
+ mem->actual_free = mem->free + kern;
344
+ mem->actual_used = mem->used - kern;
345
+
346
+ sigar_mem_calc_ram(sigar, mem);
347
+
348
+ if (get_ram(sigar, mem) != SIGAR_OK) {
349
+ /* XXX other options on failure? */
350
+ }
351
+
352
+ return SIGAR_OK;
353
+ }
354
+
355
+ int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
356
+ {
357
+ char buffer[BUFSIZ], *ptr;
358
+
359
+ /* XXX: we open/parse the same file here as sigar_mem_get */
360
+ int status = sigar_file2str(PROC_MEMINFO,
361
+ buffer, sizeof(buffer));
362
+
363
+ if (status != SIGAR_OK) {
364
+ return status;
365
+ }
366
+
367
+ swap->total = sigar_meminfo(buffer, MEMINFO_PARAM("SwapTotal"));
368
+ swap->free = sigar_meminfo(buffer, MEMINFO_PARAM("SwapFree"));
369
+ swap->used = swap->total - swap->free;
370
+
371
+ swap->page_in = swap->page_out = -1;
372
+
373
+ status = sigar_file2str(PROC_VMSTAT,
374
+ buffer, sizeof(buffer));
375
+
376
+ if (status == SIGAR_OK) {
377
+ /* 2.6+ kernel */
378
+ if ((ptr = strstr(buffer, "\npswpin"))) {
379
+ ptr = sigar_skip_token(ptr);
380
+ swap->page_in = sigar_strtoull(ptr);
381
+ ptr = sigar_skip_token(ptr);
382
+ swap->page_out = sigar_strtoull(ptr);
383
+ }
384
+ }
385
+ else {
386
+ /* 2.2, 2.4 kernels */
387
+ status = sigar_file2str(PROC_STAT,
388
+ buffer, sizeof(buffer));
389
+ if (status != SIGAR_OK) {
390
+ return status;
391
+ }
392
+
393
+ if ((ptr = strstr(buffer, "\nswap"))) {
394
+ ptr = sigar_skip_token(ptr);
395
+ swap->page_in = sigar_strtoull(ptr);
396
+ swap->page_out = sigar_strtoull(ptr);
397
+ }
398
+ }
399
+
400
+ return SIGAR_OK;
401
+ }
402
+
403
+ static void get_cpu_metrics(sigar_t *sigar, sigar_cpu_t *cpu, char *line)
404
+ {
405
+ char *ptr = sigar_skip_token(line); /* "cpu%d" */
406
+
407
+ cpu->user += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
408
+ cpu->nice += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
409
+ cpu->sys += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
410
+ cpu->idle += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
411
+ if (*ptr == ' ') {
412
+ /* 2.6+ kernels only */
413
+ cpu->wait += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
414
+ cpu->irq += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
415
+ cpu->soft_irq += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
416
+ }
417
+ if (*ptr == ' ') {
418
+ /* 2.6.11+ kernels only */
419
+ cpu->stolen += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
420
+ }
421
+ cpu->total =
422
+ cpu->user + cpu->nice + cpu->sys + cpu->idle +
423
+ cpu->wait + cpu->irq + cpu->soft_irq + cpu->stolen;
424
+ }
425
+
426
+ int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
427
+ {
428
+ char buffer[BUFSIZ];
429
+ int status = sigar_file2str(PROC_STAT, buffer, sizeof(buffer));
430
+
431
+ if (status != SIGAR_OK) {
432
+ return status;
433
+ }
434
+
435
+ SIGAR_ZERO(cpu);
436
+ get_cpu_metrics(sigar, cpu, buffer);
437
+
438
+ return SIGAR_OK;
439
+ }
440
+
441
+ int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
442
+ {
443
+ FILE *fp;
444
+ char buffer[BUFSIZ], cpu_total[BUFSIZ], *ptr;
445
+ int core_rollup = sigar_cpu_core_rollup(sigar), i=0;
446
+ sigar_cpu_t *cpu;
447
+
448
+ if (!(fp = fopen(PROC_STAT, "r"))) {
449
+ return errno;
450
+ }
451
+
452
+ /* skip first line */
453
+ (void)fgets(cpu_total, sizeof(cpu_total), fp);
454
+
455
+ sigar_cpu_list_create(cpulist);
456
+
457
+ /* XXX: merge times of logical processors if hyperthreading */
458
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
459
+ if (!strnEQ(ptr, "cpu", 3)) {
460
+ break;
461
+ }
462
+
463
+ if (core_rollup && (i % sigar->lcpu)) {
464
+ /* merge times of logical processors */
465
+ cpu = &cpulist->data[cpulist->number-1];
466
+ }
467
+ else {
468
+ SIGAR_CPU_LIST_GROW(cpulist);
469
+ cpu = &cpulist->data[cpulist->number++];
470
+ SIGAR_ZERO(cpu);
471
+ }
472
+
473
+ get_cpu_metrics(sigar, cpu, ptr);
474
+
475
+ i++;
476
+ }
477
+
478
+ fclose(fp);
479
+
480
+ if (cpulist->number == 0) {
481
+ /* likely older kernel where cpu\d is not present */
482
+ cpu = &cpulist->data[cpulist->number++];
483
+ SIGAR_ZERO(cpu);
484
+ get_cpu_metrics(sigar, cpu, cpu_total);
485
+ }
486
+
487
+ return SIGAR_OK;
488
+ }
489
+
490
+ int sigar_uptime_get(sigar_t *sigar,
491
+ sigar_uptime_t *uptime)
492
+ {
493
+ char buffer[BUFSIZ], *ptr = buffer;
494
+ int status = sigar_file2str(PROC_UPTIME, buffer, sizeof(buffer));
495
+
496
+ if (status != SIGAR_OK) {
497
+ return status;
498
+ }
499
+
500
+ uptime->uptime = strtod(buffer, &ptr);
501
+
502
+ return SIGAR_OK;
503
+ }
504
+
505
+ int sigar_loadavg_get(sigar_t *sigar,
506
+ sigar_loadavg_t *loadavg)
507
+ {
508
+ char buffer[BUFSIZ], *ptr = buffer;
509
+ int status = sigar_file2str(PROC_LOADAVG, buffer, sizeof(buffer));
510
+
511
+ if (status != SIGAR_OK) {
512
+ return status;
513
+ }
514
+
515
+ loadavg->loadavg[0] = strtod(buffer, &ptr);
516
+ loadavg->loadavg[1] = strtod(ptr, &ptr);
517
+ loadavg->loadavg[2] = strtod(ptr, &ptr);
518
+
519
+ return SIGAR_OK;
520
+ }
521
+
522
+ /*
523
+ * seems the easiest/fastest way to tell if a process listed in /proc
524
+ * is a thread is to check the "exit signal" flag in /proc/num/stat.
525
+ * any value other than SIGCHLD seems to be a thread. this make hulk mad.
526
+ * redhat's procps patch (named "threadbadhack.pat") does not use
527
+ * this flag to filter out threads. instead does much more expensive
528
+ * comparisions. their patch also bubbles up thread cpu times to the main
529
+ * process. functionality we currently lack.
530
+ * when nptl is in use, this is not the case and all threads spawned from
531
+ * a process have the same pid. however, it seems both old-style linux
532
+ * threads and nptl threads can be run on the same machine.
533
+ * there is also the "Tgid" field in /proc/self/status which could be used
534
+ * to detect threads, but this is not available in older kernels.
535
+ */
536
+ static SIGAR_INLINE int proc_isthread(sigar_t *sigar, char *pidstr, int len)
537
+ {
538
+ char buffer[BUFSIZ], *ptr=buffer;
539
+ int fd, n, offset=sigar->proc_signal_offset;
540
+
541
+ /* sprintf(buffer, "/proc/%s/stat", pidstr) */
542
+ memcpy(ptr, PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT));
543
+ ptr += SSTRLEN(PROCP_FS_ROOT);
544
+
545
+ memcpy(ptr, pidstr, len);
546
+ ptr += len;
547
+
548
+ memcpy(ptr, PROC_PSTAT, SSTRLEN(PROC_PSTAT));
549
+ ptr += SSTRLEN(PROC_PSTAT);
550
+
551
+ *ptr = '\0';
552
+
553
+ if ((fd = open(buffer, O_RDONLY)) < 0) {
554
+ /* unlikely if pid was from readdir proc */
555
+ return 0;
556
+ }
557
+
558
+ n = read(fd, buffer, sizeof(buffer));
559
+ close(fd);
560
+
561
+ if (n < 0) {
562
+ return 0; /* chances: slim..none */
563
+ }
564
+
565
+ buffer[n--] = '\0';
566
+
567
+ /* exit_signal is the second to last field so we look backwards.
568
+ * XXX if newer kernels drop more turds in this file we'll need
569
+ * to go the other way. luckily linux has no real api for this shit.
570
+ */
571
+
572
+ /* skip trailing crap */
573
+ while ((n > 0) && !isdigit(buffer[n--])) ;
574
+
575
+ while (offset-- > 0) {
576
+ /* skip last field */
577
+ while ((n > 0) && isdigit(buffer[n--])) ;
578
+
579
+ /* skip whitespace */
580
+ while ((n > 0) && !isdigit(buffer[n--])) ;
581
+ }
582
+
583
+ if (n < 3) {
584
+ return 0; /* hulk smashed /proc? */
585
+ }
586
+
587
+ ptr = &buffer[n];
588
+ /*
589
+ * '17' == SIGCHLD == real process.
590
+ * '33' and '0' are threads
591
+ */
592
+ if ((*ptr++ == '1') &&
593
+ (*ptr++ == '7') &&
594
+ (*ptr++ == ' '))
595
+ {
596
+ return 0;
597
+ }
598
+
599
+ return 1;
600
+ }
601
+
602
+ int sigar_os_proc_list_get(sigar_t *sigar,
603
+ sigar_proc_list_t *proclist)
604
+ {
605
+ DIR *dirp = opendir(PROCP_FS_ROOT);
606
+ struct dirent *ent, dbuf;
607
+ register const int threadbadhack = !sigar->has_nptl;
608
+
609
+ if (!dirp) {
610
+ return errno;
611
+ }
612
+
613
+ if (threadbadhack && (sigar->proc_signal_offset == -1)) {
614
+ sigar->proc_signal_offset = get_proc_signal_offset();
615
+ }
616
+
617
+ while (readdir_r(dirp, &dbuf, &ent) == 0) {
618
+ if (!ent) {
619
+ break;
620
+ }
621
+
622
+ if (!sigar_isdigit(*ent->d_name)) {
623
+ continue;
624
+ }
625
+
626
+ if (threadbadhack &&
627
+ proc_isthread(sigar, ent->d_name, strlen(ent->d_name)))
628
+ {
629
+ continue;
630
+ }
631
+
632
+ /* XXX: more sanity checking */
633
+
634
+ SIGAR_PROC_LIST_GROW(proclist);
635
+
636
+ proclist->data[proclist->number++] =
637
+ strtoul(ent->d_name, NULL, 10);
638
+ }
639
+
640
+ closedir(dirp);
641
+
642
+ return SIGAR_OK;
643
+ }
644
+
645
+ static int proc_stat_read(sigar_t *sigar, sigar_pid_t pid)
646
+ {
647
+ char buffer[BUFSIZ], *ptr=buffer, *tmp;
648
+ unsigned int len;
649
+ linux_proc_stat_t *pstat = &sigar->last_proc_stat;
650
+ int status;
651
+
652
+ time_t timenow = time(NULL);
653
+
654
+ /*
655
+ * short-lived cache read/parse of last /proc/pid/stat
656
+ * as this info is spread out across a few functions.
657
+ */
658
+ if (pstat->pid == pid) {
659
+ if ((timenow - pstat->mtime) < SIGAR_LAST_PROC_EXPIRE) {
660
+ return SIGAR_OK;
661
+ }
662
+ }
663
+
664
+ pstat->pid = pid;
665
+ pstat->mtime = timenow;
666
+
667
+ status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTAT);
668
+
669
+ if (status != SIGAR_OK) {
670
+ return status;
671
+ }
672
+
673
+ if (!(ptr = strchr(ptr, '('))) {
674
+ return EINVAL;
675
+ }
676
+ if (!(tmp = strrchr(++ptr, ')'))) {
677
+ return EINVAL;
678
+ }
679
+ len = tmp-ptr;
680
+
681
+ if (len >= sizeof(pstat->name)) {
682
+ len = sizeof(pstat->name)-1;
683
+ }
684
+
685
+ /* (1,2) */
686
+ memcpy(pstat->name, ptr, len);
687
+ pstat->name[len] = '\0';
688
+ ptr = tmp+1;
689
+
690
+ SIGAR_SKIP_SPACE(ptr);
691
+ pstat->state = *ptr++; /* (3) */
692
+ SIGAR_SKIP_SPACE(ptr);
693
+
694
+ pstat->ppid = sigar_strtoul(ptr); /* (4) */
695
+ ptr = sigar_skip_token(ptr); /* (5) pgrp */
696
+ ptr = sigar_skip_token(ptr); /* (6) session */
697
+ pstat->tty = sigar_strtoul(ptr); /* (7) */
698
+ ptr = sigar_skip_token(ptr); /* (8) tty pgrp */
699
+
700
+ ptr = sigar_skip_token(ptr); /* (9) flags */
701
+ pstat->minor_faults = sigar_strtoull(ptr); /* (10) */
702
+ ptr = sigar_skip_token(ptr); /* (11) cmin flt */
703
+ pstat->major_faults = sigar_strtoull(ptr); /* (12) */
704
+ ptr = sigar_skip_token(ptr); /* (13) cmaj flt */
705
+
706
+ pstat->utime = SIGAR_TICK2MSEC(sigar_strtoull(ptr)); /* (14) */
707
+ pstat->stime = SIGAR_TICK2MSEC(sigar_strtoull(ptr)); /* (15) */
708
+
709
+ ptr = sigar_skip_token(ptr); /* (16) cutime */
710
+ ptr = sigar_skip_token(ptr); /* (17) cstime */
711
+
712
+ pstat->priority = sigar_strtoul(ptr); /* (18) */
713
+ pstat->nice = sigar_strtoul(ptr); /* (19) */
714
+
715
+ ptr = sigar_skip_token(ptr); /* (20) timeout */
716
+ ptr = sigar_skip_token(ptr); /* (21) it_real_value */
717
+
718
+ pstat->start_time = sigar_strtoul(ptr); /* (22) */
719
+ pstat->start_time /= sigar->ticks;
720
+ pstat->start_time += sigar->boot_time; /* seconds */
721
+ pstat->start_time *= 1000; /* milliseconds */
722
+
723
+ pstat->vsize = sigar_strtoull(ptr); /* (23) */
724
+ pstat->rss = pageshift(sigar_strtoull(ptr)); /* (24) */
725
+
726
+ ptr = sigar_skip_token(ptr); /* (25) rlim */
727
+ ptr = sigar_skip_token(ptr); /* (26) startcode */
728
+ ptr = sigar_skip_token(ptr); /* (27) endcode */
729
+ ptr = sigar_skip_token(ptr); /* (28) startstack */
730
+ ptr = sigar_skip_token(ptr); /* (29) kstkesp */
731
+ ptr = sigar_skip_token(ptr); /* (30) kstkeip */
732
+ ptr = sigar_skip_token(ptr); /* (31) signal */
733
+ ptr = sigar_skip_token(ptr); /* (32) blocked */
734
+ ptr = sigar_skip_token(ptr); /* (33) sigignore */
735
+ ptr = sigar_skip_token(ptr); /* (34) sigcache */
736
+ ptr = sigar_skip_token(ptr); /* (35) wchan */
737
+ ptr = sigar_skip_token(ptr); /* (36) nswap */
738
+ ptr = sigar_skip_token(ptr); /* (37) cnswap */
739
+ ptr = sigar_skip_token(ptr); /* (38) exit_signal */
740
+
741
+ pstat->processor = sigar_strtoul(ptr); /* (39) */
742
+
743
+ return SIGAR_OK;
744
+ }
745
+
746
+ int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
747
+ sigar_proc_mem_t *procmem)
748
+ {
749
+ char buffer[BUFSIZ], *ptr=buffer;
750
+ int status = proc_stat_read(sigar, pid);
751
+ linux_proc_stat_t *pstat = &sigar->last_proc_stat;
752
+
753
+ procmem->minor_faults = pstat->minor_faults;
754
+ procmem->major_faults = pstat->major_faults;
755
+ procmem->page_faults =
756
+ procmem->minor_faults + procmem->major_faults;
757
+
758
+ status = SIGAR_PROC_FILE2STR(buffer, pid, "/statm");
759
+
760
+ if (status != SIGAR_OK) {
761
+ return status;
762
+ }
763
+
764
+ procmem->size = pageshift(sigar_strtoull(ptr));
765
+ procmem->resident = pageshift(sigar_strtoull(ptr));
766
+ procmem->share = pageshift(sigar_strtoull(ptr));
767
+
768
+ return SIGAR_OK;
769
+ }
770
+
771
+ #define NO_ID_MSG "[proc_cred] /proc/%lu" PROC_PSTATUS " missing "
772
+
773
+ int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
774
+ sigar_proc_cred_t *proccred)
775
+ {
776
+ char buffer[BUFSIZ], *ptr;
777
+ int status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTATUS);
778
+
779
+ if (status != SIGAR_OK) {
780
+ return status;
781
+ }
782
+
783
+ if ((ptr = strstr(buffer, "\nUid:"))) {
784
+ ptr = sigar_skip_token(ptr);
785
+
786
+ proccred->uid = sigar_strtoul(ptr);
787
+ proccred->euid = sigar_strtoul(ptr);
788
+ }
789
+ else {
790
+ sigar_log_printf(sigar, SIGAR_LOG_WARN,
791
+ NO_ID_MSG "Uid", pid);
792
+ return ENOENT;
793
+ }
794
+
795
+ if ((ptr = strstr(ptr, "\nGid:"))) {
796
+ ptr = sigar_skip_token(ptr);
797
+
798
+ proccred->gid = sigar_strtoul(ptr);
799
+ proccred->egid = sigar_strtoul(ptr);
800
+ }
801
+ else {
802
+ sigar_log_printf(sigar, SIGAR_LOG_WARN,
803
+ NO_ID_MSG "Gid", pid);
804
+ return ENOENT;
805
+ }
806
+
807
+ return SIGAR_OK;
808
+ }
809
+
810
+ int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
811
+ sigar_proc_time_t *proctime)
812
+ {
813
+ int status = proc_stat_read(sigar, pid);
814
+ linux_proc_stat_t *pstat = &sigar->last_proc_stat;
815
+
816
+ if (status != SIGAR_OK) {
817
+ return status;
818
+ }
819
+
820
+ proctime->user = pstat->utime;
821
+ proctime->sys = pstat->stime;
822
+ proctime->total = proctime->user + proctime->sys;
823
+ proctime->start_time = pstat->start_time;
824
+
825
+ return SIGAR_OK;
826
+ }
827
+
828
+ static int proc_status_get(sigar_t *sigar, sigar_pid_t pid,
829
+ sigar_proc_state_t *procstate)
830
+ {
831
+ char buffer[BUFSIZ], *ptr;
832
+ int status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTATUS);
833
+
834
+ if (status != SIGAR_OK) {
835
+ return status;
836
+ }
837
+
838
+ ptr = strstr(buffer, "\nThreads:");
839
+ if (ptr) {
840
+ /* 2.6+ kernel only */
841
+ ptr = sigar_skip_token(ptr);
842
+ procstate->threads = sigar_strtoul(ptr);
843
+ }
844
+ else {
845
+ procstate->threads = SIGAR_FIELD_NOTIMPL;
846
+ }
847
+
848
+ return SIGAR_OK;
849
+ }
850
+
851
+ int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
852
+ sigar_proc_state_t *procstate)
853
+ {
854
+ int status = proc_stat_read(sigar, pid);
855
+ linux_proc_stat_t *pstat = &sigar->last_proc_stat;
856
+
857
+ if (status != SIGAR_OK) {
858
+ return status;
859
+ }
860
+
861
+ memcpy(procstate->name, pstat->name, sizeof(procstate->name));
862
+ procstate->state = pstat->state;
863
+
864
+ procstate->ppid = pstat->ppid;
865
+ procstate->tty = pstat->tty;
866
+ procstate->priority = pstat->priority;
867
+ procstate->nice = pstat->nice;
868
+ procstate->processor = pstat->processor;
869
+
870
+ if (sigar_cpu_core_rollup(sigar)) {
871
+ procstate->processor /= sigar->lcpu;
872
+ }
873
+
874
+ proc_status_get(sigar, pid, procstate);
875
+
876
+ return SIGAR_OK;
877
+ }
878
+
879
+ int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
880
+ sigar_proc_args_t *procargs)
881
+ {
882
+ return sigar_procfs_args_get(sigar, pid, procargs);
883
+ }
884
+
885
+ /* glibc 2.8 XXX use sysconf(_SC_ARG_MAX) */
886
+ #ifndef ARG_MAX
887
+ #define ARG_MAX 131072
888
+ #endif
889
+
890
+ int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
891
+ sigar_proc_env_t *procenv)
892
+ {
893
+ int fd;
894
+ char buffer[ARG_MAX]; /* XXX: ARG_MAX == 130k */
895
+ char name[BUFSIZ];
896
+ size_t len;
897
+ char *ptr, *end;
898
+
899
+ /* optimize if pid == $$ and type == ENV_KEY */
900
+ SIGAR_PROC_ENV_KEY_LOOKUP();
901
+
902
+ (void)SIGAR_PROC_FILENAME(name, pid, "/environ");
903
+
904
+ if ((fd = open(name, O_RDONLY)) < 0) {
905
+ if (errno == ENOENT) {
906
+ return ESRCH;
907
+ }
908
+ return errno;
909
+ }
910
+
911
+ len = read(fd, buffer, sizeof(buffer));
912
+
913
+ close(fd);
914
+
915
+ buffer[len] = '\0';
916
+ ptr = buffer;
917
+
918
+ end = buffer + len;
919
+ while (ptr < end) {
920
+ char *val = strchr(ptr, '=');
921
+ int klen, vlen, status;
922
+ char key[128]; /* XXX is there a max key size? */
923
+
924
+ if (val == NULL) {
925
+ /* not key=val format */
926
+ break;
927
+ }
928
+
929
+ klen = val - ptr;
930
+ SIGAR_SSTRCPY(key, ptr);
931
+ key[klen] = '\0';
932
+ ++val;
933
+
934
+ vlen = strlen(val);
935
+ status = procenv->env_getter(procenv->data,
936
+ key, klen, val, vlen);
937
+
938
+ if (status != SIGAR_OK) {
939
+ /* not an error; just stop iterating */
940
+ break;
941
+ }
942
+
943
+ ptr += (klen + 1 + vlen + 1);
944
+ }
945
+
946
+ return SIGAR_OK;
947
+ }
948
+
949
+ int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
950
+ sigar_proc_fd_t *procfd)
951
+ {
952
+ int status =
953
+ sigar_proc_fd_count(sigar, pid, &procfd->total);
954
+
955
+ return status;
956
+ }
957
+
958
+ int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
959
+ sigar_proc_exe_t *procexe)
960
+ {
961
+ int len;
962
+ char name[BUFSIZ];
963
+
964
+ (void)SIGAR_PROC_FILENAME(name, pid, "/cwd");
965
+
966
+ if ((len = readlink(name, procexe->cwd,
967
+ sizeof(procexe->cwd)-1)) < 0)
968
+ {
969
+ return errno;
970
+ }
971
+
972
+ procexe->cwd[len] = '\0';
973
+
974
+ (void)SIGAR_PROC_FILENAME(name, pid, "/exe");
975
+
976
+ if ((len = readlink(name, procexe->name,
977
+ sizeof(procexe->name)-1)) < 0)
978
+ {
979
+ return errno;
980
+ }
981
+
982
+ procexe->name[len] = '\0';
983
+
984
+ (void)SIGAR_PROC_FILENAME(name, pid, "/root");
985
+
986
+ if ((len = readlink(name, procexe->root,
987
+ sizeof(procexe->root)-1)) < 0)
988
+ {
989
+ return errno;
990
+ }
991
+
992
+ procexe->root[len] = '\0';
993
+
994
+ return SIGAR_OK;
995
+ }
996
+
997
+ int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
998
+ sigar_proc_modules_t *procmods)
999
+ {
1000
+ FILE *fp;
1001
+ char buffer[BUFSIZ], *ptr;
1002
+ unsigned long inode, last_inode = 0;
1003
+
1004
+ (void)SIGAR_PROC_FILENAME(buffer, pid, "/maps");
1005
+
1006
+ if (!(fp = fopen(buffer, "r"))) {
1007
+ return errno;
1008
+ }
1009
+
1010
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
1011
+ int len, status;
1012
+ /* skip region, flags, offset, dev */
1013
+ ptr = sigar_skip_multiple_token(ptr, 4);
1014
+ inode = sigar_strtoul(ptr);
1015
+
1016
+ if ((inode == 0) || (inode == last_inode)) {
1017
+ last_inode = 0;
1018
+ continue;
1019
+ }
1020
+
1021
+ last_inode = inode;
1022
+ SIGAR_SKIP_SPACE(ptr);
1023
+ len = strlen(ptr);
1024
+ ptr[len-1] = '\0'; /* chop \n */
1025
+
1026
+ status =
1027
+ procmods->module_getter(procmods->data,
1028
+ ptr, len-1);
1029
+
1030
+ if (status != SIGAR_OK) {
1031
+ /* not an error; just stop iterating */
1032
+ break;
1033
+ }
1034
+ }
1035
+
1036
+ fclose(fp);
1037
+
1038
+ return SIGAR_OK;
1039
+ }
1040
+
1041
+ int sigar_thread_cpu_get(sigar_t *sigar,
1042
+ sigar_uint64_t id,
1043
+ sigar_thread_cpu_t *cpu)
1044
+ {
1045
+ struct tms now;
1046
+
1047
+ if (id != 0) {
1048
+ return SIGAR_ENOTIMPL;
1049
+ }
1050
+
1051
+ times(&now);
1052
+
1053
+ cpu->user = SIGAR_TICK2NSEC(now.tms_utime);
1054
+ cpu->sys = SIGAR_TICK2NSEC(now.tms_stime);
1055
+ cpu->total = SIGAR_TICK2NSEC(now.tms_utime + now.tms_stime);
1056
+
1057
+ return SIGAR_OK;
1058
+ }
1059
+
1060
+ #include <mntent.h>
1061
+
1062
+ int sigar_os_fs_type_get(sigar_file_system_t *fsp)
1063
+ {
1064
+ char *type = fsp->sys_type_name;
1065
+
1066
+ switch (*type) {
1067
+ case 'e':
1068
+ if (strnEQ(type, "ext", 3)) {
1069
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1070
+ }
1071
+ break;
1072
+ case 'g':
1073
+ if (strEQ(type, "gfs")) {
1074
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1075
+ }
1076
+ break;
1077
+ case 'h':
1078
+ if (strEQ(type, "hpfs")) {
1079
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1080
+ }
1081
+ break;
1082
+ case 'j':
1083
+ if (strnEQ(type, "jfs", 3)) {
1084
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1085
+ }
1086
+ break;
1087
+ case 'o':
1088
+ if (strnEQ(type, "ocfs", 4)) {
1089
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1090
+ }
1091
+ break;
1092
+ case 'p':
1093
+ if (strnEQ(type, "psfs", 4)) {
1094
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1095
+ }
1096
+ break;
1097
+ case 'r':
1098
+ if (strEQ(type, "reiserfs")) {
1099
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1100
+ }
1101
+ break;
1102
+ case 'v':
1103
+ if (strEQ(type, "vzfs")) {
1104
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1105
+ }
1106
+ break;
1107
+ case 'x':
1108
+ if (strEQ(type, "xfs") || strEQ(type, "xiafs")) {
1109
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1110
+ }
1111
+ break;
1112
+ }
1113
+
1114
+ return fsp->type;
1115
+ }
1116
+
1117
+ int sigar_file_system_list_get(sigar_t *sigar,
1118
+ sigar_file_system_list_t *fslist)
1119
+ {
1120
+ struct mntent ent;
1121
+ char buf[1025]; /* buffer for strings within ent */
1122
+ FILE *fp;
1123
+ sigar_file_system_t *fsp;
1124
+
1125
+ if (!(fp = setmntent(MOUNTED, "r"))) {
1126
+ return errno;
1127
+ }
1128
+
1129
+ sigar_file_system_list_create(fslist);
1130
+
1131
+ while (getmntent_r(fp, &ent, buf, sizeof(buf))) {
1132
+ SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
1133
+
1134
+ fsp = &fslist->data[fslist->number++];
1135
+
1136
+ fsp->type = SIGAR_FSTYPE_UNKNOWN; /* unknown, will be set later */
1137
+ SIGAR_SSTRCPY(fsp->dir_name, ent.mnt_dir);
1138
+ SIGAR_SSTRCPY(fsp->dev_name, ent.mnt_fsname);
1139
+ SIGAR_SSTRCPY(fsp->sys_type_name, ent.mnt_type);
1140
+ SIGAR_SSTRCPY(fsp->options, ent.mnt_opts);
1141
+ sigar_fs_type_get(fsp);
1142
+ }
1143
+
1144
+ endmntent(fp);
1145
+
1146
+ return SIGAR_OK;
1147
+ }
1148
+
1149
+ #define ST_MAJOR(sb) major((sb).st_rdev)
1150
+ #define ST_MINOR(sb) minor((sb).st_rdev)
1151
+
1152
+ static int get_iostat_sys(sigar_t *sigar,
1153
+ const char *dirname,
1154
+ sigar_disk_usage_t *disk,
1155
+ sigar_iodev_t **iodev)
1156
+ {
1157
+ char stat[1025], dev[1025];
1158
+ char *name, *ptr, *fsdev;
1159
+ int partition, status;
1160
+
1161
+ if (!(*iodev = sigar_iodev_get(sigar, dirname))) {
1162
+ return ENXIO;
1163
+ }
1164
+
1165
+ name = fsdev = (*iodev)->name;
1166
+
1167
+ if (SIGAR_NAME_IS_DEV(name)) {
1168
+ name += SSTRLEN(SIGAR_DEV_PREFIX); /* strip "/dev/" */
1169
+ }
1170
+
1171
+ while (!sigar_isdigit(*fsdev)) {
1172
+ fsdev++;
1173
+ }
1174
+
1175
+ partition = strtoul(fsdev, NULL, 0);
1176
+ *fsdev = '\0';
1177
+
1178
+ snprintf(stat, sizeof(stat),
1179
+ SYS_BLOCK "/%s/%s%d/stat", name, name, partition);
1180
+
1181
+ status = sigar_file2str(stat, dev, sizeof(dev));
1182
+ if (status != SIGAR_OK) {
1183
+ return status;
1184
+ }
1185
+
1186
+ ptr = dev;
1187
+ ptr = sigar_skip_token(ptr);
1188
+ disk->reads = sigar_strtoull(ptr);
1189
+ ptr = sigar_skip_token(ptr);
1190
+ disk->writes = sigar_strtoull(ptr);
1191
+
1192
+ disk->read_bytes = SIGAR_FIELD_NOTIMPL;
1193
+ disk->write_bytes = SIGAR_FIELD_NOTIMPL;
1194
+ disk->queue = SIGAR_FIELD_NOTIMPL;
1195
+
1196
+ return SIGAR_OK;
1197
+ }
1198
+
1199
+ static int get_iostat_proc_dstat(sigar_t *sigar,
1200
+ const char *dirname,
1201
+ sigar_disk_usage_t *disk,
1202
+ sigar_iodev_t **iodev,
1203
+ sigar_disk_usage_t *device_usage)
1204
+ {
1205
+ FILE *fp;
1206
+ char buffer[1025];
1207
+ char *ptr;
1208
+ struct stat sb;
1209
+ int status=ENOENT;
1210
+
1211
+ SIGAR_DISK_STATS_INIT(device_usage);
1212
+
1213
+ if (!(*iodev = sigar_iodev_get(sigar, dirname))) {
1214
+ return ENXIO;
1215
+ }
1216
+
1217
+ if (stat((*iodev)->name, &sb) < 0) {
1218
+ return errno;
1219
+ }
1220
+
1221
+ if (SIGAR_LOG_IS_DEBUG(sigar)) {
1222
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1223
+ PROC_DISKSTATS " %s -> %s [%d,%d]",
1224
+ dirname, (*iodev)->name,
1225
+ ST_MAJOR(sb), ST_MINOR(sb));
1226
+ }
1227
+
1228
+ if (!(fp = fopen(PROC_DISKSTATS, "r"))) {
1229
+ return errno;
1230
+ }
1231
+
1232
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
1233
+ unsigned long major, minor;
1234
+
1235
+ major = sigar_strtoul(ptr);
1236
+ minor = sigar_strtoul(ptr);
1237
+
1238
+ if ((major == ST_MAJOR(sb)) &&
1239
+ ((minor == ST_MINOR(sb)) || (minor == 0)))
1240
+ {
1241
+ int num;
1242
+ unsigned long
1243
+ rio, rmerge, rsect, ruse,
1244
+ wio, wmerge, wsect, wuse,
1245
+ running, use, aveq;
1246
+
1247
+ ptr = sigar_skip_token(ptr); /* name */
1248
+
1249
+ num = sscanf(ptr,
1250
+ "%lu %lu %lu %lu "
1251
+ "%lu %lu %lu %lu "
1252
+ "%lu %lu %lu",
1253
+ &rio, /* 1 # reads issued */
1254
+ &rmerge, /* 2 # reads merged */
1255
+ &rsect, /* 3 # sectors read */
1256
+ &ruse, /* 4 # millis spent reading */
1257
+ &wio, /* 5 # writes completed */
1258
+ &wmerge, /* 6 # writes merged */
1259
+ &wsect, /* 7 # sectors written */
1260
+ &wuse, /* 8 # millis spent writing */
1261
+ &running, /* 9 # I/Os currently in progress */
1262
+ &use, /* 10 # millis spent doing I/Os */
1263
+ &aveq); /* 11 # of millis spent doing I/Os (weighted) */
1264
+
1265
+ if (num == 11) {
1266
+ disk->rtime = ruse;
1267
+ disk->wtime = wuse;
1268
+ disk->time = use;
1269
+ disk->qtime = aveq;
1270
+ }
1271
+ else if (num == 4) {
1272
+ wio = rsect;
1273
+ rsect = rmerge;
1274
+ wsect = ruse;
1275
+ disk->time = disk->qtime = SIGAR_FIELD_NOTIMPL;
1276
+ }
1277
+ else {
1278
+ status = ENOENT;
1279
+ }
1280
+
1281
+ disk->reads = rio;
1282
+ disk->writes = wio;
1283
+ disk->read_bytes = rsect;
1284
+ disk->write_bytes = wsect;
1285
+
1286
+ /* convert sectors to bytes (512 is fixed size in 2.6 kernels) */
1287
+ disk->read_bytes *= 512;
1288
+ disk->write_bytes *= 512;
1289
+
1290
+ if (minor == ST_MINOR(sb)) {
1291
+ status = SIGAR_OK;
1292
+ break;
1293
+ }
1294
+ else if (minor == 0) {
1295
+ memcpy(device_usage, disk, sizeof(*device_usage));
1296
+ }
1297
+ }
1298
+ }
1299
+
1300
+ fclose(fp);
1301
+
1302
+ return status;
1303
+ }
1304
+
1305
+ static int get_iostat_procp(sigar_t *sigar,
1306
+ const char *dirname,
1307
+ sigar_disk_usage_t *disk,
1308
+ sigar_iodev_t **iodev)
1309
+ {
1310
+ FILE *fp;
1311
+ char buffer[1025];
1312
+ char *ptr;
1313
+ struct stat sb;
1314
+
1315
+ if (!(*iodev = sigar_iodev_get(sigar, dirname))) {
1316
+ return ENXIO;
1317
+ }
1318
+
1319
+ if (stat((*iodev)->name, &sb) < 0) {
1320
+ return errno;
1321
+ }
1322
+
1323
+ if (SIGAR_LOG_IS_DEBUG(sigar)) {
1324
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1325
+ PROC_PARTITIONS " %s -> %s [%d,%d]",
1326
+ dirname, (*iodev)->name,
1327
+ ST_MAJOR(sb), ST_MINOR(sb));
1328
+ }
1329
+
1330
+ if (!(fp = fopen(PROC_PARTITIONS, "r"))) {
1331
+ return errno;
1332
+ }
1333
+
1334
+ (void)fgets(buffer, sizeof(buffer), fp); /* skip header */
1335
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
1336
+ unsigned long major, minor;
1337
+
1338
+ major = sigar_strtoul(ptr);
1339
+ minor = sigar_strtoul(ptr);
1340
+
1341
+ if ((major == ST_MAJOR(sb)) && (minor == ST_MINOR(sb))) {
1342
+ ptr = sigar_skip_token(ptr); /* blocks */
1343
+ ptr = sigar_skip_token(ptr); /* name */
1344
+ disk->reads = sigar_strtoull(ptr); /* rio */
1345
+ ptr = sigar_skip_token(ptr); /* rmerge */
1346
+ disk->read_bytes = sigar_strtoull(ptr); /* rsect */
1347
+ disk->rtime = sigar_strtoull(ptr); /* ruse */
1348
+ disk->writes = sigar_strtoull(ptr); /* wio */
1349
+ ptr = sigar_skip_token(ptr); /* wmerge */
1350
+ disk->write_bytes = sigar_strtoull(ptr); /* wsect */
1351
+ disk->wtime = sigar_strtoull(ptr); /* wuse */
1352
+ ptr = sigar_skip_token(ptr); /* running */
1353
+ disk->time = sigar_strtoull(ptr); /* use */
1354
+ disk->qtime = sigar_strtoull(ptr); /* aveq */
1355
+
1356
+ /* convert sectors to bytes (512 is fixed size in 2.6 kernels) */
1357
+ disk->read_bytes *= 512;
1358
+ disk->write_bytes *= 512;
1359
+
1360
+ fclose(fp);
1361
+ return SIGAR_OK;
1362
+ }
1363
+ }
1364
+
1365
+ fclose(fp);
1366
+
1367
+ return ENOENT;
1368
+ }
1369
+
1370
+ int sigar_disk_usage_get(sigar_t *sigar, const char *name,
1371
+ sigar_disk_usage_t *disk)
1372
+ {
1373
+ int status;
1374
+ sigar_iodev_t *iodev = NULL;
1375
+ sigar_disk_usage_t device_usage;
1376
+ SIGAR_DISK_STATS_INIT(disk);
1377
+
1378
+ /*
1379
+ * 2.2 has metrics /proc/stat, but wtf is the device mapping?
1380
+ * 2.4 has /proc/partitions w/ the metrics.
1381
+ * 2.6 has /proc/partitions w/o the metrics.
1382
+ * instead the metrics are within the /proc-like /sys filesystem.
1383
+ * also has /proc/diskstats
1384
+ */
1385
+ switch (sigar->iostat) {
1386
+ case IOSTAT_SYS:
1387
+ status = get_iostat_sys(sigar, name, disk, &iodev);
1388
+ break;
1389
+ case IOSTAT_DISKSTATS:
1390
+ status = get_iostat_proc_dstat(sigar, name, disk, &iodev, &device_usage);
1391
+ break;
1392
+ case IOSTAT_PARTITIONS:
1393
+ status = get_iostat_procp(sigar, name, disk, &iodev);
1394
+ break;
1395
+ /*
1396
+ * case IOSTAT_SOME_OTHER_WIERD_THING:
1397
+ * break;
1398
+ */
1399
+ case IOSTAT_NONE:
1400
+ default:
1401
+ status = ENOENT;
1402
+ break;
1403
+ }
1404
+
1405
+ if ((status == SIGAR_OK) && iodev) {
1406
+ sigar_uptime_t uptime;
1407
+ sigar_uint64_t interval, ios;
1408
+ double tput, util;
1409
+ sigar_disk_usage_t *partition_usage=NULL;
1410
+
1411
+ sigar_uptime_get(sigar, &uptime);
1412
+
1413
+ if (iodev->is_partition &&
1414
+ (sigar->iostat == IOSTAT_DISKSTATS))
1415
+ {
1416
+ /* 2.6 kernels do not have per-partition times */
1417
+ partition_usage = disk;
1418
+ disk = &device_usage;
1419
+ }
1420
+
1421
+ disk->snaptime = uptime.uptime;
1422
+
1423
+ if (iodev->disk.snaptime) {
1424
+ interval = disk->snaptime - iodev->disk.snaptime;
1425
+ }
1426
+ else {
1427
+ interval = disk->snaptime;
1428
+ }
1429
+
1430
+ ios =
1431
+ (disk->reads - iodev->disk.reads) +
1432
+ (disk->writes - iodev->disk.writes);
1433
+
1434
+ if (disk->time == SIGAR_FIELD_NOTIMPL) {
1435
+ disk->service_time = SIGAR_FIELD_NOTIMPL;
1436
+ }
1437
+ else {
1438
+ tput = ((double)ios) * HZ / interval;
1439
+ util = ((double)(disk->time - iodev->disk.time)) / interval * HZ;
1440
+ disk->service_time = tput ? util / tput : 0.0;
1441
+ }
1442
+ if (disk->qtime == SIGAR_FIELD_NOTIMPL) {
1443
+ disk->queue = SIGAR_FIELD_NOTIMPL;
1444
+ }
1445
+ else {
1446
+ util = ((double)(disk->qtime - iodev->disk.qtime)) / interval;
1447
+ disk->queue = util / 1000.0;
1448
+ }
1449
+
1450
+ memcpy(&iodev->disk, disk, sizeof(iodev->disk));
1451
+ if (partition_usage) {
1452
+ partition_usage->service_time = disk->service_time;
1453
+ partition_usage->queue = disk->queue;
1454
+ }
1455
+ }
1456
+
1457
+ return status;
1458
+ }
1459
+
1460
+ int sigar_file_system_usage_get(sigar_t *sigar,
1461
+ const char *dirname,
1462
+ sigar_file_system_usage_t *fsusage)
1463
+ {
1464
+ int status = sigar_statvfs(sigar, dirname, fsusage);
1465
+
1466
+ if (status != SIGAR_OK) {
1467
+ return status;
1468
+ }
1469
+
1470
+ fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
1471
+
1472
+ (void)sigar_disk_usage_get(sigar, dirname, &fsusage->disk);
1473
+
1474
+ return SIGAR_OK;
1475
+ }
1476
+
1477
+ static SIGAR_INLINE char *cpu_info_strval(char *ptr)
1478
+ {
1479
+ if ((ptr = strchr(ptr, ':'))) {
1480
+ ptr++;
1481
+ while (isspace (*ptr)) ptr++;
1482
+ return ptr;
1483
+ }
1484
+ return NULL;
1485
+ }
1486
+
1487
+ static SIGAR_INLINE void cpu_info_strcpy(char *ptr, char *buf, int len)
1488
+ {
1489
+ int slen;
1490
+ ptr = cpu_info_strval(ptr);
1491
+ if (!ptr) {
1492
+ return;
1493
+ }
1494
+ slen = strlen(ptr);
1495
+ strncpy(buf, ptr, len);
1496
+ buf[len] = '\0';
1497
+ if (slen < len) {
1498
+ buf[slen-1] = '\0'; /* rid \n */
1499
+ }
1500
+ }
1501
+
1502
+ static int get_cpu_info(sigar_t *sigar, sigar_cpu_info_t *info,
1503
+ FILE *fp)
1504
+ {
1505
+ char buffer[BUFSIZ], *ptr;
1506
+
1507
+ int found = 0;
1508
+
1509
+ /* UML vm wont have "cpu MHz" or "cache size" fields */
1510
+ info->mhz = 0;
1511
+ info->cache_size = 0;
1512
+
1513
+ #ifdef __powerpc64__
1514
+ SIGAR_SSTRCPY(info->vendor, "IBM");
1515
+ #endif
1516
+
1517
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
1518
+ switch (*ptr) {
1519
+ case 'p': /* processor : 0 */
1520
+ if (strnEQ(ptr, "processor", 9)) {
1521
+ found = 1;
1522
+ }
1523
+ break;
1524
+ case 'v':
1525
+ /* "vendor_id" or "vendor" */
1526
+ if (strnEQ(ptr, "vendor", 6)) {
1527
+ cpu_info_strcpy(ptr, info->vendor, sizeof(info->vendor));
1528
+ if (strEQ(info->vendor, "GenuineIntel")) {
1529
+ SIGAR_SSTRCPY(info->vendor, "Intel");
1530
+ }
1531
+ else if (strEQ(info->vendor, "AuthenticAMD")) {
1532
+ SIGAR_SSTRCPY(info->vendor, "AMD");
1533
+ }
1534
+ }
1535
+ break;
1536
+ case 'f':
1537
+ if (strnEQ(ptr, "family", 6)) {
1538
+ /* IA64 version of "model name" */
1539
+ cpu_info_strcpy(ptr, info->model, sizeof(info->model));
1540
+ sigar_cpu_model_adjust(sigar, info);
1541
+ }
1542
+ break;
1543
+ case 'm':
1544
+ if (strnEQ(ptr, "model name", 10)) {
1545
+ cpu_info_strcpy(ptr, info->model, sizeof(info->model));
1546
+ sigar_cpu_model_adjust(sigar, info);
1547
+ }
1548
+ break;
1549
+ case 'c':
1550
+ if (strnEQ(ptr, "cpu MHz", 7)) {
1551
+ ptr = cpu_info_strval(ptr);
1552
+ info->mhz = atoi(ptr);
1553
+ }
1554
+ else if (strnEQ(ptr, "cache size", 10)) {
1555
+ ptr = cpu_info_strval(ptr);
1556
+ info->cache_size = sigar_strtoul(ptr);
1557
+ }
1558
+ #ifdef __powerpc64__
1559
+ /* each /proc/cpuinfo entry looks like so:
1560
+ * processor : 0
1561
+ * cpu : POWER5 (gr)
1562
+ * clock : 1656.392000MHz
1563
+ * revision : 2.2
1564
+ */
1565
+ else if (strnEQ(ptr, "clock", 5)) {
1566
+ ptr = cpu_info_strval(ptr);
1567
+ info->mhz = atoi(ptr);
1568
+ }
1569
+ else if (strnEQ(ptr, "cpu", 3)) {
1570
+ cpu_info_strcpy(ptr, info->model, sizeof(info->model));
1571
+
1572
+ if ((ptr = strchr(info->model, ' '))) {
1573
+ /* "POWER5 (gr)" -> "POWER5" */
1574
+ *ptr = '\0';
1575
+ }
1576
+ }
1577
+ #endif
1578
+ break;
1579
+ /* lone \n means end of info for this processor */
1580
+ case '\n':
1581
+ return found;
1582
+ }
1583
+ }
1584
+
1585
+ return found;
1586
+ }
1587
+
1588
+ /* /proc/cpuinfo MHz will change w/ AMD + PowerNow */
1589
+ static void get_cpuinfo_max_freq(sigar_cpu_info_t *cpu_info, int num)
1590
+ {
1591
+ int status;
1592
+ char max_freq[PATH_MAX];
1593
+ snprintf(max_freq, sizeof(max_freq),
1594
+ "/sys/devices/system/cpu/cpu%d"
1595
+ "/cpufreq/cpuinfo_max_freq", num);
1596
+
1597
+ status =
1598
+ sigar_file2str(max_freq, max_freq, sizeof(max_freq)-1);
1599
+
1600
+ if (status == SIGAR_OK) {
1601
+ cpu_info->mhz_max = atoi(max_freq) / 1000;
1602
+ }
1603
+ }
1604
+
1605
+ static void get_cpuinfo_min_freq(sigar_cpu_info_t *cpu_info, int num)
1606
+ {
1607
+ int status;
1608
+ char min_freq[PATH_MAX];
1609
+ snprintf(min_freq, sizeof(min_freq),
1610
+ "/sys/devices/system/cpu/cpu%d"
1611
+ "/cpufreq/cpuinfo_min_freq", num);
1612
+
1613
+ status =
1614
+ sigar_file2str(min_freq, min_freq, sizeof(min_freq)-1);
1615
+
1616
+ if (status == SIGAR_OK) {
1617
+ cpu_info->mhz_min = atoi(min_freq) / 1000;
1618
+ }
1619
+ }
1620
+
1621
+ int sigar_cpu_info_list_get(sigar_t *sigar,
1622
+ sigar_cpu_info_list_t *cpu_infos)
1623
+ {
1624
+ FILE *fp;
1625
+ int core_rollup = sigar_cpu_core_rollup(sigar), i=0;
1626
+
1627
+ if (!(fp = fopen(PROC_FS_ROOT "cpuinfo", "r"))) {
1628
+ return errno;
1629
+ }
1630
+
1631
+ (void)sigar_cpu_total_count(sigar);
1632
+ sigar_cpu_info_list_create(cpu_infos);
1633
+
1634
+ while (get_cpu_info(sigar, &cpu_infos->data[cpu_infos->number], fp)) {
1635
+ sigar_cpu_info_t *info;
1636
+
1637
+ if (core_rollup && (i++ % sigar->lcpu)) {
1638
+ continue; /* fold logical processors */
1639
+ }
1640
+
1641
+ info = &cpu_infos->data[cpu_infos->number];
1642
+ get_cpuinfo_max_freq(info, cpu_infos->number);
1643
+ get_cpuinfo_min_freq(info, cpu_infos->number);
1644
+
1645
+ info->total_cores = sigar->ncpu;
1646
+ info->cores_per_socket = sigar->lcpu;
1647
+ info->total_sockets = sigar_cpu_socket_count(sigar);
1648
+
1649
+ ++cpu_infos->number;
1650
+ SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
1651
+ }
1652
+
1653
+ fclose(fp);
1654
+
1655
+ return SIGAR_OK;
1656
+ }
1657
+
1658
+ static SIGAR_INLINE unsigned int hex2int(const char *x, int len)
1659
+ {
1660
+ int i;
1661
+ unsigned int j;
1662
+
1663
+ for (i=0, j=0; i<len; i++) {
1664
+ register int ch = x[i];
1665
+ j <<= 4;
1666
+ if (isdigit(ch)) {
1667
+ j |= ch - '0';
1668
+ }
1669
+ else if (isupper(ch)) {
1670
+ j |= ch - ('A' - 10);
1671
+ }
1672
+ else {
1673
+ j |= ch - ('a' - 10);
1674
+ }
1675
+ }
1676
+
1677
+ return j;
1678
+ }
1679
+
1680
+ #define HEX_ENT_LEN 8
1681
+
1682
+ #ifdef SIGAR_64BIT
1683
+ #define ROUTE_FMT "%16s %128s %128s %X %ld %ld %ld %128s %ld %ld %ld\n"
1684
+ #else
1685
+ #define ROUTE_FMT "%16s %128s %128s %X %lld %lld %lld %128s %lld %lld %lld\n"
1686
+ #endif
1687
+ #define RTF_UP 0x0001
1688
+
1689
+ int sigar_net_route_list_get(sigar_t *sigar,
1690
+ sigar_net_route_list_t *routelist)
1691
+ {
1692
+ FILE *fp;
1693
+ char buffer[1024];
1694
+ char net_addr[128], gate_addr[128], mask_addr[128];
1695
+ int flags;
1696
+ sigar_net_route_t *route;
1697
+
1698
+ routelist->size = routelist->number = 0;
1699
+
1700
+ if (!(fp = fopen(PROC_FS_ROOT "net/route", "r"))) {
1701
+ return errno;
1702
+ }
1703
+
1704
+ sigar_net_route_list_create(routelist);
1705
+
1706
+ (void)fgets(buffer, sizeof(buffer), fp); /* skip header */
1707
+ while (fgets(buffer, sizeof(buffer), fp)) {
1708
+ int num;
1709
+
1710
+ SIGAR_NET_ROUTE_LIST_GROW(routelist);
1711
+ route = &routelist->data[routelist->number++];
1712
+
1713
+ /* XXX rid sscanf */
1714
+ num = sscanf(buffer, ROUTE_FMT,
1715
+ route->ifname, net_addr, gate_addr,
1716
+ &flags, &route->refcnt, &route->use,
1717
+ &route->metric, mask_addr,
1718
+ &route->mtu, &route->window, &route->irtt);
1719
+
1720
+ if ((num < 10) || !(flags & RTF_UP)) {
1721
+ --routelist->number;
1722
+ continue;
1723
+ }
1724
+
1725
+ route->flags = flags;
1726
+
1727
+ sigar_net_address_set(route->destination, hex2int(net_addr, HEX_ENT_LEN));
1728
+ sigar_net_address_set(route->gateway, hex2int(gate_addr, HEX_ENT_LEN));
1729
+ sigar_net_address_set(route->mask, hex2int(mask_addr, HEX_ENT_LEN));
1730
+ }
1731
+
1732
+ fclose(fp);
1733
+
1734
+ return SIGAR_OK;
1735
+ }
1736
+
1737
+ int sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
1738
+ sigar_net_interface_stat_t *ifstat)
1739
+ {
1740
+ int found = 0;
1741
+ char buffer[BUFSIZ];
1742
+ FILE *fp = fopen(PROC_FS_ROOT "net/dev", "r");
1743
+
1744
+ if (!fp) {
1745
+ return errno;
1746
+ }
1747
+
1748
+ /* skip header */
1749
+ fgets(buffer, sizeof(buffer), fp);
1750
+ fgets(buffer, sizeof(buffer), fp);
1751
+
1752
+ while (fgets(buffer, sizeof(buffer), fp)) {
1753
+ char *ptr, *dev;
1754
+
1755
+ dev = buffer;
1756
+ while (isspace(*dev)) {
1757
+ dev++;
1758
+ }
1759
+
1760
+ if (!(ptr = strchr(dev, ':'))) {
1761
+ continue;
1762
+ }
1763
+
1764
+ *ptr++ = 0;
1765
+
1766
+ if (!strEQ(dev, name)) {
1767
+ continue;
1768
+ }
1769
+
1770
+ found = 1;
1771
+ ifstat->rx_bytes = sigar_strtoull(ptr);
1772
+ ifstat->rx_packets = sigar_strtoull(ptr);
1773
+ ifstat->rx_errors = sigar_strtoull(ptr);
1774
+ ifstat->rx_dropped = sigar_strtoull(ptr);
1775
+ ifstat->rx_overruns = sigar_strtoull(ptr);
1776
+ ifstat->rx_frame = sigar_strtoull(ptr);
1777
+
1778
+ /* skip: compressed multicast */
1779
+ ptr = sigar_skip_multiple_token(ptr, 2);
1780
+
1781
+ ifstat->tx_bytes = sigar_strtoull(ptr);
1782
+ ifstat->tx_packets = sigar_strtoull(ptr);
1783
+ ifstat->tx_errors = sigar_strtoull(ptr);
1784
+ ifstat->tx_dropped = sigar_strtoull(ptr);
1785
+ ifstat->tx_overruns = sigar_strtoull(ptr);
1786
+ ifstat->tx_collisions = sigar_strtoull(ptr);
1787
+ ifstat->tx_carrier = sigar_strtoull(ptr);
1788
+
1789
+ ifstat->speed = SIGAR_FIELD_NOTIMPL;
1790
+
1791
+ break;
1792
+ }
1793
+
1794
+ fclose(fp);
1795
+
1796
+ return found ? SIGAR_OK : ENXIO;
1797
+ }
1798
+
1799
+ static SIGAR_INLINE void convert_hex_address(sigar_net_address_t *address,
1800
+ char *ptr, int len)
1801
+ {
1802
+ if (len > HEX_ENT_LEN) {
1803
+ int i;
1804
+ for (i=0; i<=3; i++, ptr+=HEX_ENT_LEN) {
1805
+ address->addr.in6[i] = hex2int(ptr, HEX_ENT_LEN);
1806
+ }
1807
+
1808
+ address->family = SIGAR_AF_INET6;
1809
+ }
1810
+ else {
1811
+ address->addr.in =
1812
+ (len == HEX_ENT_LEN) ? hex2int(ptr, HEX_ENT_LEN) : 0;
1813
+
1814
+ address->family = SIGAR_AF_INET;
1815
+ }
1816
+ }
1817
+
1818
+ typedef struct {
1819
+ sigar_net_connection_list_t *connlist;
1820
+ sigar_net_connection_t *conn;
1821
+ unsigned long port;
1822
+ } net_conn_getter_t;
1823
+
1824
+ static int proc_net_walker(sigar_net_connection_walker_t *walker,
1825
+ sigar_net_connection_t *conn)
1826
+ {
1827
+ net_conn_getter_t *getter =
1828
+ (net_conn_getter_t *)walker->data;
1829
+
1830
+ if (getter->connlist) {
1831
+ SIGAR_NET_CONNLIST_GROW(getter->connlist);
1832
+ memcpy(&getter->connlist->data[getter->connlist->number++],
1833
+ conn, sizeof(*conn));
1834
+ }
1835
+ else {
1836
+ if ((getter->port == conn->local_port) &&
1837
+ (conn->remote_port == 0))
1838
+ {
1839
+ memcpy(getter->conn, conn, sizeof(*conn));
1840
+ return !SIGAR_OK; /* break loop */
1841
+ }
1842
+ }
1843
+
1844
+ return SIGAR_OK; /* continue loop */
1845
+ }
1846
+
1847
+ #define SKIP_WHILE(p, c) while (*p == c) p++
1848
+ #define SKIP_PAST(p, c) \
1849
+ while(*p && (*p != c)) p++; \
1850
+ SKIP_WHILE(p, c)
1851
+
1852
+ typedef struct {
1853
+ FILE *fp;
1854
+ int (*close)(FILE *);
1855
+ } xproc_t;
1856
+
1857
+ static FILE *xproc_open(const char *command, xproc_t *xproc)
1858
+ {
1859
+ struct stat sb;
1860
+ if (stat(command, &sb) == 0) {
1861
+ if (sb.st_mode & S_IXUSR) {
1862
+ /* executable script for testing large
1863
+ * conn table where we can sleep() to better
1864
+ * simulate /proc/net/tcp behavior
1865
+ */
1866
+ xproc->fp = popen(command, "r");
1867
+ xproc->close = pclose;
1868
+ }
1869
+ else {
1870
+ xproc->fp = fopen(command, "r");
1871
+ xproc->close = fclose;
1872
+ }
1873
+ return xproc->fp;
1874
+ }
1875
+ else {
1876
+ return NULL;
1877
+ }
1878
+ }
1879
+
1880
+ static int proc_net_read(sigar_net_connection_walker_t *walker,
1881
+ const char *fname,
1882
+ int type)
1883
+ {
1884
+ FILE *fp = NULL;
1885
+ char buffer[8192];
1886
+ sigar_t *sigar = walker->sigar;
1887
+ char *ptr = sigar->proc_net;
1888
+ int flags = walker->flags;
1889
+ xproc_t xproc = { NULL, fclose };
1890
+
1891
+ if (ptr) {
1892
+ snprintf(buffer, sizeof(buffer),
1893
+ "%s/%s", ptr,
1894
+ fname + sizeof(PROC_FS_ROOT)-1);
1895
+
1896
+ if ((fp = xproc_open(buffer, &xproc))) {
1897
+ if (SIGAR_LOG_IS_DEBUG(sigar)) {
1898
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1899
+ "[proc_net] using %s",
1900
+ buffer);
1901
+ }
1902
+ }
1903
+ else if (SIGAR_LOG_IS_DEBUG(sigar)) {
1904
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1905
+ "[proc_net] cannot open %s",
1906
+ buffer);
1907
+ }
1908
+ }
1909
+
1910
+ if (!(fp || (fp = fopen(fname, "r")))) {
1911
+ return errno;
1912
+ }
1913
+
1914
+ fgets(buffer, sizeof(buffer), fp); /* skip header */
1915
+
1916
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
1917
+ sigar_net_connection_t conn;
1918
+ char *laddr, *raddr;
1919
+ int laddr_len=0, raddr_len=0;
1920
+ int more;
1921
+
1922
+ /* skip leading space */
1923
+ SKIP_WHILE(ptr, ' ');
1924
+
1925
+ /* skip "%d: " */
1926
+ SKIP_PAST(ptr, ' ');
1927
+
1928
+ laddr = ptr;
1929
+ while (*ptr && (*ptr != ':')) {
1930
+ laddr_len++;
1931
+ ptr++;
1932
+ }
1933
+ SKIP_WHILE(ptr, ':');
1934
+
1935
+ conn.local_port = (strtoul(ptr, &ptr, 16) & 0xffff);
1936
+
1937
+ SKIP_WHILE(ptr, ' ');
1938
+
1939
+ raddr = ptr;
1940
+ while (*ptr && (*ptr != ':')) {
1941
+ raddr_len++;
1942
+ ptr++;
1943
+ }
1944
+ SKIP_WHILE(ptr, ':');
1945
+
1946
+ conn.remote_port = (strtoul(ptr, &ptr, 16) & 0xffff);
1947
+
1948
+ SKIP_WHILE(ptr, ' ');
1949
+
1950
+ if (!((conn.remote_port && (flags & SIGAR_NETCONN_CLIENT)) ||
1951
+ (!conn.remote_port && (flags & SIGAR_NETCONN_SERVER))))
1952
+ {
1953
+ continue;
1954
+ }
1955
+
1956
+ conn.type = type;
1957
+
1958
+ convert_hex_address(&conn.local_address,
1959
+ laddr, laddr_len);
1960
+
1961
+ convert_hex_address(&conn.remote_address,
1962
+ raddr, raddr_len);
1963
+
1964
+ /* SIGAR_TCP_* currently matches TCP_* in linux/tcp.h */
1965
+ conn.state = hex2int(ptr, 2);
1966
+ ptr += 2;
1967
+ SKIP_WHILE(ptr, ' ');
1968
+
1969
+ conn.send_queue = hex2int(ptr, HEX_ENT_LEN);
1970
+ ptr += HEX_ENT_LEN+1; /* tx + ':' */;
1971
+
1972
+ conn.receive_queue = hex2int(ptr, HEX_ENT_LEN);
1973
+ ptr += HEX_ENT_LEN;
1974
+ SKIP_WHILE(ptr, ' ');
1975
+
1976
+ SKIP_PAST(ptr, ' '); /* tr:tm->whem */
1977
+ SKIP_PAST(ptr, ' '); /* retrnsmt */
1978
+
1979
+ conn.uid = sigar_strtoul(ptr);
1980
+
1981
+ SKIP_WHILE(ptr, ' ');
1982
+ SKIP_PAST(ptr, ' '); /* timeout */
1983
+
1984
+ conn.inode = sigar_strtoul(ptr);
1985
+
1986
+ more = walker->add_connection(walker, &conn);
1987
+ if (more != SIGAR_OK) {
1988
+ xproc.close(fp);
1989
+ return SIGAR_OK;
1990
+ }
1991
+ }
1992
+
1993
+ xproc.close(fp);
1994
+
1995
+ return SIGAR_OK;
1996
+ }
1997
+
1998
+ int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
1999
+ {
2000
+ int flags = walker->flags;
2001
+ int status;
2002
+
2003
+ if (flags & SIGAR_NETCONN_TCP) {
2004
+ status = proc_net_read(walker,
2005
+ PROC_FS_ROOT "net/tcp",
2006
+ SIGAR_NETCONN_TCP);
2007
+
2008
+ if (status != SIGAR_OK) {
2009
+ return status;
2010
+ }
2011
+
2012
+ status = proc_net_read(walker,
2013
+ PROC_FS_ROOT "net/tcp6",
2014
+ SIGAR_NETCONN_TCP);
2015
+
2016
+ if (!((status == SIGAR_OK) || (status == ENOENT))) {
2017
+ return status;
2018
+ }
2019
+ }
2020
+
2021
+ if (flags & SIGAR_NETCONN_UDP) {
2022
+ status = proc_net_read(walker,
2023
+ PROC_FS_ROOT "net/udp",
2024
+ SIGAR_NETCONN_UDP);
2025
+
2026
+ if (status != SIGAR_OK) {
2027
+ return status;
2028
+ }
2029
+
2030
+ status = proc_net_read(walker,
2031
+ PROC_FS_ROOT "net/udp6",
2032
+ SIGAR_NETCONN_UDP);
2033
+
2034
+ if (!((status == SIGAR_OK) || (status == ENOENT))) {
2035
+ return status;
2036
+ }
2037
+ }
2038
+
2039
+ if (flags & SIGAR_NETCONN_RAW) {
2040
+ status = proc_net_read(walker,
2041
+ PROC_FS_ROOT "net/raw",
2042
+ SIGAR_NETCONN_RAW);
2043
+
2044
+ if (status != SIGAR_OK) {
2045
+ return status;
2046
+ }
2047
+
2048
+ status = proc_net_read(walker,
2049
+ PROC_FS_ROOT "net/raw6",
2050
+ SIGAR_NETCONN_RAW);
2051
+
2052
+ if (!((status == SIGAR_OK) || (status == ENOENT))) {
2053
+ return status;
2054
+ }
2055
+ }
2056
+
2057
+ /* XXX /proc/net/unix */
2058
+
2059
+ return SIGAR_OK;
2060
+ }
2061
+
2062
+ int sigar_net_connection_list_get(sigar_t *sigar,
2063
+ sigar_net_connection_list_t *connlist,
2064
+ int flags)
2065
+ {
2066
+ int status;
2067
+ sigar_net_connection_walker_t walker;
2068
+ net_conn_getter_t getter;
2069
+
2070
+ sigar_net_connection_list_create(connlist);
2071
+
2072
+ getter.conn = NULL;
2073
+ getter.connlist = connlist;
2074
+
2075
+ walker.sigar = sigar;
2076
+ walker.flags = flags;
2077
+ walker.data = &getter;
2078
+ walker.add_connection = proc_net_walker;
2079
+
2080
+ status = sigar_net_connection_walk(&walker);
2081
+
2082
+ if (status != SIGAR_OK) {
2083
+ sigar_net_connection_list_destroy(sigar, connlist);
2084
+ }
2085
+
2086
+ return status;
2087
+ }
2088
+
2089
+ static int sigar_net_connection_get(sigar_t *sigar,
2090
+ sigar_net_connection_t *netconn,
2091
+ unsigned long port,
2092
+ int flags)
2093
+ {
2094
+ int status;
2095
+ sigar_net_connection_walker_t walker;
2096
+ net_conn_getter_t getter;
2097
+
2098
+ getter.conn = netconn;
2099
+ getter.connlist = NULL;
2100
+ getter.port = port;
2101
+
2102
+ walker.sigar = sigar;
2103
+ walker.flags = flags;
2104
+ walker.data = &getter;
2105
+ walker.add_connection = proc_net_walker;
2106
+
2107
+ status = sigar_net_connection_walk(&walker);
2108
+
2109
+ return status;
2110
+ }
2111
+
2112
+ int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name,
2113
+ sigar_net_interface_config_t *ifconfig)
2114
+ {
2115
+ FILE *fp;
2116
+ char addr[32+1], ifname[8+1];
2117
+ int status = SIGAR_ENOENT;
2118
+ int idx, prefix, scope, flags;
2119
+
2120
+ if (!(fp = fopen(PROC_FS_ROOT "net/if_inet6", "r"))) {
2121
+ return errno;
2122
+ }
2123
+
2124
+ while (fscanf(fp, "%32s %02x %02x %02x %02x %8s\n",
2125
+ addr, &idx, &prefix, &scope, &flags, ifname) != EOF)
2126
+ {
2127
+ if (strEQ(name, ifname)) {
2128
+ status = SIGAR_OK;
2129
+ break;
2130
+ }
2131
+ }
2132
+
2133
+ fclose(fp);
2134
+
2135
+ if (status == SIGAR_OK) {
2136
+ int i=0;
2137
+ unsigned char *addr6 = (unsigned char *)&(ifconfig->address6.addr.in6);
2138
+ char *ptr = addr;
2139
+
2140
+ for (i=0; i<16; i++, ptr+=2) {
2141
+ addr6[i] = (unsigned char)hex2int(ptr, 2);
2142
+ }
2143
+
2144
+ ifconfig->prefix6_length = prefix;
2145
+ ifconfig->scope6 = scope;
2146
+ }
2147
+
2148
+ return status;
2149
+ }
2150
+
2151
+ #define SNMP_TCP_PREFIX "Tcp: "
2152
+
2153
+ SIGAR_DECLARE(int)
2154
+ sigar_tcp_get(sigar_t *sigar,
2155
+ sigar_tcp_t *tcp)
2156
+ {
2157
+ FILE *fp;
2158
+ char buffer[1024], *ptr=buffer;
2159
+ int status = SIGAR_ENOENT;
2160
+
2161
+ if (!(fp = fopen(PROC_FS_ROOT "net/snmp", "r"))) {
2162
+ return errno;
2163
+ }
2164
+
2165
+ while (fgets(buffer, sizeof(buffer), fp)) {
2166
+ if (strnEQ(buffer, SNMP_TCP_PREFIX, sizeof(SNMP_TCP_PREFIX)-1)) {
2167
+ if (fgets(buffer, sizeof(buffer), fp)) {
2168
+ status = SIGAR_OK;
2169
+ break;
2170
+ }
2171
+ }
2172
+ }
2173
+
2174
+ fclose(fp);
2175
+
2176
+ if (status == SIGAR_OK) {
2177
+ /* assuming field order, same in 2.2, 2.4 and 2.6 kernels */
2178
+ /* Tcp: RtoAlgorithm RtoMin RtoMax MaxConn */
2179
+ ptr = sigar_skip_multiple_token(ptr, 5);
2180
+ tcp->active_opens = sigar_strtoull(ptr);
2181
+ tcp->passive_opens = sigar_strtoull(ptr);
2182
+ tcp->attempt_fails = sigar_strtoull(ptr);
2183
+ tcp->estab_resets = sigar_strtoull(ptr);
2184
+ tcp->curr_estab = sigar_strtoull(ptr);
2185
+ tcp->in_segs = sigar_strtoull(ptr);
2186
+ tcp->out_segs = sigar_strtoull(ptr);
2187
+ tcp->retrans_segs = sigar_strtoull(ptr);
2188
+ tcp->in_errs = sigar_strtoull(ptr);
2189
+ tcp->out_rsts = sigar_strtoull(ptr);
2190
+ }
2191
+
2192
+ return status;
2193
+ }
2194
+
2195
+ static int sigar_proc_nfs_gets(char *file, char *tok,
2196
+ char *buffer, size_t size)
2197
+ {
2198
+ int status = ENOENT;
2199
+ int len = strlen(tok);
2200
+ FILE *fp = fopen(file, "r");
2201
+
2202
+ if (!fp) {
2203
+ return SIGAR_ENOTIMPL;
2204
+ }
2205
+
2206
+ while (fgets(buffer, size, fp)) {
2207
+ if (strnEQ(buffer, tok, len)) {
2208
+ status = SIGAR_OK;
2209
+ break;
2210
+ }
2211
+ }
2212
+
2213
+ fclose(fp);
2214
+
2215
+ return status;
2216
+ }
2217
+
2218
+ static int sigar_nfs_v2_get(char *file, sigar_nfs_v2_t *nfs)
2219
+ {
2220
+ char buffer[BUFSIZ], *ptr=buffer;
2221
+ int status =
2222
+ sigar_proc_nfs_gets(file,
2223
+ "proc2", buffer, sizeof(buffer));
2224
+
2225
+ if (status != SIGAR_OK) {
2226
+ return status;
2227
+ }
2228
+
2229
+ ptr = sigar_skip_multiple_token(ptr, 2);
2230
+
2231
+ nfs->null = sigar_strtoull(ptr);
2232
+ nfs->getattr = sigar_strtoull(ptr);
2233
+ nfs->setattr = sigar_strtoull(ptr);
2234
+ nfs->root = sigar_strtoull(ptr);
2235
+ nfs->lookup = sigar_strtoull(ptr);
2236
+ nfs->readlink = sigar_strtoull(ptr);
2237
+ nfs->read = sigar_strtoull(ptr);
2238
+ nfs->writecache = sigar_strtoull(ptr);
2239
+ nfs->write = sigar_strtoull(ptr);
2240
+ nfs->create = sigar_strtoull(ptr);
2241
+ nfs->remove = sigar_strtoull(ptr);
2242
+ nfs->rename = sigar_strtoull(ptr);
2243
+ nfs->link = sigar_strtoull(ptr);
2244
+ nfs->symlink = sigar_strtoull(ptr);
2245
+ nfs->mkdir = sigar_strtoull(ptr);
2246
+ nfs->rmdir = sigar_strtoull(ptr);
2247
+ nfs->readdir = sigar_strtoull(ptr);
2248
+ nfs->fsstat = sigar_strtoull(ptr);
2249
+
2250
+ return SIGAR_OK;
2251
+ }
2252
+
2253
+ int sigar_nfs_client_v2_get(sigar_t *sigar,
2254
+ sigar_nfs_client_v2_t *nfs)
2255
+ {
2256
+ return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfs",
2257
+ (sigar_nfs_v2_t *)nfs);
2258
+ }
2259
+
2260
+ int sigar_nfs_server_v2_get(sigar_t *sigar,
2261
+ sigar_nfs_server_v2_t *nfs)
2262
+ {
2263
+ return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfsd",
2264
+ (sigar_nfs_v2_t *)nfs);
2265
+ }
2266
+
2267
+ static int sigar_nfs_v3_get(char *file, sigar_nfs_v3_t *nfs)
2268
+ {
2269
+ char buffer[BUFSIZ], *ptr=buffer;
2270
+ int status =
2271
+ sigar_proc_nfs_gets(file,
2272
+ "proc3", buffer, sizeof(buffer));
2273
+
2274
+ if (status != SIGAR_OK) {
2275
+ return status;
2276
+ }
2277
+
2278
+ ptr = sigar_skip_multiple_token(ptr, 2);
2279
+
2280
+ nfs->null = sigar_strtoull(ptr);
2281
+ nfs->getattr = sigar_strtoull(ptr);
2282
+ nfs->setattr = sigar_strtoull(ptr);
2283
+ nfs->lookup = sigar_strtoull(ptr);
2284
+ nfs->access = sigar_strtoull(ptr);
2285
+ nfs->readlink = sigar_strtoull(ptr);
2286
+ nfs->read = sigar_strtoull(ptr);
2287
+ nfs->write = sigar_strtoull(ptr);
2288
+ nfs->create = sigar_strtoull(ptr);
2289
+ nfs->mkdir = sigar_strtoull(ptr);
2290
+ nfs->symlink = sigar_strtoull(ptr);
2291
+ nfs->mknod = sigar_strtoull(ptr);
2292
+ nfs->remove = sigar_strtoull(ptr);
2293
+ nfs->rmdir = sigar_strtoull(ptr);
2294
+ nfs->rename = sigar_strtoull(ptr);
2295
+ nfs->link = sigar_strtoull(ptr);
2296
+ nfs->readdir = sigar_strtoull(ptr);
2297
+ nfs->readdirplus = sigar_strtoull(ptr);
2298
+ nfs->fsstat = sigar_strtoull(ptr);
2299
+ nfs->fsinfo = sigar_strtoull(ptr);
2300
+ nfs->pathconf = sigar_strtoull(ptr);
2301
+ nfs->commit = sigar_strtoull(ptr);
2302
+
2303
+ return SIGAR_OK;
2304
+ }
2305
+
2306
+ int sigar_nfs_client_v3_get(sigar_t *sigar,
2307
+ sigar_nfs_client_v3_t *nfs)
2308
+ {
2309
+ return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfs",
2310
+ (sigar_nfs_v3_t *)nfs);
2311
+ }
2312
+
2313
+ int sigar_nfs_server_v3_get(sigar_t *sigar,
2314
+ sigar_nfs_server_v3_t *nfs)
2315
+ {
2316
+ return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfsd",
2317
+ (sigar_nfs_v3_t *)nfs);
2318
+ }
2319
+
2320
+ #include <net/if_arp.h>
2321
+
2322
+ static char *get_hw_type(int type)
2323
+ {
2324
+ switch (type) {
2325
+ case ARPHRD_AX25:
2326
+ return "ax25";
2327
+ case ARPHRD_ECONET:
2328
+ return "ec";
2329
+ case ARPHRD_ETHER:
2330
+ return "ether";
2331
+ case ARPHRD_FDDI:
2332
+ return "fddi";
2333
+ case ARPHRD_DLCI:
2334
+ return "dlci";
2335
+ case ARPHRD_FRAD:
2336
+ return "frad";
2337
+ case ARPHRD_HDLC:
2338
+ return "hdlc";
2339
+ case ARPHRD_LAPB:
2340
+ return "lapb";
2341
+ case ARPHRD_HIPPI:
2342
+ return "hippi";
2343
+ case ARPHRD_IRDA:
2344
+ return "irda";
2345
+ case ARPHRD_LOOPBACK:
2346
+ return "loop";
2347
+ case ARPHRD_NETROM:
2348
+ return "netrom";
2349
+ case ARPHRD_PPP:
2350
+ return "ppp";
2351
+ case ARPHRD_ROSE:
2352
+ return "rose";
2353
+ case ARPHRD_SIT:
2354
+ return "sit";
2355
+ case ARPHRD_SLIP:
2356
+ return "slip";
2357
+ case ARPHRD_CSLIP:
2358
+ return "cslip";
2359
+ case ARPHRD_SLIP6:
2360
+ return "slip6";
2361
+ case ARPHRD_CSLIP6:
2362
+ return "cslip6";
2363
+ case ARPHRD_ADAPT:
2364
+ return "adaptive";
2365
+ case ARPHRD_IEEE802:
2366
+ return "tr";
2367
+ case ARPHRD_IEEE802_TR:
2368
+ return "tr";
2369
+ case ARPHRD_TUNNEL:
2370
+ return "tunnel";
2371
+ case ARPHRD_X25:
2372
+ return "x25";
2373
+ default:
2374
+ return "unknown";
2375
+ }
2376
+ }
2377
+
2378
+ int sigar_arp_list_get(sigar_t *sigar,
2379
+ sigar_arp_list_t *arplist)
2380
+ {
2381
+ FILE *fp;
2382
+ char buffer[1024];
2383
+ char net_addr[128], hwaddr[128], mask_addr[128];
2384
+ int flags, type, status;
2385
+ sigar_arp_t *arp;
2386
+
2387
+ arplist->size = arplist->number = 0;
2388
+
2389
+ if (!(fp = fopen(PROC_FS_ROOT "net/arp", "r"))) {
2390
+ return errno;
2391
+ }
2392
+
2393
+ sigar_arp_list_create(arplist);
2394
+
2395
+ (void)fgets(buffer, sizeof(buffer), fp); /* skip header */
2396
+ while (fgets(buffer, sizeof(buffer), fp)) {
2397
+ int num;
2398
+
2399
+ SIGAR_ARP_LIST_GROW(arplist);
2400
+ arp = &arplist->data[arplist->number++];
2401
+
2402
+ /* XXX rid sscanf */
2403
+ num = sscanf(buffer, "%128s 0x%x 0x%x %128s %128s %16s",
2404
+ net_addr, &type, &flags,
2405
+ hwaddr, mask_addr, arp->ifname);
2406
+
2407
+ if (num < 6) {
2408
+ --arplist->number;
2409
+ continue;
2410
+ }
2411
+
2412
+ arp->flags = flags;
2413
+ status = inet_pton(AF_INET, net_addr, &arp->address.addr);
2414
+ if (status > 0) {
2415
+ arp->address.family = SIGAR_AF_INET;
2416
+ }
2417
+ else if ((status = inet_pton(AF_INET6, net_addr, &arp->address.addr)) > 0) {
2418
+ arp->address.family = SIGAR_AF_INET6;
2419
+ }
2420
+ else {
2421
+ sigar_log_printf(sigar, SIGAR_LOG_WARN,
2422
+ "[arp] failed to parse address='%s' (%s)\n", net_addr,
2423
+ ((status == 0) ? "Invalid format" : sigar_strerror(sigar, errno)));
2424
+ --arplist->number;
2425
+ continue;
2426
+ }
2427
+
2428
+ num = sscanf(hwaddr, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
2429
+ &arp->hwaddr.addr.mac[0],
2430
+ &arp->hwaddr.addr.mac[1],
2431
+ &arp->hwaddr.addr.mac[2],
2432
+ &arp->hwaddr.addr.mac[3],
2433
+ &arp->hwaddr.addr.mac[4],
2434
+ &arp->hwaddr.addr.mac[5]);
2435
+ if (num < 6) {
2436
+ sigar_log_printf(sigar, SIGAR_LOG_WARN,
2437
+ "[arp] failed to parse hwaddr='%s' (%s)\n", hwaddr);
2438
+ --arplist->number;
2439
+ continue;
2440
+ }
2441
+ arp->hwaddr.family = SIGAR_AF_LINK;
2442
+
2443
+ SIGAR_SSTRCPY(arp->type, get_hw_type(type));
2444
+ }
2445
+
2446
+ fclose(fp);
2447
+
2448
+ return SIGAR_OK;
2449
+ }
2450
+
2451
+ int sigar_proc_port_get(sigar_t *sigar, int protocol,
2452
+ unsigned long port, sigar_pid_t *pid)
2453
+ {
2454
+ int status;
2455
+ sigar_net_connection_t netconn;
2456
+ DIR *dirp;
2457
+ struct dirent *ent, dbuf;
2458
+
2459
+ SIGAR_ZERO(&netconn);
2460
+ *pid = 0;
2461
+
2462
+ status = sigar_net_connection_get(sigar, &netconn, port,
2463
+ SIGAR_NETCONN_SERVER|protocol);
2464
+
2465
+ if (status != SIGAR_OK) {
2466
+ return status;
2467
+ }
2468
+
2469
+ if (netconn.local_port != port) {
2470
+ return SIGAR_OK; /* XXX or ENOENT? */
2471
+ }
2472
+
2473
+ if (!(dirp = opendir(PROCP_FS_ROOT))) {
2474
+ return errno;
2475
+ }
2476
+
2477
+ while (readdir_r(dirp, &dbuf, &ent) == 0) {
2478
+ DIR *fd_dirp;
2479
+ struct dirent *fd_ent, fd_dbuf;
2480
+ struct stat sb;
2481
+ char fd_name[BUFSIZ], pid_name[BUFSIZ];
2482
+ int len, slen;
2483
+
2484
+ if (ent == NULL) {
2485
+ break;
2486
+ }
2487
+
2488
+ if (!sigar_isdigit(*ent->d_name)) {
2489
+ continue;
2490
+ }
2491
+
2492
+ /* sprintf(pid_name, "/proc/%s", ent->d_name) */
2493
+ memcpy(&pid_name[0], PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT));
2494
+ len = SSTRLEN(PROCP_FS_ROOT);
2495
+ pid_name[len++] = '/';
2496
+
2497
+ slen = strlen(ent->d_name);
2498
+ memcpy(&pid_name[len], ent->d_name, slen);
2499
+ len += slen;
2500
+ pid_name[len] = '\0';
2501
+
2502
+ if (stat(pid_name, &sb) < 0) {
2503
+ continue;
2504
+ }
2505
+ if (sb.st_uid != netconn.uid) {
2506
+ continue;
2507
+ }
2508
+
2509
+ /* sprintf(fd_name, "%s/fd", pid_name) */
2510
+ memcpy(&fd_name[0], pid_name, len);
2511
+ memcpy(&fd_name[len], "/fd", 3);
2512
+ fd_name[len+=3] = '\0';
2513
+
2514
+ if (!(fd_dirp = opendir(fd_name))) {
2515
+ continue;
2516
+ }
2517
+
2518
+ while (readdir_r(fd_dirp, &fd_dbuf, &fd_ent) == 0) {
2519
+ char fd_ent_name[BUFSIZ];
2520
+
2521
+ if (fd_ent == NULL) {
2522
+ break;
2523
+ }
2524
+
2525
+ if (!sigar_isdigit(*fd_ent->d_name)) {
2526
+ continue;
2527
+ }
2528
+
2529
+ /* sprintf(fd_ent_name, "%s/%s", fd_name, fd_ent->d_name) */
2530
+ slen = strlen(fd_ent->d_name);
2531
+ memcpy(&fd_ent_name[0], fd_name, len);
2532
+ fd_ent_name[len] = '/';
2533
+ memcpy(&fd_ent_name[len+1], fd_ent->d_name, slen);
2534
+ fd_ent_name[len+1+slen] = '\0';
2535
+
2536
+ if (stat(fd_ent_name, &sb) < 0) {
2537
+ continue;
2538
+ }
2539
+
2540
+ if (sb.st_ino == netconn.inode) {
2541
+ closedir(fd_dirp);
2542
+ closedir(dirp);
2543
+ *pid = strtoul(ent->d_name, NULL, 10);
2544
+ return SIGAR_OK;
2545
+ }
2546
+
2547
+ }
2548
+
2549
+ closedir(fd_dirp);
2550
+ }
2551
+
2552
+ closedir(dirp);
2553
+
2554
+ return SIGAR_OK;
2555
+ }
2556
+
2557
+ static void generic_vendor_parse(char *line, sigar_sys_info_t *info)
2558
+ {
2559
+ char *ptr;
2560
+ int len = 0;
2561
+
2562
+ while (*line) {
2563
+ SIGAR_SKIP_SPACE(line);
2564
+ if (!isdigit(*line)) {
2565
+ ++line;
2566
+ continue;
2567
+ }
2568
+
2569
+ ptr = line;
2570
+ while ((isdigit(*ptr) || (*ptr == '.'))) {
2571
+ ++ptr;
2572
+ ++len;
2573
+ }
2574
+
2575
+ if (len) {
2576
+ /* sanity check */
2577
+ if (len > sizeof(info->vendor_version)) {
2578
+ continue;
2579
+ }
2580
+ memcpy(info->vendor_version, line, len);/*XXX*/
2581
+ info->vendor_version[len] = '\0';
2582
+ return;
2583
+ }
2584
+ }
2585
+ }
2586
+
2587
+ static void redhat_vendor_parse(char *line, sigar_sys_info_t *info)
2588
+ {
2589
+ char *start, *end;
2590
+
2591
+ generic_vendor_parse(line, info); /* super.parse */
2592
+
2593
+ if ((start = strchr(line, '('))) {
2594
+ ++start;
2595
+ if ((end = strchr(start, ')'))) {
2596
+ int len = end-start;
2597
+ memcpy(info->vendor_code_name, start, len);/*XXX*/
2598
+ info->vendor_code_name[len] = '\0';
2599
+ }
2600
+ }
2601
+
2602
+ #define RHEL_PREFIX "Red Hat Enterprise Linux "
2603
+ #define CENTOS_VENDOR "CentOS"
2604
+ #define SL_VENDOR "Scientific Linux"
2605
+
2606
+ if (strnEQ(line, RHEL_PREFIX, sizeof(RHEL_PREFIX)-1)) {
2607
+ snprintf(info->vendor_version,
2608
+ sizeof(info->vendor_version),
2609
+ "Enterprise Linux %c",
2610
+ info->vendor_version[0]);
2611
+ }
2612
+ else if (strnEQ(line, CENTOS_VENDOR, sizeof(CENTOS_VENDOR)-1)) {
2613
+ SIGAR_SSTRCPY(info->vendor, CENTOS_VENDOR);
2614
+ }
2615
+ else if (strnEQ(line, SL_VENDOR, sizeof(SL_VENDOR)-1)) {
2616
+ SIGAR_SSTRCPY(info->vendor, SL_VENDOR);
2617
+ }
2618
+ }
2619
+
2620
+ #define is_quote(c) ((c == '\'') || (c == '"'))
2621
+
2622
+ static void kv_parse(char *data, sigar_sys_info_t *info,
2623
+ void (*func)(sigar_sys_info_t *, char *, char *))
2624
+ {
2625
+ char *ptr = data;
2626
+ int len = strlen(data);
2627
+ char *end = data+len;
2628
+
2629
+ while (ptr < end) {
2630
+ char *val = strchr(ptr, '=');
2631
+ int klen, vlen;
2632
+ char key[256], *ix;
2633
+
2634
+ if (!val) {
2635
+ continue;
2636
+ }
2637
+ klen = val - ptr;
2638
+ SIGAR_SSTRCPY(key, ptr);
2639
+ key[klen] = '\0';
2640
+ ++val;
2641
+
2642
+ if ((ix = strchr(val, '\n'))) {
2643
+ *ix = '\0';
2644
+ }
2645
+ vlen = strlen(val);
2646
+ if (is_quote(*val)) {
2647
+ if (is_quote(val[vlen-1])) {
2648
+ val[vlen-1] = '\0';
2649
+ }
2650
+ ++val;
2651
+ }
2652
+
2653
+ func(info, key, val);
2654
+
2655
+ ptr += (klen + 1 + vlen + 1);
2656
+ }
2657
+ }
2658
+
2659
+ static void lsb_parse(sigar_sys_info_t *info,
2660
+ char *key, char *val)
2661
+ {
2662
+ if (strEQ(key, "DISTRIB_ID")) {
2663
+ SIGAR_SSTRCPY(info->vendor, val);
2664
+ }
2665
+ else if (strEQ(key, "DISTRIB_RELEASE")) {
2666
+ SIGAR_SSTRCPY(info->vendor_version, val);
2667
+ }
2668
+ else if (strEQ(key, "DISTRIB_CODENAME")) {
2669
+ SIGAR_SSTRCPY(info->vendor_code_name, val);
2670
+ }
2671
+ }
2672
+
2673
+ static void lsb_vendor_parse(char *data, sigar_sys_info_t *info)
2674
+ {
2675
+ kv_parse(data, info, lsb_parse);
2676
+ }
2677
+
2678
+ static void xen_parse(sigar_sys_info_t *info,
2679
+ char *key, char *val)
2680
+ {
2681
+ if (strEQ(key, "PRODUCT_VERSION")) {
2682
+ SIGAR_SSTRCPY(info->vendor_version, val);
2683
+ }
2684
+ else if (strEQ(key, "KERNEL_VERSION")) {
2685
+ SIGAR_SSTRCPY(info->version, val);
2686
+ }
2687
+ }
2688
+
2689
+ static void xen_vendor_parse(char *data, sigar_sys_info_t *info)
2690
+ {
2691
+ kv_parse(data, info, xen_parse);
2692
+
2693
+ snprintf(info->description,
2694
+ sizeof(info->description),
2695
+ "XenServer %s",
2696
+ info->vendor_version);
2697
+ }
2698
+
2699
+ typedef struct {
2700
+ const char *name;
2701
+ const char *file;
2702
+ void (*parse)(char *, sigar_sys_info_t *);
2703
+ } linux_vendor_info_t;
2704
+
2705
+ static linux_vendor_info_t linux_vendors[] = {
2706
+ { "Fedora", "/etc/fedora-release", NULL },
2707
+ { "SuSE", "/etc/SuSE-release", NULL },
2708
+ { "Gentoo", "/etc/gentoo-release", NULL },
2709
+ { "Slackware", "/etc/slackware-version", NULL },
2710
+ { "Mandrake", "/etc/mandrake-release", NULL },
2711
+ { "VMware", "/proc/vmware/version", NULL },
2712
+ { "XenSource", "/etc/xensource-inventory", xen_vendor_parse },
2713
+ { "Red Hat", "/etc/redhat-release", redhat_vendor_parse },
2714
+ { "lsb", "/etc/lsb-release", lsb_vendor_parse },
2715
+ { "Debian", "/etc/debian_version", NULL },
2716
+ { NULL }
2717
+ };
2718
+
2719
+ static int get_linux_vendor_info(sigar_sys_info_t *info)
2720
+ {
2721
+ int i, status = ENOENT;
2722
+ /* env vars for testing */
2723
+ const char *release_file = getenv("SIGAR_OS_RELEASE_FILE");
2724
+ const char *vendor_name = getenv("SIGAR_OS_VENDOR_NAME");
2725
+ char buffer[8192], *data;
2726
+ linux_vendor_info_t *vendor = NULL;
2727
+
2728
+ for (i=0; linux_vendors[i].name; i++) {
2729
+ struct stat sb;
2730
+ vendor = &linux_vendors[i];
2731
+
2732
+ if (release_file && vendor_name) {
2733
+ if (!strEQ(vendor->name, vendor_name)) {
2734
+ continue;
2735
+ }
2736
+ }
2737
+ else {
2738
+ if (stat(vendor->file, &sb) < 0) {
2739
+ continue;
2740
+ }
2741
+ release_file = vendor->file;
2742
+ }
2743
+
2744
+ status =
2745
+ sigar_file2str(release_file, buffer, sizeof(buffer)-1);
2746
+
2747
+ break;
2748
+ }
2749
+
2750
+ if (status != SIGAR_OK) {
2751
+ return status;
2752
+ }
2753
+
2754
+ data = buffer;
2755
+
2756
+ SIGAR_SSTRCPY(info->vendor, vendor->name);
2757
+
2758
+ if (vendor->parse) {
2759
+ vendor->parse(data, info);
2760
+ }
2761
+ else {
2762
+ generic_vendor_parse(data, info);
2763
+ }
2764
+
2765
+ if (info->description[0] == '\0') {
2766
+ snprintf(info->description,
2767
+ sizeof(info->description),
2768
+ "%s %s",
2769
+ info->vendor, info->vendor_version);
2770
+ }
2771
+
2772
+ return SIGAR_OK;
2773
+ }
2774
+
2775
+ int sigar_os_sys_info_get(sigar_t *sigar,
2776
+ sigar_sys_info_t *sysinfo)
2777
+ {
2778
+
2779
+ get_linux_vendor_info(sysinfo);
2780
+
2781
+ return SIGAR_OK;
2782
+ }