ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c
Revision: 1.58
Committed: Sun Apr 4 23:26:23 2004 UTC (20 years, 1 month ago) by ats
Content type: text/plain
Branch: MAIN
Changes since 1.57: +4 -10 lines
Log Message:
Convert another realloc-managed static array to a vector.

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