home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2686 / clndr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-08  |  11.4 KB  |  456 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/mpls/mis/joel/.df.dnames"
  46. #define FN_D_OLD    "/users/mpls/mis/joel/.df.data.o"
  47. #define FN_D_NEW    "/users/mpls/mis/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_upd,
  78.             do_rpt;
  79.     extern char *optarg;
  80.  
  81.     quitnow = do_upd = do_rpt = 0;
  82.     load_disks();
  83.     dolast = 0;
  84.     while ((c = getopt(argc, argv, "a:d:l:ruh")) != EOF)
  85.         switch (c)
  86.         {
  87.             case 'a':   add_disk(optarg); quitnow = 1; break;
  88.             case 'd':   del_disk(optarg); quitnow = 1; break;
  89.             case 'l':   dolast = atoi(optarg); break;
  90.             case 'u':   do_upd = 1; break;
  91.             case 'r':   do_rpt = 1; break;
  92.             case 'h':
  93.             default:    usage(argv[0]);
  94.         }
  95.     
  96.     if (quitnow) exit(0);
  97.     gather_df();
  98.     dump_warnings();
  99.     if (do_upd)
  100.         update_data();
  101.     if (do_rpt)
  102.         report_data();
  103. }
  104.  
  105.  
  106. load_disks()
  107. {
  108.     FILE    *f1;
  109.     char    buf[132];
  110.     short   ilen;
  111.  
  112.     ldirs = 0;
  113.     if (!(f1 = fopen(FN_MAIN, "r")))
  114.         xerror(FN_MAIN);
  115.     while (fgets(buf, 132, f1))
  116.     {
  117.         ilen = strlen(buf) - 1;
  118.         if (buf[ilen] == '\n') buf[ilen] = 0;
  119.         strcpy(ldnames[ldirs++], buf);
  120.     }
  121.     fclose(f1);
  122. }
  123.  
  124. add_disk(dn)
  125. char *dn;
  126. {
  127.     FILE    *f1, *f2;
  128.     long    ibuf[60], dummy[2];
  129.     short   i, where, rsize, wsize1, wsize2, wsize3;
  130.  
  131.     for (where = 0; where < ldirs; where++)
  132.     {
  133.         i = strcmp(ldnames[where], dn);
  134.         if (!i)
  135.         {
  136.             fprintf(stderr, "Disk %s is already in the database.\n");
  137.             return;
  138.         }
  139.         if (i > 0) break;
  140.     }
  141.  
  142.     if (!(f1 = fopen(FN_D_OLD, "r")))
  143.         xerror(FN_D_OLD);
  144.     if (!(f2 = fopen(FN_D_NEW, "w")))
  145.         xerror(FN_D_NEW);
  146.     rsize = (1 + 2 * ldirs);
  147.     wsize1 = (1 + 2 * where);
  148.     wsize2 = 2;
  149.     wsize3 = (2 * (ldirs - where));
  150.  
  151.     while (fread(ibuf, rsize, sizeof(long), f1))
  152.     {
  153.         fwrite(ibuf, wsize1, sizeof(long), f2);
  154.         fwrite(dummy, wsize2, sizeof(long), f2);
  155.         fwrite(&ibuf[2 + where*2], wsize3, sizeof(long), f2);
  156.     }
  157.     fclose(f1);
  158.     fclose(f2);
  159.     if (!(f1 = fopen(FN_MAIN, "w")))
  160.         xerror(FN_MAIN);
  161.     for (i = 0; i < ldirs; i++)
  162.     {
  163.         if (i == where)
  164.             fprintf(f1, "%s\n", dn);
  165.         fprintf(f1, "%s\n", ldnames[i]);
  166.     }
  167.     if (i == where)
  168.         fprintf(f1, "%s\n", dn);
  169.     fclose(f1);
  170.  
  171.     unlink(FN_D_OLD);
  172.     link(FN_D_NEW, FN_D_OLD);
  173.     unlink(FN_D_NEW);
  174.     chmod(FN_D_OLD, 0644);
  175. }
  176.  
  177. del_disk(dn)
  178. char *dn;
  179. {
  180. }
  181.  
  182. gather_df()
  183. /*
  184.  * Get all the statistics from a call to "df".
  185.  */
  186. {
  187.     FILE    *file;
  188.     char    *tname,
  189.             *cptr,
  190.             buf[132];
  191.     long    ibuf[60];
  192.     short   i, j, p,
  193.             count;
  194.     int     cmp_ptrs();
  195.  
  196.     tname = tmpnam(0);
  197.     sprintf(buf, "df >%s", tname);
  198.     system(buf);
  199.  
  200.     dirs = 0;
  201.     if (!(file = fopen(tname, "r")))
  202.         xerror(tname);
  203.     while (fgets(buf, 132, file))
  204.     {
  205.         cptr = buf;
  206.         for (i = 0; cptr[i] && (cptr[i] != ' ') && (cptr[i] != '('); i++)
  207.             dnames[dirs][i] = cptr[i];
  208.         dnames[dirs][i] = 0;
  209.         while (*cptr != ':') cptr++;
  210.         cptr++;
  211.         SKIPWHITE(cptr);
  212.         bfree[dirs] = atoi(cptr);
  213.         SKIPTOWHITE(cptr);
  214.         SKIPWHITE(cptr);
  215.         SKIPTOWHITE(cptr);
  216.         SKIPWHITE(cptr);
  217.         ifree[dirs] = atoi(cptr);
  218.         dirs++;
  219.     }
  220.     fclose(file);
  221.     unlink(tname);
  222.     for (i = 0; i < dirs; i++)
  223.         ptrs[i] = i;
  224.     qsort(ptrs, dirs, sizeof(short), cmp_ptrs);
  225.  
  226.     if (!(file = fopen(FN_D_OLD, "r")))
  227.         xerror(FN_D_OLD);
  228.     count = (1 + ldirs * 2);
  229.     fseek(file, -10 * count * sizeof(long), 2);
  230.     for (lastc = 0; lastc < 10; lastc++)
  231.     {
  232.         if (fread(ibuf, count, sizeof(long), file) <= 0) break;
  233.         for (j = 0, p = 1; j < ldirs; j++)
  234.         {
  235.             bfree10[lastc][j] = ibuf[p++];
  236.             ifree10[lastc][j] = ibuf[p++];
  237.         }
  238.     }
  239.     fclose(file);
  240. }
  241.  
  242. cmp_ptrs(p1, p2)
  243. short *p1, *p2;
  244. {
  245.     return(strcmp(dnames[*p1], dnames[*p2]));
  246. }
  247.  
  248.  
  249. dump_df()
  250. /*
  251.  * Dump the collected info.
  252.  */
  253. {
  254.     short   i, j;
  255.  
  256.     for (j = 0; j < dirs; j++)
  257.     {
  258.         i = ptrs[j];
  259.         printf("%-24s  %8d blocks free  %8d inodes free\n",
  260.             dnames[i], bfree[i], ifree[i]);
  261.     }
  262. }
  263.  
  264. dump_warnings()
  265. /*
  266.  * Go through the data.  Dump:
  267.  *
  268.  *      Any disks that are dangerously low on space.
  269.  *      Any disks that suddenly dropped space over the last 3 updates.
  270.  *      Any disks that have been dwindling severely over the last 10 updates.
  271.  */
  272. {
  273.     short   i, j, k, l, l3;
  274.     long    bfm, ifm, diddump;
  275.     char    line[132];
  276.  
  277.     diddump = 0;
  278.     l3 = MAX(0, lastc - 3);
  279.     for (j = 0; j < dirs; j++)
  280.     {
  281.         i = ptrs[j];
  282.         if (bfree[i] < block_warn)
  283.         {
  284.             if (!diddump++) dump_df();
  285.             fprintf(stderr, "Low free space on : %s\n", dnames[i]);
  286.         }
  287.         if (ifree[i] < inode_warn)
  288.         {
  289.             if (!diddump++) dump_df();
  290.             fprintf(stderr, "Low inode count on: %s\n", dnames[i]);
  291.         }
  292.         for (k = 0; k < ldirs; k++)
  293.             if (!strcmp(ldnames[k], dnames[i]))
  294.             {
  295.                 if (bfree10[0][k] * long_threshold > bfree[i])
  296.                 {
  297.                     if (!diddump++) dump_df();
  298.                     fprintf(stderr, "Dwindling free space on: %s\n",dnames[i]);
  299.                     fprintf(stderr, "Was: %d.  Now: %d\n",
  300.                             bfree10[0][k], bfree[i]);
  301.                 }
  302.                 if (ifree10[0][k] * long_threshold > ifree[i])
  303.                 {
  304.                     if (!diddump++) dump_df();
  305.                     fprintf(stderr, "Dwindling inodes on    : %s\n",dnames[i]);
  306.                     fprintf(stderr, "Was: %d.  Now: %d\n", 
  307.                             ifree10[0][k], ifree[i]);
  308.                 }
  309.                 bfm = ifm = 0;
  310.                 for (l = l3; l < lastc; l++)
  311.                 {
  312.                     bfm = MAX(bfm, bfree10[l][k]);
  313.                     ifm = MAX(ifm, ifree10[l][k]);
  314.                 }
  315.                 if (bfm * short_threshold > bfree[i])
  316.                 {
  317.                     if (!diddump++) dump_df();
  318.                     fprintf(stderr, "Chopped free space on: %s\n",dnames[i]);
  319.                     fprintf(stderr, "Was: %d.  Now: %d\n", bfm, bfree[i]);
  320.                 }
  321.                 if (ifm * short_threshold > ifree[i])
  322.                 {
  323.                     if (!diddump++) dump_df();
  324.                     fprintf(stderr, "Chopped inodes on    : %s\n",dnames[i]);
  325.                     fprintf(stderr, "Was: %d.  Now: %d\n", ifm, ifree[i]);
  326.                 }
  327.                 break;
  328.             }
  329.     }
  330.     if (diddump)
  331.     {
  332.         printf("\nHit return to continue.\n");
  333.         gets(line);
  334.     }
  335. }
  336.  
  337. update_data()
  338. /*
  339.  * Update the collected info.
  340.  */
  341. {
  342.     FILE    *f1;
  343.     int     now;
  344.     long    ibuf[50];
  345.     short   i, j, p;
  346.  
  347.     if (!(f1 = fopen(FN_D_OLD, "a")))
  348.         xerror(FN_D_OLD);
  349.     time(&now);
  350.     ibuf[0] = now;
  351.     p = 1;
  352.     for (i = 0; i < ldirs; i++)
  353.     {
  354.         for (j = 0; j < dirs; j++)
  355.             if (!strcmp(ldnames[i], dnames[j]))
  356.             {
  357.                 ibuf[p++] = bfree[j];
  358.                 ibuf[p++] = ifree[j];
  359.             }
  360.     }
  361.     fwrite(ibuf, p, sizeof(long), f1);
  362.     fclose(f1);
  363. }
  364.  
  365. report_data()
  366. /*
  367.  * Generate a tracking report.
  368.  */
  369. {
  370.     FILE    *file;
  371.     TM      *tmptr;
  372.     long    ibuf[60], bfr, ifr;
  373.     int     count, then;
  374.     short   i, p, lcnt;
  375.     char    line[80];
  376.  
  377.     if (isatty(1))
  378.         printf("%c[?3h\n", 27);
  379.     head_dirs();
  380.  
  381.     if (!(file = fopen(FN_D_OLD, "r")))
  382.         xerror(FN_D_OLD);
  383.     count = (1 + ldirs * 2);
  384.     lcnt = 0;
  385.     if (dolast)
  386.         fseek(file, -(sizeof(long) * count * dolast), 2);
  387.     while (1)
  388.     {
  389.         if (fread(ibuf, count, sizeof(long), file) <= 0) break;
  390.         if (!(++lcnt % 18)) head_dirs();
  391.         then = ibuf[0];
  392.         tmptr = localtime(&then);
  393.         printf("%2d-%2d-%2d",
  394.             tmptr->tm_mon+1, tmptr->tm_mday, tmptr->tm_year);
  395.         for (i = 0, p = 1; i < ldirs; i++)
  396.         {
  397.             bfr = ibuf[p++];
  398.             ifr = ibuf[p++];
  399.             printf("|%6d %5d", bfr, ifr);
  400.         }
  401.         printf("|\n");
  402.     }
  403.     fclose(file);
  404.  
  405.     if (isatty(1))
  406.     {
  407.         printf("\nHit return to continue.\n");
  408.         gets(line);
  409.         printf("%c[?3l\n", 27);
  410.     }
  411. }
  412.  
  413. head_dirs()
  414. {
  415.     short   i;
  416.     char    *c1, *c2;
  417.  
  418.     printf("        ");
  419.     for (i = 0; i < ldirs; i++)
  420.     {
  421.         for (c1 = c2 = ldnames[i]; *c2; c2++)
  422.             if (*c2 == '/')
  423.             {
  424.                 c1 = c2;
  425.                 if (*(c1+1)) c1++;
  426.             }
  427.         printf("|%9s   ", c1);
  428.     }
  429.     printf("|\n        ");
  430.     for (i = 0; i < ldirs; i++)
  431.         printf("|Blocks Inode");
  432.     printf("|\n        ");
  433.     for (i = 0; i < ldirs; i++)
  434.         printf("|------ -----");
  435.     printf("|\n");
  436. }
  437.  
  438. usage(arg)
  439. char *arg;
  440. {
  441.     fprintf(stderr, "\
  442. Usage: %s [-a disk] [-d disk] [-u] [-r]\n\n\
  443.        Errors imply -r.  -u updates the database.\n\
  444.        Use -a or -d to manage the list of disks by mount point.\n", arg);
  445.     exit(-1);
  446. }
  447.  
  448. xerror(arg)
  449. char *arg;
  450. {
  451.     extern int errno;
  452.  
  453.     perror(arg)
  454.     exit(errno);
  455. }
  456.