home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2748 / clndf.c next >
Encoding:
C/C++ Source or Header  |  1991-02-13  |  12.0 KB  |  471 lines

  1. /*
  2.  * clndf: perform "df" tracking.  Maintains a database of the df
  3.  *          output and issues errors if:
  4.  *
  5.  *          drastic drop noticed
  6.  *          long-term decline noticed
  7.  *          low disk noticed
  8.  *
  9.  * Author:
  10.  *
  11.  *      Joseph P. Larson
  12.  *      Crystal Farms
  13.  *      Park Place West, Suite 200
  14.  *      6465 Wayzata Blvd.
  15.  *      St. Louis Park, Mn 55426
  16.  *
  17.  * Copyright 1991 by Crystal Farms.  Permission is granted to distribute
  18.  *      freely provided distribution is free-of-charge beyond relatively
  19.  *      minor media charges and this comment remains intact.  Also, if
  20.  *      you make changes you then distribute, please comment those
  21.  *      changes as being yours.
  22.  *
  23.  * Suggested enhancements:
  24.  *
  25.  *      o Modify -r to display only disk space or inodes as requested.
  26.  *      o Modify -r to display only requested disks.
  27.  *      o Modify -r to avoid 132-column mode if it's not needed.
  28.  *      o Modify warning thresholds so they aren't hard-coded.
  29.  *      o Add option to skip warnings, etc.
  30.  *
  31.  * Revision History
  32.  *
  33.  *      7-23-90     jpl.    Created.
  34.  *      2-6-91      jpl.    Added "-l" option.
  35.  */
  36.  
  37. #include <stdio.h>
  38. #include <ctype.h>
  39. #include <time.h>
  40. #include <usr/skip.h>
  41. #include <usr/math.h>
  42.  
  43. #define TM struct tm
  44.  
  45. #define FN_MAIN     "/users/joel/.df.dnames"
  46. #define FN_D_OLD    "/users/joel/.df.data.o"
  47. #define FN_D_NEW    "/users/joel/.df.data.n"
  48.  
  49. #define MAXDIRS     20
  50. #define FNSIZE      80
  51.  
  52. char    dnames[MAXDIRS][FNSIZE];    /* Names of disks returned by df        */
  53. long    bfree[MAXDIRS],             /* Free space on each disk              */
  54.         ifree[MAXDIRS];             /* Free inodes on each disk             */
  55. short   dirs,                       /* Number of disks in dnames.           */
  56.         ptrs[MAXDIRS];              /* Used to sort dnames.                 */
  57.  
  58. char    ldnames[MAXDIRS][FNSIZE];   /* Names of disks being tracked         */
  59. short   ldirs,                      /* Number of entries in ldnames         */
  60.         dolast;                     /* If > 0  => # entries to report       */
  61.  
  62. long    block_warn = 10000,         /* Free space threshold                 */
  63.         inode_warn =  2000,         /* Free inodes threshold                */
  64.         bfree10[10][MAXDIRS],       /* Free space, last 10 entries          */
  65.         ifree10[10][MAXDIRS],       /* Free inodes, last 10 entries         */
  66.         lastc;                      /* Number of bfree10 entries filled     */
  67.  
  68. float   long_threshold  = 0.60,     /* Used in "dwindling free space" msg   */
  69.         short_threshold = 0.85;     /* Used in "chopped free space" msg     */
  70.  
  71. main(argc,argv)
  72. int argc;
  73. char **argv;
  74. {
  75.     char    c,
  76.             quitnow,
  77.             do_inodes,
  78.             do_upd,
  79.             do_rpt;
  80.     extern char *optarg;
  81.  
  82.     quitnow = do_inodes = do_upd = do_rpt = 0;
  83.     load_disks();
  84.     dolast = 0;
  85.     while ((c = getopt(argc, argv, "a:d:l:iruh")) != EOF)
  86.         switch (c)
  87.         {
  88.             case 'a':   add_disk(optarg); quitnow = 1; break;
  89.             case 'd':   del_disk(optarg); quitnow = 1; break;
  90.             case 'l':   dolast = atoi(optarg); break;
  91.             case 'i':   do_inodes = 1; break;
  92.             case 'u':   do_upd = 1; break;
  93.             case 'r':   do_rpt = 1; break;
  94.             case 'h':
  95.             default:    usage(argv[0]);
  96.         }
  97.     
  98.     if (quitnow) exit(0);
  99.     gather_df();
  100.     dump_warnings();
  101.     if (do_upd)
  102.         update_data();
  103.     if (do_rpt)
  104.         report_data(do_inodes);
  105. }
  106.  
  107.  
  108. load_disks()
  109. {
  110.     FILE    *f1;
  111.     char    buf[132];
  112.     short   ilen;
  113.  
  114.     ldirs = 0;
  115.     if (!(f1 = fopen(FN_MAIN, "r")))
  116.         xerror(FN_MAIN);
  117.     while (fgets(buf, 132, f1))
  118.     {
  119.         ilen = strlen(buf) - 1;
  120.         if (buf[ilen] == '\n') buf[ilen] = 0;
  121.         strcpy(ldnames[ldirs++], buf);
  122.     }
  123.     fclose(f1);
  124. }
  125.  
  126. add_disk(dn)
  127. char *dn;
  128. {
  129.     FILE    *f1, *f2;
  130.     long    ibuf[60], dummy[2];
  131.     short   i, where, rsize, wsize1, wsize2, wsize3;
  132.  
  133.     for (where = 0; where < ldirs; where++)
  134.     {
  135.         i = strcmp(ldnames[where], dn);
  136.         if (!i)
  137.         {
  138.             fprintf(stderr, "Disk %s is already in the database.\n");
  139.             return;
  140.         }
  141.         if (i > 0) break;
  142.     }
  143.  
  144.     if (!(f1 = fopen(FN_D_OLD, "r")))
  145.         xerror(FN_D_OLD);
  146.     if (!(f2 = fopen(FN_D_NEW, "w")))
  147.         xerror(FN_D_NEW);
  148.     rsize = (1 + 2 * ldirs);
  149.     wsize1 = (1 + 2 * where);
  150.     wsize2 = 2;
  151.     wsize3 = rsize - wsize1;
  152.     dummy[0] = dummy[1] = 0;
  153.  
  154.     while (fread(ibuf, rsize, sizeof(long), f1))
  155.     {
  156.         fwrite(ibuf, wsize1, sizeof(long), f2);
  157.         fwrite(dummy, wsize2, sizeof(long), f2);
  158.         fwrite(&ibuf[wsize1], wsize3, sizeof(long), f2);
  159.     }
  160.     fclose(f1);
  161.     fclose(f2);
  162.     if (!(f1 = fopen(FN_MAIN, "w")))
  163.         xerror(FN_MAIN);
  164.     for (i = 0; i < ldirs; i++)
  165.     {
  166.         if (i == where)
  167.             fprintf(f1, "%s\n", dn);
  168.         fprintf(f1, "%s\n", ldnames[i]);
  169.     }
  170.     if (i == where)
  171.         fprintf(f1, "%s\n", dn);
  172.     fclose(f1);
  173.  
  174.     unlink(FN_D_OLD);
  175.     link(FN_D_NEW, FN_D_OLD);
  176.     unlink(FN_D_NEW);
  177.     chmod(FN_D_OLD, 0644);
  178. }
  179.  
  180. del_disk(dn)
  181. char *dn;
  182. {
  183. }
  184.  
  185. gather_df()
  186. /*
  187.  * Get all the statistics from a call to "df".
  188.  */
  189. {
  190.     FILE    *file;
  191.     char    *tname,
  192.             *cptr,
  193.             buf[132];
  194.     long    ibuf[60];
  195.     short   i, j, p,
  196.             count;
  197.     int     cmp_ptrs();
  198.  
  199.     tname = tmpnam(0);
  200.     sprintf(buf, "df >%s", tname);
  201.     system(buf);
  202.  
  203.     dirs = 0;
  204.     if (!(file = fopen(tname, "r")))
  205.         xerror(tname);
  206.     while (fgets(buf, 132, file))
  207.     {
  208.         cptr = buf;
  209.         for (i = 0; cptr[i] && (cptr[i] != ' ') && (cptr[i] != '('); i++)
  210.             dnames[dirs][i] = cptr[i];
  211.         dnames[dirs][i] = 0;
  212.         while (*cptr != ':') cptr++;
  213.         cptr++;
  214.         SKIPWHITE(cptr);
  215.         bfree[dirs] = atoi(cptr);
  216.         SKIPTOWHITE(cptr);
  217.         SKIPWHITE(cptr);
  218.         SKIPTOWHITE(cptr);
  219.         SKIPWHITE(cptr);
  220.         ifree[dirs] = atoi(cptr);
  221.         dirs++;
  222.     }
  223.     fclose(file);
  224.     unlink(tname);
  225.     for (i = 0; i < dirs; i++)
  226.         ptrs[i] = i;
  227.     qsort(ptrs, dirs, sizeof(short), cmp_ptrs);
  228.  
  229.     if (!(file = fopen(FN_D_OLD, "r")))
  230.         xerror(FN_D_OLD);
  231.     count = (1 + ldirs * 2);
  232.     fseek(file, -10 * count * sizeof(long), 2);
  233.     for (lastc = 0; lastc < 10; lastc++)
  234.     {
  235.         if (fread(ibuf, count, sizeof(long), file) <= 0) break;
  236.         for (j = 0, p = 1; j < ldirs; j++)
  237.         {
  238.             bfree10[lastc][j] = ibuf[p++];
  239.             ifree10[lastc][j] = ibuf[p++];
  240.         }
  241.     }
  242.     fclose(file);
  243. }
  244.  
  245. cmp_ptrs(p1, p2)
  246. short *p1, *p2;
  247. {
  248.     return(strcmp(dnames[*p1], dnames[*p2]));
  249. }
  250.  
  251.  
  252. dump_df()
  253. /*
  254.  * Dump the collected info.
  255.  */
  256. {
  257.     short   i, j;
  258.  
  259.     for (j = 0; j < dirs; j++)
  260.     {
  261.         i = ptrs[j];
  262.         printf("%-24s  %8d blocks free  %8d inodes free\n",
  263.             dnames[i], bfree[i], ifree[i]);
  264.     }
  265. }
  266.  
  267. dump_warnings()
  268. /*
  269.  * Go through the data.  Dump:
  270.  *
  271.  *      Any disks that are dangerously low on space.
  272.  *      Any disks that suddenly dropped space over the last 3 updates.
  273.  *      Any disks that have been dwindling severely over the last 10 updates.
  274.  */
  275. {
  276.     short   i, j, k, l, l3;
  277.     long    bfm, ifm, diddump;
  278.     char    line[132];
  279.  
  280.     diddump = 0;
  281.     l3 = MAX(0, lastc - 3);
  282.     for (j = 0; j < dirs; j++)
  283.     {
  284.         i = ptrs[j];
  285.         if (bfree[i] < block_warn)
  286.         {
  287.             if (!diddump++) dump_df();
  288.             fprintf(stderr, "Low free space on : %s\n", dnames[i]);
  289.         }
  290.         if (ifree[i] < inode_warn)
  291.         {
  292.             if (!diddump++) dump_df();
  293.             fprintf(stderr, "Low inode count on: %s\n", dnames[i]);
  294.         }
  295.         for (k = 0; k < ldirs; k++)
  296.             if (!strcmp(ldnames[k], dnames[i]))
  297.             {
  298.                 if (bfree10[0][k] * long_threshold > bfree[i])
  299.                 {
  300.                     if (!diddump++) dump_df();
  301.                     fprintf(stderr, "Dwindling free space on: %s\n",dnames[i]);
  302.                     fprintf(stderr, "Was: %d.  Now: %d\n",
  303.                             bfree10[0][k], bfree[i]);
  304.                 }
  305.                 if (ifree10[0][k] * long_threshold > ifree[i])
  306.                 {
  307.                     if (!diddump++) dump_df();
  308.                     fprintf(stderr, "Dwindling inodes on    : %s\n",dnames[i]);
  309.                     fprintf(stderr, "Was: %d.  Now: %d\n", 
  310.                             ifree10[0][k], ifree[i]);
  311.                 }
  312.                 bfm = ifm = 0;
  313.                 for (l = l3; l < lastc; l++)
  314.                 {
  315.                     bfm = MAX(bfm, bfree10[l][k]);
  316.                     ifm = MAX(ifm, ifree10[l][k]);
  317.                 }
  318.                 if (bfm * short_threshold > bfree[i])
  319.                 {
  320.                     if (!diddump++) dump_df();
  321.                     fprintf(stderr, "Chopped free space on: %s\n",dnames[i]);
  322.                     fprintf(stderr, "Was: %d.  Now: %d\n", bfm, bfree[i]);
  323.                 }
  324.                 if (ifm * short_threshold > ifree[i])
  325.                 {
  326.                     if (!diddump++) dump_df();
  327.                     fprintf(stderr, "Chopped inodes on    : %s\n",dnames[i]);
  328.                     fprintf(stderr, "Was: %d.  Now: %d\n", ifm, ifree[i]);
  329.                 }
  330.                 break;
  331.             }
  332.     }
  333. }
  334.  
  335. update_data()
  336. /*
  337.  * Update the collected info.
  338.  */
  339. {
  340.     FILE    *f1;
  341.     int     now;
  342.     long    ibuf[50];
  343.     short   i, j, p;
  344.  
  345.     if (!(f1 = fopen(FN_D_OLD, "a")))
  346.         xerror(FN_D_OLD);
  347.     time(&now);
  348.     ibuf[0] = now;
  349.     p = 1;
  350.     for (i = 0; i < ldirs; i++)
  351.     {
  352.         for (j = 0; j < dirs; j++)
  353.             if (!strcmp(ldnames[i], dnames[j]))
  354.             {
  355.                 ibuf[p++] = bfree[j];
  356.                 ibuf[p++] = ifree[j];
  357.             }
  358.     }
  359.     fwrite(ibuf, p, sizeof(long), f1);
  360.     fclose(f1);
  361. }
  362.  
  363. report_data(do_inodes)
  364. char *do_inodes;
  365. /*
  366.  * Generate a tracking report.
  367.  */
  368. {
  369.     FILE    *file;
  370.     TM      *tmptr;
  371.     long    ibuf[60], bfr, ifr;
  372.     int     count, then;
  373.     short   i, p, lcnt, width;
  374.     char    line[80];
  375.  
  376.     if (isatty(1))
  377.     {
  378.         width = ldirs * 8 + 10;
  379.         if (do_inodes)
  380.             width = ldirs * 13 + 12;
  381.         if (width > 80)
  382.         {
  383.             printf("\nHit return to continue.\n");
  384.             gets(line);
  385.             printf("%c[?3h\n", 27);
  386.         }
  387.     }
  388.     head_dirs(do_inodes);
  389.  
  390.     if (!(file = fopen(FN_D_OLD, "r")))
  391.         xerror(FN_D_OLD);
  392.     count = (1 + ldirs * 2);
  393.     lcnt = 0;
  394.     if (dolast)
  395.         fseek(file, -(sizeof(long) * count * dolast), 2);
  396.     while (1)
  397.     {
  398.         if (fread(ibuf, count, sizeof(long), file) <= 0) break;
  399.         if (!(++lcnt % 18)) head_dirs(do_inodes);
  400.         then = ibuf[0];
  401.         tmptr = localtime(&then);
  402.         printf("%2d-%2d-%2d",
  403.             tmptr->tm_mon+1, tmptr->tm_mday, tmptr->tm_year);
  404.         for (i = 0, p = 1; i < ldirs; i++)
  405.         {
  406.             bfr = ibuf[p++];
  407.             ifr = ibuf[p++];
  408.             if (!do_inodes)
  409.                 printf("| %6d", bfr);
  410.             else
  411.                 printf("|%6d %5d", bfr, ifr);
  412.         }
  413.         printf("|\n");
  414.     }
  415.     fclose(file);
  416.  
  417.     if (isatty(1) && (width > 80))
  418.     {
  419.         printf("\nHit return to continue.\n");
  420.         gets(line);
  421.         printf("%c[?3l\n", 27);
  422.     }
  423. }
  424.  
  425. head_dirs(do_inodes)
  426. char do_inodes;
  427. {
  428.     short   i;
  429.     char    *c1, *c2;
  430.  
  431.     printf("        ");
  432.     for (i = 0; i < ldirs; i++)
  433.     {
  434.         for (c1 = c2 = ldnames[i]; *c2; c2++)
  435.             if (*c2 == '/')
  436.             {
  437.                 c1 = c2;
  438.                 if (*(c1+1)) c1++;
  439.             }
  440.         if (!do_inodes)
  441.             printf("|%7s", c1);
  442.         else
  443.             printf("|%9s   ", c1);
  444.     }
  445.     printf("|\n        ");
  446.     for (i = 0; i < ldirs; i++)
  447.         if (!do_inodes)
  448.             printf("| Blocks");
  449.         else
  450.             printf("|Blocks Inode");
  451.     printf("|\n        ");
  452.     for (i = 0; i < ldirs; i++)
  453.     {
  454.         if (!do_inodes)
  455.             printf("| ------");
  456.         else
  457.             printf("|------ -----");
  458.     }
  459.     printf("|\n");
  460. }
  461.  
  462. usage(arg)
  463. char *arg;
  464. {
  465.     fprintf(stderr, "\
  466. Usage: %s [-a disk] [-d disk] [-u] [-r]\n\n\
  467.        Errors imply -r.  -u updates the database.\n\
  468.        Use -a or -d to manage the list of disks by mount point.\n", arg);
  469.     exit(-1);
  470. }
  471.