ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c
Revision: 1.28
Committed: Thu Oct 9 15:22:59 2003 UTC (20 years, 7 months ago) by pajs
Content type: text/plain
Branch: MAIN
CVS Tags: LIBSTATGRAB_0_6_1, LIBSTATGRAB_0_6
Changes since 1.27: +5 -3 lines
Log Message:
Fixed a forgotten line from the patch

File Contents

# Content
1 /*
2 * i-scream central monitoring system
3 * http://www.i-scream.org
4 * Copyright (C) 2000-2003 i-scream
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "statgrab.h"
29
30 #ifdef SOLARIS
31 #include <sys/mnttab.h>
32 #include <sys/statvfs.h>
33 #include <kstat.h>
34 #define VALID_FS_TYPES {"ufs", "tmpfs"}
35 #endif
36
37 #ifdef LINUX
38 #include <sys/vfs.h>
39 #include <mntent.h>
40 #include "tools.h"
41 #define VALID_FS_TYPES {"ext2", "ext3", "xfs", "reiserfs", "vfat", "tmpfs"}
42 #endif
43
44 #ifdef FREEBSD
45 #include <sys/param.h>
46 #include <sys/ucred.h>
47 #include <sys/mount.h>
48 #include <sys/dkstat.h>
49 #include <devstat.h>
50 #define VALID_FS_TYPES {"ufs", "mfs"}
51 #endif
52 #define START_VAL 1
53
54 char *copy_string(char *orig_ptr, const char *newtext){
55
56 /* Maybe free if not NULL, and strdup rather than realloc and strcpy? */
57 orig_ptr=realloc(orig_ptr, (1+strlen(newtext)));
58 if(orig_ptr==NULL){
59 return NULL;
60 }
61 strcpy(orig_ptr, newtext);
62
63 return orig_ptr;
64 }
65
66
67 void init_disk_stat(int start, int end, disk_stat_t *disk_stats){
68
69 for(disk_stats+=start; start<=end; start++){
70 disk_stats->device_name=NULL;
71 disk_stats->fs_type=NULL;
72 disk_stats->mnt_point=NULL;
73
74 disk_stats++;
75 }
76 }
77
78 disk_stat_t *get_disk_stats(int *entries){
79
80 static disk_stat_t *disk_stats;
81 static int watermark=-1;
82
83 char *fs_types[] = VALID_FS_TYPES;
84 int x, valid_type;
85 int num_disks=0;
86 #if defined(LINUX) || defined (SOLARIS)
87 FILE *f;
88 #endif
89
90 disk_stat_t *disk_ptr;
91
92 #ifdef SOLARIS
93 struct mnttab mp;
94 struct statvfs fs;
95 #endif
96 #ifdef LINUX
97 struct mntent *mp;
98 struct statfs fs;
99 #endif
100 #ifdef FREEBSD
101 int nummnt;
102 struct statfs *mp;
103 #endif
104
105 if(watermark==-1){
106 disk_stats=malloc(START_VAL * sizeof(disk_stat_t));
107 if(disk_stats==NULL){
108 return NULL;
109 }
110 watermark=START_VAL;
111 init_disk_stat(0, watermark-1, disk_stats);
112 }
113 #ifdef FREEBSD
114 nummnt=getmntinfo(&mp , MNT_LOCAL);
115 if (nummnt<=0){
116 return NULL;
117 }
118 for(;nummnt--; mp++){
119 valid_type=0;
120 for(x=0;x<((sizeof(fs_types))/(sizeof(char*)));x++){
121 if(strcmp(mp->f_fstypename, fs_types[x]) ==0){
122 valid_type=1;
123 break;
124 }
125 }
126 #endif
127
128 #ifdef LINUX
129 if ((f=setmntent("/etc/mtab", "r" ))==NULL){
130 return NULL;
131 }
132
133 while((mp=getmntent(f))){
134 if((statfs(mp->mnt_dir, &fs)) !=0){
135 continue;
136 }
137
138 valid_type=0;
139 for(x=0;x<((sizeof(fs_types))/(sizeof(char*)));x++){
140 if(strcmp(mp->mnt_type, fs_types[x]) ==0){
141 valid_type=1;
142 break;
143 }
144 }
145 #endif
146
147 #ifdef SOLARIS
148 if ((f=fopen("/etc/mnttab", "r" ))==NULL){
149 return NULL;
150 }
151 while((getmntent(f, &mp)) == 0){
152 if ((statvfs(mp.mnt_mountp, &fs)) !=0){
153 continue;
154 }
155 valid_type=0;
156 for(x=0;x<((sizeof(fs_types))/(sizeof(char*)));x++){
157 if(strcmp(mp.mnt_fstype, fs_types[x]) ==0){
158 valid_type=1;
159 break;
160 }
161 }
162 #endif
163
164 if(valid_type){
165 if(num_disks>watermark-1){
166 disk_ptr=disk_stats;
167 if((disk_stats=realloc(disk_stats, (watermark*2 * sizeof(disk_stat_t))))==NULL){
168 disk_stats=disk_ptr;
169 return NULL;
170 }
171
172 watermark=watermark*2;
173 init_disk_stat(num_disks, watermark-1, disk_stats);
174 }
175
176 disk_ptr=disk_stats+num_disks;
177 #ifdef FREEBSD
178 if((disk_ptr->device_name=copy_string(disk_ptr->device_name, mp->f_mntfromname))==NULL){
179 return NULL;
180 }
181
182 if((disk_ptr->fs_type=copy_string(disk_ptr->fs_type, mp->f_fstypename))==NULL){
183 return NULL;
184 }
185
186 if((disk_ptr->mnt_point=copy_string(disk_ptr->mnt_point, mp->f_mntonname))==NULL){
187 return NULL;
188 }
189
190 disk_ptr->size = (long long)mp->f_bsize * (long long) mp->f_blocks;
191 disk_ptr->avail = (long long)mp->f_bsize * (long long) mp->f_bavail;
192 disk_ptr->used = (disk_ptr->size) - ((long long)mp->f_bsize * (long long)mp->f_bfree);
193
194 disk_ptr->total_inodes=(long long)mp->f_files;
195 disk_ptr->free_inodes=(long long)mp->f_ffree;
196 /* Freebsd doesn't have a "available" inodes */
197 disk_ptr->used_inodes=disk_ptr->total_inodes-disk_ptr->free_inodes;
198 #endif
199 #ifdef LINUX
200 if((disk_ptr->device_name=copy_string(disk_ptr->device_name, mp->mnt_fsname))==NULL){
201 return NULL;
202 }
203
204 if((disk_ptr->fs_type=copy_string(disk_ptr->fs_type, mp->mnt_type))==NULL){
205 return NULL;
206 }
207
208 if((disk_ptr->mnt_point=copy_string(disk_ptr->mnt_point, mp->mnt_dir))==NULL){
209 return NULL;
210 }
211 disk_ptr->size = (long long)fs.f_bsize * (long long)fs.f_blocks;
212 disk_ptr->avail = (long long)fs.f_bsize * (long long)fs.f_bavail;
213 disk_ptr->used = (disk_ptr->size) - ((long long)fs.f_bsize * (long long)fs.f_bfree);
214
215 disk_ptr->total_inodes=(long long)fs.f_files;
216 disk_ptr->free_inodes=(long long)fs.f_ffree;
217 /* Linux doesn't have a "available" inodes */
218 disk_ptr->used_inodes=disk_ptr->total_inodes-disk_ptr->free_inodes;
219 #endif
220
221 #ifdef SOLARIS
222 /* Memory leak in event of realloc failing */
223 /* Maybe make this char[bigenough] and do strncpy's and put a null in the end?
224 * Downside is its a bit hungry for a lot of mounts, as MNT_MAX_SIZE would prob
225 * be upwards of a k each
226 */
227 if((disk_ptr->device_name=copy_string(disk_ptr->device_name, mp.mnt_special))==NULL){
228 return NULL;
229 }
230
231 if((disk_ptr->fs_type=copy_string(disk_ptr->fs_type, mp.mnt_fstype))==NULL){
232 return NULL;
233 }
234
235 if((disk_ptr->mnt_point=copy_string(disk_ptr->mnt_point, mp.mnt_mountp))==NULL){
236 return NULL;
237 }
238
239 disk_ptr->size = (long long)fs.f_frsize * (long long)fs.f_blocks;
240 disk_ptr->avail = (long long)fs.f_frsize * (long long)fs.f_bavail;
241 disk_ptr->used = (disk_ptr->size) - ((long long)fs.f_frsize * (long long)fs.f_bfree);
242
243 disk_ptr->total_inodes=(long long)fs.f_files;
244 disk_ptr->used_inodes=disk_ptr->total_inodes - (long long)fs.f_ffree;
245 disk_ptr->free_inodes=(long long)fs.f_favail;
246 #endif
247 num_disks++;
248 }
249 }
250
251 *entries=num_disks;
252
253 /* If this fails, there is very little i can do about it, so i'll ignore it :) */
254 #if defined(LINUX) || defined(SOLARIS)
255 fclose(f);
256 #endif
257
258 return disk_stats;
259
260 }
261 void diskio_stat_init(int start, int end, diskio_stat_t *diskio_stats){
262
263 for(diskio_stats+=start; start<end; start++){
264 diskio_stats->disk_name=NULL;
265
266 diskio_stats++;
267 }
268 }
269
270 diskio_stat_t *diskio_stat_malloc(int needed_entries, int *cur_entries, diskio_stat_t *diskio_stats){
271
272 if(diskio_stats==NULL){
273
274 if((diskio_stats=malloc(needed_entries * sizeof(diskio_stat_t)))==NULL){
275 return NULL;
276 }
277 diskio_stat_init(0, needed_entries, diskio_stats);
278 *cur_entries=needed_entries;
279
280 return diskio_stats;
281 }
282
283
284 if(*cur_entries<needed_entries){
285 diskio_stats=realloc(diskio_stats, (sizeof(diskio_stat_t)*needed_entries));
286 if(diskio_stats==NULL){
287 return NULL;
288 }
289 diskio_stat_init(*cur_entries, needed_entries, diskio_stats);
290 *cur_entries=needed_entries;
291 }
292
293 return diskio_stats;
294 }
295
296 static diskio_stat_t *diskio_stats=NULL;
297 static int num_diskio=0;
298
299 #ifdef LINUX
300 typedef struct {
301 int major;
302 int minor;
303 } partition;
304 #endif
305
306 diskio_stat_t *get_diskio_stats(int *entries){
307
308 static int sizeof_diskio_stats=0;
309 diskio_stat_t *diskio_stats_ptr;
310
311 #ifdef SOLARIS
312 kstat_ctl_t *kc;
313 kstat_t *ksp;
314 kstat_io_t kios;
315 #endif
316 #ifdef LINUX
317 FILE *f;
318 char *line_ptr;
319 int major, minor;
320 char dev_letter;
321 int has_pp_stats = 1;
322 static partition *parts = NULL;
323 static int alloc_parts = 0;
324 int i, n;
325 time_t now;
326 #endif
327 #ifdef FREEBSD
328 static struct statinfo stats;
329 static int stats_init = 0;
330 int counter;
331 struct device_selection *dev_sel = NULL;
332 int n_selected, n_selections;
333 long sel_gen;
334 struct devstat *dev_ptr;
335 #endif
336 num_diskio=0;
337
338 #ifdef FREEBSD
339 if (!stats_init) {
340 stats.dinfo=malloc(sizeof(struct devinfo));
341 bzero(stats.dinfo, sizeof(struct devinfo));
342 if(stats.dinfo==NULL) return NULL;
343 stats_init = 1;
344 }
345 #ifdef FREEBSD5
346 if ((devstat_getdevs(NULL, &stats)) < 0) return NULL;
347 /* Not aware of a get all devices, so i said 999. If we ever * find a machine with more than 999 disks, then i'll change * this number :) */
348 if (devstat_selectdevs(&dev_sel, &n_selected, &n_selections, &sel_gen, stats.dinfo->generation, stats.dinfo->devices, stats.dinfo->numdevs, NULL, 0, NULL, 0, DS_SELECT_ONLY, 999, 1) < 0) return NULL;
349 #else
350 if ((getdevs(&stats)) < 0) return NULL;
351 /* Not aware of a get all devices, so i said 999. If we ever
352 * find a machine with more than 999 disks, then i'll change
353 * this number :)
354 */
355 if (selectdevs(&dev_sel, &n_selected, &n_selections, &sel_gen, stats.dinfo->generation, stats.dinfo->devices, stats.dinfo->numdevs, NULL, 0, NULL, 0, DS_SELECT_ONLY, 999, 1) < 0) return NULL;
356 #endif
357
358 for(counter=0;counter<stats.dinfo->numdevs;counter++){
359 dev_ptr=&stats.dinfo->devices[dev_sel[counter].position];
360
361 /* Throw away devices that have done nothing, ever.. Eg "odd"
362 * devices.. like mem, proc.. and also doesn't report floppy
363 * drives etc unless they are doing stuff :)
364 */
365 #ifdef FREEBSD5
366 if((dev_ptr->bytes[DEVSTAT_READ]==0) && (dev_ptr->bytes[DEVSTAT_WRITE]==0)) continue;
367 #else
368 if((dev_ptr->bytes_read==0) && (dev_ptr->bytes_written==0)) continue;
369 #endif
370 if((diskio_stats=diskio_stat_malloc(num_diskio+1, &sizeof_diskio_stats, diskio_stats))==NULL){
371 return NULL;
372 }
373 diskio_stats_ptr=diskio_stats+num_diskio;
374
375 #ifdef FREEBSD5
376 diskio_stats_ptr->read_bytes=dev_ptr->bytes[DEVSTAT_READ];
377 diskio_stats_ptr->write_bytes=dev_ptr->bytes[DEVSTAT_WRITE];
378 #else
379 diskio_stats_ptr->read_bytes=dev_ptr->bytes_read;
380 diskio_stats_ptr->write_bytes=dev_ptr->bytes_written;
381 #endif
382 if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
383 asprintf((&diskio_stats_ptr->disk_name), "%s%d", dev_ptr->device_name, dev_ptr->unit_number);
384 diskio_stats_ptr->systime=time(NULL);
385
386 num_diskio++;
387 }
388 free(dev_sel);
389
390 #endif
391 #ifdef SOLARIS
392 if ((kc = kstat_open()) == NULL) {
393 return NULL;
394 }
395
396 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
397 if (!strcmp(ksp->ks_class, "disk")) {
398
399 if(ksp->ks_type != KSTAT_TYPE_IO) continue;
400 /* We dont want metadevices appearins as num_diskio */
401 if(strcmp(ksp->ks_module, "md")==0) continue;
402 if((kstat_read(kc, ksp, &kios))==-1){
403 }
404
405 if((diskio_stats=diskio_stat_malloc(num_diskio+1, &sizeof_diskio_stats, diskio_stats))==NULL){
406 kstat_close(kc);
407 return NULL;
408 }
409 diskio_stats_ptr=diskio_stats+num_diskio;
410
411 diskio_stats_ptr->read_bytes=kios.nread;
412
413 diskio_stats_ptr->write_bytes=kios.nwritten;
414
415 if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
416
417 diskio_stats_ptr->disk_name=strdup(ksp->ks_name);
418 diskio_stats_ptr->systime=time(NULL);
419 num_diskio++;
420 }
421 }
422
423 kstat_close(kc);
424 #endif
425
426 #ifdef LINUX
427 num_diskio = 0;
428 n = 0;
429
430 /* Read /proc/partitions to find what devices exist. Recent 2.4 kernels
431 have statistics in here too, so we can use those directly. */
432
433 f = fopen("/proc/partitions", "r");
434 if (f == NULL) goto out;
435 now = time(NULL);
436
437 while ((line_ptr = f_read_line(f, "")) != NULL) {
438 char name[20];
439 char *s;
440 long long rsect, wsect;
441
442 int nr = sscanf(line_ptr,
443 " %d %d %*d %19s %*d %*d %lld %*d %*d %*d %lld",
444 &major, &minor, name, &rsect, &wsect);
445 if (nr < 3) continue;
446 if (nr < 5) {
447 has_pp_stats = 0;
448 rsect = 0;
449 wsect = 0;
450 }
451
452 /* Skip device names ending in numbers, since they're
453 partitions. */
454 s = name;
455 while (*s != '\0') s++;
456 --s;
457 if (*s >= '0' && *s <= '9') continue;
458
459 diskio_stats = diskio_stat_malloc(n + 1, &sizeof_diskio_stats,
460 diskio_stats);
461 if (diskio_stats == NULL) goto out;
462 if (n >= alloc_parts) {
463 alloc_parts += 16;
464 parts = realloc(parts, alloc_parts * sizeof *parts);
465 if (parts == NULL) {
466 alloc_parts = 0;
467 goto out;
468 }
469 }
470
471 if (diskio_stats[n].disk_name != NULL)
472 free(diskio_stats[n].disk_name);
473 diskio_stats[n].disk_name = strdup(name);
474 diskio_stats[n].read_bytes = rsect * 512;
475 diskio_stats[n].write_bytes = wsect * 512;
476 diskio_stats[n].systime = now;
477 parts[n].major = major;
478 parts[n].minor = minor;
479
480 n++;
481 }
482
483 if (!has_pp_stats) {
484 /* This is an older kernel without stats in /proc/partitions.
485 Read what we can from /proc/stat instead. */
486
487 f = fopen("/proc/stat", "r");
488 if (f == NULL) goto out;
489 now = time(NULL);
490
491 line_ptr = f_read_line(f, "disk_io:");
492 if (line_ptr == NULL) goto out;
493
494 while((line_ptr=strchr(line_ptr, ' '))!=NULL){
495 long long rsect, wsect;
496
497 if (*++line_ptr == '\0') break;
498
499 if((sscanf(line_ptr,
500 "(%d,%d):(%*d, %*d, %lld, %*d, %lld)",
501 &major, &minor, &rsect, &wsect)) != 4) {
502 continue;
503 }
504
505 /* Find the corresponding device from earlier.
506 Just to add to the fun, "minor" is actually the disk
507 number, not the device minor, so we need to figure
508 out the real minor number based on the major!
509 This list is not exhaustive; if you're running
510 an older kernel you probably don't have fancy
511 I2O hardware anyway... */
512 switch (major) {
513 case 3:
514 case 21:
515 case 22:
516 case 33:
517 case 34:
518 case 36:
519 case 56:
520 case 57:
521 case 88:
522 case 89:
523 case 90:
524 case 91:
525 minor *= 64;
526 break;
527 case 9:
528 case 43:
529 break;
530 default:
531 minor *= 16;
532 break;
533 }
534 for (i = 0; i < n; i++) {
535 if (major == parts[i].major
536 && minor == parts[i].minor)
537 break;
538 }
539 if (i == n) continue;
540
541 /* We read the number of blocks. Blocks are stored in
542 512 bytes */
543 diskio_stats[i].read_bytes = rsect * 512;
544 diskio_stats[i].write_bytes = wsect * 512;
545 diskio_stats[i].systime = now;
546 }
547 }
548
549 num_diskio = n;
550 out:
551 if (f != NULL) fclose(f);
552
553 #endif
554 *entries=num_diskio;
555
556 return diskio_stats;
557 }
558
559 diskio_stat_t *get_diskio_stats_diff(int *entries){
560 static diskio_stat_t *diskio_stats_diff=NULL;
561 static int sizeof_diskio_stats_diff=0;
562 diskio_stat_t *diskio_stats_diff_ptr, *diskio_stats_ptr;
563 int disks, x, y;
564
565 if(diskio_stats==NULL){
566 diskio_stats_ptr=get_diskio_stats(&disks);
567 *entries=disks;
568 return diskio_stats_ptr;
569 }
570
571 diskio_stats_diff=diskio_stat_malloc(num_diskio, &sizeof_diskio_stats_diff, diskio_stats_diff);
572 if(diskio_stats_diff==NULL){
573 return NULL;
574 }
575
576 diskio_stats_diff_ptr=diskio_stats_diff;
577 diskio_stats_ptr=diskio_stats;
578
579 for(disks=0;disks<num_diskio;disks++){
580 if(diskio_stats_diff_ptr->disk_name!=NULL){
581 free(diskio_stats_diff_ptr->disk_name);
582 }
583 diskio_stats_diff_ptr->disk_name=strdup(diskio_stats_ptr->disk_name);
584 diskio_stats_diff_ptr->read_bytes=diskio_stats_ptr->read_bytes;
585 diskio_stats_diff_ptr->write_bytes=diskio_stats_ptr->write_bytes;
586 diskio_stats_diff_ptr->systime=diskio_stats_ptr->systime;
587
588 diskio_stats_diff_ptr++;
589 diskio_stats_ptr++;
590 }
591
592 diskio_stats_ptr=get_diskio_stats(&disks);
593 diskio_stats_diff_ptr=diskio_stats_diff;
594
595 for(x=0;x<sizeof_diskio_stats_diff;x++){
596
597 if((strcmp(diskio_stats_diff_ptr->disk_name, diskio_stats_ptr->disk_name))==0){
598 diskio_stats_diff_ptr->read_bytes=diskio_stats_ptr->read_bytes-diskio_stats_diff_ptr->read_bytes;
599 diskio_stats_diff_ptr->write_bytes=diskio_stats_ptr->write_bytes-diskio_stats_diff_ptr->write_bytes;
600 diskio_stats_diff_ptr->systime=diskio_stats_ptr->systime-diskio_stats_diff_ptr->systime;
601 }else{
602 diskio_stats_ptr=diskio_stats;
603 for(y=0;y<disks;y++){
604 if((strcmp(diskio_stats_diff_ptr->disk_name, diskio_stats_ptr->disk_name))==0){
605 diskio_stats_diff_ptr->read_bytes=diskio_stats_ptr->read_bytes-diskio_stats_diff_ptr->read_bytes;
606 diskio_stats_diff_ptr->write_bytes=diskio_stats_ptr->write_bytes-diskio_stats_diff_ptr->write_bytes;
607 diskio_stats_diff_ptr->systime=diskio_stats_ptr->systime-diskio_stats_diff_ptr->systime;
608
609 break;
610 }
611
612 diskio_stats_ptr++;
613 }
614 }
615
616 diskio_stats_ptr++;
617 diskio_stats_diff_ptr++;
618
619 }
620
621 *entries=sizeof_diskio_stats_diff;
622 return diskio_stats_diff;
623 }