ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c
Revision: 1.53
Committed: Mon Feb 16 14:55:32 2004 UTC (20 years, 3 months ago) by tdb
Content type: text/plain
Branch: MAIN
CVS Tags: LIBSTATGRAB_0_9
Changes since 1.52: +4 -4 lines
Log Message:
Add support for DragonFly BSD 1.0.
Also a minor tweak to the network interface code to make it more portable.

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 tdb 1.53 * $Id: disk_stats.c,v 1.52 2004/02/13 16:46:21 tdb 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 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 tdb 1.53 #if defined(FREEBSD) || defined(DFBSD)
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 tdb 1.51 #if defined(NETBSD) || defined(OPENBSD)
71 ats 1.34 #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 tdb 1.53 #if defined(FREEBSD) || defined(DFBSD)
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 tdb 1.51 #endif
364     #ifdef OPENBSD
365 tdb 1.52 int diskcount;
366     char *disknames, *name, *bufpp;
367     char **dk_name;
368 tdb 1.51 struct diskstats *stats;
369     #endif
370     #ifdef NETBSD
371     #define MIBSIZE 3
372     #endif
373     #ifdef OPENBSD
374     #define MIBSIZE 2
375     #endif
376     #if defined(NETBSD) || defined(OPENBSD)
377 ats 1.34 int num_disks, i;
378 tdb 1.51 int mib[MIBSIZE];
379 ats 1.34 size_t size;
380 pajs 1.17 #endif
381 ats 1.34
382 pajs 1.10 num_diskio=0;
383 ats 1.34
384 tdb 1.52 #ifdef OPENBSD
385     mib[0] = CTL_HW;
386     mib[1] = HW_DISKCOUNT;
387    
388     size = sizeof(diskcount);
389     if (sysctl(mib, MIBSIZE, &diskcount, &size, NULL, 0) < 0) {
390     return NULL;
391     }
392    
393     mib[0] = CTL_HW;
394     mib[1] = HW_DISKNAMES;
395    
396     if (sysctl(mib, MIBSIZE, NULL, &size, NULL, 0) < 0) {
397     return NULL;
398     }
399    
400     disknames = malloc(size);
401     if (disknames == NULL) {
402     return NULL;
403     }
404    
405     if (sysctl(mib, MIBSIZE, disknames, &size, NULL, 0) < 0) {
406     return NULL;
407     }
408    
409     dk_name = calloc(diskcount, sizeof(char *));
410     bufpp = disknames;
411     for (i = 0; i < diskcount && (name = strsep(&bufpp, ",")) != NULL; i++) {
412     dk_name[i] = name;
413     }
414     #endif
415    
416 tdb 1.51 #if defined(NETBSD) || defined(OPENBSD)
417 ats 1.34 mib[0] = CTL_HW;
418     mib[1] = HW_DISKSTATS;
419 tdb 1.51 #ifdef NETBSD
420 ats 1.34 mib[2] = sizeof(struct disk_sysctl);
421 tdb 1.51 #endif
422 ats 1.34
423 tdb 1.51 if (sysctl(mib, MIBSIZE, NULL, &size, NULL, 0) < 0) {
424 ats 1.34 return NULL;
425     }
426 tdb 1.51
427     #ifdef NETBSD
428 ats 1.34 num_disks = size / sizeof(struct disk_sysctl);
429 tdb 1.51 #else
430     num_disks = size / sizeof(struct diskstats);
431     #endif
432 ats 1.34
433     stats = malloc(size);
434     if (stats == NULL) {
435     return NULL;
436     }
437    
438 tdb 1.51 if (sysctl(mib, MIBSIZE, stats, &size, NULL, 0) < 0) {
439 ats 1.34 return NULL;
440     }
441    
442     for (i = 0; i < num_disks; i++) {
443     u_int64_t rbytes, wbytes;
444    
445 tdb 1.51 #ifdef NETBSD
446 ats 1.34 #ifdef HAVE_DK_RBYTES
447     rbytes = stats[i].dk_rbytes;
448     wbytes = stats[i].dk_wbytes;
449     #else
450 ats 1.37 /* Before 1.7, NetBSD merged reads and writes. */
451 ats 1.34 rbytes = wbytes = stats[i].dk_bytes;
452     #endif
453 tdb 1.51 #else
454     rbytes = wbytes = stats[i].ds_bytes;
455     #endif
456 ats 1.34
457     /* Don't keep stats for disks that have never been used. */
458     if (rbytes == 0 && wbytes == 0) {
459     continue;
460     }
461    
462     diskio_stats = diskio_stat_malloc(num_diskio + 1,
463     &sizeof_diskio_stats,
464     diskio_stats);
465     if (diskio_stats == NULL) {
466     return NULL;
467     }
468     diskio_stats_ptr = diskio_stats + num_diskio;
469    
470     diskio_stats_ptr->read_bytes = rbytes;
471     diskio_stats_ptr->write_bytes = wbytes;
472     if (diskio_stats_ptr->disk_name != NULL) {
473     free(diskio_stats_ptr->disk_name);
474     }
475 tdb 1.51 #ifdef NETBSD
476 ats 1.34 diskio_stats_ptr->disk_name = strdup(stats[i].dk_name);
477 tdb 1.51 #else
478 tdb 1.52 diskio_stats_ptr->disk_name = strdup(dk_name[i]);
479 tdb 1.51 #endif
480 ats 1.34 diskio_stats_ptr->systime = time(NULL);
481    
482     num_diskio++;
483     }
484    
485     free(stats);
486 tdb 1.52 #ifdef OPENBSD
487     free(dk_name);
488     free(disknames);
489     #endif
490 ats 1.34 #endif
491 pajs 1.4
492 tdb 1.53 #if defined(FREEBSD) || defined(DFBSD)
493 ats 1.21 if (!stats_init) {
494     stats.dinfo=malloc(sizeof(struct devinfo));
495 ats 1.33 if(stats.dinfo==NULL) return NULL;
496 tdb 1.25 bzero(stats.dinfo, sizeof(struct devinfo));
497 ats 1.21 stats_init = 1;
498     }
499 pajs 1.28 #ifdef FREEBSD5
500     if ((devstat_getdevs(NULL, &stats)) < 0) return NULL;
501 ats 1.29 /* Not aware of a get all devices, so i said 999. If we ever
502     * find a machine with more than 999 disks, then i'll change
503     * this number :)
504     */
505 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;
506     #else
507 pajs 1.17 if ((getdevs(&stats)) < 0) return NULL;
508     /* Not aware of a get all devices, so i said 999. If we ever
509     * find a machine with more than 999 disks, then i'll change
510     * this number :)
511     */
512     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;
513 pajs 1.27 #endif
514 pajs 1.17
515     for(counter=0;counter<stats.dinfo->numdevs;counter++){
516     dev_ptr=&stats.dinfo->devices[dev_sel[counter].position];
517    
518     /* Throw away devices that have done nothing, ever.. Eg "odd"
519     * devices.. like mem, proc.. and also doesn't report floppy
520     * drives etc unless they are doing stuff :)
521     */
522 pajs 1.27 #ifdef FREEBSD5
523     if((dev_ptr->bytes[DEVSTAT_READ]==0) && (dev_ptr->bytes[DEVSTAT_WRITE]==0)) continue;
524     #else
525 pajs 1.17 if((dev_ptr->bytes_read==0) && (dev_ptr->bytes_written==0)) continue;
526 pajs 1.27 #endif
527 pajs 1.17 if((diskio_stats=diskio_stat_malloc(num_diskio+1, &sizeof_diskio_stats, diskio_stats))==NULL){
528     return NULL;
529     }
530     diskio_stats_ptr=diskio_stats+num_diskio;
531 pajs 1.27
532     #ifdef FREEBSD5
533     diskio_stats_ptr->read_bytes=dev_ptr->bytes[DEVSTAT_READ];
534     diskio_stats_ptr->write_bytes=dev_ptr->bytes[DEVSTAT_WRITE];
535     #else
536 pajs 1.17 diskio_stats_ptr->read_bytes=dev_ptr->bytes_read;
537     diskio_stats_ptr->write_bytes=dev_ptr->bytes_written;
538 pajs 1.27 #endif
539 pajs 1.17 if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
540     asprintf((&diskio_stats_ptr->disk_name), "%s%d", dev_ptr->device_name, dev_ptr->unit_number);
541     diskio_stats_ptr->systime=time(NULL);
542    
543     num_diskio++;
544     }
545     free(dev_sel);
546    
547     #endif
548 pajs 1.10 #ifdef SOLARIS
549 pajs 1.4 if ((kc = kstat_open()) == NULL) {
550     return NULL;
551     }
552    
553     for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
554     if (!strcmp(ksp->ks_class, "disk")) {
555    
556     if(ksp->ks_type != KSTAT_TYPE_IO) continue;
557 pajs 1.5 /* We dont want metadevices appearins as num_diskio */
558 pajs 1.4 if(strcmp(ksp->ks_module, "md")==0) continue;
559     if((kstat_read(kc, ksp, &kios))==-1){
560     }
561    
562 pajs 1.5 if((diskio_stats=diskio_stat_malloc(num_diskio+1, &sizeof_diskio_stats, diskio_stats))==NULL){
563 pajs 1.4 kstat_close(kc);
564     return NULL;
565     }
566 pajs 1.5 diskio_stats_ptr=diskio_stats+num_diskio;
567 pajs 1.4
568     diskio_stats_ptr->read_bytes=kios.nread;
569    
570     diskio_stats_ptr->write_bytes=kios.nwritten;
571    
572     if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
573    
574 tdb 1.43 diskio_stats_ptr->disk_name=strdup((char *) get_svr_from_bsd(ksp->ks_name));
575 pajs 1.14 diskio_stats_ptr->systime=time(NULL);
576 pajs 1.5 num_diskio++;
577 pajs 1.4 }
578     }
579    
580     kstat_close(kc);
581 pajs 1.10 #endif
582 pajs 1.4
583 pajs 1.10 #ifdef LINUX
584 ats 1.20 num_diskio = 0;
585     n = 0;
586 pajs 1.10
587 ats 1.20 /* Read /proc/partitions to find what devices exist. Recent 2.4 kernels
588 ats 1.38 have statistics in here too, so we can use those directly.
589     2.6 kernels have /proc/diskstats instead with almost (but not quite)
590     the same format. */
591    
592     f = fopen("/proc/diskstats", "r");
593     format = " %d %d %19s %*d %*d %lld %*d %*d %*d %lld";
594     if (f == NULL) {
595     f = fopen("/proc/partitions", "r");
596     format = " %d %d %*d %19s %*d %*d %lld %*d %*d %*d %lld";
597     }
598 ats 1.20 if (f == NULL) goto out;
599     now = time(NULL);
600    
601     while ((line_ptr = f_read_line(f, "")) != NULL) {
602     char name[20];
603     char *s;
604     long long rsect, wsect;
605    
606 ats 1.38 int nr = sscanf(line_ptr, format,
607 ats 1.20 &major, &minor, name, &rsect, &wsect);
608     if (nr < 3) continue;
609    
610     /* Skip device names ending in numbers, since they're
611     partitions. */
612     s = name;
613     while (*s != '\0') s++;
614     --s;
615     if (*s >= '0' && *s <= '9') continue;
616 ats 1.38
617     if (nr < 5) {
618     has_pp_stats = 0;
619     rsect = 0;
620     wsect = 0;
621     }
622 ats 1.20
623     diskio_stats = diskio_stat_malloc(n + 1, &sizeof_diskio_stats,
624     diskio_stats);
625     if (diskio_stats == NULL) goto out;
626     if (n >= alloc_parts) {
627     alloc_parts += 16;
628     parts = realloc(parts, alloc_parts * sizeof *parts);
629     if (parts == NULL) {
630     alloc_parts = 0;
631     goto out;
632     }
633 pajs 1.11 }
634 pajs 1.12
635 ats 1.20 if (diskio_stats[n].disk_name != NULL)
636     free(diskio_stats[n].disk_name);
637     diskio_stats[n].disk_name = strdup(name);
638     diskio_stats[n].read_bytes = rsect * 512;
639     diskio_stats[n].write_bytes = wsect * 512;
640     diskio_stats[n].systime = now;
641     parts[n].major = major;
642     parts[n].minor = minor;
643 pajs 1.10
644 ats 1.20 n++;
645     }
646 pajs 1.10
647 ats 1.45 fclose(f);
648 ats 1.46 f = NULL;
649 pajs 1.44
650 ats 1.20 if (!has_pp_stats) {
651 ats 1.45 /* This is an older kernel where /proc/partitions doesn't
652     contain stats. Read what we can from /proc/stat instead, and
653     fill in the appropriate bits of the list allocated above. */
654 ats 1.20
655     f = fopen("/proc/stat", "r");
656     if (f == NULL) goto out;
657     now = time(NULL);
658    
659     line_ptr = f_read_line(f, "disk_io:");
660     if (line_ptr == NULL) goto out;
661    
662     while((line_ptr=strchr(line_ptr, ' '))!=NULL){
663     long long rsect, wsect;
664    
665     if (*++line_ptr == '\0') break;
666    
667     if((sscanf(line_ptr,
668     "(%d,%d):(%*d, %*d, %lld, %*d, %lld)",
669     &major, &minor, &rsect, &wsect)) != 4) {
670     continue;
671     }
672 pajs 1.10
673 ats 1.20 /* Find the corresponding device from earlier.
674     Just to add to the fun, "minor" is actually the disk
675     number, not the device minor, so we need to figure
676     out the real minor number based on the major!
677     This list is not exhaustive; if you're running
678     an older kernel you probably don't have fancy
679     I2O hardware anyway... */
680     switch (major) {
681     case 3:
682     case 21:
683 pajs 1.10 case 22:
684 ats 1.20 case 33:
685     case 34:
686     case 36:
687     case 56:
688     case 57:
689     case 88:
690     case 89:
691     case 90:
692     case 91:
693     minor *= 64;
694 pajs 1.11 break;
695 ats 1.20 case 9:
696     case 43:
697 pajs 1.11 break;
698 pajs 1.10 default:
699 ats 1.20 minor *= 16;
700 pajs 1.11 break;
701 ats 1.20 }
702     for (i = 0; i < n; i++) {
703     if (major == parts[i].major
704     && minor == parts[i].minor)
705     break;
706     }
707     if (i == n) continue;
708    
709     /* We read the number of blocks. Blocks are stored in
710     512 bytes */
711     diskio_stats[i].read_bytes = rsect * 512;
712     diskio_stats[i].write_bytes = wsect * 512;
713     diskio_stats[i].systime = now;
714 pajs 1.10 }
715     }
716 pajs 1.16
717 ats 1.20 num_diskio = n;
718     out:
719     if (f != NULL) fclose(f);
720 ats 1.42 #endif
721 pajs 1.10
722 ats 1.42 #ifdef CYGWIN
723     return NULL;
724 pajs 1.10 #endif
725 ats 1.42
726 pajs 1.5 *entries=num_diskio;
727 pajs 1.4
728     return diskio_stats;
729 pajs 1.5 }
730    
731 pajs 1.6 diskio_stat_t *get_diskio_stats_diff(int *entries){
732 ats 1.50 static diskio_stat_t *diff = NULL;
733     static int diff_count = 0;
734     diskio_stat_t *src, *dest;
735     int i, j, new_count;
736    
737     if (diskio_stats == NULL) {
738     /* No previous stats, so we can't calculate a difference. */
739     return get_diskio_stats(entries);
740 pajs 1.5 }
741    
742 ats 1.50 /* Resize the results array to match the previous stats. */
743     diff = diskio_stat_malloc(num_diskio, &diff_count, diff);
744     if (diff == NULL) {
745 pajs 1.5 return NULL;
746     }
747    
748 ats 1.50 /* Copy the previous stats into the result. */
749     for (i = 0; i < diff_count; i++) {
750     src = &diskio_stats[i];
751     dest = &diff[i];
752    
753     if (dest->disk_name != NULL) {
754     free(dest->disk_name);
755     }
756     dest->disk_name = strdup(src->disk_name);
757     dest->read_bytes = src->read_bytes;
758     dest->write_bytes = src->write_bytes;
759     dest->systime = src->systime;
760 pajs 1.5 }
761    
762 ats 1.50 /* Get a new set of stats. */
763     if (get_diskio_stats(&new_count) == NULL) {
764 ats 1.47 return NULL;
765     }
766 pajs 1.5
767 ats 1.50 /* For each previous stat... */
768     for (i = 0; i < diff_count; i++) {
769     dest = &diff[i];
770    
771     /* ... find the corresponding new stat ... */
772     for (j = 0; j < new_count; j++) {
773     /* Try the new stat in the same position first,
774     since that's most likely to be it. */
775     src = &diskio_stats[(i + j) % new_count];
776     if (strcmp(src->disk_name, dest->disk_name) == 0) {
777     break;
778 pajs 1.5 }
779     }
780 ats 1.50 if (j == new_count) {
781     /* No match found. */
782     continue;
783     }
784 pajs 1.5
785 ats 1.50 /* ... and subtract the previous stat from it to get the
786     difference. */
787     dest->read_bytes = src->read_bytes - dest->read_bytes;
788     dest->write_bytes = src->write_bytes - dest->write_bytes;
789     dest->systime = src->systime - dest->systime;
790     }
791 pajs 1.5
792 ats 1.50 *entries = diff_count;
793     return diff;
794 pajs 1.2 }
795 ats 1.50