sigar-test 0.7.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/NOTICE +117 -0
  4. data/README +2 -0
  5. data/Rakefile +105 -0
  6. data/bindings/SigarBuild.pm +301 -0
  7. data/bindings/SigarWrapper.pm +3025 -0
  8. data/bindings/ruby/extconf.rb +131 -0
  9. data/bindings/ruby/rbsigar.c +888 -0
  10. data/include/sigar.h +984 -0
  11. data/include/sigar_fileinfo.h +157 -0
  12. data/include/sigar_format.h +65 -0
  13. data/include/sigar_getline.h +18 -0
  14. data/include/sigar_log.h +80 -0
  15. data/include/sigar_private.h +429 -0
  16. data/include/sigar_ptql.h +53 -0
  17. data/include/sigar_util.h +197 -0
  18. data/src/os/aix/aix_sigar.c +2168 -0
  19. data/src/os/aix/sigar_os.h +73 -0
  20. data/src/os/darwin/Info.plist.in +27 -0
  21. data/src/os/darwin/darwin_sigar.c +3718 -0
  22. data/src/os/darwin/sigar_os.h +80 -0
  23. data/src/os/hpux/hpux_sigar.c +1361 -0
  24. data/src/os/hpux/sigar_os.h +49 -0
  25. data/src/os/linux/linux_sigar.c +2810 -0
  26. data/src/os/linux/sigar_os.h +82 -0
  27. data/src/os/solaris/get_mib2.c +321 -0
  28. data/src/os/solaris/get_mib2.h +127 -0
  29. data/src/os/solaris/kstats.c +181 -0
  30. data/src/os/solaris/procfs.c +97 -0
  31. data/src/os/solaris/sigar_os.h +224 -0
  32. data/src/os/solaris/solaris_sigar.c +2732 -0
  33. data/src/os/win32/peb.c +212 -0
  34. data/src/os/win32/sigar.rc.in +40 -0
  35. data/src/os/win32/sigar_os.h +685 -0
  36. data/src/os/win32/sigar_pdh.h +47 -0
  37. data/src/os/win32/win32_sigar.c +4109 -0
  38. data/src/sigar.c +2444 -0
  39. data/src/sigar_cache.c +253 -0
  40. data/src/sigar_fileinfo.c +815 -0
  41. data/src/sigar_format.c +696 -0
  42. data/src/sigar_getline.c +1849 -0
  43. data/src/sigar_ptql.c +1976 -0
  44. data/src/sigar_signal.c +216 -0
  45. data/src/sigar_util.c +1060 -0
  46. data/src/sigar_version.c.in +22 -0
  47. data/src/sigar_version_autoconf.c.in +22 -0
  48. data/version.properties +11 -0
  49. metadata +91 -0
@@ -0,0 +1,2810 @@
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
+ SIGAR_INLINE sigar_uint64_t get_named_proc_token(char *buffer,
772
+ char *token) {
773
+ char *ptr = strstr(buffer, token);
774
+ if (!ptr) {
775
+ return SIGAR_FIELD_NOTIMPL;
776
+ }
777
+ ptr = sigar_skip_token(ptr);
778
+ return sigar_strtoul(ptr);
779
+ }
780
+
781
+ int sigar_proc_cumulative_disk_io_get(sigar_t *sigar, sigar_pid_t pid,
782
+ sigar_proc_cumulative_disk_io_t *proc_cumulative_disk_io)
783
+ {
784
+ char buffer[BUFSIZ];
785
+
786
+ int status = SIGAR_PROC_FILE2STR(buffer, pid, "/io");
787
+
788
+ if (status != SIGAR_OK) {
789
+ return status;
790
+ }
791
+
792
+ proc_cumulative_disk_io->bytes_read = get_named_proc_token(buffer, "\nread_bytes");
793
+ proc_cumulative_disk_io->bytes_written = get_named_proc_token(buffer, "\nwrite_bytes");
794
+ proc_cumulative_disk_io->bytes_total = proc_cumulative_disk_io->bytes_read + proc_cumulative_disk_io->bytes_written;
795
+
796
+ return SIGAR_OK;
797
+ }
798
+
799
+ #define NO_ID_MSG "[proc_cred] /proc/%lu" PROC_PSTATUS " missing "
800
+
801
+ int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
802
+ sigar_proc_cred_t *proccred)
803
+ {
804
+ char buffer[BUFSIZ], *ptr;
805
+ int status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTATUS);
806
+
807
+ if (status != SIGAR_OK) {
808
+ return status;
809
+ }
810
+
811
+ if ((ptr = strstr(buffer, "\nUid:"))) {
812
+ ptr = sigar_skip_token(ptr);
813
+
814
+ proccred->uid = sigar_strtoul(ptr);
815
+ proccred->euid = sigar_strtoul(ptr);
816
+ }
817
+ else {
818
+ sigar_log_printf(sigar, SIGAR_LOG_WARN,
819
+ NO_ID_MSG "Uid", pid);
820
+ return ENOENT;
821
+ }
822
+
823
+ if ((ptr = strstr(ptr, "\nGid:"))) {
824
+ ptr = sigar_skip_token(ptr);
825
+
826
+ proccred->gid = sigar_strtoul(ptr);
827
+ proccred->egid = sigar_strtoul(ptr);
828
+ }
829
+ else {
830
+ sigar_log_printf(sigar, SIGAR_LOG_WARN,
831
+ NO_ID_MSG "Gid", pid);
832
+ return ENOENT;
833
+ }
834
+
835
+ return SIGAR_OK;
836
+ }
837
+
838
+ int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
839
+ sigar_proc_time_t *proctime)
840
+ {
841
+ int status = proc_stat_read(sigar, pid);
842
+ linux_proc_stat_t *pstat = &sigar->last_proc_stat;
843
+
844
+ if (status != SIGAR_OK) {
845
+ return status;
846
+ }
847
+
848
+ proctime->user = pstat->utime;
849
+ proctime->sys = pstat->stime;
850
+ proctime->total = proctime->user + proctime->sys;
851
+ proctime->start_time = pstat->start_time;
852
+
853
+ return SIGAR_OK;
854
+ }
855
+
856
+ static int proc_status_get(sigar_t *sigar, sigar_pid_t pid,
857
+ sigar_proc_state_t *procstate)
858
+ {
859
+ char buffer[BUFSIZ], *ptr;
860
+ int status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTATUS);
861
+
862
+ if (status != SIGAR_OK) {
863
+ return status;
864
+ }
865
+
866
+ ptr = strstr(buffer, "\nThreads:");
867
+ if (ptr) {
868
+ /* 2.6+ kernel only */
869
+ ptr = sigar_skip_token(ptr);
870
+ procstate->threads = sigar_strtoul(ptr);
871
+ }
872
+ else {
873
+ procstate->threads = SIGAR_FIELD_NOTIMPL;
874
+ }
875
+
876
+ return SIGAR_OK;
877
+ }
878
+
879
+ int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
880
+ sigar_proc_state_t *procstate)
881
+ {
882
+ int status = proc_stat_read(sigar, pid);
883
+ linux_proc_stat_t *pstat = &sigar->last_proc_stat;
884
+
885
+ if (status != SIGAR_OK) {
886
+ return status;
887
+ }
888
+
889
+ memcpy(procstate->name, pstat->name, sizeof(procstate->name));
890
+ procstate->state = pstat->state;
891
+
892
+ procstate->ppid = pstat->ppid;
893
+ procstate->tty = pstat->tty;
894
+ procstate->priority = pstat->priority;
895
+ procstate->nice = pstat->nice;
896
+ procstate->processor = pstat->processor;
897
+
898
+ if (sigar_cpu_core_rollup(sigar)) {
899
+ procstate->processor /= sigar->lcpu;
900
+ }
901
+
902
+ proc_status_get(sigar, pid, procstate);
903
+
904
+ return SIGAR_OK;
905
+ }
906
+
907
+ int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
908
+ sigar_proc_args_t *procargs)
909
+ {
910
+ return sigar_procfs_args_get(sigar, pid, procargs);
911
+ }
912
+
913
+ /* glibc 2.8 XXX use sysconf(_SC_ARG_MAX) */
914
+ #ifndef ARG_MAX
915
+ #define ARG_MAX 131072
916
+ #endif
917
+
918
+ int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
919
+ sigar_proc_env_t *procenv)
920
+ {
921
+ int fd;
922
+ char buffer[ARG_MAX]; /* XXX: ARG_MAX == 130k */
923
+ char name[BUFSIZ];
924
+ size_t len;
925
+ char *ptr, *end;
926
+
927
+ /* optimize if pid == $$ and type == ENV_KEY */
928
+ SIGAR_PROC_ENV_KEY_LOOKUP();
929
+
930
+ (void)SIGAR_PROC_FILENAME(name, pid, "/environ");
931
+
932
+ if ((fd = open(name, O_RDONLY)) < 0) {
933
+ if (errno == ENOENT) {
934
+ return ESRCH;
935
+ }
936
+ return errno;
937
+ }
938
+
939
+ len = read(fd, buffer, sizeof(buffer));
940
+
941
+ close(fd);
942
+
943
+ buffer[len] = '\0';
944
+ ptr = buffer;
945
+
946
+ end = buffer + len;
947
+ while (ptr < end) {
948
+ char *val = strchr(ptr, '=');
949
+ int klen, vlen, status;
950
+ char key[128]; /* XXX is there a max key size? */
951
+
952
+ if (val == NULL) {
953
+ /* not key=val format */
954
+ break;
955
+ }
956
+
957
+ klen = val - ptr;
958
+ SIGAR_SSTRCPY(key, ptr);
959
+ key[klen] = '\0';
960
+ ++val;
961
+
962
+ vlen = strlen(val);
963
+ status = procenv->env_getter(procenv->data,
964
+ key, klen, val, vlen);
965
+
966
+ if (status != SIGAR_OK) {
967
+ /* not an error; just stop iterating */
968
+ break;
969
+ }
970
+
971
+ ptr += (klen + 1 + vlen + 1);
972
+ }
973
+
974
+ return SIGAR_OK;
975
+ }
976
+
977
+ int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
978
+ sigar_proc_fd_t *procfd)
979
+ {
980
+ int status =
981
+ sigar_proc_fd_count(sigar, pid, &procfd->total);
982
+
983
+ return status;
984
+ }
985
+
986
+ int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
987
+ sigar_proc_exe_t *procexe)
988
+ {
989
+ int len;
990
+ char name[BUFSIZ];
991
+
992
+ (void)SIGAR_PROC_FILENAME(name, pid, "/cwd");
993
+
994
+ if ((len = readlink(name, procexe->cwd,
995
+ sizeof(procexe->cwd)-1)) < 0)
996
+ {
997
+ return errno;
998
+ }
999
+
1000
+ procexe->cwd[len] = '\0';
1001
+
1002
+ (void)SIGAR_PROC_FILENAME(name, pid, "/exe");
1003
+
1004
+ if ((len = readlink(name, procexe->name,
1005
+ sizeof(procexe->name)-1)) < 0)
1006
+ {
1007
+ return errno;
1008
+ }
1009
+
1010
+ procexe->name[len] = '\0';
1011
+
1012
+ (void)SIGAR_PROC_FILENAME(name, pid, "/root");
1013
+
1014
+ if ((len = readlink(name, procexe->root,
1015
+ sizeof(procexe->root)-1)) < 0)
1016
+ {
1017
+ return errno;
1018
+ }
1019
+
1020
+ procexe->root[len] = '\0';
1021
+
1022
+ return SIGAR_OK;
1023
+ }
1024
+
1025
+ int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
1026
+ sigar_proc_modules_t *procmods)
1027
+ {
1028
+ FILE *fp;
1029
+ char buffer[BUFSIZ], *ptr;
1030
+ unsigned long inode, last_inode = 0;
1031
+
1032
+ (void)SIGAR_PROC_FILENAME(buffer, pid, "/maps");
1033
+
1034
+ if (!(fp = fopen(buffer, "r"))) {
1035
+ return errno;
1036
+ }
1037
+
1038
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
1039
+ int len, status;
1040
+ /* skip region, flags, offset, dev */
1041
+ ptr = sigar_skip_multiple_token(ptr, 4);
1042
+ inode = sigar_strtoul(ptr);
1043
+
1044
+ if ((inode == 0) || (inode == last_inode)) {
1045
+ last_inode = 0;
1046
+ continue;
1047
+ }
1048
+
1049
+ last_inode = inode;
1050
+ SIGAR_SKIP_SPACE(ptr);
1051
+ len = strlen(ptr);
1052
+ ptr[len-1] = '\0'; /* chop \n */
1053
+
1054
+ status =
1055
+ procmods->module_getter(procmods->data,
1056
+ ptr, len-1);
1057
+
1058
+ if (status != SIGAR_OK) {
1059
+ /* not an error; just stop iterating */
1060
+ break;
1061
+ }
1062
+ }
1063
+
1064
+ fclose(fp);
1065
+
1066
+ return SIGAR_OK;
1067
+ }
1068
+
1069
+ int sigar_thread_cpu_get(sigar_t *sigar,
1070
+ sigar_uint64_t id,
1071
+ sigar_thread_cpu_t *cpu)
1072
+ {
1073
+ struct tms now;
1074
+
1075
+ if (id != 0) {
1076
+ return SIGAR_ENOTIMPL;
1077
+ }
1078
+
1079
+ times(&now);
1080
+
1081
+ cpu->user = SIGAR_TICK2NSEC(now.tms_utime);
1082
+ cpu->sys = SIGAR_TICK2NSEC(now.tms_stime);
1083
+ cpu->total = SIGAR_TICK2NSEC(now.tms_utime + now.tms_stime);
1084
+
1085
+ return SIGAR_OK;
1086
+ }
1087
+
1088
+ #include <mntent.h>
1089
+
1090
+ int sigar_os_fs_type_get(sigar_file_system_t *fsp)
1091
+ {
1092
+ char *type = fsp->sys_type_name;
1093
+
1094
+ switch (*type) {
1095
+ case 'e':
1096
+ if (strnEQ(type, "ext", 3)) {
1097
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1098
+ }
1099
+ break;
1100
+ case 'g':
1101
+ if (strEQ(type, "gfs")) {
1102
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1103
+ }
1104
+ break;
1105
+ case 'h':
1106
+ if (strEQ(type, "hpfs")) {
1107
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1108
+ }
1109
+ break;
1110
+ case 'j':
1111
+ if (strnEQ(type, "jfs", 3)) {
1112
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1113
+ }
1114
+ break;
1115
+ case 'o':
1116
+ if (strnEQ(type, "ocfs", 4)) {
1117
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1118
+ }
1119
+ break;
1120
+ case 'p':
1121
+ if (strnEQ(type, "psfs", 4)) {
1122
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1123
+ }
1124
+ break;
1125
+ case 'r':
1126
+ if (strEQ(type, "reiserfs")) {
1127
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1128
+ }
1129
+ break;
1130
+ case 'v':
1131
+ if (strEQ(type, "vzfs")) {
1132
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1133
+ }
1134
+ break;
1135
+ case 'x':
1136
+ if (strEQ(type, "xfs") || strEQ(type, "xiafs")) {
1137
+ fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
1138
+ }
1139
+ break;
1140
+ }
1141
+
1142
+ return fsp->type;
1143
+ }
1144
+
1145
+ int sigar_file_system_list_get(sigar_t *sigar,
1146
+ sigar_file_system_list_t *fslist)
1147
+ {
1148
+ struct mntent ent;
1149
+ char buf[1025]; /* buffer for strings within ent */
1150
+ FILE *fp;
1151
+ sigar_file_system_t *fsp;
1152
+
1153
+ if (!(fp = setmntent(MOUNTED, "r"))) {
1154
+ return errno;
1155
+ }
1156
+
1157
+ sigar_file_system_list_create(fslist);
1158
+
1159
+ while (getmntent_r(fp, &ent, buf, sizeof(buf))) {
1160
+ SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
1161
+
1162
+ fsp = &fslist->data[fslist->number++];
1163
+
1164
+ fsp->type = SIGAR_FSTYPE_UNKNOWN; /* unknown, will be set later */
1165
+ SIGAR_SSTRCPY(fsp->dir_name, ent.mnt_dir);
1166
+ SIGAR_SSTRCPY(fsp->dev_name, ent.mnt_fsname);
1167
+ SIGAR_SSTRCPY(fsp->sys_type_name, ent.mnt_type);
1168
+ SIGAR_SSTRCPY(fsp->options, ent.mnt_opts);
1169
+ sigar_fs_type_get(fsp);
1170
+ }
1171
+
1172
+ endmntent(fp);
1173
+
1174
+ return SIGAR_OK;
1175
+ }
1176
+
1177
+ #define ST_MAJOR(sb) major((sb).st_rdev)
1178
+ #define ST_MINOR(sb) minor((sb).st_rdev)
1179
+
1180
+ static int get_iostat_sys(sigar_t *sigar,
1181
+ const char *dirname,
1182
+ sigar_disk_usage_t *disk,
1183
+ sigar_iodev_t **iodev)
1184
+ {
1185
+ char stat[1025], dev[1025];
1186
+ char *name, *ptr, *fsdev;
1187
+ int partition, status;
1188
+
1189
+ if (!(*iodev = sigar_iodev_get(sigar, dirname))) {
1190
+ return ENXIO;
1191
+ }
1192
+
1193
+ name = fsdev = (*iodev)->name;
1194
+
1195
+ if (SIGAR_NAME_IS_DEV(name)) {
1196
+ name += SSTRLEN(SIGAR_DEV_PREFIX); /* strip "/dev/" */
1197
+ }
1198
+
1199
+ while (!sigar_isdigit(*fsdev)) {
1200
+ fsdev++;
1201
+ }
1202
+
1203
+ partition = strtoul(fsdev, NULL, 0);
1204
+ *fsdev = '\0';
1205
+
1206
+ snprintf(stat, sizeof(stat),
1207
+ SYS_BLOCK "/%s/%s%d/stat", name, name, partition);
1208
+
1209
+ status = sigar_file2str(stat, dev, sizeof(dev));
1210
+ if (status != SIGAR_OK) {
1211
+ return status;
1212
+ }
1213
+
1214
+ ptr = dev;
1215
+ ptr = sigar_skip_token(ptr);
1216
+ disk->reads = sigar_strtoull(ptr);
1217
+ ptr = sigar_skip_token(ptr);
1218
+ disk->writes = sigar_strtoull(ptr);
1219
+
1220
+ disk->read_bytes = SIGAR_FIELD_NOTIMPL;
1221
+ disk->write_bytes = SIGAR_FIELD_NOTIMPL;
1222
+ disk->queue = SIGAR_FIELD_NOTIMPL;
1223
+
1224
+ return SIGAR_OK;
1225
+ }
1226
+
1227
+ static int get_iostat_proc_dstat(sigar_t *sigar,
1228
+ const char *dirname,
1229
+ sigar_disk_usage_t *disk,
1230
+ sigar_iodev_t **iodev,
1231
+ sigar_disk_usage_t *device_usage)
1232
+ {
1233
+ FILE *fp;
1234
+ char buffer[1025];
1235
+ char *ptr;
1236
+ struct stat sb;
1237
+ int status=ENOENT;
1238
+
1239
+ SIGAR_DISK_STATS_INIT(device_usage);
1240
+
1241
+ if (!(*iodev = sigar_iodev_get(sigar, dirname))) {
1242
+ return ENXIO;
1243
+ }
1244
+
1245
+ if (stat((*iodev)->name, &sb) < 0) {
1246
+ return errno;
1247
+ }
1248
+
1249
+ if (SIGAR_LOG_IS_DEBUG(sigar)) {
1250
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1251
+ PROC_DISKSTATS " %s -> %s [%d,%d]",
1252
+ dirname, (*iodev)->name,
1253
+ ST_MAJOR(sb), ST_MINOR(sb));
1254
+ }
1255
+
1256
+ if (!(fp = fopen(PROC_DISKSTATS, "r"))) {
1257
+ return errno;
1258
+ }
1259
+
1260
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
1261
+ unsigned long major, minor;
1262
+
1263
+ major = sigar_strtoul(ptr);
1264
+ minor = sigar_strtoul(ptr);
1265
+
1266
+ if ((major == ST_MAJOR(sb)) &&
1267
+ ((minor == ST_MINOR(sb)) || (minor == 0)))
1268
+ {
1269
+ int num;
1270
+ unsigned long
1271
+ rio, rmerge, rsect, ruse,
1272
+ wio, wmerge, wsect, wuse,
1273
+ running, use, aveq;
1274
+
1275
+ ptr = sigar_skip_token(ptr); /* name */
1276
+
1277
+ num = sscanf(ptr,
1278
+ "%lu %lu %lu %lu "
1279
+ "%lu %lu %lu %lu "
1280
+ "%lu %lu %lu",
1281
+ &rio, /* 1 # reads issued */
1282
+ &rmerge, /* 2 # reads merged */
1283
+ &rsect, /* 3 # sectors read */
1284
+ &ruse, /* 4 # millis spent reading */
1285
+ &wio, /* 5 # writes completed */
1286
+ &wmerge, /* 6 # writes merged */
1287
+ &wsect, /* 7 # sectors written */
1288
+ &wuse, /* 8 # millis spent writing */
1289
+ &running, /* 9 # I/Os currently in progress */
1290
+ &use, /* 10 # millis spent doing I/Os */
1291
+ &aveq); /* 11 # of millis spent doing I/Os (weighted) */
1292
+
1293
+ if (num == 11) {
1294
+ disk->rtime = ruse;
1295
+ disk->wtime = wuse;
1296
+ disk->time = use;
1297
+ disk->qtime = aveq;
1298
+ }
1299
+ else if (num == 4) {
1300
+ wio = rsect;
1301
+ rsect = rmerge;
1302
+ wsect = ruse;
1303
+ disk->time = disk->qtime = SIGAR_FIELD_NOTIMPL;
1304
+ }
1305
+ else {
1306
+ status = ENOENT;
1307
+ }
1308
+
1309
+ disk->reads = rio;
1310
+ disk->writes = wio;
1311
+ disk->read_bytes = rsect;
1312
+ disk->write_bytes = wsect;
1313
+
1314
+ /* convert sectors to bytes (512 is fixed size in 2.6 kernels) */
1315
+ disk->read_bytes *= 512;
1316
+ disk->write_bytes *= 512;
1317
+
1318
+ if (minor == ST_MINOR(sb)) {
1319
+ status = SIGAR_OK;
1320
+ break;
1321
+ }
1322
+ else if (minor == 0) {
1323
+ memcpy(device_usage, disk, sizeof(*device_usage));
1324
+ }
1325
+ }
1326
+ }
1327
+
1328
+ fclose(fp);
1329
+
1330
+ return status;
1331
+ }
1332
+
1333
+ static int get_iostat_procp(sigar_t *sigar,
1334
+ const char *dirname,
1335
+ sigar_disk_usage_t *disk,
1336
+ sigar_iodev_t **iodev)
1337
+ {
1338
+ FILE *fp;
1339
+ char buffer[1025];
1340
+ char *ptr;
1341
+ struct stat sb;
1342
+
1343
+ if (!(*iodev = sigar_iodev_get(sigar, dirname))) {
1344
+ return ENXIO;
1345
+ }
1346
+
1347
+ if (stat((*iodev)->name, &sb) < 0) {
1348
+ return errno;
1349
+ }
1350
+
1351
+ if (SIGAR_LOG_IS_DEBUG(sigar)) {
1352
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1353
+ PROC_PARTITIONS " %s -> %s [%d,%d]",
1354
+ dirname, (*iodev)->name,
1355
+ ST_MAJOR(sb), ST_MINOR(sb));
1356
+ }
1357
+
1358
+ if (!(fp = fopen(PROC_PARTITIONS, "r"))) {
1359
+ return errno;
1360
+ }
1361
+
1362
+ (void)fgets(buffer, sizeof(buffer), fp); /* skip header */
1363
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
1364
+ unsigned long major, minor;
1365
+
1366
+ major = sigar_strtoul(ptr);
1367
+ minor = sigar_strtoul(ptr);
1368
+
1369
+ if ((major == ST_MAJOR(sb)) && (minor == ST_MINOR(sb))) {
1370
+ ptr = sigar_skip_token(ptr); /* blocks */
1371
+ ptr = sigar_skip_token(ptr); /* name */
1372
+ disk->reads = sigar_strtoull(ptr); /* rio */
1373
+ ptr = sigar_skip_token(ptr); /* rmerge */
1374
+ disk->read_bytes = sigar_strtoull(ptr); /* rsect */
1375
+ disk->rtime = sigar_strtoull(ptr); /* ruse */
1376
+ disk->writes = sigar_strtoull(ptr); /* wio */
1377
+ ptr = sigar_skip_token(ptr); /* wmerge */
1378
+ disk->write_bytes = sigar_strtoull(ptr); /* wsect */
1379
+ disk->wtime = sigar_strtoull(ptr); /* wuse */
1380
+ ptr = sigar_skip_token(ptr); /* running */
1381
+ disk->time = sigar_strtoull(ptr); /* use */
1382
+ disk->qtime = sigar_strtoull(ptr); /* aveq */
1383
+
1384
+ /* convert sectors to bytes (512 is fixed size in 2.6 kernels) */
1385
+ disk->read_bytes *= 512;
1386
+ disk->write_bytes *= 512;
1387
+
1388
+ fclose(fp);
1389
+ return SIGAR_OK;
1390
+ }
1391
+ }
1392
+
1393
+ fclose(fp);
1394
+
1395
+ return ENOENT;
1396
+ }
1397
+
1398
+ int sigar_disk_usage_get(sigar_t *sigar, const char *name,
1399
+ sigar_disk_usage_t *disk)
1400
+ {
1401
+ int status;
1402
+ sigar_iodev_t *iodev = NULL;
1403
+ sigar_disk_usage_t device_usage;
1404
+ SIGAR_DISK_STATS_INIT(disk);
1405
+
1406
+ /*
1407
+ * 2.2 has metrics /proc/stat, but wtf is the device mapping?
1408
+ * 2.4 has /proc/partitions w/ the metrics.
1409
+ * 2.6 has /proc/partitions w/o the metrics.
1410
+ * instead the metrics are within the /proc-like /sys filesystem.
1411
+ * also has /proc/diskstats
1412
+ */
1413
+ switch (sigar->iostat) {
1414
+ case IOSTAT_SYS:
1415
+ status = get_iostat_sys(sigar, name, disk, &iodev);
1416
+ break;
1417
+ case IOSTAT_DISKSTATS:
1418
+ status = get_iostat_proc_dstat(sigar, name, disk, &iodev, &device_usage);
1419
+ break;
1420
+ case IOSTAT_PARTITIONS:
1421
+ status = get_iostat_procp(sigar, name, disk, &iodev);
1422
+ break;
1423
+ /*
1424
+ * case IOSTAT_SOME_OTHER_WIERD_THING:
1425
+ * break;
1426
+ */
1427
+ case IOSTAT_NONE:
1428
+ default:
1429
+ status = ENOENT;
1430
+ break;
1431
+ }
1432
+
1433
+ if ((status == SIGAR_OK) && iodev) {
1434
+ sigar_uptime_t uptime;
1435
+ sigar_uint64_t interval, ios;
1436
+ double tput, util;
1437
+ sigar_disk_usage_t *partition_usage=NULL;
1438
+
1439
+ sigar_uptime_get(sigar, &uptime);
1440
+
1441
+ if (iodev->is_partition &&
1442
+ (sigar->iostat == IOSTAT_DISKSTATS))
1443
+ {
1444
+ /* 2.6 kernels do not have per-partition times */
1445
+ partition_usage = disk;
1446
+ disk = &device_usage;
1447
+ }
1448
+
1449
+ disk->snaptime = uptime.uptime;
1450
+
1451
+ if (iodev->disk.snaptime) {
1452
+ interval = disk->snaptime - iodev->disk.snaptime;
1453
+ }
1454
+ else {
1455
+ interval = disk->snaptime;
1456
+ }
1457
+
1458
+ ios =
1459
+ (disk->reads - iodev->disk.reads) +
1460
+ (disk->writes - iodev->disk.writes);
1461
+
1462
+ if (disk->time == SIGAR_FIELD_NOTIMPL) {
1463
+ disk->service_time = SIGAR_FIELD_NOTIMPL;
1464
+ }
1465
+ else {
1466
+ tput = ((double)ios) * HZ / interval;
1467
+ util = ((double)(disk->time - iodev->disk.time)) / interval * HZ;
1468
+ disk->service_time = tput ? util / tput : 0.0;
1469
+ }
1470
+ if (disk->qtime == SIGAR_FIELD_NOTIMPL) {
1471
+ disk->queue = SIGAR_FIELD_NOTIMPL;
1472
+ }
1473
+ else {
1474
+ util = ((double)(disk->qtime - iodev->disk.qtime)) / interval;
1475
+ disk->queue = util / 1000.0;
1476
+ }
1477
+
1478
+ memcpy(&iodev->disk, disk, sizeof(iodev->disk));
1479
+ if (partition_usage) {
1480
+ partition_usage->service_time = disk->service_time;
1481
+ partition_usage->queue = disk->queue;
1482
+ }
1483
+ }
1484
+
1485
+ return status;
1486
+ }
1487
+
1488
+ int sigar_file_system_usage_get(sigar_t *sigar,
1489
+ const char *dirname,
1490
+ sigar_file_system_usage_t *fsusage)
1491
+ {
1492
+ int status = sigar_statvfs(sigar, dirname, fsusage);
1493
+
1494
+ if (status != SIGAR_OK) {
1495
+ return status;
1496
+ }
1497
+
1498
+ fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
1499
+
1500
+ (void)sigar_disk_usage_get(sigar, dirname, &fsusage->disk);
1501
+
1502
+ return SIGAR_OK;
1503
+ }
1504
+
1505
+ static SIGAR_INLINE char *cpu_info_strval(char *ptr)
1506
+ {
1507
+ if ((ptr = strchr(ptr, ':'))) {
1508
+ ptr++;
1509
+ while (isspace (*ptr)) ptr++;
1510
+ return ptr;
1511
+ }
1512
+ return NULL;
1513
+ }
1514
+
1515
+ static SIGAR_INLINE void cpu_info_strcpy(char *ptr, char *buf, int len)
1516
+ {
1517
+ int slen;
1518
+ ptr = cpu_info_strval(ptr);
1519
+ if (!ptr) {
1520
+ return;
1521
+ }
1522
+ slen = strlen(ptr);
1523
+ strncpy(buf, ptr, len);
1524
+ buf[len] = '\0';
1525
+ if (slen < len) {
1526
+ buf[slen-1] = '\0'; /* rid \n */
1527
+ }
1528
+ }
1529
+
1530
+ static int get_cpu_info(sigar_t *sigar, sigar_cpu_info_t *info,
1531
+ FILE *fp)
1532
+ {
1533
+ char buffer[BUFSIZ], *ptr;
1534
+
1535
+ int found = 0;
1536
+
1537
+ /* UML vm wont have "cpu MHz" or "cache size" fields */
1538
+ info->mhz = 0;
1539
+ info->cache_size = 0;
1540
+
1541
+ #ifdef __powerpc64__
1542
+ SIGAR_SSTRCPY(info->vendor, "IBM");
1543
+ #endif
1544
+
1545
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
1546
+ switch (*ptr) {
1547
+ case 'p': /* processor : 0 */
1548
+ if (strnEQ(ptr, "processor", 9)) {
1549
+ found = 1;
1550
+ }
1551
+ break;
1552
+ case 'v':
1553
+ /* "vendor_id" or "vendor" */
1554
+ if (strnEQ(ptr, "vendor", 6)) {
1555
+ cpu_info_strcpy(ptr, info->vendor, sizeof(info->vendor));
1556
+ if (strEQ(info->vendor, "GenuineIntel")) {
1557
+ SIGAR_SSTRCPY(info->vendor, "Intel");
1558
+ }
1559
+ else if (strEQ(info->vendor, "AuthenticAMD")) {
1560
+ SIGAR_SSTRCPY(info->vendor, "AMD");
1561
+ }
1562
+ }
1563
+ break;
1564
+ case 'f':
1565
+ if (strnEQ(ptr, "family", 6)) {
1566
+ /* IA64 version of "model name" */
1567
+ cpu_info_strcpy(ptr, info->model, sizeof(info->model));
1568
+ sigar_cpu_model_adjust(sigar, info);
1569
+ }
1570
+ break;
1571
+ case 'm':
1572
+ if (strnEQ(ptr, "model name", 10)) {
1573
+ cpu_info_strcpy(ptr, info->model, sizeof(info->model));
1574
+ sigar_cpu_model_adjust(sigar, info);
1575
+ }
1576
+ break;
1577
+ case 'c':
1578
+ if (strnEQ(ptr, "cpu MHz", 7)) {
1579
+ ptr = cpu_info_strval(ptr);
1580
+ info->mhz = atoi(ptr);
1581
+ }
1582
+ else if (strnEQ(ptr, "cache size", 10)) {
1583
+ ptr = cpu_info_strval(ptr);
1584
+ info->cache_size = sigar_strtoul(ptr);
1585
+ }
1586
+ #ifdef __powerpc64__
1587
+ /* each /proc/cpuinfo entry looks like so:
1588
+ * processor : 0
1589
+ * cpu : POWER5 (gr)
1590
+ * clock : 1656.392000MHz
1591
+ * revision : 2.2
1592
+ */
1593
+ else if (strnEQ(ptr, "clock", 5)) {
1594
+ ptr = cpu_info_strval(ptr);
1595
+ info->mhz = atoi(ptr);
1596
+ }
1597
+ else if (strnEQ(ptr, "cpu", 3)) {
1598
+ cpu_info_strcpy(ptr, info->model, sizeof(info->model));
1599
+
1600
+ if ((ptr = strchr(info->model, ' '))) {
1601
+ /* "POWER5 (gr)" -> "POWER5" */
1602
+ *ptr = '\0';
1603
+ }
1604
+ }
1605
+ #endif
1606
+ break;
1607
+ /* lone \n means end of info for this processor */
1608
+ case '\n':
1609
+ return found;
1610
+ }
1611
+ }
1612
+
1613
+ return found;
1614
+ }
1615
+
1616
+ /* /proc/cpuinfo MHz will change w/ AMD + PowerNow */
1617
+ static void get_cpuinfo_max_freq(sigar_cpu_info_t *cpu_info, int num)
1618
+ {
1619
+ int status;
1620
+ char max_freq[PATH_MAX];
1621
+ snprintf(max_freq, sizeof(max_freq),
1622
+ "/sys/devices/system/cpu/cpu%d"
1623
+ "/cpufreq/cpuinfo_max_freq", num);
1624
+
1625
+ status =
1626
+ sigar_file2str(max_freq, max_freq, sizeof(max_freq)-1);
1627
+
1628
+ if (status == SIGAR_OK) {
1629
+ cpu_info->mhz_max = atoi(max_freq) / 1000;
1630
+ }
1631
+ }
1632
+
1633
+ static void get_cpuinfo_min_freq(sigar_cpu_info_t *cpu_info, int num)
1634
+ {
1635
+ int status;
1636
+ char min_freq[PATH_MAX];
1637
+ snprintf(min_freq, sizeof(min_freq),
1638
+ "/sys/devices/system/cpu/cpu%d"
1639
+ "/cpufreq/cpuinfo_min_freq", num);
1640
+
1641
+ status =
1642
+ sigar_file2str(min_freq, min_freq, sizeof(min_freq)-1);
1643
+
1644
+ if (status == SIGAR_OK) {
1645
+ cpu_info->mhz_min = atoi(min_freq) / 1000;
1646
+ }
1647
+ }
1648
+
1649
+ int sigar_cpu_info_list_get(sigar_t *sigar,
1650
+ sigar_cpu_info_list_t *cpu_infos)
1651
+ {
1652
+ FILE *fp;
1653
+ int core_rollup = sigar_cpu_core_rollup(sigar), i=0;
1654
+
1655
+ if (!(fp = fopen(PROC_FS_ROOT "cpuinfo", "r"))) {
1656
+ return errno;
1657
+ }
1658
+
1659
+ (void)sigar_cpu_total_count(sigar);
1660
+ sigar_cpu_info_list_create(cpu_infos);
1661
+
1662
+ while (get_cpu_info(sigar, &cpu_infos->data[cpu_infos->number], fp)) {
1663
+ sigar_cpu_info_t *info;
1664
+
1665
+ if (core_rollup && (i++ % sigar->lcpu)) {
1666
+ continue; /* fold logical processors */
1667
+ }
1668
+
1669
+ info = &cpu_infos->data[cpu_infos->number];
1670
+ get_cpuinfo_max_freq(info, cpu_infos->number);
1671
+ get_cpuinfo_min_freq(info, cpu_infos->number);
1672
+
1673
+ info->total_cores = sigar->ncpu;
1674
+ info->cores_per_socket = sigar->lcpu;
1675
+ info->total_sockets = sigar_cpu_socket_count(sigar);
1676
+
1677
+ ++cpu_infos->number;
1678
+ SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
1679
+ }
1680
+
1681
+ fclose(fp);
1682
+
1683
+ return SIGAR_OK;
1684
+ }
1685
+
1686
+ static SIGAR_INLINE unsigned int hex2int(const char *x, int len)
1687
+ {
1688
+ int i;
1689
+ unsigned int j;
1690
+
1691
+ for (i=0, j=0; i<len; i++) {
1692
+ register int ch = x[i];
1693
+ j <<= 4;
1694
+ if (isdigit(ch)) {
1695
+ j |= ch - '0';
1696
+ }
1697
+ else if (isupper(ch)) {
1698
+ j |= ch - ('A' - 10);
1699
+ }
1700
+ else {
1701
+ j |= ch - ('a' - 10);
1702
+ }
1703
+ }
1704
+
1705
+ return j;
1706
+ }
1707
+
1708
+ #define HEX_ENT_LEN 8
1709
+
1710
+ #ifdef SIGAR_64BIT
1711
+ #define ROUTE_FMT "%16s %128s %128s %X %ld %ld %ld %128s %ld %ld %ld\n"
1712
+ #else
1713
+ #define ROUTE_FMT "%16s %128s %128s %X %lld %lld %lld %128s %lld %lld %lld\n"
1714
+ #endif
1715
+ #define RTF_UP 0x0001
1716
+
1717
+ int sigar_net_route_list_get(sigar_t *sigar,
1718
+ sigar_net_route_list_t *routelist)
1719
+ {
1720
+ FILE *fp;
1721
+ char buffer[1024];
1722
+ char net_addr[128], gate_addr[128], mask_addr[128];
1723
+ int flags;
1724
+ sigar_net_route_t *route;
1725
+
1726
+ routelist->size = routelist->number = 0;
1727
+
1728
+ if (!(fp = fopen(PROC_FS_ROOT "net/route", "r"))) {
1729
+ return errno;
1730
+ }
1731
+
1732
+ sigar_net_route_list_create(routelist);
1733
+
1734
+ (void)fgets(buffer, sizeof(buffer), fp); /* skip header */
1735
+ while (fgets(buffer, sizeof(buffer), fp)) {
1736
+ int num;
1737
+
1738
+ SIGAR_NET_ROUTE_LIST_GROW(routelist);
1739
+ route = &routelist->data[routelist->number++];
1740
+
1741
+ /* XXX rid sscanf */
1742
+ num = sscanf(buffer, ROUTE_FMT,
1743
+ route->ifname, net_addr, gate_addr,
1744
+ &flags, &route->refcnt, &route->use,
1745
+ &route->metric, mask_addr,
1746
+ &route->mtu, &route->window, &route->irtt);
1747
+
1748
+ if ((num < 10) || !(flags & RTF_UP)) {
1749
+ --routelist->number;
1750
+ continue;
1751
+ }
1752
+
1753
+ route->flags = flags;
1754
+
1755
+ sigar_net_address_set(route->destination, hex2int(net_addr, HEX_ENT_LEN));
1756
+ sigar_net_address_set(route->gateway, hex2int(gate_addr, HEX_ENT_LEN));
1757
+ sigar_net_address_set(route->mask, hex2int(mask_addr, HEX_ENT_LEN));
1758
+ }
1759
+
1760
+ fclose(fp);
1761
+
1762
+ return SIGAR_OK;
1763
+ }
1764
+
1765
+ int sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
1766
+ sigar_net_interface_stat_t *ifstat)
1767
+ {
1768
+ int found = 0;
1769
+ char buffer[BUFSIZ];
1770
+ FILE *fp = fopen(PROC_FS_ROOT "net/dev", "r");
1771
+
1772
+ if (!fp) {
1773
+ return errno;
1774
+ }
1775
+
1776
+ /* skip header */
1777
+ fgets(buffer, sizeof(buffer), fp);
1778
+ fgets(buffer, sizeof(buffer), fp);
1779
+
1780
+ while (fgets(buffer, sizeof(buffer), fp)) {
1781
+ char *ptr, *dev;
1782
+
1783
+ dev = buffer;
1784
+ while (isspace(*dev)) {
1785
+ dev++;
1786
+ }
1787
+
1788
+ if (!(ptr = strchr(dev, ':'))) {
1789
+ continue;
1790
+ }
1791
+
1792
+ *ptr++ = 0;
1793
+
1794
+ if (!strEQ(dev, name)) {
1795
+ continue;
1796
+ }
1797
+
1798
+ found = 1;
1799
+ ifstat->rx_bytes = sigar_strtoull(ptr);
1800
+ ifstat->rx_packets = sigar_strtoull(ptr);
1801
+ ifstat->rx_errors = sigar_strtoull(ptr);
1802
+ ifstat->rx_dropped = sigar_strtoull(ptr);
1803
+ ifstat->rx_overruns = sigar_strtoull(ptr);
1804
+ ifstat->rx_frame = sigar_strtoull(ptr);
1805
+
1806
+ /* skip: compressed multicast */
1807
+ ptr = sigar_skip_multiple_token(ptr, 2);
1808
+
1809
+ ifstat->tx_bytes = sigar_strtoull(ptr);
1810
+ ifstat->tx_packets = sigar_strtoull(ptr);
1811
+ ifstat->tx_errors = sigar_strtoull(ptr);
1812
+ ifstat->tx_dropped = sigar_strtoull(ptr);
1813
+ ifstat->tx_overruns = sigar_strtoull(ptr);
1814
+ ifstat->tx_collisions = sigar_strtoull(ptr);
1815
+ ifstat->tx_carrier = sigar_strtoull(ptr);
1816
+
1817
+ ifstat->speed = SIGAR_FIELD_NOTIMPL;
1818
+
1819
+ break;
1820
+ }
1821
+
1822
+ fclose(fp);
1823
+
1824
+ return found ? SIGAR_OK : ENXIO;
1825
+ }
1826
+
1827
+ static SIGAR_INLINE void convert_hex_address(sigar_net_address_t *address,
1828
+ char *ptr, int len)
1829
+ {
1830
+ if (len > HEX_ENT_LEN) {
1831
+ int i;
1832
+ for (i=0; i<=3; i++, ptr+=HEX_ENT_LEN) {
1833
+ address->addr.in6[i] = hex2int(ptr, HEX_ENT_LEN);
1834
+ }
1835
+
1836
+ address->family = SIGAR_AF_INET6;
1837
+ }
1838
+ else {
1839
+ address->addr.in =
1840
+ (len == HEX_ENT_LEN) ? hex2int(ptr, HEX_ENT_LEN) : 0;
1841
+
1842
+ address->family = SIGAR_AF_INET;
1843
+ }
1844
+ }
1845
+
1846
+ typedef struct {
1847
+ sigar_net_connection_list_t *connlist;
1848
+ sigar_net_connection_t *conn;
1849
+ unsigned long port;
1850
+ } net_conn_getter_t;
1851
+
1852
+ static int proc_net_walker(sigar_net_connection_walker_t *walker,
1853
+ sigar_net_connection_t *conn)
1854
+ {
1855
+ net_conn_getter_t *getter =
1856
+ (net_conn_getter_t *)walker->data;
1857
+
1858
+ if (getter->connlist) {
1859
+ SIGAR_NET_CONNLIST_GROW(getter->connlist);
1860
+ memcpy(&getter->connlist->data[getter->connlist->number++],
1861
+ conn, sizeof(*conn));
1862
+ }
1863
+ else {
1864
+ if ((getter->port == conn->local_port) &&
1865
+ (conn->remote_port == 0))
1866
+ {
1867
+ memcpy(getter->conn, conn, sizeof(*conn));
1868
+ return !SIGAR_OK; /* break loop */
1869
+ }
1870
+ }
1871
+
1872
+ return SIGAR_OK; /* continue loop */
1873
+ }
1874
+
1875
+ #define SKIP_WHILE(p, c) while (*p == c) p++
1876
+ #define SKIP_PAST(p, c) \
1877
+ while(*p && (*p != c)) p++; \
1878
+ SKIP_WHILE(p, c)
1879
+
1880
+ typedef struct {
1881
+ FILE *fp;
1882
+ int (*close)(FILE *);
1883
+ } xproc_t;
1884
+
1885
+ static FILE *xproc_open(const char *command, xproc_t *xproc)
1886
+ {
1887
+ struct stat sb;
1888
+ if (stat(command, &sb) == 0) {
1889
+ if (sb.st_mode & S_IXUSR) {
1890
+ /* executable script for testing large
1891
+ * conn table where we can sleep() to better
1892
+ * simulate /proc/net/tcp behavior
1893
+ */
1894
+ xproc->fp = popen(command, "r");
1895
+ xproc->close = pclose;
1896
+ }
1897
+ else {
1898
+ xproc->fp = fopen(command, "r");
1899
+ xproc->close = fclose;
1900
+ }
1901
+ return xproc->fp;
1902
+ }
1903
+ else {
1904
+ return NULL;
1905
+ }
1906
+ }
1907
+
1908
+ static int proc_net_read(sigar_net_connection_walker_t *walker,
1909
+ const char *fname,
1910
+ int type)
1911
+ {
1912
+ FILE *fp = NULL;
1913
+ char buffer[8192];
1914
+ sigar_t *sigar = walker->sigar;
1915
+ char *ptr = sigar->proc_net;
1916
+ int flags = walker->flags;
1917
+ xproc_t xproc = { NULL, fclose };
1918
+
1919
+ if (ptr) {
1920
+ snprintf(buffer, sizeof(buffer),
1921
+ "%s/%s", ptr,
1922
+ fname + sizeof(PROC_FS_ROOT)-1);
1923
+
1924
+ if ((fp = xproc_open(buffer, &xproc))) {
1925
+ if (SIGAR_LOG_IS_DEBUG(sigar)) {
1926
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1927
+ "[proc_net] using %s",
1928
+ buffer);
1929
+ }
1930
+ }
1931
+ else if (SIGAR_LOG_IS_DEBUG(sigar)) {
1932
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1933
+ "[proc_net] cannot open %s",
1934
+ buffer);
1935
+ }
1936
+ }
1937
+
1938
+ if (!(fp || (fp = fopen(fname, "r")))) {
1939
+ return errno;
1940
+ }
1941
+
1942
+ fgets(buffer, sizeof(buffer), fp); /* skip header */
1943
+
1944
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
1945
+ sigar_net_connection_t conn;
1946
+ char *laddr, *raddr;
1947
+ int laddr_len=0, raddr_len=0;
1948
+ int more;
1949
+
1950
+ /* skip leading space */
1951
+ SKIP_WHILE(ptr, ' ');
1952
+
1953
+ /* skip "%d: " */
1954
+ SKIP_PAST(ptr, ' ');
1955
+
1956
+ laddr = ptr;
1957
+ while (*ptr && (*ptr != ':')) {
1958
+ laddr_len++;
1959
+ ptr++;
1960
+ }
1961
+ SKIP_WHILE(ptr, ':');
1962
+
1963
+ conn.local_port = (strtoul(ptr, &ptr, 16) & 0xffff);
1964
+
1965
+ SKIP_WHILE(ptr, ' ');
1966
+
1967
+ raddr = ptr;
1968
+ while (*ptr && (*ptr != ':')) {
1969
+ raddr_len++;
1970
+ ptr++;
1971
+ }
1972
+ SKIP_WHILE(ptr, ':');
1973
+
1974
+ conn.remote_port = (strtoul(ptr, &ptr, 16) & 0xffff);
1975
+
1976
+ SKIP_WHILE(ptr, ' ');
1977
+
1978
+ if (!((conn.remote_port && (flags & SIGAR_NETCONN_CLIENT)) ||
1979
+ (!conn.remote_port && (flags & SIGAR_NETCONN_SERVER))))
1980
+ {
1981
+ continue;
1982
+ }
1983
+
1984
+ conn.type = type;
1985
+
1986
+ convert_hex_address(&conn.local_address,
1987
+ laddr, laddr_len);
1988
+
1989
+ convert_hex_address(&conn.remote_address,
1990
+ raddr, raddr_len);
1991
+
1992
+ /* SIGAR_TCP_* currently matches TCP_* in linux/tcp.h */
1993
+ conn.state = hex2int(ptr, 2);
1994
+ ptr += 2;
1995
+ SKIP_WHILE(ptr, ' ');
1996
+
1997
+ conn.send_queue = hex2int(ptr, HEX_ENT_LEN);
1998
+ ptr += HEX_ENT_LEN+1; /* tx + ':' */;
1999
+
2000
+ conn.receive_queue = hex2int(ptr, HEX_ENT_LEN);
2001
+ ptr += HEX_ENT_LEN;
2002
+ SKIP_WHILE(ptr, ' ');
2003
+
2004
+ SKIP_PAST(ptr, ' '); /* tr:tm->whem */
2005
+ SKIP_PAST(ptr, ' '); /* retrnsmt */
2006
+
2007
+ conn.uid = sigar_strtoul(ptr);
2008
+
2009
+ SKIP_WHILE(ptr, ' ');
2010
+ SKIP_PAST(ptr, ' '); /* timeout */
2011
+
2012
+ conn.inode = sigar_strtoul(ptr);
2013
+
2014
+ more = walker->add_connection(walker, &conn);
2015
+ if (more != SIGAR_OK) {
2016
+ xproc.close(fp);
2017
+ return SIGAR_OK;
2018
+ }
2019
+ }
2020
+
2021
+ xproc.close(fp);
2022
+
2023
+ return SIGAR_OK;
2024
+ }
2025
+
2026
+ int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
2027
+ {
2028
+ int flags = walker->flags;
2029
+ int status;
2030
+
2031
+ if (flags & SIGAR_NETCONN_TCP) {
2032
+ status = proc_net_read(walker,
2033
+ PROC_FS_ROOT "net/tcp",
2034
+ SIGAR_NETCONN_TCP);
2035
+
2036
+ if (status != SIGAR_OK) {
2037
+ return status;
2038
+ }
2039
+
2040
+ status = proc_net_read(walker,
2041
+ PROC_FS_ROOT "net/tcp6",
2042
+ SIGAR_NETCONN_TCP);
2043
+
2044
+ if (!((status == SIGAR_OK) || (status == ENOENT))) {
2045
+ return status;
2046
+ }
2047
+ }
2048
+
2049
+ if (flags & SIGAR_NETCONN_UDP) {
2050
+ status = proc_net_read(walker,
2051
+ PROC_FS_ROOT "net/udp",
2052
+ SIGAR_NETCONN_UDP);
2053
+
2054
+ if (status != SIGAR_OK) {
2055
+ return status;
2056
+ }
2057
+
2058
+ status = proc_net_read(walker,
2059
+ PROC_FS_ROOT "net/udp6",
2060
+ SIGAR_NETCONN_UDP);
2061
+
2062
+ if (!((status == SIGAR_OK) || (status == ENOENT))) {
2063
+ return status;
2064
+ }
2065
+ }
2066
+
2067
+ if (flags & SIGAR_NETCONN_RAW) {
2068
+ status = proc_net_read(walker,
2069
+ PROC_FS_ROOT "net/raw",
2070
+ SIGAR_NETCONN_RAW);
2071
+
2072
+ if (status != SIGAR_OK) {
2073
+ return status;
2074
+ }
2075
+
2076
+ status = proc_net_read(walker,
2077
+ PROC_FS_ROOT "net/raw6",
2078
+ SIGAR_NETCONN_RAW);
2079
+
2080
+ if (!((status == SIGAR_OK) || (status == ENOENT))) {
2081
+ return status;
2082
+ }
2083
+ }
2084
+
2085
+ /* XXX /proc/net/unix */
2086
+
2087
+ return SIGAR_OK;
2088
+ }
2089
+
2090
+ int sigar_net_connection_list_get(sigar_t *sigar,
2091
+ sigar_net_connection_list_t *connlist,
2092
+ int flags)
2093
+ {
2094
+ int status;
2095
+ sigar_net_connection_walker_t walker;
2096
+ net_conn_getter_t getter;
2097
+
2098
+ sigar_net_connection_list_create(connlist);
2099
+
2100
+ getter.conn = NULL;
2101
+ getter.connlist = connlist;
2102
+
2103
+ walker.sigar = sigar;
2104
+ walker.flags = flags;
2105
+ walker.data = &getter;
2106
+ walker.add_connection = proc_net_walker;
2107
+
2108
+ status = sigar_net_connection_walk(&walker);
2109
+
2110
+ if (status != SIGAR_OK) {
2111
+ sigar_net_connection_list_destroy(sigar, connlist);
2112
+ }
2113
+
2114
+ return status;
2115
+ }
2116
+
2117
+ static int sigar_net_connection_get(sigar_t *sigar,
2118
+ sigar_net_connection_t *netconn,
2119
+ unsigned long port,
2120
+ int flags)
2121
+ {
2122
+ int status;
2123
+ sigar_net_connection_walker_t walker;
2124
+ net_conn_getter_t getter;
2125
+
2126
+ getter.conn = netconn;
2127
+ getter.connlist = NULL;
2128
+ getter.port = port;
2129
+
2130
+ walker.sigar = sigar;
2131
+ walker.flags = flags;
2132
+ walker.data = &getter;
2133
+ walker.add_connection = proc_net_walker;
2134
+
2135
+ status = sigar_net_connection_walk(&walker);
2136
+
2137
+ return status;
2138
+ }
2139
+
2140
+ int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name,
2141
+ sigar_net_interface_config_t *ifconfig)
2142
+ {
2143
+ FILE *fp;
2144
+ char addr[32+1], ifname[8+1];
2145
+ int status = SIGAR_ENOENT;
2146
+ int idx, prefix, scope, flags;
2147
+
2148
+ if (!(fp = fopen(PROC_FS_ROOT "net/if_inet6", "r"))) {
2149
+ return errno;
2150
+ }
2151
+
2152
+ while (fscanf(fp, "%32s %02x %02x %02x %02x %8s\n",
2153
+ addr, &idx, &prefix, &scope, &flags, ifname) != EOF)
2154
+ {
2155
+ if (strEQ(name, ifname)) {
2156
+ status = SIGAR_OK;
2157
+ break;
2158
+ }
2159
+ }
2160
+
2161
+ fclose(fp);
2162
+
2163
+ if (status == SIGAR_OK) {
2164
+ int i=0;
2165
+ unsigned char *addr6 = (unsigned char *)&(ifconfig->address6.addr.in6);
2166
+ char *ptr = addr;
2167
+
2168
+ for (i=0; i<16; i++, ptr+=2) {
2169
+ addr6[i] = (unsigned char)hex2int(ptr, 2);
2170
+ }
2171
+
2172
+ ifconfig->prefix6_length = prefix;
2173
+ ifconfig->scope6 = scope;
2174
+ }
2175
+
2176
+ return status;
2177
+ }
2178
+
2179
+ #define SNMP_TCP_PREFIX "Tcp: "
2180
+
2181
+ SIGAR_DECLARE(int)
2182
+ sigar_tcp_get(sigar_t *sigar,
2183
+ sigar_tcp_t *tcp)
2184
+ {
2185
+ FILE *fp;
2186
+ char buffer[1024], *ptr=buffer;
2187
+ int status = SIGAR_ENOENT;
2188
+
2189
+ if (!(fp = fopen(PROC_FS_ROOT "net/snmp", "r"))) {
2190
+ return errno;
2191
+ }
2192
+
2193
+ while (fgets(buffer, sizeof(buffer), fp)) {
2194
+ if (strnEQ(buffer, SNMP_TCP_PREFIX, sizeof(SNMP_TCP_PREFIX)-1)) {
2195
+ if (fgets(buffer, sizeof(buffer), fp)) {
2196
+ status = SIGAR_OK;
2197
+ break;
2198
+ }
2199
+ }
2200
+ }
2201
+
2202
+ fclose(fp);
2203
+
2204
+ if (status == SIGAR_OK) {
2205
+ /* assuming field order, same in 2.2, 2.4 and 2.6 kernels */
2206
+ /* Tcp: RtoAlgorithm RtoMin RtoMax MaxConn */
2207
+ ptr = sigar_skip_multiple_token(ptr, 5);
2208
+ tcp->active_opens = sigar_strtoull(ptr);
2209
+ tcp->passive_opens = sigar_strtoull(ptr);
2210
+ tcp->attempt_fails = sigar_strtoull(ptr);
2211
+ tcp->estab_resets = sigar_strtoull(ptr);
2212
+ tcp->curr_estab = sigar_strtoull(ptr);
2213
+ tcp->in_segs = sigar_strtoull(ptr);
2214
+ tcp->out_segs = sigar_strtoull(ptr);
2215
+ tcp->retrans_segs = sigar_strtoull(ptr);
2216
+ tcp->in_errs = sigar_strtoull(ptr);
2217
+ tcp->out_rsts = sigar_strtoull(ptr);
2218
+ }
2219
+
2220
+ return status;
2221
+ }
2222
+
2223
+ static int sigar_proc_nfs_gets(char *file, char *tok,
2224
+ char *buffer, size_t size)
2225
+ {
2226
+ int status = ENOENT;
2227
+ int len = strlen(tok);
2228
+ FILE *fp = fopen(file, "r");
2229
+
2230
+ if (!fp) {
2231
+ return SIGAR_ENOTIMPL;
2232
+ }
2233
+
2234
+ while (fgets(buffer, size, fp)) {
2235
+ if (strnEQ(buffer, tok, len)) {
2236
+ status = SIGAR_OK;
2237
+ break;
2238
+ }
2239
+ }
2240
+
2241
+ fclose(fp);
2242
+
2243
+ return status;
2244
+ }
2245
+
2246
+ static int sigar_nfs_v2_get(char *file, sigar_nfs_v2_t *nfs)
2247
+ {
2248
+ char buffer[BUFSIZ], *ptr=buffer;
2249
+ int status =
2250
+ sigar_proc_nfs_gets(file,
2251
+ "proc2", buffer, sizeof(buffer));
2252
+
2253
+ if (status != SIGAR_OK) {
2254
+ return status;
2255
+ }
2256
+
2257
+ ptr = sigar_skip_multiple_token(ptr, 2);
2258
+
2259
+ nfs->null = sigar_strtoull(ptr);
2260
+ nfs->getattr = sigar_strtoull(ptr);
2261
+ nfs->setattr = sigar_strtoull(ptr);
2262
+ nfs->root = sigar_strtoull(ptr);
2263
+ nfs->lookup = sigar_strtoull(ptr);
2264
+ nfs->readlink = sigar_strtoull(ptr);
2265
+ nfs->read = sigar_strtoull(ptr);
2266
+ nfs->writecache = sigar_strtoull(ptr);
2267
+ nfs->write = sigar_strtoull(ptr);
2268
+ nfs->create = sigar_strtoull(ptr);
2269
+ nfs->remove = sigar_strtoull(ptr);
2270
+ nfs->rename = sigar_strtoull(ptr);
2271
+ nfs->link = sigar_strtoull(ptr);
2272
+ nfs->symlink = sigar_strtoull(ptr);
2273
+ nfs->mkdir = sigar_strtoull(ptr);
2274
+ nfs->rmdir = sigar_strtoull(ptr);
2275
+ nfs->readdir = sigar_strtoull(ptr);
2276
+ nfs->fsstat = sigar_strtoull(ptr);
2277
+
2278
+ return SIGAR_OK;
2279
+ }
2280
+
2281
+ int sigar_nfs_client_v2_get(sigar_t *sigar,
2282
+ sigar_nfs_client_v2_t *nfs)
2283
+ {
2284
+ return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfs",
2285
+ (sigar_nfs_v2_t *)nfs);
2286
+ }
2287
+
2288
+ int sigar_nfs_server_v2_get(sigar_t *sigar,
2289
+ sigar_nfs_server_v2_t *nfs)
2290
+ {
2291
+ return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfsd",
2292
+ (sigar_nfs_v2_t *)nfs);
2293
+ }
2294
+
2295
+ static int sigar_nfs_v3_get(char *file, sigar_nfs_v3_t *nfs)
2296
+ {
2297
+ char buffer[BUFSIZ], *ptr=buffer;
2298
+ int status =
2299
+ sigar_proc_nfs_gets(file,
2300
+ "proc3", buffer, sizeof(buffer));
2301
+
2302
+ if (status != SIGAR_OK) {
2303
+ return status;
2304
+ }
2305
+
2306
+ ptr = sigar_skip_multiple_token(ptr, 2);
2307
+
2308
+ nfs->null = sigar_strtoull(ptr);
2309
+ nfs->getattr = sigar_strtoull(ptr);
2310
+ nfs->setattr = sigar_strtoull(ptr);
2311
+ nfs->lookup = sigar_strtoull(ptr);
2312
+ nfs->access = sigar_strtoull(ptr);
2313
+ nfs->readlink = sigar_strtoull(ptr);
2314
+ nfs->read = sigar_strtoull(ptr);
2315
+ nfs->write = sigar_strtoull(ptr);
2316
+ nfs->create = sigar_strtoull(ptr);
2317
+ nfs->mkdir = sigar_strtoull(ptr);
2318
+ nfs->symlink = sigar_strtoull(ptr);
2319
+ nfs->mknod = sigar_strtoull(ptr);
2320
+ nfs->remove = sigar_strtoull(ptr);
2321
+ nfs->rmdir = sigar_strtoull(ptr);
2322
+ nfs->rename = sigar_strtoull(ptr);
2323
+ nfs->link = sigar_strtoull(ptr);
2324
+ nfs->readdir = sigar_strtoull(ptr);
2325
+ nfs->readdirplus = sigar_strtoull(ptr);
2326
+ nfs->fsstat = sigar_strtoull(ptr);
2327
+ nfs->fsinfo = sigar_strtoull(ptr);
2328
+ nfs->pathconf = sigar_strtoull(ptr);
2329
+ nfs->commit = sigar_strtoull(ptr);
2330
+
2331
+ return SIGAR_OK;
2332
+ }
2333
+
2334
+ int sigar_nfs_client_v3_get(sigar_t *sigar,
2335
+ sigar_nfs_client_v3_t *nfs)
2336
+ {
2337
+ return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfs",
2338
+ (sigar_nfs_v3_t *)nfs);
2339
+ }
2340
+
2341
+ int sigar_nfs_server_v3_get(sigar_t *sigar,
2342
+ sigar_nfs_server_v3_t *nfs)
2343
+ {
2344
+ return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfsd",
2345
+ (sigar_nfs_v3_t *)nfs);
2346
+ }
2347
+
2348
+ #include <net/if_arp.h>
2349
+
2350
+ static char *get_hw_type(int type)
2351
+ {
2352
+ switch (type) {
2353
+ case ARPHRD_AX25:
2354
+ return "ax25";
2355
+ case ARPHRD_ECONET:
2356
+ return "ec";
2357
+ case ARPHRD_ETHER:
2358
+ return "ether";
2359
+ case ARPHRD_FDDI:
2360
+ return "fddi";
2361
+ case ARPHRD_DLCI:
2362
+ return "dlci";
2363
+ case ARPHRD_FRAD:
2364
+ return "frad";
2365
+ case ARPHRD_HDLC:
2366
+ return "hdlc";
2367
+ case ARPHRD_LAPB:
2368
+ return "lapb";
2369
+ case ARPHRD_HIPPI:
2370
+ return "hippi";
2371
+ case ARPHRD_IRDA:
2372
+ return "irda";
2373
+ case ARPHRD_LOOPBACK:
2374
+ return "loop";
2375
+ case ARPHRD_NETROM:
2376
+ return "netrom";
2377
+ case ARPHRD_PPP:
2378
+ return "ppp";
2379
+ case ARPHRD_ROSE:
2380
+ return "rose";
2381
+ case ARPHRD_SIT:
2382
+ return "sit";
2383
+ case ARPHRD_SLIP:
2384
+ return "slip";
2385
+ case ARPHRD_CSLIP:
2386
+ return "cslip";
2387
+ case ARPHRD_SLIP6:
2388
+ return "slip6";
2389
+ case ARPHRD_CSLIP6:
2390
+ return "cslip6";
2391
+ case ARPHRD_ADAPT:
2392
+ return "adaptive";
2393
+ case ARPHRD_IEEE802:
2394
+ return "tr";
2395
+ case ARPHRD_IEEE802_TR:
2396
+ return "tr";
2397
+ case ARPHRD_TUNNEL:
2398
+ return "tunnel";
2399
+ case ARPHRD_X25:
2400
+ return "x25";
2401
+ default:
2402
+ return "unknown";
2403
+ }
2404
+ }
2405
+
2406
+ int sigar_arp_list_get(sigar_t *sigar,
2407
+ sigar_arp_list_t *arplist)
2408
+ {
2409
+ FILE *fp;
2410
+ char buffer[1024];
2411
+ char net_addr[128], hwaddr[128], mask_addr[128];
2412
+ int flags, type, status;
2413
+ sigar_arp_t *arp;
2414
+
2415
+ arplist->size = arplist->number = 0;
2416
+
2417
+ if (!(fp = fopen(PROC_FS_ROOT "net/arp", "r"))) {
2418
+ return errno;
2419
+ }
2420
+
2421
+ sigar_arp_list_create(arplist);
2422
+
2423
+ (void)fgets(buffer, sizeof(buffer), fp); /* skip header */
2424
+ while (fgets(buffer, sizeof(buffer), fp)) {
2425
+ int num;
2426
+
2427
+ SIGAR_ARP_LIST_GROW(arplist);
2428
+ arp = &arplist->data[arplist->number++];
2429
+
2430
+ /* XXX rid sscanf */
2431
+ num = sscanf(buffer, "%128s 0x%x 0x%x %128s %128s %16s",
2432
+ net_addr, &type, &flags,
2433
+ hwaddr, mask_addr, arp->ifname);
2434
+
2435
+ if (num < 6) {
2436
+ --arplist->number;
2437
+ continue;
2438
+ }
2439
+
2440
+ arp->flags = flags;
2441
+ status = inet_pton(AF_INET, net_addr, &arp->address.addr);
2442
+ if (status > 0) {
2443
+ arp->address.family = SIGAR_AF_INET;
2444
+ }
2445
+ else if ((status = inet_pton(AF_INET6, net_addr, &arp->address.addr)) > 0) {
2446
+ arp->address.family = SIGAR_AF_INET6;
2447
+ }
2448
+ else {
2449
+ sigar_log_printf(sigar, SIGAR_LOG_WARN,
2450
+ "[arp] failed to parse address='%s' (%s)\n", net_addr,
2451
+ ((status == 0) ? "Invalid format" : sigar_strerror(sigar, errno)));
2452
+ --arplist->number;
2453
+ continue;
2454
+ }
2455
+
2456
+ num = sscanf(hwaddr, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
2457
+ &arp->hwaddr.addr.mac[0],
2458
+ &arp->hwaddr.addr.mac[1],
2459
+ &arp->hwaddr.addr.mac[2],
2460
+ &arp->hwaddr.addr.mac[3],
2461
+ &arp->hwaddr.addr.mac[4],
2462
+ &arp->hwaddr.addr.mac[5]);
2463
+ if (num < 6) {
2464
+ sigar_log_printf(sigar, SIGAR_LOG_WARN,
2465
+ "[arp] failed to parse hwaddr='%s' (%s)\n", hwaddr);
2466
+ --arplist->number;
2467
+ continue;
2468
+ }
2469
+ arp->hwaddr.family = SIGAR_AF_LINK;
2470
+
2471
+ SIGAR_SSTRCPY(arp->type, get_hw_type(type));
2472
+ }
2473
+
2474
+ fclose(fp);
2475
+
2476
+ return SIGAR_OK;
2477
+ }
2478
+
2479
+ int sigar_proc_port_get(sigar_t *sigar, int protocol,
2480
+ unsigned long port, sigar_pid_t *pid)
2481
+ {
2482
+ int status;
2483
+ sigar_net_connection_t netconn;
2484
+ DIR *dirp;
2485
+ struct dirent *ent, dbuf;
2486
+
2487
+ SIGAR_ZERO(&netconn);
2488
+ *pid = 0;
2489
+
2490
+ status = sigar_net_connection_get(sigar, &netconn, port,
2491
+ SIGAR_NETCONN_SERVER|protocol);
2492
+
2493
+ if (status != SIGAR_OK) {
2494
+ return status;
2495
+ }
2496
+
2497
+ if (netconn.local_port != port) {
2498
+ return SIGAR_OK; /* XXX or ENOENT? */
2499
+ }
2500
+
2501
+ if (!(dirp = opendir(PROCP_FS_ROOT))) {
2502
+ return errno;
2503
+ }
2504
+
2505
+ while (readdir_r(dirp, &dbuf, &ent) == 0) {
2506
+ DIR *fd_dirp;
2507
+ struct dirent *fd_ent, fd_dbuf;
2508
+ struct stat sb;
2509
+ char fd_name[BUFSIZ], pid_name[BUFSIZ];
2510
+ int len, slen;
2511
+
2512
+ if (ent == NULL) {
2513
+ break;
2514
+ }
2515
+
2516
+ if (!sigar_isdigit(*ent->d_name)) {
2517
+ continue;
2518
+ }
2519
+
2520
+ /* sprintf(pid_name, "/proc/%s", ent->d_name) */
2521
+ memcpy(&pid_name[0], PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT));
2522
+ len = SSTRLEN(PROCP_FS_ROOT);
2523
+ pid_name[len++] = '/';
2524
+
2525
+ slen = strlen(ent->d_name);
2526
+ memcpy(&pid_name[len], ent->d_name, slen);
2527
+ len += slen;
2528
+ pid_name[len] = '\0';
2529
+
2530
+ if (stat(pid_name, &sb) < 0) {
2531
+ continue;
2532
+ }
2533
+ if (sb.st_uid != netconn.uid) {
2534
+ continue;
2535
+ }
2536
+
2537
+ /* sprintf(fd_name, "%s/fd", pid_name) */
2538
+ memcpy(&fd_name[0], pid_name, len);
2539
+ memcpy(&fd_name[len], "/fd", 3);
2540
+ fd_name[len+=3] = '\0';
2541
+
2542
+ if (!(fd_dirp = opendir(fd_name))) {
2543
+ continue;
2544
+ }
2545
+
2546
+ while (readdir_r(fd_dirp, &fd_dbuf, &fd_ent) == 0) {
2547
+ char fd_ent_name[BUFSIZ];
2548
+
2549
+ if (fd_ent == NULL) {
2550
+ break;
2551
+ }
2552
+
2553
+ if (!sigar_isdigit(*fd_ent->d_name)) {
2554
+ continue;
2555
+ }
2556
+
2557
+ /* sprintf(fd_ent_name, "%s/%s", fd_name, fd_ent->d_name) */
2558
+ slen = strlen(fd_ent->d_name);
2559
+ memcpy(&fd_ent_name[0], fd_name, len);
2560
+ fd_ent_name[len] = '/';
2561
+ memcpy(&fd_ent_name[len+1], fd_ent->d_name, slen);
2562
+ fd_ent_name[len+1+slen] = '\0';
2563
+
2564
+ if (stat(fd_ent_name, &sb) < 0) {
2565
+ continue;
2566
+ }
2567
+
2568
+ if (sb.st_ino == netconn.inode) {
2569
+ closedir(fd_dirp);
2570
+ closedir(dirp);
2571
+ *pid = strtoul(ent->d_name, NULL, 10);
2572
+ return SIGAR_OK;
2573
+ }
2574
+
2575
+ }
2576
+
2577
+ closedir(fd_dirp);
2578
+ }
2579
+
2580
+ closedir(dirp);
2581
+
2582
+ return SIGAR_OK;
2583
+ }
2584
+
2585
+ static void generic_vendor_parse(char *line, sigar_sys_info_t *info)
2586
+ {
2587
+ char *ptr;
2588
+ int len = 0;
2589
+
2590
+ while (*line) {
2591
+ SIGAR_SKIP_SPACE(line);
2592
+ if (!isdigit(*line)) {
2593
+ ++line;
2594
+ continue;
2595
+ }
2596
+
2597
+ ptr = line;
2598
+ while ((isdigit(*ptr) || (*ptr == '.'))) {
2599
+ ++ptr;
2600
+ ++len;
2601
+ }
2602
+
2603
+ if (len) {
2604
+ /* sanity check */
2605
+ if (len > sizeof(info->vendor_version)) {
2606
+ continue;
2607
+ }
2608
+ memcpy(info->vendor_version, line, len);/*XXX*/
2609
+ info->vendor_version[len] = '\0';
2610
+ return;
2611
+ }
2612
+ }
2613
+ }
2614
+
2615
+ static void redhat_vendor_parse(char *line, sigar_sys_info_t *info)
2616
+ {
2617
+ char *start, *end;
2618
+
2619
+ generic_vendor_parse(line, info); /* super.parse */
2620
+
2621
+ if ((start = strchr(line, '('))) {
2622
+ ++start;
2623
+ if ((end = strchr(start, ')'))) {
2624
+ int len = end-start;
2625
+ memcpy(info->vendor_code_name, start, len);/*XXX*/
2626
+ info->vendor_code_name[len] = '\0';
2627
+ }
2628
+ }
2629
+
2630
+ #define RHEL_PREFIX "Red Hat Enterprise Linux "
2631
+ #define CENTOS_VENDOR "CentOS"
2632
+ #define SL_VENDOR "Scientific Linux"
2633
+
2634
+ if (strnEQ(line, RHEL_PREFIX, sizeof(RHEL_PREFIX)-1)) {
2635
+ snprintf(info->vendor_version,
2636
+ sizeof(info->vendor_version),
2637
+ "Enterprise Linux %c",
2638
+ info->vendor_version[0]);
2639
+ }
2640
+ else if (strnEQ(line, CENTOS_VENDOR, sizeof(CENTOS_VENDOR)-1)) {
2641
+ SIGAR_SSTRCPY(info->vendor, CENTOS_VENDOR);
2642
+ }
2643
+ else if (strnEQ(line, SL_VENDOR, sizeof(SL_VENDOR)-1)) {
2644
+ SIGAR_SSTRCPY(info->vendor, SL_VENDOR);
2645
+ }
2646
+ }
2647
+
2648
+ #define is_quote(c) ((c == '\'') || (c == '"'))
2649
+
2650
+ static void kv_parse(char *data, sigar_sys_info_t *info,
2651
+ void (*func)(sigar_sys_info_t *, char *, char *))
2652
+ {
2653
+ char *ptr = data;
2654
+ int len = strlen(data);
2655
+ char *end = data+len;
2656
+
2657
+ while (ptr < end) {
2658
+ char *val = strchr(ptr, '=');
2659
+ int klen, vlen;
2660
+ char key[256], *ix;
2661
+
2662
+ if (!val) {
2663
+ continue;
2664
+ }
2665
+ klen = val - ptr;
2666
+ SIGAR_SSTRCPY(key, ptr);
2667
+ key[klen] = '\0';
2668
+ ++val;
2669
+
2670
+ if ((ix = strchr(val, '\n'))) {
2671
+ *ix = '\0';
2672
+ }
2673
+ vlen = strlen(val);
2674
+ if (is_quote(*val)) {
2675
+ if (is_quote(val[vlen-1])) {
2676
+ val[vlen-1] = '\0';
2677
+ }
2678
+ ++val;
2679
+ }
2680
+
2681
+ func(info, key, val);
2682
+
2683
+ ptr += (klen + 1 + vlen + 1);
2684
+ }
2685
+ }
2686
+
2687
+ static void lsb_parse(sigar_sys_info_t *info,
2688
+ char *key, char *val)
2689
+ {
2690
+ if (strEQ(key, "DISTRIB_ID")) {
2691
+ SIGAR_SSTRCPY(info->vendor, val);
2692
+ }
2693
+ else if (strEQ(key, "DISTRIB_RELEASE")) {
2694
+ SIGAR_SSTRCPY(info->vendor_version, val);
2695
+ }
2696
+ else if (strEQ(key, "DISTRIB_CODENAME")) {
2697
+ SIGAR_SSTRCPY(info->vendor_code_name, val);
2698
+ }
2699
+ }
2700
+
2701
+ static void lsb_vendor_parse(char *data, sigar_sys_info_t *info)
2702
+ {
2703
+ kv_parse(data, info, lsb_parse);
2704
+ }
2705
+
2706
+ static void xen_parse(sigar_sys_info_t *info,
2707
+ char *key, char *val)
2708
+ {
2709
+ if (strEQ(key, "PRODUCT_VERSION")) {
2710
+ SIGAR_SSTRCPY(info->vendor_version, val);
2711
+ }
2712
+ else if (strEQ(key, "KERNEL_VERSION")) {
2713
+ SIGAR_SSTRCPY(info->version, val);
2714
+ }
2715
+ }
2716
+
2717
+ static void xen_vendor_parse(char *data, sigar_sys_info_t *info)
2718
+ {
2719
+ kv_parse(data, info, xen_parse);
2720
+
2721
+ snprintf(info->description,
2722
+ sizeof(info->description),
2723
+ "XenServer %s",
2724
+ info->vendor_version);
2725
+ }
2726
+
2727
+ typedef struct {
2728
+ const char *name;
2729
+ const char *file;
2730
+ void (*parse)(char *, sigar_sys_info_t *);
2731
+ } linux_vendor_info_t;
2732
+
2733
+ static linux_vendor_info_t linux_vendors[] = {
2734
+ { "Fedora", "/etc/fedora-release", NULL },
2735
+ { "SuSE", "/etc/SuSE-release", NULL },
2736
+ { "Gentoo", "/etc/gentoo-release", NULL },
2737
+ { "Slackware", "/etc/slackware-version", NULL },
2738
+ { "Mandrake", "/etc/mandrake-release", NULL },
2739
+ { "VMware", "/proc/vmware/version", NULL },
2740
+ { "XenSource", "/etc/xensource-inventory", xen_vendor_parse },
2741
+ { "Red Hat", "/etc/redhat-release", redhat_vendor_parse },
2742
+ { "lsb", "/etc/lsb-release", lsb_vendor_parse },
2743
+ { "Debian", "/etc/debian_version", NULL },
2744
+ { NULL }
2745
+ };
2746
+
2747
+ static int get_linux_vendor_info(sigar_sys_info_t *info)
2748
+ {
2749
+ int i, status = ENOENT;
2750
+ /* env vars for testing */
2751
+ const char *release_file = getenv("SIGAR_OS_RELEASE_FILE");
2752
+ const char *vendor_name = getenv("SIGAR_OS_VENDOR_NAME");
2753
+ char buffer[8192], *data;
2754
+ linux_vendor_info_t *vendor = NULL;
2755
+
2756
+ for (i=0; linux_vendors[i].name; i++) {
2757
+ struct stat sb;
2758
+ vendor = &linux_vendors[i];
2759
+
2760
+ if (release_file && vendor_name) {
2761
+ if (!strEQ(vendor->name, vendor_name)) {
2762
+ continue;
2763
+ }
2764
+ }
2765
+ else {
2766
+ if (stat(vendor->file, &sb) < 0) {
2767
+ continue;
2768
+ }
2769
+ release_file = vendor->file;
2770
+ }
2771
+
2772
+ status =
2773
+ sigar_file2str(release_file, buffer, sizeof(buffer)-1);
2774
+
2775
+ break;
2776
+ }
2777
+
2778
+ if (status != SIGAR_OK) {
2779
+ return status;
2780
+ }
2781
+
2782
+ data = buffer;
2783
+
2784
+ SIGAR_SSTRCPY(info->vendor, vendor->name);
2785
+
2786
+ if (vendor->parse) {
2787
+ vendor->parse(data, info);
2788
+ }
2789
+ else {
2790
+ generic_vendor_parse(data, info);
2791
+ }
2792
+
2793
+ if (info->description[0] == '\0') {
2794
+ snprintf(info->description,
2795
+ sizeof(info->description),
2796
+ "%s %s",
2797
+ info->vendor, info->vendor_version);
2798
+ }
2799
+
2800
+ return SIGAR_OK;
2801
+ }
2802
+
2803
+ int sigar_os_sys_info_get(sigar_t *sigar,
2804
+ sigar_sys_info_t *sysinfo)
2805
+ {
2806
+
2807
+ get_linux_vendor_info(sysinfo);
2808
+
2809
+ return SIGAR_OK;
2810
+ }