ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c
Revision: 1.55
Committed: Sun Apr 4 21:38:02 2004 UTC (20 years, 1 month ago) by ats
Content type: text/plain
Branch: MAIN
Changes since 1.54: +2 -2 lines
Log Message:
Silence a (harmless) "may be used uninitialised" error.

File Contents

# Content
1 /*
2 * i-scream central monitoring system
3 * http://www.i-scream.org
4 * Copyright (C) 2000-2004 i-scream
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 *
21 * $Id: disk_stats.c,v 1.54 2004/03/19 23:44:30 ats Exp $
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include "statgrab.h"
33
34 #ifdef SOLARIS
35 #include <sys/mnttab.h>
36 #include <sys/statvfs.h>
37 #include <kstat.h>
38 #define VALID_FS_TYPES {"ufs", "tmpfs"}
39 #endif
40
41 #if defined(LINUX) || defined(CYGWIN)
42 #include <mntent.h>
43 #include <sys/vfs.h>
44 #include "tools.h"
45 #endif
46
47 #ifdef LINUX
48 #define VALID_FS_TYPES {"adfs", "affs", "befs", "bfs", "efs", "ext2", \
49 "ext3", "vxfs", "hfs", "hfsplus", "hpfs", "jffs", \
50 "jffs2", "minix", "msdos", "ntfs", "qnx4", "ramfs", \
51 "rootfs", "reiserfs", "sysv", "v7", "udf", "ufs", \
52 "umsdos", "vfat", "xfs", "jfs"}
53 #endif
54
55 #ifdef CYGWIN
56 #define VALID_FS_TYPES {"user"}
57 #endif
58
59 #ifdef ALLBSD
60 #include <sys/param.h>
61 #include <sys/ucred.h>
62 #include <sys/mount.h>
63 #endif
64 #if defined(FREEBSD) || defined(DFBSD)
65 #include <sys/dkstat.h>
66 #include <devstat.h>
67 #define VALID_FS_TYPES {"hpfs", "msdosfs", "ntfs", "udf", "ext2fs", \
68 "ufs", "mfs"}
69 #endif
70 #if defined(NETBSD) || defined(OPENBSD)
71 #include <sys/param.h>
72 #include <sys/sysctl.h>
73 #include <sys/disk.h>
74 #define VALID_FS_TYPES {"ffs", "mfs", "msdos", "lfs", "adosfs", "ext2fs", \
75 "ntfs"}
76 #endif
77
78 #define START_VAL 1
79
80 char *copy_string(char *orig_ptr, const char *newtext){
81
82 /* Maybe free if not NULL, and strdup rather than realloc and strcpy? */
83 orig_ptr=realloc(orig_ptr, (1+strlen(newtext)));
84 if(orig_ptr==NULL){
85 return NULL;
86 }
87 strcpy(orig_ptr, newtext);
88
89 return orig_ptr;
90 }
91
92
93 void init_disk_stat(int start, int end, disk_stat_t *disk_stats){
94
95 for(disk_stats+=start; start<=end; start++){
96 disk_stats->device_name=NULL;
97 disk_stats->fs_type=NULL;
98 disk_stats->mnt_point=NULL;
99
100 disk_stats++;
101 }
102 }
103
104 int is_valid_fs_type(const char *type) {
105 const char *types[] = VALID_FS_TYPES;
106 int i;
107
108 for (i = 0; i < (sizeof types / sizeof *types); i++) {
109 if (strcmp(types[i], type) == 0) {
110 return 1;
111 }
112 }
113 return 0;
114 }
115
116 disk_stat_t *get_disk_stats(int *entries){
117
118 static disk_stat_t *disk_stats;
119 static int watermark=-1;
120
121 int valid_type;
122 int num_disks=0;
123 #if defined(LINUX) || defined (SOLARIS) || defined(CYGWIN)
124 FILE *f;
125 #endif
126
127 disk_stat_t *disk_ptr;
128
129 #ifdef SOLARIS
130 struct mnttab mp;
131 struct statvfs fs;
132 #endif
133 #if defined(LINUX) || defined(CYGWIN)
134 struct mntent *mp;
135 struct statfs fs;
136 #endif
137 #ifdef ALLBSD
138 int nummnt;
139 struct statfs *mp;
140 #endif
141
142 if(watermark==-1){
143 disk_stats=malloc(START_VAL * sizeof(disk_stat_t));
144 if(disk_stats==NULL){
145 return NULL;
146 }
147 watermark=START_VAL;
148 init_disk_stat(0, watermark-1, disk_stats);
149 }
150 #ifdef ALLBSD
151 nummnt=getmntinfo(&mp , MNT_LOCAL);
152 if (nummnt<=0){
153 return NULL;
154 }
155 for(;nummnt--; mp++){
156 valid_type = is_valid_fs_type(mp->f_fstypename);
157 #endif
158
159 #if defined(LINUX) || defined(CYGWIN)
160 if ((f=setmntent("/etc/mtab", "r" ))==NULL){
161 return NULL;
162 }
163
164 while((mp=getmntent(f))){
165 if((statfs(mp->mnt_dir, &fs)) !=0){
166 continue;
167 }
168
169 valid_type = is_valid_fs_type(mp->mnt_type);
170 #endif
171
172 #ifdef SOLARIS
173 if ((f=fopen("/etc/mnttab", "r" ))==NULL){
174 return NULL;
175 }
176 while((getmntent(f, &mp)) == 0){
177 if ((statvfs(mp.mnt_mountp, &fs)) !=0){
178 continue;
179 }
180 valid_type = is_valid_fs_type(mp.mnt_fstype);
181 #endif
182
183 if(valid_type){
184 if(num_disks>watermark-1){
185 disk_ptr=disk_stats;
186 if((disk_stats=realloc(disk_stats, (watermark*2 * sizeof(disk_stat_t))))==NULL){
187 disk_stats=disk_ptr;
188 return NULL;
189 }
190
191 watermark=watermark*2;
192 init_disk_stat(num_disks, watermark-1, disk_stats);
193 }
194
195 disk_ptr=disk_stats+num_disks;
196 #ifdef ALLBSD
197 if((disk_ptr->device_name=copy_string(disk_ptr->device_name, mp->f_mntfromname))==NULL){
198 return NULL;
199 }
200
201 if((disk_ptr->fs_type=copy_string(disk_ptr->fs_type, mp->f_fstypename))==NULL){
202 return NULL;
203 }
204
205 if((disk_ptr->mnt_point=copy_string(disk_ptr->mnt_point, mp->f_mntonname))==NULL){
206 return NULL;
207 }
208
209 disk_ptr->size = (long long)mp->f_bsize * (long long) mp->f_blocks;
210 disk_ptr->avail = (long long)mp->f_bsize * (long long) mp->f_bavail;
211 disk_ptr->used = (disk_ptr->size) - ((long long)mp->f_bsize * (long long)mp->f_bfree);
212
213 disk_ptr->total_inodes=(long long)mp->f_files;
214 disk_ptr->free_inodes=(long long)mp->f_ffree;
215 /* Freebsd doesn't have a "available" inodes */
216 disk_ptr->used_inodes=disk_ptr->total_inodes-disk_ptr->free_inodes;
217 #endif
218 #if defined(LINUX) || defined(CYGWIN)
219 if((disk_ptr->device_name=copy_string(disk_ptr->device_name, mp->mnt_fsname))==NULL){
220 return NULL;
221 }
222
223 if((disk_ptr->fs_type=copy_string(disk_ptr->fs_type, mp->mnt_type))==NULL){
224 return NULL;
225 }
226
227 if((disk_ptr->mnt_point=copy_string(disk_ptr->mnt_point, mp->mnt_dir))==NULL){
228 return NULL;
229 }
230 disk_ptr->size = (long long)fs.f_bsize * (long long)fs.f_blocks;
231 disk_ptr->avail = (long long)fs.f_bsize * (long long)fs.f_bavail;
232 disk_ptr->used = (disk_ptr->size) - ((long long)fs.f_bsize * (long long)fs.f_bfree);
233
234 disk_ptr->total_inodes=(long long)fs.f_files;
235 disk_ptr->free_inodes=(long long)fs.f_ffree;
236 /* Linux doesn't have a "available" inodes */
237 disk_ptr->used_inodes=disk_ptr->total_inodes-disk_ptr->free_inodes;
238 #endif
239
240 #ifdef SOLARIS
241 /* Memory leak in event of realloc failing */
242 /* Maybe make this char[bigenough] and do strncpy's and put a null in the end?
243 * Downside is its a bit hungry for a lot of mounts, as MNT_MAX_SIZE would prob
244 * be upwards of a k each
245 */
246 if((disk_ptr->device_name=copy_string(disk_ptr->device_name, mp.mnt_special))==NULL){
247 return NULL;
248 }
249
250 if((disk_ptr->fs_type=copy_string(disk_ptr->fs_type, mp.mnt_fstype))==NULL){
251 return NULL;
252 }
253
254 if((disk_ptr->mnt_point=copy_string(disk_ptr->mnt_point, mp.mnt_mountp))==NULL){
255 return NULL;
256 }
257
258 disk_ptr->size = (long long)fs.f_frsize * (long long)fs.f_blocks;
259 disk_ptr->avail = (long long)fs.f_frsize * (long long)fs.f_bavail;
260 disk_ptr->used = (disk_ptr->size) - ((long long)fs.f_frsize * (long long)fs.f_bfree);
261
262 disk_ptr->total_inodes=(long long)fs.f_files;
263 disk_ptr->used_inodes=disk_ptr->total_inodes - (long long)fs.f_ffree;
264 disk_ptr->free_inodes=(long long)fs.f_favail;
265 #endif
266 num_disks++;
267 }
268 }
269
270 *entries=num_disks;
271
272 /* If this fails, there is very little i can do about it, so
273 I'll ignore it :) */
274 #if defined(LINUX) || defined(CYGWIN)
275 endmntent(f);
276 #endif
277 #if defined(SOLARIS)
278 fclose(f);
279 #endif
280
281 return disk_stats;
282
283 }
284 void diskio_stat_init(int start, int end, diskio_stat_t *diskio_stats){
285
286 for(diskio_stats+=start; start<end; start++){
287 diskio_stats->disk_name=NULL;
288
289 diskio_stats++;
290 }
291 }
292
293 diskio_stat_t *diskio_stat_malloc(int needed_entries, int *cur_entries, diskio_stat_t *diskio_stats){
294
295 if(diskio_stats==NULL){
296
297 if((diskio_stats=malloc(needed_entries * sizeof(diskio_stat_t)))==NULL){
298 return NULL;
299 }
300 diskio_stat_init(0, needed_entries, diskio_stats);
301 *cur_entries=needed_entries;
302
303 return diskio_stats;
304 }
305
306
307 if(*cur_entries<needed_entries){
308 diskio_stats=realloc(diskio_stats, (sizeof(diskio_stat_t)*needed_entries));
309 if(diskio_stats==NULL){
310 return NULL;
311 }
312 diskio_stat_init(*cur_entries, needed_entries, diskio_stats);
313 *cur_entries=needed_entries;
314 }
315
316 return diskio_stats;
317 }
318
319 static diskio_stat_t *diskio_stats=NULL;
320 static int num_diskio=0;
321
322 #ifdef LINUX
323 typedef struct {
324 int major;
325 int minor;
326 } partition;
327 #endif
328
329 diskio_stat_t *get_diskio_stats(int *entries){
330
331 static int sizeof_diskio_stats=0;
332 #ifndef LINUX
333 diskio_stat_t *diskio_stats_ptr;
334 #endif
335
336 #ifdef SOLARIS
337 kstat_ctl_t *kc;
338 kstat_t *ksp;
339 kstat_io_t kios;
340 #endif
341 #ifdef LINUX
342 FILE *f;
343 char *line_ptr;
344 int major, minor;
345 int has_pp_stats = 1;
346 static partition *parts = NULL;
347 static int alloc_parts = 0;
348 int i, n;
349 time_t now;
350 const char *format;
351 #endif
352 #if defined(FREEBSD) || defined(DFBSD)
353 static struct statinfo stats;
354 static int stats_init = 0;
355 int counter;
356 struct device_selection *dev_sel = NULL;
357 int n_selected, n_selections;
358 long sel_gen;
359 struct devstat *dev_ptr;
360 #endif
361 #ifdef NETBSD
362 struct disk_sysctl *stats;
363 #endif
364 #ifdef OPENBSD
365 int diskcount;
366 char *disknames, *name, *bufpp;
367 char **dk_name;
368 struct diskstats *stats;
369 #endif
370 #ifdef NETBSD
371 #define MIBSIZE 3
372 #endif
373 #ifdef OPENBSD
374 #define MIBSIZE 2
375 #endif
376 #if defined(NETBSD) || defined(OPENBSD)
377 int num_disks, i;
378 int mib[MIBSIZE];
379 size_t size;
380 #endif
381
382 num_diskio=0;
383
384 #ifdef OPENBSD
385 mib[0] = CTL_HW;
386 mib[1] = HW_DISKCOUNT;
387
388 size = sizeof(diskcount);
389 if (sysctl(mib, MIBSIZE, &diskcount, &size, NULL, 0) < 0) {
390 return NULL;
391 }
392
393 mib[0] = CTL_HW;
394 mib[1] = HW_DISKNAMES;
395
396 if (sysctl(mib, MIBSIZE, NULL, &size, NULL, 0) < 0) {
397 return NULL;
398 }
399
400 disknames = malloc(size);
401 if (disknames == NULL) {
402 return NULL;
403 }
404
405 if (sysctl(mib, MIBSIZE, disknames, &size, NULL, 0) < 0) {
406 return NULL;
407 }
408
409 dk_name = calloc(diskcount, sizeof(char *));
410 bufpp = disknames;
411 for (i = 0; i < diskcount && (name = strsep(&bufpp, ",")) != NULL; i++) {
412 dk_name[i] = name;
413 }
414 #endif
415
416 #if defined(NETBSD) || defined(OPENBSD)
417 mib[0] = CTL_HW;
418 mib[1] = HW_DISKSTATS;
419 #ifdef NETBSD
420 mib[2] = sizeof(struct disk_sysctl);
421 #endif
422
423 if (sysctl(mib, MIBSIZE, NULL, &size, NULL, 0) < 0) {
424 return NULL;
425 }
426
427 #ifdef NETBSD
428 num_disks = size / sizeof(struct disk_sysctl);
429 #else
430 num_disks = size / sizeof(struct diskstats);
431 #endif
432
433 stats = malloc(size);
434 if (stats == NULL) {
435 return NULL;
436 }
437
438 if (sysctl(mib, MIBSIZE, stats, &size, NULL, 0) < 0) {
439 return NULL;
440 }
441
442 for (i = 0; i < num_disks; i++) {
443 u_int64_t rbytes, wbytes;
444
445 #ifdef NETBSD
446 #ifdef HAVE_DK_RBYTES
447 rbytes = stats[i].dk_rbytes;
448 wbytes = stats[i].dk_wbytes;
449 #else
450 /* Before 1.7, NetBSD merged reads and writes. */
451 rbytes = wbytes = stats[i].dk_bytes;
452 #endif
453 #else
454 rbytes = wbytes = stats[i].ds_bytes;
455 #endif
456
457 /* Don't keep stats for disks that have never been used. */
458 if (rbytes == 0 && wbytes == 0) {
459 continue;
460 }
461
462 diskio_stats = diskio_stat_malloc(num_diskio + 1,
463 &sizeof_diskio_stats,
464 diskio_stats);
465 if (diskio_stats == NULL) {
466 return NULL;
467 }
468 diskio_stats_ptr = diskio_stats + num_diskio;
469
470 diskio_stats_ptr->read_bytes = rbytes;
471 diskio_stats_ptr->write_bytes = wbytes;
472 if (diskio_stats_ptr->disk_name != NULL) {
473 free(diskio_stats_ptr->disk_name);
474 }
475 #ifdef NETBSD
476 diskio_stats_ptr->disk_name = strdup(stats[i].dk_name);
477 #else
478 diskio_stats_ptr->disk_name = strdup(dk_name[i]);
479 #endif
480 diskio_stats_ptr->systime = time(NULL);
481
482 num_diskio++;
483 }
484
485 free(stats);
486 #ifdef OPENBSD
487 free(dk_name);
488 free(disknames);
489 #endif
490 #endif
491
492 #if defined(FREEBSD) || defined(DFBSD)
493 if (!stats_init) {
494 stats.dinfo=malloc(sizeof(struct devinfo));
495 if(stats.dinfo==NULL) return NULL;
496 bzero(stats.dinfo, sizeof(struct devinfo));
497 stats_init = 1;
498 }
499 #ifdef FREEBSD5
500 if ((devstat_getdevs(NULL, &stats)) < 0) return NULL;
501 /* Not aware of a get all devices, so i said 999. If we ever
502 * find a machine with more than 999 disks, then i'll change
503 * this number :)
504 */
505 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;
506 #else
507 if ((getdevs(&stats)) < 0) return NULL;
508 /* Not aware of a get all devices, so i said 999. If we ever
509 * find a machine with more than 999 disks, then i'll change
510 * this number :)
511 */
512 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;
513 #endif
514
515 for(counter=0;counter<stats.dinfo->numdevs;counter++){
516 dev_ptr=&stats.dinfo->devices[dev_sel[counter].position];
517
518 /* Throw away devices that have done nothing, ever.. Eg "odd"
519 * devices.. like mem, proc.. and also doesn't report floppy
520 * drives etc unless they are doing stuff :)
521 */
522 #ifdef FREEBSD5
523 if((dev_ptr->bytes[DEVSTAT_READ]==0) && (dev_ptr->bytes[DEVSTAT_WRITE]==0)) continue;
524 #else
525 if((dev_ptr->bytes_read==0) && (dev_ptr->bytes_written==0)) continue;
526 #endif
527 if((diskio_stats=diskio_stat_malloc(num_diskio+1, &sizeof_diskio_stats, diskio_stats))==NULL){
528 return NULL;
529 }
530 diskio_stats_ptr=diskio_stats+num_diskio;
531
532 #ifdef FREEBSD5
533 diskio_stats_ptr->read_bytes=dev_ptr->bytes[DEVSTAT_READ];
534 diskio_stats_ptr->write_bytes=dev_ptr->bytes[DEVSTAT_WRITE];
535 #else
536 diskio_stats_ptr->read_bytes=dev_ptr->bytes_read;
537 diskio_stats_ptr->write_bytes=dev_ptr->bytes_written;
538 #endif
539 if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
540 asprintf((&diskio_stats_ptr->disk_name), "%s%d", dev_ptr->device_name, dev_ptr->unit_number);
541 diskio_stats_ptr->systime=time(NULL);
542
543 num_diskio++;
544 }
545 free(dev_sel);
546
547 #endif
548 #ifdef SOLARIS
549 if ((kc = kstat_open()) == NULL) {
550 return NULL;
551 }
552
553 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
554 if (!strcmp(ksp->ks_class, "disk")) {
555
556 if(ksp->ks_type != KSTAT_TYPE_IO) continue;
557 /* We dont want metadevices appearins as num_diskio */
558 if(strcmp(ksp->ks_module, "md")==0) continue;
559 if((kstat_read(kc, ksp, &kios))==-1){
560 }
561
562 if((diskio_stats=diskio_stat_malloc(num_diskio+1, &sizeof_diskio_stats, diskio_stats))==NULL){
563 kstat_close(kc);
564 return NULL;
565 }
566 diskio_stats_ptr=diskio_stats+num_diskio;
567
568 diskio_stats_ptr->read_bytes=kios.nread;
569
570 diskio_stats_ptr->write_bytes=kios.nwritten;
571
572 if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
573
574 diskio_stats_ptr->disk_name=strdup((char *) get_svr_from_bsd(ksp->ks_name));
575 diskio_stats_ptr->systime=time(NULL);
576 num_diskio++;
577 }
578 }
579
580 kstat_close(kc);
581 #endif
582
583 #ifdef LINUX
584 num_diskio = 0;
585 n = 0;
586
587 /* Read /proc/partitions to find what devices exist. Recent 2.4 kernels
588 have statistics in here too, so we can use those directly.
589 2.6 kernels have /proc/diskstats instead with almost (but not quite)
590 the same format. */
591
592 f = fopen("/proc/diskstats", "r");
593 format = " %d %d %99s %*d %*d %lld %*d %*d %*d %lld";
594 if (f == NULL) {
595 f = fopen("/proc/partitions", "r");
596 format = " %d %d %*d %99s %*d %*d %lld %*d %*d %*d %lld";
597 }
598 if (f == NULL) goto out;
599 now = time(NULL);
600
601 while ((line_ptr = f_read_line(f, "")) != NULL) {
602 char name[100];
603 char *s;
604 long long rsect, wsect;
605
606 int nr = sscanf(line_ptr, format,
607 &major, &minor, name, &rsect, &wsect);
608 if (nr < 3) continue;
609
610 /* Skip device names ending in numbers, since they're
611 partitions. */
612 s = name;
613 while (*s != '\0') s++;
614 --s;
615 if (*s >= '0' && *s <= '9') continue;
616
617 if (nr < 5) {
618 has_pp_stats = 0;
619 rsect = 0;
620 wsect = 0;
621 }
622
623 diskio_stats = diskio_stat_malloc(n + 1, &sizeof_diskio_stats,
624 diskio_stats);
625 if (diskio_stats == NULL) goto out;
626 if (n >= alloc_parts) {
627 alloc_parts += 16;
628 parts = realloc(parts, alloc_parts * sizeof *parts);
629 if (parts == NULL) {
630 alloc_parts = 0;
631 goto out;
632 }
633 }
634
635 if (diskio_stats[n].disk_name != NULL)
636 free(diskio_stats[n].disk_name);
637 diskio_stats[n].disk_name = strdup(name);
638 diskio_stats[n].read_bytes = rsect * 512;
639 diskio_stats[n].write_bytes = wsect * 512;
640 diskio_stats[n].systime = now;
641 parts[n].major = major;
642 parts[n].minor = minor;
643
644 n++;
645 }
646
647 fclose(f);
648 f = NULL;
649
650 if (!has_pp_stats) {
651 /* This is an older kernel where /proc/partitions doesn't
652 contain stats. Read what we can from /proc/stat instead, and
653 fill in the appropriate bits of the list allocated above. */
654
655 f = fopen("/proc/stat", "r");
656 if (f == NULL) goto out;
657 now = time(NULL);
658
659 line_ptr = f_read_line(f, "disk_io:");
660 if (line_ptr == NULL) goto out;
661
662 while((line_ptr=strchr(line_ptr, ' '))!=NULL){
663 long long rsect, wsect;
664
665 if (*++line_ptr == '\0') break;
666
667 if((sscanf(line_ptr,
668 "(%d,%d):(%*d, %*d, %lld, %*d, %lld)",
669 &major, &minor, &rsect, &wsect)) != 4) {
670 continue;
671 }
672
673 /* Find the corresponding device from earlier.
674 Just to add to the fun, "minor" is actually the disk
675 number, not the device minor, so we need to figure
676 out the real minor number based on the major!
677 This list is not exhaustive; if you're running
678 an older kernel you probably don't have fancy
679 I2O hardware anyway... */
680 switch (major) {
681 case 3:
682 case 21:
683 case 22:
684 case 33:
685 case 34:
686 case 36:
687 case 56:
688 case 57:
689 case 88:
690 case 89:
691 case 90:
692 case 91:
693 minor *= 64;
694 break;
695 case 9:
696 case 43:
697 break;
698 default:
699 minor *= 16;
700 break;
701 }
702 for (i = 0; i < n; i++) {
703 if (major == parts[i].major
704 && minor == parts[i].minor)
705 break;
706 }
707 if (i == n) continue;
708
709 /* We read the number of blocks. Blocks are stored in
710 512 bytes */
711 diskio_stats[i].read_bytes = rsect * 512;
712 diskio_stats[i].write_bytes = wsect * 512;
713 diskio_stats[i].systime = now;
714 }
715 }
716
717 num_diskio = n;
718 out:
719 if (f != NULL) fclose(f);
720 #endif
721
722 #ifdef CYGWIN
723 return NULL;
724 #endif
725
726 *entries=num_diskio;
727
728 return diskio_stats;
729 }
730
731 diskio_stat_t *get_diskio_stats_diff(int *entries){
732 static diskio_stat_t *diff = NULL;
733 static int diff_count = 0;
734 diskio_stat_t *src = NULL, *dest;
735 int i, j, new_count;
736
737 if (diskio_stats == NULL) {
738 /* No previous stats, so we can't calculate a difference. */
739 return get_diskio_stats(entries);
740 }
741
742 /* Resize the results array to match the previous stats. */
743 diff = diskio_stat_malloc(num_diskio, &diff_count, diff);
744 if (diff == NULL) {
745 return NULL;
746 }
747
748 /* Copy the previous stats into the result. */
749 for (i = 0; i < diff_count; i++) {
750 src = &diskio_stats[i];
751 dest = &diff[i];
752
753 if (dest->disk_name != NULL) {
754 free(dest->disk_name);
755 }
756 dest->disk_name = strdup(src->disk_name);
757 dest->read_bytes = src->read_bytes;
758 dest->write_bytes = src->write_bytes;
759 dest->systime = src->systime;
760 }
761
762 /* Get a new set of stats. */
763 if (get_diskio_stats(&new_count) == NULL) {
764 return NULL;
765 }
766
767 /* For each previous stat... */
768 for (i = 0; i < diff_count; i++) {
769 dest = &diff[i];
770
771 /* ... find the corresponding new stat ... */
772 for (j = 0; j < new_count; j++) {
773 /* Try the new stat in the same position first,
774 since that's most likely to be it. */
775 src = &diskio_stats[(i + j) % new_count];
776 if (strcmp(src->disk_name, dest->disk_name) == 0) {
777 break;
778 }
779 }
780 if (j == new_count) {
781 /* No match found. */
782 continue;
783 }
784
785 /* ... and subtract the previous stat from it to get the
786 difference. */
787 dest->read_bytes = src->read_bytes - dest->read_bytes;
788 dest->write_bytes = src->write_bytes - dest->write_bytes;
789 dest->systime = src->systime - dest->systime;
790 }
791
792 *entries = diff_count;
793 return diff;
794 }
795