home *** CD-ROM | disk | FTP | other *** search
- /*
- * clndf: perform "df" tracking. Maintains a database of the df
- * output and issues errors if:
- *
- * drastic drop noticed
- * long-term decline noticed
- * low disk noticed
- *
- * Author:
- *
- * Joseph P. Larson
- * Crystal Farms
- * Park Place West, Suite 200
- * 6465 Wayzata Blvd.
- * St. Louis Park, Mn 55426
- *
- * Copyright 1991 by Crystal Farms. Permission is granted to distribute
- * freely provided distribution is free-of-charge beyond relatively
- * minor media charges and this comment remains intact. Also, if
- * you make changes you then distribute, please comment those
- * changes as being yours.
- *
- * Suggested enhancements:
- *
- * o Modify -r to display only disk space or inodes as requested.
- * o Modify -r to display only requested disks.
- * o Modify -r to avoid 132-column mode if it's not needed.
- * o Modify warning thresholds so they aren't hard-coded.
- * o Add option to skip warnings, etc.
- *
- * Revision History
- *
- * 7-23-90 jpl. Created.
- * 2-6-91 jpl. Added "-l" option.
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <time.h>
- #include <usr/skip.h>
- #include <usr/math.h>
-
- #define TM struct tm
-
- #define FN_MAIN "/users/mpls/mis/joel/.df.dnames"
- #define FN_D_OLD "/users/mpls/mis/joel/.df.data.o"
- #define FN_D_NEW "/users/mpls/mis/joel/.df.data.n"
-
- #define MAXDIRS 20
- #define FNSIZE 80
-
- char dnames[MAXDIRS][FNSIZE]; /* Names of disks returned by df */
- long bfree[MAXDIRS], /* Free space on each disk */
- ifree[MAXDIRS]; /* Free inodes on each disk */
- short dirs, /* Number of disks in dnames. */
- ptrs[MAXDIRS]; /* Used to sort dnames. */
-
- char ldnames[MAXDIRS][FNSIZE]; /* Names of disks being tracked */
- short ldirs, /* Number of entries in ldnames */
- dolast; /* If > 0 => # entries to report */
-
- long block_warn = 10000, /* Free space threshold */
- inode_warn = 2000, /* Free inodes threshold */
- bfree10[10][MAXDIRS], /* Free space, last 10 entries */
- ifree10[10][MAXDIRS], /* Free inodes, last 10 entries */
- lastc; /* Number of bfree10 entries filled */
-
- float long_threshold = 0.60, /* Used in "dwindling free space" msg */
- short_threshold = 0.85; /* Used in "chopped free space" msg */
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- char c,
- quitnow,
- do_upd,
- do_rpt;
- extern char *optarg;
-
- quitnow = do_upd = do_rpt = 0;
- load_disks();
- dolast = 0;
- while ((c = getopt(argc, argv, "a:d:l:ruh")) != EOF)
- switch (c)
- {
- case 'a': add_disk(optarg); quitnow = 1; break;
- case 'd': del_disk(optarg); quitnow = 1; break;
- case 'l': dolast = atoi(optarg); break;
- case 'u': do_upd = 1; break;
- case 'r': do_rpt = 1; break;
- case 'h':
- default: usage(argv[0]);
- }
-
- if (quitnow) exit(0);
- gather_df();
- dump_warnings();
- if (do_upd)
- update_data();
- if (do_rpt)
- report_data();
- }
-
-
- load_disks()
- {
- FILE *f1;
- char buf[132];
- short ilen;
-
- ldirs = 0;
- if (!(f1 = fopen(FN_MAIN, "r")))
- xerror(FN_MAIN);
- while (fgets(buf, 132, f1))
- {
- ilen = strlen(buf) - 1;
- if (buf[ilen] == '\n') buf[ilen] = 0;
- strcpy(ldnames[ldirs++], buf);
- }
- fclose(f1);
- }
-
- add_disk(dn)
- char *dn;
- {
- FILE *f1, *f2;
- long ibuf[60], dummy[2];
- short i, where, rsize, wsize1, wsize2, wsize3;
-
- for (where = 0; where < ldirs; where++)
- {
- i = strcmp(ldnames[where], dn);
- if (!i)
- {
- fprintf(stderr, "Disk %s is already in the database.\n");
- return;
- }
- if (i > 0) break;
- }
-
- if (!(f1 = fopen(FN_D_OLD, "r")))
- xerror(FN_D_OLD);
- if (!(f2 = fopen(FN_D_NEW, "w")))
- xerror(FN_D_NEW);
- rsize = (1 + 2 * ldirs);
- wsize1 = (1 + 2 * where);
- wsize2 = 2;
- wsize3 = (2 * (ldirs - where));
-
- while (fread(ibuf, rsize, sizeof(long), f1))
- {
- fwrite(ibuf, wsize1, sizeof(long), f2);
- fwrite(dummy, wsize2, sizeof(long), f2);
- fwrite(&ibuf[2 + where*2], wsize3, sizeof(long), f2);
- }
- fclose(f1);
- fclose(f2);
- if (!(f1 = fopen(FN_MAIN, "w")))
- xerror(FN_MAIN);
- for (i = 0; i < ldirs; i++)
- {
- if (i == where)
- fprintf(f1, "%s\n", dn);
- fprintf(f1, "%s\n", ldnames[i]);
- }
- if (i == where)
- fprintf(f1, "%s\n", dn);
- fclose(f1);
-
- unlink(FN_D_OLD);
- link(FN_D_NEW, FN_D_OLD);
- unlink(FN_D_NEW);
- chmod(FN_D_OLD, 0644);
- }
-
- del_disk(dn)
- char *dn;
- {
- }
-
- gather_df()
- /*
- * Get all the statistics from a call to "df".
- */
- {
- FILE *file;
- char *tname,
- *cptr,
- buf[132];
- long ibuf[60];
- short i, j, p,
- count;
- int cmp_ptrs();
-
- tname = tmpnam(0);
- sprintf(buf, "df >%s", tname);
- system(buf);
-
- dirs = 0;
- if (!(file = fopen(tname, "r")))
- xerror(tname);
- while (fgets(buf, 132, file))
- {
- cptr = buf;
- for (i = 0; cptr[i] && (cptr[i] != ' ') && (cptr[i] != '('); i++)
- dnames[dirs][i] = cptr[i];
- dnames[dirs][i] = 0;
- while (*cptr != ':') cptr++;
- cptr++;
- SKIPWHITE(cptr);
- bfree[dirs] = atoi(cptr);
- SKIPTOWHITE(cptr);
- SKIPWHITE(cptr);
- SKIPTOWHITE(cptr);
- SKIPWHITE(cptr);
- ifree[dirs] = atoi(cptr);
- dirs++;
- }
- fclose(file);
- unlink(tname);
- for (i = 0; i < dirs; i++)
- ptrs[i] = i;
- qsort(ptrs, dirs, sizeof(short), cmp_ptrs);
-
- if (!(file = fopen(FN_D_OLD, "r")))
- xerror(FN_D_OLD);
- count = (1 + ldirs * 2);
- fseek(file, -10 * count * sizeof(long), 2);
- for (lastc = 0; lastc < 10; lastc++)
- {
- if (fread(ibuf, count, sizeof(long), file) <= 0) break;
- for (j = 0, p = 1; j < ldirs; j++)
- {
- bfree10[lastc][j] = ibuf[p++];
- ifree10[lastc][j] = ibuf[p++];
- }
- }
- fclose(file);
- }
-
- cmp_ptrs(p1, p2)
- short *p1, *p2;
- {
- return(strcmp(dnames[*p1], dnames[*p2]));
- }
-
-
- dump_df()
- /*
- * Dump the collected info.
- */
- {
- short i, j;
-
- for (j = 0; j < dirs; j++)
- {
- i = ptrs[j];
- printf("%-24s %8d blocks free %8d inodes free\n",
- dnames[i], bfree[i], ifree[i]);
- }
- }
-
- dump_warnings()
- /*
- * Go through the data. Dump:
- *
- * Any disks that are dangerously low on space.
- * Any disks that suddenly dropped space over the last 3 updates.
- * Any disks that have been dwindling severely over the last 10 updates.
- */
- {
- short i, j, k, l, l3;
- long bfm, ifm, diddump;
- char line[132];
-
- diddump = 0;
- l3 = MAX(0, lastc - 3);
- for (j = 0; j < dirs; j++)
- {
- i = ptrs[j];
- if (bfree[i] < block_warn)
- {
- if (!diddump++) dump_df();
- fprintf(stderr, "Low free space on : %s\n", dnames[i]);
- }
- if (ifree[i] < inode_warn)
- {
- if (!diddump++) dump_df();
- fprintf(stderr, "Low inode count on: %s\n", dnames[i]);
- }
- for (k = 0; k < ldirs; k++)
- if (!strcmp(ldnames[k], dnames[i]))
- {
- if (bfree10[0][k] * long_threshold > bfree[i])
- {
- if (!diddump++) dump_df();
- fprintf(stderr, "Dwindling free space on: %s\n",dnames[i]);
- fprintf(stderr, "Was: %d. Now: %d\n",
- bfree10[0][k], bfree[i]);
- }
- if (ifree10[0][k] * long_threshold > ifree[i])
- {
- if (!diddump++) dump_df();
- fprintf(stderr, "Dwindling inodes on : %s\n",dnames[i]);
- fprintf(stderr, "Was: %d. Now: %d\n",
- ifree10[0][k], ifree[i]);
- }
- bfm = ifm = 0;
- for (l = l3; l < lastc; l++)
- {
- bfm = MAX(bfm, bfree10[l][k]);
- ifm = MAX(ifm, ifree10[l][k]);
- }
- if (bfm * short_threshold > bfree[i])
- {
- if (!diddump++) dump_df();
- fprintf(stderr, "Chopped free space on: %s\n",dnames[i]);
- fprintf(stderr, "Was: %d. Now: %d\n", bfm, bfree[i]);
- }
- if (ifm * short_threshold > ifree[i])
- {
- if (!diddump++) dump_df();
- fprintf(stderr, "Chopped inodes on : %s\n",dnames[i]);
- fprintf(stderr, "Was: %d. Now: %d\n", ifm, ifree[i]);
- }
- break;
- }
- }
- if (diddump)
- {
- printf("\nHit return to continue.\n");
- gets(line);
- }
- }
-
- update_data()
- /*
- * Update the collected info.
- */
- {
- FILE *f1;
- int now;
- long ibuf[50];
- short i, j, p;
-
- if (!(f1 = fopen(FN_D_OLD, "a")))
- xerror(FN_D_OLD);
- time(&now);
- ibuf[0] = now;
- p = 1;
- for (i = 0; i < ldirs; i++)
- {
- for (j = 0; j < dirs; j++)
- if (!strcmp(ldnames[i], dnames[j]))
- {
- ibuf[p++] = bfree[j];
- ibuf[p++] = ifree[j];
- }
- }
- fwrite(ibuf, p, sizeof(long), f1);
- fclose(f1);
- }
-
- report_data()
- /*
- * Generate a tracking report.
- */
- {
- FILE *file;
- TM *tmptr;
- long ibuf[60], bfr, ifr;
- int count, then;
- short i, p, lcnt;
- char line[80];
-
- if (isatty(1))
- printf("%c[?3h\n", 27);
- head_dirs();
-
- if (!(file = fopen(FN_D_OLD, "r")))
- xerror(FN_D_OLD);
- count = (1 + ldirs * 2);
- lcnt = 0;
- if (dolast)
- fseek(file, -(sizeof(long) * count * dolast), 2);
- while (1)
- {
- if (fread(ibuf, count, sizeof(long), file) <= 0) break;
- if (!(++lcnt % 18)) head_dirs();
- then = ibuf[0];
- tmptr = localtime(&then);
- printf("%2d-%2d-%2d",
- tmptr->tm_mon+1, tmptr->tm_mday, tmptr->tm_year);
- for (i = 0, p = 1; i < ldirs; i++)
- {
- bfr = ibuf[p++];
- ifr = ibuf[p++];
- printf("|%6d %5d", bfr, ifr);
- }
- printf("|\n");
- }
- fclose(file);
-
- if (isatty(1))
- {
- printf("\nHit return to continue.\n");
- gets(line);
- printf("%c[?3l\n", 27);
- }
- }
-
- head_dirs()
- {
- short i;
- char *c1, *c2;
-
- printf(" ");
- for (i = 0; i < ldirs; i++)
- {
- for (c1 = c2 = ldnames[i]; *c2; c2++)
- if (*c2 == '/')
- {
- c1 = c2;
- if (*(c1+1)) c1++;
- }
- printf("|%9s ", c1);
- }
- printf("|\n ");
- for (i = 0; i < ldirs; i++)
- printf("|Blocks Inode");
- printf("|\n ");
- for (i = 0; i < ldirs; i++)
- printf("|------ -----");
- printf("|\n");
- }
-
- usage(arg)
- char *arg;
- {
- fprintf(stderr, "\
- Usage: %s [-a disk] [-d disk] [-u] [-r]\n\n\
- Errors imply -r. -u updates the database.\n\
- Use -a or -d to manage the list of disks by mount point.\n", arg);
- exit(-1);
- }
-
- xerror(arg)
- char *arg;
- {
- extern int errno;
-
- perror(arg)
- exit(errno);
- }
-