hyperic-sigar 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. data/COPYING +339 -0
  2. data/EXCEPTIONS +104 -0
  3. data/README +2 -0
  4. data/Rakefile +87 -0
  5. data/bindings/SigarWrapper.pm +2934 -0
  6. data/bindings/ruby/examples/cpu_info.rb +16 -0
  7. data/bindings/ruby/examples/df.rb +32 -0
  8. data/bindings/ruby/examples/free.rb +19 -0
  9. data/bindings/ruby/examples/ifconfig.rb +67 -0
  10. data/bindings/ruby/examples/netstat.rb +54 -0
  11. data/bindings/ruby/examples/pargs.rb +18 -0
  12. data/bindings/ruby/examples/penv.rb +14 -0
  13. data/bindings/ruby/examples/route.rb +31 -0
  14. data/bindings/ruby/examples/who.rb +13 -0
  15. data/bindings/ruby/extconf.rb +110 -0
  16. data/bindings/ruby/rbsigar.c +628 -0
  17. data/include/sigar.h +901 -0
  18. data/include/sigar_fileinfo.h +141 -0
  19. data/include/sigar_format.h +65 -0
  20. data/include/sigar_getline.h +18 -0
  21. data/include/sigar_log.h +82 -0
  22. data/include/sigar_private.h +365 -0
  23. data/include/sigar_ptql.h +55 -0
  24. data/include/sigar_util.h +192 -0
  25. data/src/os/aix/aix_sigar.c +1927 -0
  26. data/src/os/aix/sigar_os.h +71 -0
  27. data/src/os/darwin/darwin_sigar.c +3450 -0
  28. data/src/os/darwin/sigar_os.h +82 -0
  29. data/src/os/hpux/dlpi.c +284 -0
  30. data/src/os/hpux/hpux_sigar.c +1205 -0
  31. data/src/os/hpux/sigar_os.h +51 -0
  32. data/src/os/linux/linux_sigar.c +2595 -0
  33. data/src/os/linux/sigar_os.h +84 -0
  34. data/src/os/netware/netware_sigar.c +719 -0
  35. data/src/os/netware/sigar_os.h +26 -0
  36. data/src/os/osf1/osf1_sigar.c +593 -0
  37. data/src/os/osf1/sigar_os.h +42 -0
  38. data/src/os/solaris/get_mib2.c +321 -0
  39. data/src/os/solaris/get_mib2.h +127 -0
  40. data/src/os/solaris/hmekstat.h +77 -0
  41. data/src/os/solaris/kstats.c +182 -0
  42. data/src/os/solaris/procfs.c +99 -0
  43. data/src/os/solaris/sigar_os.h +225 -0
  44. data/src/os/solaris/solaris_sigar.c +2561 -0
  45. data/src/os/stub/sigar_os.h +8 -0
  46. data/src/os/stub/stub_sigar.c +303 -0
  47. data/src/os/win32/peb.c +213 -0
  48. data/src/os/win32/sigar_os.h +623 -0
  49. data/src/os/win32/sigar_pdh.h +49 -0
  50. data/src/os/win32/win32_sigar.c +3718 -0
  51. data/src/sigar.c +2292 -0
  52. data/src/sigar_cache.c +181 -0
  53. data/src/sigar_fileinfo.c +792 -0
  54. data/src/sigar_format.c +649 -0
  55. data/src/sigar_getline.c +1849 -0
  56. data/src/sigar_ptql.c +1966 -0
  57. data/src/sigar_signal.c +218 -0
  58. data/src/sigar_util.c +1061 -0
  59. data/version.properties +11 -0
  60. metadata +112 -0
@@ -0,0 +1,51 @@
1
+ /*
2
+ * Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
3
+ * This file is part of SIGAR.
4
+ *
5
+ * SIGAR is free software; you can redistribute it and/or modify
6
+ * it under the terms version 2 of the GNU General Public License as
7
+ * published by the Free Software Foundation. This program is distributed
8
+ * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
9
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10
+ * PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ * details.
12
+ *
13
+ * You should have received a copy of the GNU General Public License
14
+ * along with this program; if not, write to the Free Software
15
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
16
+ * USA.
17
+ */
18
+
19
+ #ifndef SIGAR_OS_H
20
+ #define SIGAR_OS_H
21
+
22
+ #if defined(__ia64) && !defined(__ia64__)
23
+ #define __ia64__
24
+ #endif
25
+
26
+ #ifdef __ia64__
27
+ #ifndef _LP64
28
+ #define _LP64
29
+ #endif
30
+ #endif
31
+
32
+ #define _PSTAT64
33
+
34
+ #include <sys/pstat.h>
35
+ #include <sys/mib.h>
36
+ #include <stdlib.h>
37
+ #include <fcntl.h>
38
+
39
+ struct sigar_t {
40
+ SIGAR_T_BASE;
41
+ struct pst_static pstatic;
42
+ time_t last_getprocs;
43
+ sigar_pid_t last_pid;
44
+ struct pst_status *pinfo;
45
+
46
+ int mib;
47
+ };
48
+
49
+ int hpux_get_mib_ifentry(int ppa, mib_ifEntry *mib);
50
+
51
+ #endif /* SIGAR_OS_H */
@@ -0,0 +1,2595 @@
1
+ /*
2
+ * Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
3
+ * This file is part of SIGAR.
4
+ *
5
+ * SIGAR is free software; you can redistribute it and/or modify
6
+ * it under the terms version 2 of the GNU General Public License as
7
+ * published by the Free Software Foundation. This program is distributed
8
+ * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
9
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10
+ * PARTICULAR PURPOSE. See the GNU General Public License for more
11
+ * details.
12
+ *
13
+ * You should have received a copy of the GNU General Public License
14
+ * along with this program; if not, write to the Free Software
15
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
16
+ * USA.
17
+ */
18
+
19
+ #include <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 = atoi(max_freq) / 1000;
1602
+ }
1603
+ }
1604
+
1605
+ int sigar_cpu_info_list_get(sigar_t *sigar,
1606
+ sigar_cpu_info_list_t *cpu_infos)
1607
+ {
1608
+ FILE *fp;
1609
+ int core_rollup = sigar_cpu_core_rollup(sigar), i=0;
1610
+
1611
+ if (!(fp = fopen(PROC_FS_ROOT "cpuinfo", "r"))) {
1612
+ return errno;
1613
+ }
1614
+
1615
+ (void)sigar_cpu_total_count(sigar);
1616
+ sigar_cpu_info_list_create(cpu_infos);
1617
+
1618
+ while (get_cpu_info(sigar, &cpu_infos->data[cpu_infos->number], fp)) {
1619
+ sigar_cpu_info_t *info;
1620
+
1621
+ if (core_rollup && (i++ % sigar->lcpu)) {
1622
+ continue; /* fold logical processors */
1623
+ }
1624
+
1625
+ info = &cpu_infos->data[cpu_infos->number];
1626
+ get_cpuinfo_max_freq(info, cpu_infos->number);
1627
+
1628
+ info->total_cores = sigar->ncpu;
1629
+ info->cores_per_socket = sigar->lcpu;
1630
+ info->total_sockets = sigar_cpu_socket_count(sigar);
1631
+
1632
+ ++cpu_infos->number;
1633
+ SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
1634
+ }
1635
+
1636
+ fclose(fp);
1637
+
1638
+ return SIGAR_OK;
1639
+ }
1640
+
1641
+ static SIGAR_INLINE unsigned int hex2int(const char *x, int len)
1642
+ {
1643
+ int i;
1644
+ unsigned int j;
1645
+
1646
+ for (i=0, j=0; i<len; i++) {
1647
+ register int ch = x[i];
1648
+ j <<= 4;
1649
+ if (isdigit(ch)) {
1650
+ j |= ch - '0';
1651
+ }
1652
+ else if (isupper(ch)) {
1653
+ j |= ch - ('A' - 10);
1654
+ }
1655
+ else {
1656
+ j |= ch - ('a' - 10);
1657
+ }
1658
+ }
1659
+
1660
+ return j;
1661
+ }
1662
+
1663
+ #define HEX_ENT_LEN 8
1664
+
1665
+ #ifdef SIGAR_64BIT
1666
+ #define ROUTE_FMT "%16s %128s %128s %X %ld %ld %ld %128s %ld %ld %ld\n"
1667
+ #else
1668
+ #define ROUTE_FMT "%16s %128s %128s %X %lld %lld %lld %128s %lld %lld %lld\n"
1669
+ #endif
1670
+ #define RTF_UP 0x0001
1671
+
1672
+ int sigar_net_route_list_get(sigar_t *sigar,
1673
+ sigar_net_route_list_t *routelist)
1674
+ {
1675
+ FILE *fp;
1676
+ char buffer[1024];
1677
+ char net_addr[128], gate_addr[128], mask_addr[128];
1678
+ int flags;
1679
+ sigar_net_route_t *route;
1680
+
1681
+ routelist->size = routelist->number = 0;
1682
+
1683
+ if (!(fp = fopen(PROC_FS_ROOT "net/route", "r"))) {
1684
+ return errno;
1685
+ }
1686
+
1687
+ sigar_net_route_list_create(routelist);
1688
+
1689
+ (void)fgets(buffer, sizeof(buffer), fp); /* skip header */
1690
+ while (fgets(buffer, sizeof(buffer), fp)) {
1691
+ int num;
1692
+
1693
+ SIGAR_NET_ROUTE_LIST_GROW(routelist);
1694
+ route = &routelist->data[routelist->number++];
1695
+
1696
+ /* XXX rid sscanf */
1697
+ num = sscanf(buffer, ROUTE_FMT,
1698
+ route->ifname, net_addr, gate_addr,
1699
+ &flags, &route->refcnt, &route->use,
1700
+ &route->metric, mask_addr,
1701
+ &route->mtu, &route->window, &route->irtt);
1702
+
1703
+ if ((num < 10) || !(flags & RTF_UP)) {
1704
+ --routelist->number;
1705
+ continue;
1706
+ }
1707
+
1708
+ route->flags = flags;
1709
+
1710
+ sigar_net_address_set(route->destination, hex2int(net_addr, HEX_ENT_LEN));
1711
+ sigar_net_address_set(route->gateway, hex2int(gate_addr, HEX_ENT_LEN));
1712
+ sigar_net_address_set(route->mask, hex2int(mask_addr, HEX_ENT_LEN));
1713
+ }
1714
+
1715
+ fclose(fp);
1716
+
1717
+ return SIGAR_OK;
1718
+ }
1719
+
1720
+ int sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
1721
+ sigar_net_interface_stat_t *ifstat)
1722
+ {
1723
+ int found = 0;
1724
+ char buffer[BUFSIZ];
1725
+ FILE *fp = fopen(PROC_FS_ROOT "net/dev", "r");
1726
+
1727
+ if (!fp) {
1728
+ return errno;
1729
+ }
1730
+
1731
+ /* skip header */
1732
+ fgets(buffer, sizeof(buffer), fp);
1733
+ fgets(buffer, sizeof(buffer), fp);
1734
+
1735
+ while (fgets(buffer, sizeof(buffer), fp)) {
1736
+ char *ptr, *dev;
1737
+
1738
+ dev = buffer;
1739
+ while (isspace(*dev)) {
1740
+ dev++;
1741
+ }
1742
+
1743
+ if (!(ptr = strchr(dev, ':'))) {
1744
+ continue;
1745
+ }
1746
+
1747
+ *ptr++ = 0;
1748
+
1749
+ if (!strEQ(dev, name)) {
1750
+ continue;
1751
+ }
1752
+
1753
+ found = 1;
1754
+ ifstat->rx_bytes = sigar_strtoull(ptr);
1755
+ ifstat->rx_packets = sigar_strtoull(ptr);
1756
+ ifstat->rx_errors = sigar_strtoull(ptr);
1757
+ ifstat->rx_dropped = sigar_strtoull(ptr);
1758
+ ifstat->rx_overruns = sigar_strtoull(ptr);
1759
+ ifstat->rx_frame = sigar_strtoull(ptr);
1760
+
1761
+ /* skip: compressed multicast */
1762
+ ptr = sigar_skip_multiple_token(ptr, 2);
1763
+
1764
+ ifstat->tx_bytes = sigar_strtoull(ptr);
1765
+ ifstat->tx_packets = sigar_strtoull(ptr);
1766
+ ifstat->tx_errors = sigar_strtoull(ptr);
1767
+ ifstat->tx_dropped = sigar_strtoull(ptr);
1768
+ ifstat->tx_overruns = sigar_strtoull(ptr);
1769
+ ifstat->tx_collisions = sigar_strtoull(ptr);
1770
+ ifstat->tx_carrier = sigar_strtoull(ptr);
1771
+
1772
+ ifstat->speed = SIGAR_FIELD_NOTIMPL;
1773
+
1774
+ break;
1775
+ }
1776
+
1777
+ fclose(fp);
1778
+
1779
+ return found ? SIGAR_OK : ENXIO;
1780
+ }
1781
+
1782
+ static SIGAR_INLINE void convert_hex_address(sigar_net_address_t *address,
1783
+ char *ptr, int len)
1784
+ {
1785
+ if (len > HEX_ENT_LEN) {
1786
+ int i;
1787
+ for (i=0; i<=3; i++, ptr+=HEX_ENT_LEN) {
1788
+ address->addr.in6[i] = hex2int(ptr, HEX_ENT_LEN);
1789
+ }
1790
+
1791
+ address->family = SIGAR_AF_INET6;
1792
+ }
1793
+ else {
1794
+ address->addr.in =
1795
+ (len == HEX_ENT_LEN) ? hex2int(ptr, HEX_ENT_LEN) : 0;
1796
+
1797
+ address->family = SIGAR_AF_INET;
1798
+ }
1799
+ }
1800
+
1801
+ typedef struct {
1802
+ sigar_net_connection_list_t *connlist;
1803
+ sigar_net_connection_t *conn;
1804
+ unsigned long port;
1805
+ } net_conn_getter_t;
1806
+
1807
+ static int proc_net_walker(sigar_net_connection_walker_t *walker,
1808
+ sigar_net_connection_t *conn)
1809
+ {
1810
+ net_conn_getter_t *getter =
1811
+ (net_conn_getter_t *)walker->data;
1812
+
1813
+ if (getter->connlist) {
1814
+ SIGAR_NET_CONNLIST_GROW(getter->connlist);
1815
+ memcpy(&getter->connlist->data[getter->connlist->number++],
1816
+ conn, sizeof(*conn));
1817
+ }
1818
+ else {
1819
+ if ((getter->port == conn->local_port) &&
1820
+ (conn->remote_port == 0))
1821
+ {
1822
+ memcpy(getter->conn, conn, sizeof(*conn));
1823
+ return !SIGAR_OK; /* break loop */
1824
+ }
1825
+ }
1826
+
1827
+ return SIGAR_OK; /* continue loop */
1828
+ }
1829
+
1830
+ #define SKIP_WHILE(p, c) while (*p == c) p++
1831
+ #define SKIP_PAST(p, c) \
1832
+ while(*p && (*p != c)) p++; \
1833
+ SKIP_WHILE(p, c)
1834
+
1835
+ typedef struct {
1836
+ FILE *fp;
1837
+ int (*close)(FILE *);
1838
+ } xproc_t;
1839
+
1840
+ static FILE *xproc_open(const char *command, xproc_t *xproc)
1841
+ {
1842
+ struct stat sb;
1843
+ if (stat(command, &sb) == 0) {
1844
+ if (sb.st_mode & S_IXUSR) {
1845
+ /* executable script for testing large
1846
+ * conn table where we can sleep() to better
1847
+ * simulate /proc/net/tcp behavior
1848
+ */
1849
+ xproc->fp = popen(command, "r");
1850
+ xproc->close = pclose;
1851
+ }
1852
+ else {
1853
+ xproc->fp = fopen(command, "r");
1854
+ xproc->close = fclose;
1855
+ }
1856
+ return xproc->fp;
1857
+ }
1858
+ else {
1859
+ return NULL;
1860
+ }
1861
+ }
1862
+
1863
+ static int proc_net_read(sigar_net_connection_walker_t *walker,
1864
+ const char *fname,
1865
+ int type)
1866
+ {
1867
+ FILE *fp = NULL;
1868
+ char buffer[8192];
1869
+ sigar_t *sigar = walker->sigar;
1870
+ char *ptr = sigar->proc_net;
1871
+ int flags = walker->flags;
1872
+ xproc_t xproc = { NULL, fclose };
1873
+
1874
+ if (ptr) {
1875
+ snprintf(buffer, sizeof(buffer),
1876
+ "%s/%s", ptr,
1877
+ fname + sizeof(PROC_FS_ROOT)-1);
1878
+
1879
+ if ((fp = xproc_open(buffer, &xproc))) {
1880
+ if (SIGAR_LOG_IS_DEBUG(sigar)) {
1881
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1882
+ "[proc_net] using %s",
1883
+ buffer);
1884
+ }
1885
+ }
1886
+ else if (SIGAR_LOG_IS_DEBUG(sigar)) {
1887
+ sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
1888
+ "[proc_net] cannot open %s",
1889
+ buffer);
1890
+ }
1891
+ }
1892
+
1893
+ if (!(fp || (fp = fopen(fname, "r")))) {
1894
+ return errno;
1895
+ }
1896
+
1897
+ fgets(buffer, sizeof(buffer), fp); /* skip header */
1898
+
1899
+ while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
1900
+ sigar_net_connection_t conn;
1901
+ char *laddr, *raddr;
1902
+ int laddr_len=0, raddr_len=0;
1903
+ int more;
1904
+
1905
+ /* skip leading space */
1906
+ SKIP_WHILE(ptr, ' ');
1907
+
1908
+ /* skip "%d: " */
1909
+ SKIP_PAST(ptr, ' ');
1910
+
1911
+ laddr = ptr;
1912
+ while (*ptr && (*ptr != ':')) {
1913
+ laddr_len++;
1914
+ ptr++;
1915
+ }
1916
+ SKIP_WHILE(ptr, ':');
1917
+
1918
+ conn.local_port = (strtoul(ptr, &ptr, 16) & 0xffff);
1919
+
1920
+ SKIP_WHILE(ptr, ' ');
1921
+
1922
+ raddr = ptr;
1923
+ while (*ptr && (*ptr != ':')) {
1924
+ raddr_len++;
1925
+ ptr++;
1926
+ }
1927
+ SKIP_WHILE(ptr, ':');
1928
+
1929
+ conn.remote_port = (strtoul(ptr, &ptr, 16) & 0xffff);
1930
+
1931
+ SKIP_WHILE(ptr, ' ');
1932
+
1933
+ if (!((conn.remote_port && (flags & SIGAR_NETCONN_CLIENT)) ||
1934
+ (!conn.remote_port && (flags & SIGAR_NETCONN_SERVER))))
1935
+ {
1936
+ continue;
1937
+ }
1938
+
1939
+ conn.type = type;
1940
+
1941
+ convert_hex_address(&conn.local_address,
1942
+ laddr, laddr_len);
1943
+
1944
+ convert_hex_address(&conn.remote_address,
1945
+ raddr, raddr_len);
1946
+
1947
+ /* SIGAR_TCP_* currently matches TCP_* in linux/tcp.h */
1948
+ conn.state = hex2int(ptr, 2);
1949
+ ptr += 2;
1950
+ SKIP_WHILE(ptr, ' ');
1951
+
1952
+ conn.send_queue = hex2int(ptr, HEX_ENT_LEN);
1953
+ ptr += HEX_ENT_LEN+1; /* tx + ':' */;
1954
+
1955
+ conn.receive_queue = hex2int(ptr, HEX_ENT_LEN);
1956
+ ptr += HEX_ENT_LEN;
1957
+ SKIP_WHILE(ptr, ' ');
1958
+
1959
+ SKIP_PAST(ptr, ' '); /* tr:tm->whem */
1960
+ SKIP_PAST(ptr, ' '); /* retrnsmt */
1961
+
1962
+ conn.uid = sigar_strtoul(ptr);
1963
+
1964
+ SKIP_WHILE(ptr, ' ');
1965
+ SKIP_PAST(ptr, ' '); /* timeout */
1966
+
1967
+ conn.inode = sigar_strtoul(ptr);
1968
+
1969
+ more = walker->add_connection(walker, &conn);
1970
+ if (more != SIGAR_OK) {
1971
+ xproc.close(fp);
1972
+ return SIGAR_OK;
1973
+ }
1974
+ }
1975
+
1976
+ xproc.close(fp);
1977
+
1978
+ return SIGAR_OK;
1979
+ }
1980
+
1981
+ int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
1982
+ {
1983
+ int flags = walker->flags;
1984
+ int status;
1985
+
1986
+ if (flags & SIGAR_NETCONN_TCP) {
1987
+ status = proc_net_read(walker,
1988
+ PROC_FS_ROOT "net/tcp",
1989
+ SIGAR_NETCONN_TCP);
1990
+
1991
+ if (status != SIGAR_OK) {
1992
+ return status;
1993
+ }
1994
+
1995
+ status = proc_net_read(walker,
1996
+ PROC_FS_ROOT "net/tcp6",
1997
+ SIGAR_NETCONN_TCP);
1998
+
1999
+ if (!((status == SIGAR_OK) || (status == ENOENT))) {
2000
+ return status;
2001
+ }
2002
+ }
2003
+
2004
+ if (flags & SIGAR_NETCONN_UDP) {
2005
+ status = proc_net_read(walker,
2006
+ PROC_FS_ROOT "net/udp",
2007
+ SIGAR_NETCONN_UDP);
2008
+
2009
+ if (status != SIGAR_OK) {
2010
+ return status;
2011
+ }
2012
+
2013
+ status = proc_net_read(walker,
2014
+ PROC_FS_ROOT "net/udp6",
2015
+ SIGAR_NETCONN_UDP);
2016
+
2017
+ if (!((status == SIGAR_OK) || (status == ENOENT))) {
2018
+ return status;
2019
+ }
2020
+ }
2021
+
2022
+ if (flags & SIGAR_NETCONN_RAW) {
2023
+ status = proc_net_read(walker,
2024
+ PROC_FS_ROOT "net/raw",
2025
+ SIGAR_NETCONN_RAW);
2026
+
2027
+ if (status != SIGAR_OK) {
2028
+ return status;
2029
+ }
2030
+
2031
+ status = proc_net_read(walker,
2032
+ PROC_FS_ROOT "net/raw6",
2033
+ SIGAR_NETCONN_RAW);
2034
+
2035
+ if (!((status == SIGAR_OK) || (status == ENOENT))) {
2036
+ return status;
2037
+ }
2038
+ }
2039
+
2040
+ /* XXX /proc/net/unix */
2041
+
2042
+ return SIGAR_OK;
2043
+ }
2044
+
2045
+ int sigar_net_connection_list_get(sigar_t *sigar,
2046
+ sigar_net_connection_list_t *connlist,
2047
+ int flags)
2048
+ {
2049
+ int status;
2050
+ sigar_net_connection_walker_t walker;
2051
+ net_conn_getter_t getter;
2052
+
2053
+ sigar_net_connection_list_create(connlist);
2054
+
2055
+ getter.conn = NULL;
2056
+ getter.connlist = connlist;
2057
+
2058
+ walker.sigar = sigar;
2059
+ walker.flags = flags;
2060
+ walker.data = &getter;
2061
+ walker.add_connection = proc_net_walker;
2062
+
2063
+ status = sigar_net_connection_walk(&walker);
2064
+
2065
+ if (status != SIGAR_OK) {
2066
+ sigar_net_connection_list_destroy(sigar, connlist);
2067
+ }
2068
+
2069
+ return status;
2070
+ }
2071
+
2072
+ static int sigar_net_connection_get(sigar_t *sigar,
2073
+ sigar_net_connection_t *netconn,
2074
+ unsigned long port,
2075
+ int flags)
2076
+ {
2077
+ int status;
2078
+ sigar_net_connection_walker_t walker;
2079
+ net_conn_getter_t getter;
2080
+
2081
+ getter.conn = netconn;
2082
+ getter.connlist = NULL;
2083
+ getter.port = port;
2084
+
2085
+ walker.sigar = sigar;
2086
+ walker.flags = flags;
2087
+ walker.data = &getter;
2088
+ walker.add_connection = proc_net_walker;
2089
+
2090
+ status = sigar_net_connection_walk(&walker);
2091
+
2092
+ return status;
2093
+ }
2094
+
2095
+ #define SNMP_TCP_PREFIX "Tcp: "
2096
+
2097
+ SIGAR_DECLARE(int)
2098
+ sigar_tcp_get(sigar_t *sigar,
2099
+ sigar_tcp_t *tcp)
2100
+ {
2101
+ FILE *fp;
2102
+ char buffer[1024], *ptr=buffer;
2103
+ int status = SIGAR_ENOENT;
2104
+
2105
+ if (!(fp = fopen(PROC_FS_ROOT "net/snmp", "r"))) {
2106
+ return errno;
2107
+ }
2108
+
2109
+ while (fgets(buffer, sizeof(buffer), fp)) {
2110
+ if (strnEQ(buffer, SNMP_TCP_PREFIX, sizeof(SNMP_TCP_PREFIX)-1)) {
2111
+ if (fgets(buffer, sizeof(buffer), fp)) {
2112
+ status = SIGAR_OK;
2113
+ break;
2114
+ }
2115
+ }
2116
+ }
2117
+
2118
+ fclose(fp);
2119
+
2120
+ if (status == SIGAR_OK) {
2121
+ /* assuming field order, same in 2.2, 2.4 and 2.6 kernels */
2122
+ /* Tcp: RtoAlgorithm RtoMin RtoMax MaxConn */
2123
+ ptr = sigar_skip_multiple_token(ptr, 5);
2124
+ tcp->active_opens = sigar_strtoull(ptr);
2125
+ tcp->passive_opens = sigar_strtoull(ptr);
2126
+ tcp->attempt_fails = sigar_strtoull(ptr);
2127
+ tcp->estab_resets = sigar_strtoull(ptr);
2128
+ tcp->curr_estab = sigar_strtoull(ptr);
2129
+ tcp->in_segs = sigar_strtoull(ptr);
2130
+ tcp->out_segs = sigar_strtoull(ptr);
2131
+ tcp->retrans_segs = sigar_strtoull(ptr);
2132
+ tcp->in_errs = sigar_strtoull(ptr);
2133
+ tcp->out_rsts = sigar_strtoull(ptr);
2134
+ }
2135
+
2136
+ return status;
2137
+ }
2138
+
2139
+ static int sigar_proc_nfs_gets(char *file, char *tok,
2140
+ char *buffer, size_t size)
2141
+ {
2142
+ int status = ENOENT;
2143
+ int len = strlen(tok);
2144
+ FILE *fp = fopen(file, "r");
2145
+
2146
+ if (!fp) {
2147
+ return SIGAR_ENOTIMPL;
2148
+ }
2149
+
2150
+ while (fgets(buffer, size, fp)) {
2151
+ if (strnEQ(buffer, tok, len)) {
2152
+ status = SIGAR_OK;
2153
+ break;
2154
+ }
2155
+ }
2156
+
2157
+ fclose(fp);
2158
+
2159
+ return status;
2160
+ }
2161
+
2162
+ static int sigar_nfs_v2_get(char *file, sigar_nfs_v2_t *nfs)
2163
+ {
2164
+ char buffer[BUFSIZ], *ptr=buffer;
2165
+ int status =
2166
+ sigar_proc_nfs_gets(file,
2167
+ "proc2", buffer, sizeof(buffer));
2168
+
2169
+ if (status != SIGAR_OK) {
2170
+ return status;
2171
+ }
2172
+
2173
+ ptr = sigar_skip_multiple_token(ptr, 2);
2174
+
2175
+ nfs->null = sigar_strtoull(ptr);
2176
+ nfs->getattr = sigar_strtoull(ptr);
2177
+ nfs->setattr = sigar_strtoull(ptr);
2178
+ nfs->root = sigar_strtoull(ptr);
2179
+ nfs->lookup = sigar_strtoull(ptr);
2180
+ nfs->readlink = sigar_strtoull(ptr);
2181
+ nfs->read = sigar_strtoull(ptr);
2182
+ nfs->writecache = sigar_strtoull(ptr);
2183
+ nfs->write = sigar_strtoull(ptr);
2184
+ nfs->create = sigar_strtoull(ptr);
2185
+ nfs->remove = sigar_strtoull(ptr);
2186
+ nfs->rename = sigar_strtoull(ptr);
2187
+ nfs->link = sigar_strtoull(ptr);
2188
+ nfs->symlink = sigar_strtoull(ptr);
2189
+ nfs->mkdir = sigar_strtoull(ptr);
2190
+ nfs->rmdir = sigar_strtoull(ptr);
2191
+ nfs->readdir = sigar_strtoull(ptr);
2192
+ nfs->fsstat = sigar_strtoull(ptr);
2193
+
2194
+ return SIGAR_OK;
2195
+ }
2196
+
2197
+ int sigar_nfs_client_v2_get(sigar_t *sigar,
2198
+ sigar_nfs_client_v2_t *nfs)
2199
+ {
2200
+ return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfs",
2201
+ (sigar_nfs_v2_t *)nfs);
2202
+ }
2203
+
2204
+ int sigar_nfs_server_v2_get(sigar_t *sigar,
2205
+ sigar_nfs_server_v2_t *nfs)
2206
+ {
2207
+ return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfsd",
2208
+ (sigar_nfs_v2_t *)nfs);
2209
+ }
2210
+
2211
+ static int sigar_nfs_v3_get(char *file, sigar_nfs_v3_t *nfs)
2212
+ {
2213
+ char buffer[BUFSIZ], *ptr=buffer;
2214
+ int status =
2215
+ sigar_proc_nfs_gets(file,
2216
+ "proc3", buffer, sizeof(buffer));
2217
+
2218
+ if (status != SIGAR_OK) {
2219
+ return status;
2220
+ }
2221
+
2222
+ ptr = sigar_skip_multiple_token(ptr, 2);
2223
+
2224
+ nfs->null = sigar_strtoull(ptr);
2225
+ nfs->getattr = sigar_strtoull(ptr);
2226
+ nfs->setattr = sigar_strtoull(ptr);
2227
+ nfs->lookup = sigar_strtoull(ptr);
2228
+ nfs->access = sigar_strtoull(ptr);
2229
+ nfs->readlink = sigar_strtoull(ptr);
2230
+ nfs->read = sigar_strtoull(ptr);
2231
+ nfs->write = sigar_strtoull(ptr);
2232
+ nfs->create = sigar_strtoull(ptr);
2233
+ nfs->mkdir = sigar_strtoull(ptr);
2234
+ nfs->symlink = sigar_strtoull(ptr);
2235
+ nfs->mknod = sigar_strtoull(ptr);
2236
+ nfs->remove = sigar_strtoull(ptr);
2237
+ nfs->rmdir = sigar_strtoull(ptr);
2238
+ nfs->rename = sigar_strtoull(ptr);
2239
+ nfs->link = sigar_strtoull(ptr);
2240
+ nfs->readdir = sigar_strtoull(ptr);
2241
+ nfs->readdirplus = sigar_strtoull(ptr);
2242
+ nfs->fsstat = sigar_strtoull(ptr);
2243
+ nfs->fsinfo = sigar_strtoull(ptr);
2244
+ nfs->pathconf = sigar_strtoull(ptr);
2245
+ nfs->commit = sigar_strtoull(ptr);
2246
+
2247
+ return SIGAR_OK;
2248
+ }
2249
+
2250
+ int sigar_nfs_client_v3_get(sigar_t *sigar,
2251
+ sigar_nfs_client_v3_t *nfs)
2252
+ {
2253
+ return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfs",
2254
+ (sigar_nfs_v3_t *)nfs);
2255
+ }
2256
+
2257
+ int sigar_nfs_server_v3_get(sigar_t *sigar,
2258
+ sigar_nfs_server_v3_t *nfs)
2259
+ {
2260
+ return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfsd",
2261
+ (sigar_nfs_v3_t *)nfs);
2262
+ }
2263
+
2264
+ int sigar_proc_port_get(sigar_t *sigar, int protocol,
2265
+ unsigned long port, sigar_pid_t *pid)
2266
+ {
2267
+ int status;
2268
+ sigar_net_connection_t netconn;
2269
+ DIR *dirp;
2270
+ struct dirent *ent, dbuf;
2271
+
2272
+ SIGAR_ZERO(&netconn);
2273
+ *pid = 0;
2274
+
2275
+ status = sigar_net_connection_get(sigar, &netconn, port,
2276
+ SIGAR_NETCONN_SERVER|protocol);
2277
+
2278
+ if (status != SIGAR_OK) {
2279
+ return status;
2280
+ }
2281
+
2282
+ if (netconn.local_port != port) {
2283
+ return SIGAR_OK; /* XXX or ENOENT? */
2284
+ }
2285
+
2286
+ if (!(dirp = opendir(PROCP_FS_ROOT))) {
2287
+ return errno;
2288
+ }
2289
+
2290
+ while (readdir_r(dirp, &dbuf, &ent) == 0) {
2291
+ DIR *fd_dirp;
2292
+ struct dirent *fd_ent, fd_dbuf;
2293
+ struct stat sb;
2294
+ char fd_name[BUFSIZ], pid_name[BUFSIZ];
2295
+ int len, slen;
2296
+
2297
+ if (ent == NULL) {
2298
+ break;
2299
+ }
2300
+
2301
+ if (!sigar_isdigit(*ent->d_name)) {
2302
+ continue;
2303
+ }
2304
+
2305
+ /* sprintf(pid_name, "/proc/%s", ent->d_name) */
2306
+ memcpy(&pid_name[0], PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT));
2307
+ len = SSTRLEN(PROCP_FS_ROOT);
2308
+ pid_name[len++] = '/';
2309
+
2310
+ slen = strlen(ent->d_name);
2311
+ memcpy(&pid_name[len], ent->d_name, slen);
2312
+ len += slen;
2313
+ pid_name[len] = '\0';
2314
+
2315
+ if (stat(pid_name, &sb) < 0) {
2316
+ continue;
2317
+ }
2318
+ if (sb.st_uid != netconn.uid) {
2319
+ continue;
2320
+ }
2321
+
2322
+ /* sprintf(fd_name, "%s/fd", pid_name) */
2323
+ memcpy(&fd_name[0], pid_name, len);
2324
+ memcpy(&fd_name[len], "/fd", 3);
2325
+ fd_name[len+=3] = '\0';
2326
+
2327
+ if (!(fd_dirp = opendir(fd_name))) {
2328
+ continue;
2329
+ }
2330
+
2331
+ while (readdir_r(fd_dirp, &fd_dbuf, &fd_ent) == 0) {
2332
+ char fd_ent_name[BUFSIZ];
2333
+
2334
+ if (fd_ent == NULL) {
2335
+ break;
2336
+ }
2337
+
2338
+ if (!sigar_isdigit(*fd_ent->d_name)) {
2339
+ continue;
2340
+ }
2341
+
2342
+ /* sprintf(fd_ent_name, "%s/%s", fd_name, fd_ent->d_name) */
2343
+ slen = strlen(fd_ent->d_name);
2344
+ memcpy(&fd_ent_name[0], fd_name, len);
2345
+ fd_ent_name[len] = '/';
2346
+ memcpy(&fd_ent_name[len+1], fd_ent->d_name, slen);
2347
+ fd_ent_name[len+1+slen] = '\0';
2348
+
2349
+ if (stat(fd_ent_name, &sb) < 0) {
2350
+ continue;
2351
+ }
2352
+
2353
+ if (sb.st_ino == netconn.inode) {
2354
+ closedir(fd_dirp);
2355
+ closedir(dirp);
2356
+ *pid = strtoul(ent->d_name, NULL, 10);
2357
+ return SIGAR_OK;
2358
+ }
2359
+
2360
+ }
2361
+
2362
+ closedir(fd_dirp);
2363
+ }
2364
+
2365
+ closedir(dirp);
2366
+
2367
+ return SIGAR_OK;
2368
+ }
2369
+
2370
+ static void generic_vendor_parse(char *line, sigar_sys_info_t *info)
2371
+ {
2372
+ char *ptr;
2373
+ int len = 0;
2374
+
2375
+ while (*line) {
2376
+ SIGAR_SKIP_SPACE(line);
2377
+ if (!isdigit(*line)) {
2378
+ ++line;
2379
+ continue;
2380
+ }
2381
+
2382
+ ptr = line;
2383
+ while ((isdigit(*ptr) || (*ptr == '.'))) {
2384
+ ++ptr;
2385
+ ++len;
2386
+ }
2387
+
2388
+ if (len) {
2389
+ /* sanity check */
2390
+ if (len > sizeof(info->vendor_version)) {
2391
+ continue;
2392
+ }
2393
+ memcpy(info->vendor_version, line, len);/*XXX*/
2394
+ info->vendor_version[len] = '\0';
2395
+ return;
2396
+ }
2397
+ }
2398
+ }
2399
+
2400
+ static void redhat_vendor_parse(char *line, sigar_sys_info_t *info)
2401
+ {
2402
+ char *start, *end;
2403
+
2404
+ generic_vendor_parse(line, info); /* super.parse */
2405
+
2406
+ if ((start = strchr(line, '('))) {
2407
+ ++start;
2408
+ if ((end = strchr(start, ')'))) {
2409
+ int len = end-start;
2410
+ memcpy(info->vendor_code_name, start, len);/*XXX*/
2411
+ info->vendor_code_name[len] = '\0';
2412
+ }
2413
+ }
2414
+
2415
+ #define RHEL_PREFIX "Red Hat Enterprise Linux "
2416
+ #define CENTOS_VENDOR "CentOS"
2417
+ #define SL_VENDOR "Scientific Linux"
2418
+
2419
+ if (strnEQ(line, RHEL_PREFIX, sizeof(RHEL_PREFIX)-1)) {
2420
+ snprintf(info->vendor_version,
2421
+ sizeof(info->vendor_version),
2422
+ "Enterprise Linux %c",
2423
+ info->vendor_version[0]);
2424
+ }
2425
+ else if (strnEQ(line, CENTOS_VENDOR, sizeof(CENTOS_VENDOR)-1)) {
2426
+ SIGAR_SSTRCPY(info->vendor, CENTOS_VENDOR);
2427
+ }
2428
+ else if (strnEQ(line, SL_VENDOR, sizeof(SL_VENDOR)-1)) {
2429
+ SIGAR_SSTRCPY(info->vendor, SL_VENDOR);
2430
+ }
2431
+ }
2432
+
2433
+ #define is_quote(c) ((c == '\'') || (c == '"'))
2434
+
2435
+ static void kv_parse(char *data, sigar_sys_info_t *info,
2436
+ void (*func)(sigar_sys_info_t *, char *, char *))
2437
+ {
2438
+ char *ptr = data;
2439
+ int len = strlen(data);
2440
+ char *end = data+len;
2441
+
2442
+ while (ptr < end) {
2443
+ char *val = strchr(ptr, '=');
2444
+ int klen, vlen;
2445
+ char key[256], *ix;
2446
+
2447
+ if (!val) {
2448
+ continue;
2449
+ }
2450
+ klen = val - ptr;
2451
+ SIGAR_SSTRCPY(key, ptr);
2452
+ key[klen] = '\0';
2453
+ ++val;
2454
+
2455
+ if ((ix = strchr(val, '\n'))) {
2456
+ *ix = '\0';
2457
+ }
2458
+ vlen = strlen(val);
2459
+ if (is_quote(*val)) {
2460
+ if (is_quote(val[vlen-1])) {
2461
+ val[vlen-1] = '\0';
2462
+ }
2463
+ ++val;
2464
+ }
2465
+
2466
+ func(info, key, val);
2467
+
2468
+ ptr += (klen + 1 + vlen + 1);
2469
+ }
2470
+ }
2471
+
2472
+ static void lsb_parse(sigar_sys_info_t *info,
2473
+ char *key, char *val)
2474
+ {
2475
+ if (strEQ(key, "DISTRIB_ID")) {
2476
+ SIGAR_SSTRCPY(info->vendor, val);
2477
+ }
2478
+ else if (strEQ(key, "DISTRIB_RELEASE")) {
2479
+ SIGAR_SSTRCPY(info->vendor_version, val);
2480
+ }
2481
+ else if (strEQ(key, "DISTRIB_CODENAME")) {
2482
+ SIGAR_SSTRCPY(info->vendor_code_name, val);
2483
+ }
2484
+ }
2485
+
2486
+ static void lsb_vendor_parse(char *data, sigar_sys_info_t *info)
2487
+ {
2488
+ kv_parse(data, info, lsb_parse);
2489
+ }
2490
+
2491
+ static void xen_parse(sigar_sys_info_t *info,
2492
+ char *key, char *val)
2493
+ {
2494
+ if (strEQ(key, "PRODUCT_VERSION")) {
2495
+ SIGAR_SSTRCPY(info->vendor_version, val);
2496
+ }
2497
+ else if (strEQ(key, "KERNEL_VERSION")) {
2498
+ SIGAR_SSTRCPY(info->version, val);
2499
+ }
2500
+ }
2501
+
2502
+ static void xen_vendor_parse(char *data, sigar_sys_info_t *info)
2503
+ {
2504
+ kv_parse(data, info, xen_parse);
2505
+
2506
+ snprintf(info->description,
2507
+ sizeof(info->description),
2508
+ "XenServer %s",
2509
+ info->vendor_version);
2510
+ }
2511
+
2512
+ typedef struct {
2513
+ const char *name;
2514
+ const char *file;
2515
+ void (*parse)(char *, sigar_sys_info_t *);
2516
+ } linux_vendor_info_t;
2517
+
2518
+ static linux_vendor_info_t linux_vendors[] = {
2519
+ { "Fedora", "/etc/fedora-release", NULL },
2520
+ { "SuSE", "/etc/SuSE-release", NULL },
2521
+ { "Gentoo", "/etc/gentoo-release", NULL },
2522
+ { "Slackware", "/etc/slackware-version", NULL },
2523
+ { "Mandrake", "/etc/mandrake-release", NULL },
2524
+ { "VMware", "/proc/vmware/version", NULL },
2525
+ { "XenSource", "/etc/xensource-inventory", xen_vendor_parse },
2526
+ { "Red Hat", "/etc/redhat-release", redhat_vendor_parse },
2527
+ { "lsb", "/etc/lsb-release", lsb_vendor_parse },
2528
+ { "Debian", "/etc/debian_version", NULL },
2529
+ { NULL }
2530
+ };
2531
+
2532
+ static int get_linux_vendor_info(sigar_sys_info_t *info)
2533
+ {
2534
+ int i, status = ENOENT;
2535
+ /* env vars for testing */
2536
+ const char *release_file = getenv("SIGAR_OS_RELEASE_FILE");
2537
+ const char *vendor_name = getenv("SIGAR_OS_VENDOR_NAME");
2538
+ char buffer[8192], *data;
2539
+ linux_vendor_info_t *vendor = NULL;
2540
+
2541
+ for (i=0; linux_vendors[i].name; i++) {
2542
+ struct stat sb;
2543
+ vendor = &linux_vendors[i];
2544
+
2545
+ if (release_file && vendor_name) {
2546
+ if (!strEQ(vendor->name, vendor_name)) {
2547
+ continue;
2548
+ }
2549
+ }
2550
+ else {
2551
+ if (stat(vendor->file, &sb) < 0) {
2552
+ continue;
2553
+ }
2554
+ release_file = vendor->file;
2555
+ }
2556
+
2557
+ status =
2558
+ sigar_file2str(release_file, buffer, sizeof(buffer)-1);
2559
+
2560
+ break;
2561
+ }
2562
+
2563
+ if (status != SIGAR_OK) {
2564
+ return status;
2565
+ }
2566
+
2567
+ data = buffer;
2568
+
2569
+ SIGAR_SSTRCPY(info->vendor, vendor->name);
2570
+
2571
+ if (vendor->parse) {
2572
+ vendor->parse(data, info);
2573
+ }
2574
+ else {
2575
+ generic_vendor_parse(data, info);
2576
+ }
2577
+
2578
+ if (info->description[0] == '\0') {
2579
+ snprintf(info->description,
2580
+ sizeof(info->description),
2581
+ "%s %s",
2582
+ info->vendor, info->vendor_version);
2583
+ }
2584
+
2585
+ return SIGAR_OK;
2586
+ }
2587
+
2588
+ int sigar_os_sys_info_get(sigar_t *sigar,
2589
+ sigar_sys_info_t *sysinfo)
2590
+ {
2591
+
2592
+ get_linux_vendor_info(sysinfo);
2593
+
2594
+ return SIGAR_OK;
2595
+ }