ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c
Revision: 1.58
Committed: Sun Apr 4 23:26:23 2004 UTC (20 years, 1 month ago) by ats
Content type: text/plain
Branch: MAIN
Changes since 1.57: +4 -10 lines
Log Message:
Convert another realloc-managed static array to a vector.

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