ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c
Revision: 1.59
Committed: Sun Apr 4 23:55:48 2004 UTC (20 years, 1 month ago) by ats
Content type: text/plain
Branch: MAIN
Changes since 1.58: +10 -23 lines
Log Message:
I like copy_string. We should use it EVERYWHERE. Also, the name needed
changing.

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