5 #include <net-snmp/net-snmp-config.h>
19 #if HAVE_MACHINE_PARAM_H
20 #include <machine/param.h>
22 #if HAVE_SYS_VMMETER_H
23 #if !(defined(bsdi2) || defined(netbsd1))
24 #include <sys/vmmeter.h>
28 #include <sys/param.h>
45 #ifdef HAVE_SYS_STAT_H
48 #ifdef HAVE_SYS_VNODE_H
49 #include <sys/vnode.h>
51 #ifdef HAVE_UFS_UFS_QUOTA_H
52 #include <ufs/ufs/quota.h>
54 #ifdef HAVE_UFS_UFS_INODE_H
55 #include <ufs/ufs/inode.h>
58 #include <ufs/ffs/fs.h>
68 #include <sys/statfs.h>
70 #if HAVE_SYS_STATVFS_H
71 #include <sys/statvfs.h>
76 #if (!defined(HAVE_STATVFS)) && defined(HAVE_STATFS)
78 #include <sys/mount.h>
81 #include <sys/sysctl.h>
83 #define statvfs statfs
88 #if HAVE_VM_SWAP_PAGER_H
89 #include <vm/swap_pager.h>
91 #if HAVE_SYS_FIXPOINT_H
92 #include <sys/fixpoint.h>
106 #if HAVE_SYS_MNTTAB_H
107 #include <sys/mnttab.h>
109 #if HAVE_NETINET_IN_H
110 #include <netinet/in.h>
112 #if TIME_WITH_SYS_TIME
114 # include <sys/timeb.h>
116 # include <sys/time.h>
121 # include <sys/time.h>
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>
140 #include "util_funcs.h"
141 #if USING_UCD_SNMP_ERRORMIB_MODULE
142 #include "errormib.h"
144 #define setPerrorstatus(x) snmp_log_perror(x)
148 struct diskpart disks[MAXDISKS];
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,
155 {DISKMINIMUM, ASN_INTEGER, RONLY, var_extensible_disk, 1,
157 {DISKMINPERCENT, ASN_INTEGER, RONLY, var_extensible_disk, 1,
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,
164 {DISKPERCENTNODE, ASN_INTEGER, RONLY, var_extensible_disk, 1,
166 {ERRORFLAG, ASN_INTEGER, RONLY, var_extensible_disk, 1, {ERRORFLAG}},
167 {ERRORMSG, ASN_OCTET_STR, RONLY, var_extensible_disk, 1, {ERRORMSG}}
171 * Define the OID pointer to the top of the mib tree that we're
172 * registering underneath
174 oid disk_variables_oid[] = { UCDAVIS_MIB, DISKMIBNUM, 1 };
180 * register ourselves with the agent to handle our mib tree
182 REGISTER_MIB("ucd-snmp/disk", extensible_disk_variables, variable2,
185 snmpd_register_config_handler("disk", disk_parse_config,
187 "path [ minspace | minpercent% ]");
191 disk_free_config(void)
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;
205 disk_parse_config(const char *token, char *cptr)
208 #if HAVE_SYS_MNTTAB_H
209 struct mnttab mnttab;
211 struct mntent *mntent;
221 #endif /* HAVE_STATFS */
222 #endif /* HAVE_FSTAB_H */
223 #endif /* HAVE_GETMNTENT */
225 #if defined(HAVE_GETMNTENT) && !defined(HAVE_SETMNTENT)
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);
237 * read disk path (eg, /1 or /usr)
239 copy_nword(cptr, disks[numdisks].path,
240 sizeof(disks[numdisks].path));
241 cptr = skip_not_white(cptr);
242 cptr = skip_white(cptr);
244 * read optional minimum disk usage spec
247 if (strchr(cptr, '%') == 0) {
248 disks[numdisks].minimumspace = atoi(cptr);
249 disks[numdisks].minpercent = -1;
251 disks[numdisks].minimumspace = -1;
252 disks[numdisks].minpercent = atoi(cptr);
255 disks[numdisks].minimumspace = DEFDISKMINIMUMSPACE;
256 disks[numdisks].minpercent = -1;
259 * find the device associated with the directory
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));
273 DEBUGMSGTL(("ucd-snmp/disk", " %s != %s\n",
274 disks[numdisks].path, mntent->mnt_dir));
278 if (disks[numdisks].device[0] != 0) {
280 * dummy clause for else below
282 numdisks += 1; /* but inc numdisks here after test */
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)
290 DEBUGMSGTL(("ucd-snmp/disk", " %s != %s\n",
291 disks[numdisks].path, mnttab.mnt_mountp));
295 copy_nword(mnttab.mnt_special, disks[numdisks].device,
296 sizeof(disks[numdisks].device));
299 #endif /* HAVE_SETMNTENT */
302 stat(disks[numdisks].path, &stat1);
304 if ((fstab = getfsfile(disks[numdisks].path))) {
305 copy_nword(fstab->fs_spec, disks[numdisks].device,
306 sizeof(disks[numdisks].device));
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));
316 DEBUGMSGT(("ucd-snmp/disk", " %s != %s\n",
317 disks[numdisks].path, statf.f_mntfromname));
319 if (disks[numdisks].device[0] != 0) {
321 * dummy clause for else below
323 numdisks += 1; /* but inc numdisks here after test */
325 #endif /* HAVE_STATFS */
326 #endif /* HAVE_FSTAB_H */
327 #endif /* HAVE_GETMNTENT */
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;
343 config_perror("'disk' checks not supported on this architecture.");
344 #endif /* HAVE_FSTAB_H || HAVE_GETMNTENT || HAVE_STATFS */
348 * var_extensible_disk(...
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
360 var_extensible_disk(struct variable *vp,
364 size_t * var_len, WriteMethod ** write_method)
367 int percent, iserror, disknum = 0;
368 #if !defined(HAVE_SYS_STATVFS_H) && !defined(HAVE_STATFS)
369 double totalblks, free, used, avail, availblks;
372 #if defined(STRUCT_STATVFS_HAS_F_FILES) || defined(STRUCT_STATFS_HAS_F_FILES)
376 static long long_ret;
377 static char errmsg[300];
379 #if defined(HAVE_STATVFS) || defined(HAVE_STATFS)
380 #ifdef STAT_STATFS_FS_DATA
383 u_int f_blocks, f_bfree, f_bavail, f_bsize;
395 #define filesys sb.iu_fs
399 if (header_simple_table
400 (vp, name, length, exact, var_len, write_method, numdisks))
402 disknum = name[*length - 1] - 1;
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);
411 *var_len = strlen(disks[disknum].device);
412 return ((u_char *) disks[disknum].device);
414 long_ret = disks[disknum].minimumspace;
415 return ((u_char *) (&long_ret));
417 long_ret = disks[disknum].minpercent;
418 return ((u_char *) (&long_ret));
420 #if defined(HAVE_STATVFS) || defined(HAVE_STATFS)
421 #ifdef STAT_STATFS_FS_DATA
422 if (statvfs(disks[disknum].path, &fsd) == -1) {
424 if (statvfs(disks[disknum].path, &vfs) == -1) {
426 snmp_log(LOG_ERR, "Couldn't open device %s\n",
427 disks[disknum].device);
428 setPerrorstatus("statvfs dev/disk");
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. */
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];
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);
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);
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);
465 #endif /* defined(STRUCT_STATVFS_HAS_F_FILES) */
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);
473 return ((u_char *) (&long_ret));
475 return ((u_char *) (&avail));
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)
481 (vfs.f_blocks - vfs.f_bfree) * (vfs.f_frsize / 1024);
483 return ((u_char *) (&long_ret));
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));
494 return ((u_char *) (&long_ret));
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,
503 snprintf(errmsg, sizeof(errmsg),
504 "%s: less than %d%% free (= %d%%)",
505 disks[disknum].path, disks[disknum].minpercent,
507 errmsg[ sizeof(errmsg)-1 ] = 0;
510 *var_len = strlen(errmsg);
511 return ((u_char *) (errmsg));
516 * read the disk information
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");
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);
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;
541 0 ? 100 : (int) ((double) used / (double) totalblks * 100.0 + 0.5);
543 (disks[disknum].minimumspace >=
544 0 ? avail * filesys.fs_fsize / 1024 <
545 disks[disknum].minimumspace : 100 - percent <=
546 disks[disknum].minpercent) ? 1 : 0;
549 long_ret = (totalblks * filesys.fs_fsize / 1024);
550 return ((u_char *) (&long_ret));
552 long_ret = avail * filesys.fs_fsize / 1024;
553 return ((u_char *) (&long_ret));
555 long_ret = used * filesys.fs_fsize / 1024;
556 return ((u_char *) (&long_ret));
559 return ((u_char *) (&long_ret));
562 return ((u_char *) (&long_ret));
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);
571 snprintf(errmsg, sizeof(errmsg),
572 "%s: less than %d%% free (= %d%%)",
573 disks[disknum].path, disks[disknum].minpercent,
575 errmsg[ sizeof(errmsg)-1 ] = 0;
578 *var_len = strlen(errmsg);
579 return ((u_char *) (errmsg));