ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c
Revision: 1.48
Committed: Fri Jan 16 15:54:54 2004 UTC (20 years, 4 months ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.47: +13 -12 lines
Log Message:
Alter the licensing of libstatgrab. The library part is now under the
LGPL, whilst the tools/examples are under the GPL. Both licenses are
included in the distribution (and are both now in CVS). Also made a
minor alteration to the webpage where it said everything was licensed
under the GPL.

File Contents

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