ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c
Revision: 1.49
Committed: Mon Jan 19 16:49:21 2004 UTC (20 years, 3 months ago) by tdb
Content type: text/plain
Branch: MAIN
CVS Tags: LIBSTATGRAB_0_8_1
Changes since 1.48: +2 -0 lines
Log Message:
A whole bunch of minor cosmetic changes.

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