ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c
Revision: 1.40
Committed: Mon Nov 10 23:25:45 2003 UTC (20 years, 6 months ago) by ats
Content type: text/plain
Branch: MAIN
Changes since 1.39: +14 -11 lines
Log Message:
Make Cygwin its own platform, rather than defining LINUX. This stops
libstatgrab from trying to fetch stats that Cygwin doesn't have.

File Contents

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