ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c
Revision: 1.17
Committed: Sat Apr 5 23:56:25 2003 UTC (21 years, 1 month ago) by pajs
Content type: text/plain
Branch: MAIN
CVS Tags: LIBSTATGRAB_0_4
Changes since 1.16: +46 -2 lines
Log Message:
Should now work on freebsd.

File Contents

# User Rev Content
1 pajs 1.1 /*
2     * i-scream central monitoring system
3     * http://www.i-scream.org.uk
4     * Copyright (C) 2000-2002 i-scream
5     *
6     * This program is free software; you can redistribute it and/or
7     * modify it under the terms of the GNU General Public License
8     * as published by the Free Software Foundation; either version 2
9     * of the License, or (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19     */
20    
21     #ifdef HAVE_CONFIG_H
22     #include "config.h"
23     #endif
24    
25 pajs 1.17 #include <stdio.h>
26 pajs 1.1 #include <stdlib.h>
27     #include <string.h>
28 tdb 1.7 #include "statgrab.h"
29 pajs 1.1
30     #ifdef SOLARIS
31     #include <sys/mnttab.h>
32     #include <sys/statvfs.h>
33 pajs 1.4 #include <kstat.h>
34 pajs 1.1 #define VALID_FS_TYPES {"ufs", "tmpfs"}
35     #endif
36    
37 pajs 1.9 #ifdef LINUX
38     #include <sys/vfs.h>
39     #include <mntent.h>
40 pajs 1.10 #include "tools.h"
41 pajs 1.9 #define VALID_FS_TYPES {"ext2", "ext3", "xfs", "reiserfs", "vfat", "tmpfs"}
42     #endif
43    
44 pajs 1.16 #ifdef FREEBSD
45     #include <sys/param.h>
46     #include <sys/ucred.h>
47     #include <sys/mount.h>
48 pajs 1.17 #include <sys/dkstat.h>
49     #include <devstat.h>
50 pajs 1.16 #define VALID_FS_TYPES {"ufs", "mfs"}
51     #endif
52 pajs 1.1 #define START_VAL 1
53    
54     char *copy_string(char *orig_ptr, const char *newtext){
55    
56     /* Maybe free if not NULL, and strdup rather than realloc and strcpy? */
57     orig_ptr=realloc(orig_ptr, (1+strlen(newtext)));
58     if(orig_ptr==NULL){
59     return NULL;
60     }
61     strcpy(orig_ptr, newtext);
62    
63     return orig_ptr;
64     }
65    
66    
67     void init_disk_stat(int start, int end, disk_stat_t *disk_stats){
68    
69     for(disk_stats+=start; start<=end; start++){
70     disk_stats->device_name=NULL;
71     disk_stats->fs_type=NULL;
72     disk_stats->mnt_point=NULL;
73    
74     disk_stats++;
75     }
76     }
77    
78     disk_stat_t *get_disk_stats(int *entries){
79    
80     static disk_stat_t *disk_stats;
81     static int watermark=-1;
82    
83     char *fs_types[] = VALID_FS_TYPES;
84     int x, valid_type;
85     int num_disks=0;
86 pajs 1.16 #if defined(LINUX) || defined (SOLARIS)
87 pajs 1.1 FILE *f;
88 pajs 1.16 #endif
89 pajs 1.1
90     disk_stat_t *disk_ptr;
91    
92 pajs 1.9 #ifdef SOLARIS
93 tdb 1.13 struct mnttab mp;
94 pajs 1.9 struct statvfs fs;
95     #endif
96     #ifdef LINUX
97     struct mntent *mp;
98     struct statfs fs;
99     #endif
100 pajs 1.16 #ifdef FREEBSD
101     int nummnt;
102     struct statfs *mp;
103     #endif
104 pajs 1.9
105 pajs 1.1 if(watermark==-1){
106     disk_stats=malloc(START_VAL * sizeof(disk_stat_t));
107     if(disk_stats==NULL){
108     return NULL;
109     }
110     watermark=START_VAL;
111     init_disk_stat(0, watermark-1, disk_stats);
112     }
113 pajs 1.16 #ifdef FREEBSD
114     nummnt=getmntinfo(&mp , MNT_LOCAL);
115     if (nummnt<=0){
116     return NULL;
117     }
118     for(;nummnt--; mp++){
119     valid_type=0;
120     for(x=0;x<((sizeof(fs_types))/(sizeof(char*)));x++){
121     if(strcmp(mp->f_fstypename, fs_types[x]) ==0){
122     valid_type=1;
123     break;
124     }
125     }
126     #endif
127    
128 pajs 1.9 #ifdef LINUX
129     if ((f=setmntent("/etc/mtab", "r" ))==NULL){
130     return NULL;
131     }
132 pajs 1.1
133 pajs 1.9 while((mp=getmntent(f))){
134     if((statfs(mp->mnt_dir, &fs)) !=0){
135     continue;
136     }
137 pajs 1.1
138 pajs 1.9 valid_type=0;
139     for(x=0;x<((sizeof(fs_types))/(sizeof(char*)));x++){
140     if(strcmp(mp->mnt_type, fs_types[x]) ==0){
141     valid_type=1;
142     break;
143     }
144     }
145     #endif
146    
147     #ifdef SOLARIS
148 pajs 1.1 if ((f=fopen("/etc/mnttab", "r" ))==NULL){
149     return NULL;
150     }
151     while((getmntent(f, &mp)) == 0){
152     if ((statvfs(mp.mnt_mountp, &fs)) !=0){
153     continue;
154     }
155     valid_type=0;
156     for(x=0;x<((sizeof(fs_types))/(sizeof(char*)));x++){
157     if(strcmp(mp.mnt_fstype, fs_types[x]) ==0){
158     valid_type=1;
159     break;
160     }
161     }
162 pajs 1.9 #endif
163 pajs 1.1
164     if(valid_type){
165     if(num_disks>watermark-1){
166     disk_ptr=disk_stats;
167     if((disk_stats=realloc(disk_stats, (watermark*2 * sizeof(disk_stat_t))))==NULL){
168     disk_stats=disk_ptr;
169     return NULL;
170     }
171    
172     watermark=watermark*2;
173     init_disk_stat(num_disks, watermark-1, disk_stats);
174     }
175    
176     disk_ptr=disk_stats+num_disks;
177 pajs 1.16 #ifdef FREEBSD
178     if((disk_ptr->device_name=copy_string(disk_ptr->device_name, mp->f_mntfromname))==NULL){
179     return NULL;
180     }
181    
182     if((disk_ptr->fs_type=copy_string(disk_ptr->fs_type, mp->f_fstypename))==NULL){
183     return NULL;
184     }
185    
186     if((disk_ptr->mnt_point=copy_string(disk_ptr->mnt_point, mp->f_mntonname))==NULL){
187     return NULL;
188     }
189    
190     disk_ptr->size = (long long)mp->f_bsize * (long long) mp->f_blocks;
191     disk_ptr->avail = (long long)mp->f_bsize * (long long) mp->f_bavail;
192     disk_ptr->used = (disk_ptr->size) - ((long long)mp->f_bsize * (long long)mp->f_bfree);
193    
194     disk_ptr->total_inodes=(long long)mp->f_files;
195     disk_ptr->free_inodes=(long long)mp->f_ffree;
196     /* Freebsd doesn't have a "available" inodes */
197     disk_ptr->used_inodes=disk_ptr->total_inodes-disk_ptr->free_inodes;
198     #endif
199 pajs 1.9 #ifdef LINUX
200     if((disk_ptr->device_name=copy_string(disk_ptr->device_name, mp->mnt_fsname))==NULL){
201     return NULL;
202     }
203    
204     if((disk_ptr->fs_type=copy_string(disk_ptr->fs_type, mp->mnt_type))==NULL){
205     return NULL;
206     }
207    
208     if((disk_ptr->mnt_point=copy_string(disk_ptr->mnt_point, mp->mnt_dir))==NULL){
209     return NULL;
210     }
211     disk_ptr->size = (long long)fs.f_bsize * (long long)fs.f_blocks;
212     disk_ptr->avail = (long long)fs.f_bsize * (long long)fs.f_bavail;
213     disk_ptr->used = (disk_ptr->size) - ((long long)fs.f_bsize * (long long)fs.f_bfree);
214    
215     disk_ptr->total_inodes=(long long)fs.f_files;
216     disk_ptr->free_inodes=(long long)fs.f_ffree;
217     /* Linux doesn't have a "available" inodes */
218     disk_ptr->used_inodes=disk_ptr->total_inodes-disk_ptr->free_inodes;
219     #endif
220    
221     #ifdef SOLARIS
222 pajs 1.1 /* Memory leak in event of realloc failing */
223     /* 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 pajs 1.1 if((disk_ptr->device_name=copy_string(disk_ptr->device_name, mp.mnt_special))==NULL){
228     return NULL;
229     }
230    
231     if((disk_ptr->fs_type=copy_string(disk_ptr->fs_type, mp.mnt_fstype))==NULL){
232     return NULL;
233     }
234    
235     if((disk_ptr->mnt_point=copy_string(disk_ptr->mnt_point, mp.mnt_mountp))==NULL){
236     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     /* If this fails, there is very little i can do about it, so i'll ignore it :) */
254 pajs 1.16 #if defined(LINUX) || defined(SOLARIS)
255 pajs 1.1 fclose(f);
256 pajs 1.16 #endif
257 pajs 1.1
258     return disk_stats;
259    
260     }
261 pajs 1.4 void diskio_stat_init(int start, int end, diskio_stat_t *diskio_stats){
262    
263     for(diskio_stats+=start; start<end; start++){
264     diskio_stats->disk_name=NULL;
265    
266     diskio_stats++;
267     }
268     }
269    
270     diskio_stat_t *diskio_stat_malloc(int needed_entries, int *cur_entries, diskio_stat_t *diskio_stats){
271    
272     if(diskio_stats==NULL){
273    
274     if((diskio_stats=malloc(needed_entries * sizeof(diskio_stat_t)))==NULL){
275     return NULL;
276     }
277     diskio_stat_init(0, needed_entries, diskio_stats);
278     *cur_entries=needed_entries;
279    
280     return diskio_stats;
281     }
282    
283    
284     if(*cur_entries<needed_entries){
285     diskio_stats=realloc(diskio_stats, (sizeof(diskio_stat_t)*needed_entries));
286     if(diskio_stats==NULL){
287     return NULL;
288     }
289     diskio_stat_init(*cur_entries, needed_entries, diskio_stats);
290     *cur_entries=needed_entries;
291     }
292    
293     return diskio_stats;
294     }
295    
296     static diskio_stat_t *diskio_stats=NULL;
297 pajs 1.5 static int num_diskio=0;
298 pajs 1.4
299 tdb 1.3 diskio_stat_t *get_diskio_stats(int *entries){
300 pajs 1.2
301 pajs 1.4 static int sizeof_diskio_stats=0;
302     diskio_stat_t *diskio_stats_ptr;
303    
304 pajs 1.10 #ifdef SOLARIS
305 pajs 1.4 kstat_ctl_t *kc;
306     kstat_t *ksp;
307     kstat_io_t kios;
308 pajs 1.10 #endif
309     #ifdef LINUX
310     FILE *f;
311     char *line_ptr;
312     int major, minor;
313     char dev_letter;
314     #endif
315 pajs 1.17 #ifdef FREEBSD
316     struct statinfo stats;
317     int counter;
318     struct device_selection *dev_sel = NULL;
319     int n_selected, n_selections;
320     long sel_gen;
321     struct devstat *dev_ptr;
322     #endif
323 pajs 1.10 num_diskio=0;
324 pajs 1.4
325 pajs 1.17 #ifdef FREEBSD
326     stats.dinfo=malloc(sizeof(struct devinfo));
327     if(stats.dinfo==NULL) return NULL;
328     if ((getdevs(&stats)) < 0) return NULL;
329     /* Not aware of a get all devices, so i said 999. If we ever
330     * find a machine with more than 999 disks, then i'll change
331     * this number :)
332     */
333     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;
334    
335     for(counter=0;counter<stats.dinfo->numdevs;counter++){
336     dev_ptr=&stats.dinfo->devices[dev_sel[counter].position];
337    
338     /* Throw away devices that have done nothing, ever.. Eg "odd"
339     * devices.. like mem, proc.. and also doesn't report floppy
340     * drives etc unless they are doing stuff :)
341     */
342     if((dev_ptr->bytes_read==0) && (dev_ptr->bytes_written==0)) continue;
343     if((diskio_stats=diskio_stat_malloc(num_diskio+1, &sizeof_diskio_stats, diskio_stats))==NULL){
344     return NULL;
345     }
346     diskio_stats_ptr=diskio_stats+num_diskio;
347    
348     diskio_stats_ptr->read_bytes=dev_ptr->bytes_read;
349     diskio_stats_ptr->write_bytes=dev_ptr->bytes_written;
350     if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
351     asprintf((&diskio_stats_ptr->disk_name), "%s%d", dev_ptr->device_name, dev_ptr->unit_number);
352     diskio_stats_ptr->systime=time(NULL);
353    
354     num_diskio++;
355     }
356     free(dev_sel);
357     free(stats.dinfo);
358    
359     #endif
360 pajs 1.10 #ifdef SOLARIS
361 pajs 1.4 if ((kc = kstat_open()) == NULL) {
362     return NULL;
363     }
364    
365     for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
366     if (!strcmp(ksp->ks_class, "disk")) {
367    
368     if(ksp->ks_type != KSTAT_TYPE_IO) continue;
369 pajs 1.5 /* We dont want metadevices appearins as num_diskio */
370 pajs 1.4 if(strcmp(ksp->ks_module, "md")==0) continue;
371     if((kstat_read(kc, ksp, &kios))==-1){
372     }
373    
374 pajs 1.5 if((diskio_stats=diskio_stat_malloc(num_diskio+1, &sizeof_diskio_stats, diskio_stats))==NULL){
375 pajs 1.4 kstat_close(kc);
376     return NULL;
377     }
378 pajs 1.5 diskio_stats_ptr=diskio_stats+num_diskio;
379 pajs 1.4
380     diskio_stats_ptr->read_bytes=kios.nread;
381    
382     diskio_stats_ptr->write_bytes=kios.nwritten;
383    
384     if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
385    
386     diskio_stats_ptr->disk_name=strdup(ksp->ks_name);
387 pajs 1.14 diskio_stats_ptr->systime=time(NULL);
388 pajs 1.5 num_diskio++;
389 pajs 1.4 }
390     }
391    
392     kstat_close(kc);
393 pajs 1.10 #endif
394 pajs 1.4
395 pajs 1.10 #ifdef LINUX
396     f=fopen("/proc/stat", "r");
397     if(f==NULL){
398 pajs 1.11 *entries=0;
399     fclose(f);
400 pajs 1.10 return NULL;
401     }
402     if((line_ptr=f_read_line(f, "disk_io:"))==NULL){
403 pajs 1.11 *entries=0;
404     fclose(f);
405 pajs 1.10 return NULL;
406     }
407     while((line_ptr=strchr(line_ptr, ' '))!=NULL){
408 pajs 1.11 line_ptr++;
409     if(*line_ptr=='\0'){
410     break;
411     }
412 pajs 1.10 if((diskio_stats=diskio_stat_malloc(num_diskio+1, &sizeof_diskio_stats, diskio_stats))==NULL){
413     fclose(f);
414 pajs 1.11 *entries=0;
415 pajs 1.10 return NULL;
416     }
417     diskio_stats_ptr=diskio_stats+num_diskio;
418    
419    
420 pajs 1.12 if((sscanf(line_ptr, "(%d,%d):(%*d, %*d, %lld, %*d, %lld)", \
421 pajs 1.10 &major, \
422     &minor, \
423     &diskio_stats_ptr->read_bytes, \
424 pajs 1.11 &diskio_stats_ptr->write_bytes))!=4) {
425     continue;
426     }
427 pajs 1.12
428     /* We read the number of blocks. Blocks are stored in 512 bytes */
429     diskio_stats_ptr->read_bytes=diskio_stats_ptr->read_bytes*512;
430     diskio_stats_ptr->write_bytes=diskio_stats_ptr->write_bytes*512;
431 pajs 1.10
432     if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
433    
434     switch(major){
435 pajs 1.11 case 2:
436     if(minor==0){
437     diskio_stats_ptr->disk_name=strdup("fd0");
438     }
439     break;
440    
441 pajs 1.10 case 3:
442     if(minor==0){
443     diskio_stats_ptr->disk_name=strdup("hda");
444     }else{
445     diskio_stats_ptr->disk_name=strdup("hdb");
446     }
447     break;
448    
449     case 22:
450     if(minor==0){
451     diskio_stats_ptr->disk_name=strdup("hdc");
452     }else{
453     diskio_stats_ptr->disk_name=strdup("hdd");
454     }
455 pajs 1.11 break;
456 pajs 1.10 case 8:
457     dev_letter='a'+(minor/16);
458     diskio_stats_ptr->disk_name=malloc(4);
459     snprintf(diskio_stats_ptr->disk_name, 4, "sd%c", dev_letter);
460 pajs 1.11 break;
461 pajs 1.10 default:
462     /* I have no idea what it is then :) */
463     diskio_stats_ptr->disk_name=malloc(16);
464     snprintf(diskio_stats_ptr->disk_name, 16, "%d %d", major, minor);
465 pajs 1.11 break;
466 pajs 1.10 }
467    
468 pajs 1.14 diskio_stats_ptr->systime=time(NULL);
469 pajs 1.10 num_diskio++;
470     }
471 pajs 1.16
472 pajs 1.15 fclose(f);
473 pajs 1.10
474     #endif
475 pajs 1.5 *entries=num_diskio;
476 pajs 1.4
477     return diskio_stats;
478 pajs 1.5 }
479    
480 pajs 1.6 diskio_stat_t *get_diskio_stats_diff(int *entries){
481 pajs 1.5 static diskio_stat_t *diskio_stats_diff=NULL;
482     static int sizeof_diskio_stats_diff=0;
483     diskio_stat_t *diskio_stats_diff_ptr, *diskio_stats_ptr;
484     int disks, x, y;
485    
486     if(diskio_stats==NULL){
487     diskio_stats_ptr=get_diskio_stats(&disks);
488     *entries=disks;
489     return diskio_stats_ptr;
490     }
491    
492     diskio_stats_diff=diskio_stat_malloc(num_diskio, &sizeof_diskio_stats_diff, diskio_stats_diff);
493     if(diskio_stats_diff==NULL){
494     return NULL;
495     }
496    
497     diskio_stats_diff_ptr=diskio_stats_diff;
498     diskio_stats_ptr=diskio_stats;
499    
500     for(disks=0;disks<num_diskio;disks++){
501     if(diskio_stats_diff_ptr->disk_name!=NULL){
502     free(diskio_stats_diff_ptr->disk_name);
503     }
504     diskio_stats_diff_ptr->disk_name=strdup(diskio_stats_ptr->disk_name);
505     diskio_stats_diff_ptr->read_bytes=diskio_stats_ptr->read_bytes;
506     diskio_stats_diff_ptr->write_bytes=diskio_stats_ptr->write_bytes;
507     diskio_stats_diff_ptr->systime=diskio_stats_ptr->systime;
508    
509     diskio_stats_diff_ptr++;
510     diskio_stats_ptr++;
511     }
512    
513     diskio_stats_ptr=get_diskio_stats(&disks);
514     diskio_stats_diff_ptr=diskio_stats_diff;
515    
516     for(x=0;x<sizeof_diskio_stats_diff;x++){
517    
518     if((strcmp(diskio_stats_diff_ptr->disk_name, diskio_stats_ptr->disk_name))==0){
519     diskio_stats_diff_ptr->read_bytes=diskio_stats_ptr->read_bytes-diskio_stats_diff_ptr->read_bytes;
520     diskio_stats_diff_ptr->write_bytes=diskio_stats_ptr->write_bytes-diskio_stats_diff_ptr->write_bytes;
521     diskio_stats_diff_ptr->systime=diskio_stats_ptr->systime-diskio_stats_diff_ptr->systime;
522     }else{
523     diskio_stats_ptr=diskio_stats;
524     for(y=0;y<disks;y++){
525     if((strcmp(diskio_stats_diff_ptr->disk_name, diskio_stats_ptr->disk_name))==0){
526     diskio_stats_diff_ptr->read_bytes=diskio_stats_ptr->read_bytes-diskio_stats_diff_ptr->read_bytes;
527     diskio_stats_diff_ptr->write_bytes=diskio_stats_ptr->write_bytes-diskio_stats_diff_ptr->write_bytes;
528     diskio_stats_diff_ptr->systime=diskio_stats_ptr->systime-diskio_stats_diff_ptr->systime;
529    
530     break;
531     }
532    
533     diskio_stats_ptr++;
534     }
535     }
536    
537     diskio_stats_ptr++;
538     diskio_stats_diff_ptr++;
539    
540     }
541 pajs 1.8
542     *entries=sizeof_diskio_stats_diff;
543 pajs 1.5 return diskio_stats_diff;
544 pajs 1.2 }