ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c
Revision: 1.51
Committed: Thu Feb 12 23:04:52 2004 UTC (20 years, 3 months ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.50: +32 -6 lines
Log Message:
Add preliminary support for OpenBSD (tested on 3.3).

All works apart from Disk IO stats - currently the disks are not named
correctly. The fix for this is probably to use KVM.

Mostly similar to the NetBSD code, the notable exception being the uvm
stuff. In NetBSD there's a function to get it, in OpenBSD sysctl is needed
to get hold of it.

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.50 2004/01/21 23:46:54 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 #ifdef FREEBSD
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 #ifdef FREEBSD
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 struct diskstats *stats;
366 #endif
367 #ifdef NETBSD
368 #define MIBSIZE 3
369 #endif
370 #ifdef OPENBSD
371 #define MIBSIZE 2
372 #endif
373 #if defined(NETBSD) || defined(OPENBSD)
374 int num_disks, i;
375 int mib[MIBSIZE];
376 size_t size;
377 #endif
378
379 num_diskio=0;
380
381 #if defined(NETBSD) || defined(OPENBSD)
382 mib[0] = CTL_HW;
383 mib[1] = HW_DISKSTATS;
384 #ifdef NETBSD
385 mib[2] = sizeof(struct disk_sysctl);
386 #endif
387
388 if (sysctl(mib, MIBSIZE, NULL, &size, NULL, 0) < 0) {
389 return NULL;
390 }
391
392 #ifdef NETBSD
393 num_disks = size / sizeof(struct disk_sysctl);
394 #else
395 num_disks = size / sizeof(struct diskstats);
396 #endif
397
398 stats = malloc(size);
399 if (stats == NULL) {
400 return NULL;
401 }
402
403 if (sysctl(mib, MIBSIZE, stats, &size, NULL, 0) < 0) {
404 return NULL;
405 }
406
407 for (i = 0; i < num_disks; i++) {
408 u_int64_t rbytes, wbytes;
409
410 #ifdef NETBSD
411 #ifdef HAVE_DK_RBYTES
412 rbytes = stats[i].dk_rbytes;
413 wbytes = stats[i].dk_wbytes;
414 #else
415 /* Before 1.7, NetBSD merged reads and writes. */
416 rbytes = wbytes = stats[i].dk_bytes;
417 #endif
418 #else
419 rbytes = wbytes = stats[i].ds_bytes;
420 #endif
421
422 /* Don't keep stats for disks that have never been used. */
423 if (rbytes == 0 && wbytes == 0) {
424 continue;
425 }
426
427 diskio_stats = diskio_stat_malloc(num_diskio + 1,
428 &sizeof_diskio_stats,
429 diskio_stats);
430 if (diskio_stats == NULL) {
431 return NULL;
432 }
433 diskio_stats_ptr = diskio_stats + num_diskio;
434
435 diskio_stats_ptr->read_bytes = rbytes;
436 diskio_stats_ptr->write_bytes = wbytes;
437 if (diskio_stats_ptr->disk_name != NULL) {
438 free(diskio_stats_ptr->disk_name);
439 }
440 #ifdef NETBSD
441 diskio_stats_ptr->disk_name = strdup(stats[i].dk_name);
442 #else
443 asprintf((&diskio_stats_ptr->disk_name), "%s%d", "disk", i);
444 #endif
445 diskio_stats_ptr->systime = time(NULL);
446
447 num_diskio++;
448 }
449
450 free(stats);
451 #endif
452
453 #ifdef FREEBSD
454 if (!stats_init) {
455 stats.dinfo=malloc(sizeof(struct devinfo));
456 if(stats.dinfo==NULL) return NULL;
457 bzero(stats.dinfo, sizeof(struct devinfo));
458 stats_init = 1;
459 }
460 #ifdef FREEBSD5
461 if ((devstat_getdevs(NULL, &stats)) < 0) return NULL;
462 /* Not aware of a get all devices, so i said 999. If we ever
463 * find a machine with more than 999 disks, then i'll change
464 * this number :)
465 */
466 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;
467 #else
468 if ((getdevs(&stats)) < 0) return NULL;
469 /* Not aware of a get all devices, so i said 999. If we ever
470 * find a machine with more than 999 disks, then i'll change
471 * this number :)
472 */
473 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;
474 #endif
475
476 for(counter=0;counter<stats.dinfo->numdevs;counter++){
477 dev_ptr=&stats.dinfo->devices[dev_sel[counter].position];
478
479 /* Throw away devices that have done nothing, ever.. Eg "odd"
480 * devices.. like mem, proc.. and also doesn't report floppy
481 * drives etc unless they are doing stuff :)
482 */
483 #ifdef FREEBSD5
484 if((dev_ptr->bytes[DEVSTAT_READ]==0) && (dev_ptr->bytes[DEVSTAT_WRITE]==0)) continue;
485 #else
486 if((dev_ptr->bytes_read==0) && (dev_ptr->bytes_written==0)) continue;
487 #endif
488 if((diskio_stats=diskio_stat_malloc(num_diskio+1, &sizeof_diskio_stats, diskio_stats))==NULL){
489 return NULL;
490 }
491 diskio_stats_ptr=diskio_stats+num_diskio;
492
493 #ifdef FREEBSD5
494 diskio_stats_ptr->read_bytes=dev_ptr->bytes[DEVSTAT_READ];
495 diskio_stats_ptr->write_bytes=dev_ptr->bytes[DEVSTAT_WRITE];
496 #else
497 diskio_stats_ptr->read_bytes=dev_ptr->bytes_read;
498 diskio_stats_ptr->write_bytes=dev_ptr->bytes_written;
499 #endif
500 if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
501 asprintf((&diskio_stats_ptr->disk_name), "%s%d", dev_ptr->device_name, dev_ptr->unit_number);
502 diskio_stats_ptr->systime=time(NULL);
503
504 num_diskio++;
505 }
506 free(dev_sel);
507
508 #endif
509 #ifdef SOLARIS
510 if ((kc = kstat_open()) == NULL) {
511 return NULL;
512 }
513
514 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
515 if (!strcmp(ksp->ks_class, "disk")) {
516
517 if(ksp->ks_type != KSTAT_TYPE_IO) continue;
518 /* We dont want metadevices appearins as num_diskio */
519 if(strcmp(ksp->ks_module, "md")==0) continue;
520 if((kstat_read(kc, ksp, &kios))==-1){
521 }
522
523 if((diskio_stats=diskio_stat_malloc(num_diskio+1, &sizeof_diskio_stats, diskio_stats))==NULL){
524 kstat_close(kc);
525 return NULL;
526 }
527 diskio_stats_ptr=diskio_stats+num_diskio;
528
529 diskio_stats_ptr->read_bytes=kios.nread;
530
531 diskio_stats_ptr->write_bytes=kios.nwritten;
532
533 if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
534
535 diskio_stats_ptr->disk_name=strdup((char *) get_svr_from_bsd(ksp->ks_name));
536 diskio_stats_ptr->systime=time(NULL);
537 num_diskio++;
538 }
539 }
540
541 kstat_close(kc);
542 #endif
543
544 #ifdef LINUX
545 num_diskio = 0;
546 n = 0;
547
548 /* Read /proc/partitions to find what devices exist. Recent 2.4 kernels
549 have statistics in here too, so we can use those directly.
550 2.6 kernels have /proc/diskstats instead with almost (but not quite)
551 the same format. */
552
553 f = fopen("/proc/diskstats", "r");
554 format = " %d %d %19s %*d %*d %lld %*d %*d %*d %lld";
555 if (f == NULL) {
556 f = fopen("/proc/partitions", "r");
557 format = " %d %d %*d %19s %*d %*d %lld %*d %*d %*d %lld";
558 }
559 if (f == NULL) goto out;
560 now = time(NULL);
561
562 while ((line_ptr = f_read_line(f, "")) != NULL) {
563 char name[20];
564 char *s;
565 long long rsect, wsect;
566
567 int nr = sscanf(line_ptr, format,
568 &major, &minor, name, &rsect, &wsect);
569 if (nr < 3) continue;
570
571 /* Skip device names ending in numbers, since they're
572 partitions. */
573 s = name;
574 while (*s != '\0') s++;
575 --s;
576 if (*s >= '0' && *s <= '9') continue;
577
578 if (nr < 5) {
579 has_pp_stats = 0;
580 rsect = 0;
581 wsect = 0;
582 }
583
584 diskio_stats = diskio_stat_malloc(n + 1, &sizeof_diskio_stats,
585 diskio_stats);
586 if (diskio_stats == NULL) goto out;
587 if (n >= alloc_parts) {
588 alloc_parts += 16;
589 parts = realloc(parts, alloc_parts * sizeof *parts);
590 if (parts == NULL) {
591 alloc_parts = 0;
592 goto out;
593 }
594 }
595
596 if (diskio_stats[n].disk_name != NULL)
597 free(diskio_stats[n].disk_name);
598 diskio_stats[n].disk_name = strdup(name);
599 diskio_stats[n].read_bytes = rsect * 512;
600 diskio_stats[n].write_bytes = wsect * 512;
601 diskio_stats[n].systime = now;
602 parts[n].major = major;
603 parts[n].minor = minor;
604
605 n++;
606 }
607
608 fclose(f);
609 f = NULL;
610
611 if (!has_pp_stats) {
612 /* This is an older kernel where /proc/partitions doesn't
613 contain stats. Read what we can from /proc/stat instead, and
614 fill in the appropriate bits of the list allocated above. */
615
616 f = fopen("/proc/stat", "r");
617 if (f == NULL) goto out;
618 now = time(NULL);
619
620 line_ptr = f_read_line(f, "disk_io:");
621 if (line_ptr == NULL) goto out;
622
623 while((line_ptr=strchr(line_ptr, ' '))!=NULL){
624 long long rsect, wsect;
625
626 if (*++line_ptr == '\0') break;
627
628 if((sscanf(line_ptr,
629 "(%d,%d):(%*d, %*d, %lld, %*d, %lld)",
630 &major, &minor, &rsect, &wsect)) != 4) {
631 continue;
632 }
633
634 /* Find the corresponding device from earlier.
635 Just to add to the fun, "minor" is actually the disk
636 number, not the device minor, so we need to figure
637 out the real minor number based on the major!
638 This list is not exhaustive; if you're running
639 an older kernel you probably don't have fancy
640 I2O hardware anyway... */
641 switch (major) {
642 case 3:
643 case 21:
644 case 22:
645 case 33:
646 case 34:
647 case 36:
648 case 56:
649 case 57:
650 case 88:
651 case 89:
652 case 90:
653 case 91:
654 minor *= 64;
655 break;
656 case 9:
657 case 43:
658 break;
659 default:
660 minor *= 16;
661 break;
662 }
663 for (i = 0; i < n; i++) {
664 if (major == parts[i].major
665 && minor == parts[i].minor)
666 break;
667 }
668 if (i == n) continue;
669
670 /* We read the number of blocks. Blocks are stored in
671 512 bytes */
672 diskio_stats[i].read_bytes = rsect * 512;
673 diskio_stats[i].write_bytes = wsect * 512;
674 diskio_stats[i].systime = now;
675 }
676 }
677
678 num_diskio = n;
679 out:
680 if (f != NULL) fclose(f);
681 #endif
682
683 #ifdef CYGWIN
684 return NULL;
685 #endif
686
687 *entries=num_diskio;
688
689 return diskio_stats;
690 }
691
692 diskio_stat_t *get_diskio_stats_diff(int *entries){
693 static diskio_stat_t *diff = NULL;
694 static int diff_count = 0;
695 diskio_stat_t *src, *dest;
696 int i, j, new_count;
697
698 if (diskio_stats == NULL) {
699 /* No previous stats, so we can't calculate a difference. */
700 return get_diskio_stats(entries);
701 }
702
703 /* Resize the results array to match the previous stats. */
704 diff = diskio_stat_malloc(num_diskio, &diff_count, diff);
705 if (diff == NULL) {
706 return NULL;
707 }
708
709 /* Copy the previous stats into the result. */
710 for (i = 0; i < diff_count; i++) {
711 src = &diskio_stats[i];
712 dest = &diff[i];
713
714 if (dest->disk_name != NULL) {
715 free(dest->disk_name);
716 }
717 dest->disk_name = strdup(src->disk_name);
718 dest->read_bytes = src->read_bytes;
719 dest->write_bytes = src->write_bytes;
720 dest->systime = src->systime;
721 }
722
723 /* Get a new set of stats. */
724 if (get_diskio_stats(&new_count) == NULL) {
725 return NULL;
726 }
727
728 /* For each previous stat... */
729 for (i = 0; i < diff_count; i++) {
730 dest = &diff[i];
731
732 /* ... find the corresponding new stat ... */
733 for (j = 0; j < new_count; j++) {
734 /* Try the new stat in the same position first,
735 since that's most likely to be it. */
736 src = &diskio_stats[(i + j) % new_count];
737 if (strcmp(src->disk_name, dest->disk_name) == 0) {
738 break;
739 }
740 }
741 if (j == new_count) {
742 /* No match found. */
743 continue;
744 }
745
746 /* ... and subtract the previous stat from it to get the
747 difference. */
748 dest->read_bytes = src->read_bytes - dest->read_bytes;
749 dest->write_bytes = src->write_bytes - dest->write_bytes;
750 dest->systime = src->systime - dest->systime;
751 }
752
753 *entries = diff_count;
754 return diff;
755 }
756