ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c
Revision: 1.46
Committed: Sat Jan 10 16:12:34 2004 UTC (20 years, 4 months ago) by ats
Content type: text/plain
Branch: MAIN
Changes since 1.45: +1 -0 lines
Log Message:
Don't close f twice.

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