and added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / ucd-snmp / disk.c
1 /*
2  * disk.c
3  */
4
5 #include <net-snmp/net-snmp-config.h>
6
7 #include <stdio.h>
8
9 #if HAVE_STDLIB_H
10 #include <stdlib.h>
11 #endif
12 #if HAVE_UNISTD_H
13 #include <unistd.h>
14 #endif
15 #if HAVE_FCNTL_H
16 #include <fcntl.h>
17 #endif
18 #include <signal.h>
19 #if HAVE_MACHINE_PARAM_H
20 #include <machine/param.h>
21 #endif
22 #if HAVE_SYS_VMMETER_H
23 #if !(defined(bsdi2) || defined(netbsd1))
24 #include <sys/vmmeter.h>
25 #endif
26 #endif
27 #if HAVE_SYS_PARAM_H
28 #include <sys/param.h>
29 #endif
30 #if HAVE_SYS_CONF_H
31 #include <sys/conf.h>
32 #endif
33 #if HAVE_ASM_PAGE_H
34 #include <asm/page.h>
35 #endif
36 #if HAVE_SYS_SWAP_H
37 #include <sys/swap.h>
38 #endif
39 #if HAVE_SYS_FS_H
40 #include <sys/fs.h>
41 #else
42 #if HAVE_UFS_FS_H
43 #include <ufs/fs.h>
44 #else
45 #ifdef HAVE_SYS_STAT_H
46 #include <sys/stat.h>
47 #endif
48 #ifdef HAVE_SYS_VNODE_H
49 #include <sys/vnode.h>
50 #endif
51 #ifdef HAVE_UFS_UFS_QUOTA_H
52 #include <ufs/ufs/quota.h>
53 #endif
54 #ifdef HAVE_UFS_UFS_INODE_H
55 #include <ufs/ufs/inode.h>
56 #endif
57 #if HAVE_UFS_FFS_FS_H
58 #include <ufs/ffs/fs.h>
59 #endif
60 #endif
61 #endif
62 #if HAVE_MTAB_H
63 #include <mtab.h>
64 #endif
65 #include <sys/stat.h>
66 #include <errno.h>
67 #if HAVE_SYS_STATFS_H
68 #include <sys/statfs.h>
69 #endif
70 #if HAVE_SYS_STATVFS_H
71 #include <sys/statvfs.h>
72 #endif
73 #if HAVE_SYS_VFS_H
74 #include <sys/vfs.h>
75 #endif
76 #if (!defined(HAVE_STATVFS)) && defined(HAVE_STATFS)
77 #if HAVE_SYS_MOUNT_H
78 #include <sys/mount.h>
79 #endif
80 #if HAVE_SYS_SYSCTL_H
81 #include <sys/sysctl.h>
82 #endif
83 #define statvfs statfs
84 #endif
85 #if HAVE_VM_VM_H
86 #include <vm/vm.h>
87 #endif
88 #if HAVE_VM_SWAP_PAGER_H
89 #include <vm/swap_pager.h>
90 #endif
91 #if HAVE_SYS_FIXPOINT_H
92 #include <sys/fixpoint.h>
93 #endif
94 #if HAVE_MALLOC_H
95 #include <malloc.h>
96 #endif
97 #if HAVE_STRING_H
98 #include <string.h>
99 #endif
100 #if HAVE_FSTAB_H
101 #include <fstab.h>
102 #endif
103 #if HAVE_MNTENT_H
104 #include <mntent.h>
105 #endif
106 #if HAVE_SYS_MNTTAB_H
107 #include <sys/mnttab.h>
108 #endif
109 #if HAVE_NETINET_IN_H
110 #include <netinet/in.h>
111 #endif
112 #if TIME_WITH_SYS_TIME
113 # ifdef WIN32
114 #  include <sys/timeb.h>
115 # else
116 #  include <sys/time.h>
117 # endif
118 # include <time.h>
119 #else
120 # if HAVE_SYS_TIME_H
121 #  include <sys/time.h>
122 # else
123 #  include <time.h>
124 # endif
125 #endif
126 #if HAVE_WINSOCK_H
127 #include <winsock.h>
128 #endif
129
130 #if HAVE_DMALLOC_H
131 #include <dmalloc.h>
132 #endif
133
134 #include <net-snmp/net-snmp-includes.h>
135 #include <net-snmp/agent/net-snmp-agent-includes.h>
136 #include <net-snmp/agent/auto_nlist.h>
137
138 #include "struct.h"
139 #include "disk.h"
140 #include "util_funcs.h"
141 #if USING_UCD_SNMP_ERRORMIB_MODULE
142 #include "errormib.h"
143 #else
144 #define setPerrorstatus(x) snmp_log_perror(x)
145 #endif
146
147 int             numdisks;
148 struct diskpart disks[MAXDISKS];
149
150 struct variable2 extensible_disk_variables[] = {
151     {MIBINDEX, ASN_INTEGER, RONLY, var_extensible_disk, 1, {MIBINDEX}},
152     {ERRORNAME, ASN_OCTET_STR, RONLY, var_extensible_disk, 1, {ERRORNAME}},
153     {DISKDEVICE, ASN_OCTET_STR, RONLY, var_extensible_disk, 1,
154      {DISKDEVICE}},
155     {DISKMINIMUM, ASN_INTEGER, RONLY, var_extensible_disk, 1,
156      {DISKMINIMUM}},
157     {DISKMINPERCENT, ASN_INTEGER, RONLY, var_extensible_disk, 1,
158      {DISKMINPERCENT}},
159     {DISKTOTAL, ASN_INTEGER, RONLY, var_extensible_disk, 1, {DISKTOTAL}},
160     {DISKAVAIL, ASN_INTEGER, RONLY, var_extensible_disk, 1, {DISKAVAIL}},
161     {DISKUSED, ASN_INTEGER, RONLY, var_extensible_disk, 1, {DISKUSED}},
162     {DISKPERCENT, ASN_INTEGER, RONLY, var_extensible_disk, 1,
163      {DISKPERCENT}},
164     {DISKPERCENTNODE, ASN_INTEGER, RONLY, var_extensible_disk, 1,
165      {DISKPERCENTNODE}},
166     {ERRORFLAG, ASN_INTEGER, RONLY, var_extensible_disk, 1, {ERRORFLAG}},
167     {ERRORMSG, ASN_OCTET_STR, RONLY, var_extensible_disk, 1, {ERRORMSG}}
168 };
169
170 /*
171  * Define the OID pointer to the top of the mib tree that we're
172  * registering underneath 
173  */
174 oid             disk_variables_oid[] = { UCDAVIS_MIB, DISKMIBNUM, 1 };
175
176 void
177 init_disk(void)
178 {
179     /*
180      * register ourselves with the agent to handle our mib tree 
181      */
182     REGISTER_MIB("ucd-snmp/disk", extensible_disk_variables, variable2,
183                  disk_variables_oid);
184
185     snmpd_register_config_handler("disk", disk_parse_config,
186                                   disk_free_config,
187                                   "path [ minspace | minpercent% ]");
188 }
189
190 void
191 disk_free_config(void)
192 {
193     int             i;
194
195     numdisks = 0;
196     for (i = 0; i < MAXDISKS; i++) {    /* init/erase disk db */
197         disks[i].device[0] = 0;
198         disks[i].path[0] = 0;
199         disks[i].minimumspace = -1;
200         disks[i].minpercent = -1;
201     }
202 }
203
204 void
205 disk_parse_config(const char *token, char *cptr)
206 {
207 #if HAVE_GETMNTENT
208 #if HAVE_SYS_MNTTAB_H
209     struct mnttab   mnttab;
210 #else
211     struct mntent  *mntent;
212 #endif
213     FILE           *mntfp;
214 #else
215 #if HAVE_FSTAB_H
216     struct fstab   *fstab;
217     struct stat     stat1;
218 #else
219 #if HAVE_STATFS
220     struct statfs   statf;
221 #endif                          /* HAVE_STATFS */
222 #endif                          /* HAVE_FSTAB_H */
223 #endif                          /* HAVE_GETMNTENT */
224     char            tmpbuf[1024];
225 #if defined(HAVE_GETMNTENT) && !defined(HAVE_SETMNTENT)
226     int             i;
227 #endif
228
229 #if HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS
230     if (numdisks == MAXDISKS) {
231         config_perror("Too many disks specified.");
232         snprintf(tmpbuf, sizeof(tmpbuf), "\tignoring:  %s", cptr);
233         tmpbuf[ sizeof(tmpbuf)-1 ] = 0;
234         config_perror(tmpbuf);
235     } else {
236         /*
237          * read disk path (eg, /1 or /usr) 
238          */
239         copy_nword(cptr, disks[numdisks].path,
240                    sizeof(disks[numdisks].path));
241         cptr = skip_not_white(cptr);
242         cptr = skip_white(cptr);
243         /*
244          * read optional minimum disk usage spec 
245          */
246         if (cptr != NULL) {
247             if (strchr(cptr, '%') == 0) {
248                 disks[numdisks].minimumspace = atoi(cptr);
249                 disks[numdisks].minpercent = -1;
250             } else {
251                 disks[numdisks].minimumspace = -1;
252                 disks[numdisks].minpercent = atoi(cptr);
253             }
254         } else {
255             disks[numdisks].minimumspace = DEFDISKMINIMUMSPACE;
256             disks[numdisks].minpercent = -1;
257         }
258         /*
259          * find the device associated with the directory 
260          */
261 #if HAVE_GETMNTENT
262 #if HAVE_SETMNTENT
263         mntfp = setmntent(ETC_MNTTAB, "r");
264         disks[numdisks].device[0] = 0;
265         while (NULL != (mntent = getmntent(mntfp)))
266             if (strcmp(disks[numdisks].path, mntent->mnt_dir) == 0) {
267                 copy_nword(mntent->mnt_fsname, disks[numdisks].device,
268                            sizeof(disks[numdisks].device));
269                 DEBUGMSGTL(("ucd-snmp/disk", "Disk:  %s\n",
270                             mntent->mnt_fsname));
271                 break;
272             } else {
273                 DEBUGMSGTL(("ucd-snmp/disk", "  %s != %s\n",
274                             disks[numdisks].path, mntent->mnt_dir));
275             }
276         if (mntfp)
277             endmntent(mntfp);
278         if (disks[numdisks].device[0] != 0) {
279             /*
280              * dummy clause for else below 
281              */
282             numdisks += 1;      /* but inc numdisks here after test */
283         }
284 #else                           /* getmentent but not setmntent */
285         mntfp = fopen(ETC_MNTTAB, "r");
286         while ((i = getmntent(mntfp, &mnttab)) == 0)
287             if (strcmp(disks[numdisks].path, mnttab.mnt_mountp) == 0)
288                 break;
289             else {
290                 DEBUGMSGTL(("ucd-snmp/disk", "  %s != %s\n",
291                             disks[numdisks].path, mnttab.mnt_mountp));
292             }
293         fclose(mntfp);
294         if (i == 0) {
295             copy_nword(mnttab.mnt_special, disks[numdisks].device,
296                        sizeof(disks[numdisks].device));
297             numdisks += 1;
298         }
299 #endif                          /* HAVE_SETMNTENT */
300 #else
301 #if HAVE_FSTAB_H
302         stat(disks[numdisks].path, &stat1);
303         setfsent();
304         if ((fstab = getfsfile(disks[numdisks].path))) {
305             copy_nword(fstab->fs_spec, disks[numdisks].device,
306                        sizeof(disks[numdisks].device));
307             numdisks += 1;
308         }
309 #else
310 #if HAVE_STATFS
311         if (statfs(disks[numdisks].path, &statf) == 0) {
312             copy_word(statf.f_mntfromname, disks[numdisks].device);
313             DEBUGMSGTL(("ucd-snmp/disk", "Disk:  %s\n",
314                         statf.f_mntfromname));
315         } else {
316             DEBUGMSGT(("ucd-snmp/disk", "  %s != %s\n",
317                        disks[numdisks].path, statf.f_mntfromname));
318         }
319         if (disks[numdisks].device[0] != 0) {
320             /*
321              * dummy clause for else below 
322              */
323             numdisks += 1;      /* but inc numdisks here after test */
324         }
325 #endif  /* HAVE_STATFS */
326 #endif                          /* HAVE_FSTAB_H */
327 #endif                          /* HAVE_GETMNTENT */
328         else {
329             snprintf(tmpbuf, sizeof(tmpbuf),
330                     "Couldn't find device for disk %s",
331                     disks[numdisks].path);
332             tmpbuf[ sizeof(tmpbuf)-1 ] = 0;
333             config_pwarn(tmpbuf);
334             disks[numdisks].minimumspace = -1;
335             disks[numdisks].minpercent = -1;
336             disks[numdisks].path[0] = 0;
337         }
338 #if HAVE_FSTAB_H
339         endfsent();
340 #endif
341     }
342 #else
343     config_perror("'disk' checks not supported on this architecture.");
344 #endif                          /* HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS */
345 }
346
347 /*
348  * var_extensible_disk(...
349  * Arguments:
350  * vp     IN      - pointer to variable entry that points here
351  * name    IN/OUT  - IN/name requested, OUT/name found
352  * length  IN/OUT  - length of IN/OUT oid's 
353  * exact   IN      - TRUE if an exact match was requested
354  * var_len OUT     - length of variable or 0 if function returned
355  * write_method
356  * 
357  */
358
359 u_char         *
360 var_extensible_disk(struct variable *vp,
361                     oid * name,
362                     size_t * length,
363                     int exact,
364                     size_t * var_len, WriteMethod ** write_method)
365 {
366
367     int             percent, iserror, disknum = 0;
368 #if !defined(HAVE_SYS_STATVFS_H) && !defined(HAVE_STATFS)
369     double          totalblks, free, used, avail, availblks;
370 #else
371     static long     avail;
372 #if defined(STRUCT_STATVFS_HAS_F_FILES) || defined(STRUCT_STATFS_HAS_F_FILES)
373     int             percent_inode;
374 #endif
375 #endif
376     static long     long_ret;
377     static char     errmsg[300];
378
379 #if defined(HAVE_STATVFS) || defined(HAVE_STATFS)
380 #ifdef STAT_STATFS_FS_DATA
381     struct fs_data  fsd;
382     struct {
383         u_int           f_blocks, f_bfree, f_bavail, f_bsize;
384     } vfs;
385 #else
386     struct statvfs  vfs;
387 #endif
388 #else
389 #if HAVE_FSTAB_H
390     int             file;
391     union {
392         struct fs       iu_fs;
393         char            dummy[SBSIZE];
394     } sb;
395 #define filesys sb.iu_fs
396 #endif
397 #endif
398
399     if (header_simple_table
400         (vp, name, length, exact, var_len, write_method, numdisks))
401         return (NULL);
402     disknum = name[*length - 1] - 1;
403     switch (vp->magic) {
404     case MIBINDEX:
405         long_ret = disknum + 1;
406         return ((u_char *) (&long_ret));
407     case ERRORNAME:            /* DISKPATH */
408         *var_len = strlen(disks[disknum].path);
409         return ((u_char *) disks[disknum].path);
410     case DISKDEVICE:
411         *var_len = strlen(disks[disknum].device);
412         return ((u_char *) disks[disknum].device);
413     case DISKMINIMUM:
414         long_ret = disks[disknum].minimumspace;
415         return ((u_char *) (&long_ret));
416     case DISKMINPERCENT:
417         long_ret = disks[disknum].minpercent;
418         return ((u_char *) (&long_ret));
419     }
420 #if defined(HAVE_STATVFS) || defined(HAVE_STATFS)
421 #ifdef STAT_STATFS_FS_DATA
422     if (statvfs(disks[disknum].path, &fsd) == -1) {
423 #else
424     if (statvfs(disks[disknum].path, &vfs) == -1) {
425 #endif
426         snmp_log(LOG_ERR, "Couldn't open device %s\n",
427                  disks[disknum].device);
428         setPerrorstatus("statvfs dev/disk");
429         return NULL;
430     }
431 #ifdef STAT_STATFS_FS_DATA
432     vfs.f_blocks = fsd.fd_btot;
433     vfs.f_bfree = fsd.fd_bfree;
434     vfs.f_bavail = fsd.fd_bfreen;
435     vfs.f_bsize = 1024;         /*  Ultrix f_bsize is a VM parameter apparently.  */
436 #endif
437 #if defined(HAVE_ODS)
438     vfs.f_blocks = vfs.f_spare[0];
439     vfs.f_bfree = vfs.f_spare[1];
440     vfs.f_bavail = vfs.f_spare[2];
441 #endif
442     percent = vfs.f_bavail <= 0 ? 100 :
443         (int) ((double) (vfs.f_blocks - vfs.f_bfree) /
444                (double) (vfs.f_blocks -
445                          (vfs.f_bfree - vfs.f_bavail)) * 100.0 + 0.5);
446     avail = vfs.f_bavail * (vfs.f_bsize / 1024);
447 #ifdef STRUCT_STATVFS_HAS_F_FRSIZE
448     if (vfs.f_frsize > 255)
449         avail = vfs.f_bavail * (vfs.f_frsize / 1024);
450 #endif
451     iserror = (disks[disknum].minimumspace >= 0 ?
452                avail < disks[disknum].minimumspace :
453                100 - percent <= disks[disknum].minpercent) ? 1 : 0;
454 #if defined(STRUCT_STATVFS_HAS_F_FILES) || defined STRUCT_STATFS_HAS_F_FAVAIL
455     percent_inode = vfs.f_favail <= 0 ? 100 :
456         (int) ((double) (vfs.f_files - vfs.f_ffree) /
457                (double) (vfs.f_files -
458                          (vfs.f_ffree - vfs.f_favail)) * 100.0 + 0.5);
459 #else
460 #if defined(STRUCT_STATFS_HAS_F_FILES) && defined(STRUCT_STATFS_HAS_F_FFREE)
461    percent_inode = vfs.f_files == 0 ? 100.0 :
462       (int) ((double) (vfs.f_files - vfs.f_ffree) /
463                   (double) (vfs.f_files) * 100.0 + 0.5);
464 #endif 
465 #endif /* defined(STRUCT_STATVFS_HAS_F_FILES) */ 
466     switch (vp->magic) {
467     case DISKTOTAL:
468         long_ret = vfs.f_blocks * (vfs.f_bsize / 1024);
469 #ifdef STRUCT_STATVFS_HAS_F_FRSIZE
470         if (vfs.f_frsize > 255)
471             long_ret = vfs.f_blocks * (vfs.f_frsize / 1024);
472 #endif
473         return ((u_char *) (&long_ret));
474     case DISKAVAIL:
475         return ((u_char *) (&avail));
476     case DISKUSED:
477         long_ret = (vfs.f_blocks - vfs.f_bfree) * (vfs.f_bsize / 1024);
478 #ifdef STRUCT_STATVFS_HAS_F_FRSIZE
479         if (vfs.f_frsize > 255)
480             long_ret =
481                 (vfs.f_blocks - vfs.f_bfree) * (vfs.f_frsize / 1024);
482 #endif
483         return ((u_char *) (&long_ret));
484     case DISKPERCENT:
485         long_ret = percent;
486         return ((u_char *) (&long_ret));
487 #if defined(STRUCT_STATVFS_HAS_F_FILES) || defined (STRUCT_STATFS_HAS_F_FILES)
488     case DISKPERCENTNODE:
489         long_ret = percent_inode;
490         return ((u_char *) (&long_ret));
491 #endif
492     case ERRORFLAG:
493         long_ret = iserror;
494         return ((u_char *) (&long_ret));
495     case ERRORMSG:
496         if (iserror) {
497             if (disks[disknum].minimumspace >= 0)
498                 snprintf(errmsg, sizeof(errmsg),
499                         "%s: less than %d free (= %d)",
500                         disks[disknum].path, disks[disknum].minimumspace,
501                         (int) avail);
502             else
503                 snprintf(errmsg, sizeof(errmsg),
504                         "%s: less than %d%% free (= %d%%)",
505                         disks[disknum].path, disks[disknum].minpercent,
506                         percent);
507             errmsg[ sizeof(errmsg)-1 ] = 0;
508         } else
509             errmsg[0] = 0;
510         *var_len = strlen(errmsg);
511         return ((u_char *) (errmsg));
512     }
513 #else
514 #if HAVE_FSTAB_H
515     /*
516      * read the disk information 
517      */
518     if ((file = open(disks[disknum].device, 0)) < 0) {
519         snmp_log(LOG_ERR, "Couldn't open device %s\n",
520                  disks[disknum].device);
521         setPerrorstatus("open dev/disk");
522         return (NULL);
523     }
524     lseek(file, (long) (SBLOCK * DEV_BSIZE), 0);
525     if (read(file, (char *) &filesys, SBSIZE) != SBSIZE) {
526         setPerrorstatus("open dev/disk");
527         snmp_log(LOG_ERR, "Error reading device %s\n",
528                  disks[disknum].device);
529         close(file);
530         return (NULL);
531     }
532     close(file);
533     totalblks = filesys.fs_dsize;
534     free = filesys.fs_cstotal.cs_nbfree * filesys.fs_frag +
535         filesys.fs_cstotal.cs_nffree;
536     used = totalblks - free;
537     availblks = totalblks * (100 - filesys.fs_minfree) / 100;
538     avail = availblks > used ? availblks - used : 0;
539     percent =
540         availblks ==
541         0 ? 100 : (int) ((double) used / (double) totalblks * 100.0 + 0.5);
542     iserror =
543         (disks[disknum].minimumspace >=
544          0 ? avail * filesys.fs_fsize / 1024 <
545          disks[disknum].minimumspace : 100 - percent <=
546          disks[disknum].minpercent) ? 1 : 0;
547     switch (vp->magic) {
548     case DISKTOTAL:
549         long_ret = (totalblks * filesys.fs_fsize / 1024);
550         return ((u_char *) (&long_ret));
551     case DISKAVAIL:
552         long_ret = avail * filesys.fs_fsize / 1024;
553         return ((u_char *) (&long_ret));
554     case DISKUSED:
555         long_ret = used * filesys.fs_fsize / 1024;
556         return ((u_char *) (&long_ret));
557     case DISKPERCENT:
558         long_ret = percent;
559         return ((u_char *) (&long_ret));
560     case ERRORFLAG:
561         long_ret = iserror;
562         return ((u_char *) (&long_ret));
563     case ERRORMSG:
564         if (iserror) {
565             if (disks[disknum].minimumspace >= 0)
566                 snprintf(errmsg, sizeof(errmsg),
567                         "%s: less than %d free (= %d)",
568                         disks[disknum].path, disks[disknum].minimumspace,
569                         avail * filesys.fs_fsize / 1024);
570             else
571                 snprintf(errmsg, sizeof(errmsg),
572                         "%s: less than %d%% free (= %d%%)",
573                         disks[disknum].path, disks[disknum].minpercent,
574                         percent);
575             errmsg[ sizeof(errmsg)-1 ] = 0;
576         } else
577             errmsg[0] = 0;
578         *var_len = strlen(errmsg);
579         return ((u_char *) (errmsg));
580     }
581 #endif
582 #endif
583     return NULL;
584 }