home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume39 / enh-du2 / part02 / du.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-21  |  8.6 KB  |  397 lines

  1. #ifndef lint
  2. static char SCCSID[] = "@(#) du.c 1.16 93/08/18 00:09:01";
  3. #endif
  4. static char Copyright[] = "@(#) Copyright 1990-1993, Unicom Systems Development, Inc.  All rights reserved.";
  5.  
  6. /*
  7.  * "du" enhanced disk usage summary - version 2.
  8.  *
  9.  * Copyright 1990-1993, Unicom Systems Development.  All rights reserved.
  10.  * See accompanying README file for terms of distribution and use.
  11.  *
  12.  * Edit at tabstops=4.
  13.  */
  14.  
  15. #define USAGE "usage: %s [ options ] [ path ... ]  (try \"-h\" for help)\n"
  16.  
  17. #include "config.h"
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <pwd.h>
  22. #include <time.h>
  23. #ifdef TIMEOUT
  24. # include <signal.h>
  25. #endif
  26. #ifdef USE_STDARG
  27. # include <stdarg.h>
  28. #else
  29. # include <varargs.h>
  30. #endif
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #define INTERN
  34. #include "du.h"
  35. #include "patchlevel.h"
  36.  
  37. static void do_help __ARGS((void));
  38. static void set_breakdown __ARGS((char *));
  39. static int get_userid __ARGS((char *));
  40.  
  41.  
  42. #ifdef TIMEOUT
  43. /*ARGSUSED*/
  44. void alarm_catcher(n)
  45. int n;
  46. {
  47.     errmssg(ERR_ABORT, 0, "timeout occurred -- giving up");
  48.     /*NOTREACHED*/
  49. }
  50. #endif
  51.  
  52.  
  53. main(argc, argv)
  54. int argc;
  55. char *argv[];
  56. {
  57.     int i;
  58.     struct dusage tot_usage, ent_usage;
  59.     extern char *optarg;
  60.     extern int optind;
  61.  
  62.     Progname = argv[0];
  63.  
  64.     /* 
  65.      * Crack command line options.
  66.      */
  67.     while ((i = getopt(argc, argv, "abB:c:CDdfFhiklLrstuU:")) != EOF) {
  68.         switch (i) {
  69.             case 'a':    Handle_output = PR_EVERYTHING;        break;
  70.             case 'b':   Report_blksize = 1;                    break;
  71.             case 'B':   Report_blksize = atoi(optarg);        break;
  72.             case 'c':    set_breakdown(optarg);                break;
  73.             case 'C':    Do_file_counts = TRUE;                break;
  74. #ifdef OBSOLETEOPT
  75.             case 'd':    Do_descend_dirs = FALSE;            break;
  76. #endif
  77.             case 'f':    Handle_filesys = FS_NEVER_CROSS;    break;
  78.             case 'F':    Handle_filesys = FS_LOCAL_ONLY;        break;
  79.             case 'h':    do_help();                            exit(0);
  80.             case 'i':    Do_accum_subdirs = FALSE;            break;
  81.             case 'k':   Report_blksize = 1024;                break;
  82.             case 'l':    Handle_links = LK_COUNT_ALL;        break;
  83.             case 'L':    Handle_links = LK_COUNT_AVERAGE;    break;
  84.             case 'r':    Do_print_errors = TRUE;                break;
  85.             case 's':    Handle_output = PR_TOTALS_ONLY;        break;
  86.             case 't':    Do_print_grand_total = TRUE;        break;
  87.             case 'u':    Handle_links = LK_COUNT_NONE;        break;
  88.             case 'U':    Selected_user = get_userid(optarg);    break;
  89. #ifdef DEBUG
  90.             case 'D':    Debug = TRUE;                        break;
  91. #endif
  92.             default:    fprintf(stderr, USAGE, Progname);
  93.                         exit(1);
  94.         }
  95.     }
  96.  
  97. #ifdef TIMEOUT
  98.     /*
  99.      * Install the handler to trap timeouts.
  100.      */
  101.     (void) signal(SIGALRM, alarm_catcher);
  102. #endif
  103.  
  104.     /*
  105.      * Initialize the filesystem information tables.
  106.      */
  107.     fs_initinfo();
  108.  
  109.     /*
  110.      * Get the time so we can do the breakdown of usage by age.
  111.      */
  112.     (void) time(&Curr_time);
  113.  
  114.     /*
  115.      * Go get the usage.
  116.      */
  117.     if (argc == optind) {
  118.         du_entry(".", &tot_usage);
  119.     } else {
  120.         zero_usage(&tot_usage);
  121.         for (i = optind ; i < argc ; ++i) {
  122.             du_entry(argv[i], &ent_usage);
  123.             add_usage(&tot_usage, &ent_usage);
  124.         }
  125.     }
  126.  
  127.     if (Do_print_grand_total)
  128.         print_usage("TOTAL", &tot_usage);
  129.     exit(0);
  130.     /*NOTREACHED*/
  131. }
  132.  
  133.  
  134. static char *help_text[] = {
  135.     "du - version %V",
  136.     "    %C",
  137.     "Usage:",
  138.     "    %P [ options ] [ path ... ]",
  139.     "Options:",
  140.     "    -a          Report all entries, i.e. files as well as directories.",
  141.     "    -b          Equivalent to \"-B 1\".",
  142.     "    -B n        Report in blocks of \"n\" bytes (default %B).",
  143.     "                  (Use \"0\" to report in native filesystem blocks.)",
  144.     "    -c n,n,...  Breakdown by age, one col for each \"n\" days or older.",
  145.     "    -C          Display file counts as well as disk usage.",
  146. #ifdef OBSOLETEOPT
  147.     "    -d          Do not descend into directories.",
  148. #endif
  149.     "    -f          Do not cross any filesystem mount points.",
  150.     "    -F          Do not cross remote filesystem mount points.",
  151.     "    -h          Display this help message.",
  152.     "    -i          Do not accumulate subdirectory usages into parent dir.",
  153.     "    -k          Equivalent to \"-B 1024\".",
  154.     "    -l          Count multiply linked files each time encountered.",
  155.     "    -L          Average usage of multiply linked files across the links.",
  156. #ifndef PRINT_ERRORS
  157.     "    -r          Print (do not suppress) errors which occur during scan.",
  158. #endif
  159.     "    -s          Only report a total for each argument on command line.",
  160.     "    -t          Report a grand total of all items.",
  161.     "    -u          Skip (do not count) multiply linked files entirely.",
  162.     "    -U user     Report only usage by given user (specify name or id num).",
  163.     NULL
  164. };
  165.  
  166.  
  167. static void do_help()
  168. {
  169.     char *s, *p;
  170.     int i;
  171.  
  172.     for (i = 0 ; help_text[i] != NULL ; ++i) {
  173.         for (s = help_text[i] ; *s != '\0' ; ++s) {
  174.             if (*s != '%') {
  175.                 putchar(*s);
  176.             } else {
  177.                 switch (*++s) {
  178.                     case 'B':
  179.                         printf("%d", REPORT_BLKSIZE);
  180.                         break;
  181.                     case 'C':
  182.                         for (p = Copyright ; *p != ' ' ; ++p)
  183.                             ;
  184.                         fputs(p+1, stdout);
  185.                         break;
  186.                     case 'P':
  187.                         fputs(Progname, stdout);
  188.                         break;
  189.                     case 'V':
  190.                         fputs(VERSION, stdout);
  191.                         break;
  192.                     default:
  193.                         putchar('%');
  194.                         putchar(*s);
  195.                         break;
  196.                 }
  197.             }
  198.         }
  199.         putchar('\n');
  200.     }
  201.     exit(0);
  202. }
  203.  
  204.  
  205. static void set_breakdown(str)
  206. char *str;
  207. {
  208.     char *s;
  209.     Num_break = 0;
  210.     while ((s = strtok(str, " \t,")) != NULL) {
  211.         str = NULL;
  212.         if (Num_break >= MAX_BREAK)
  213.             errmssg(ERR_ABORT, 0, "too many breakdown catagories");
  214.         if ((Breakdown[Num_break++] = atoi(s)) <= 0 && strcmp(s, "0") != 0)
  215.             errmssg(ERR_ABORT, 0, "bad breakdown value \"%s\"", s);
  216.     }
  217.     if (Num_break == 0)
  218.         errmssg(ERR_ABORT, 0, "no breakdown catagories specified");
  219. }
  220.  
  221.  
  222. static int get_userid(id)
  223. char *id;
  224. {
  225.     int n;
  226.     struct passwd *pw;
  227.     extern struct passwd *getpwnam();
  228.  
  229.     if ((n = atoi(id)) != 0 || strcmp(id, "0") == 0)
  230.         return n;
  231.     pw = getpwnam(id);
  232.     endpwent();
  233.     if (pw != NULL)
  234.         return pw->pw_uid;
  235.     errmssg(ERR_ABORT, 0, "bad user id \"%s\" specified", id);
  236.     /*NOTREACHED*/
  237. }
  238.  
  239.  
  240. PTRTYPE *xmalloc(n)
  241. unsigned n;
  242. {
  243.     PTRTYPE *s;
  244.     if ((s = malloc(n)) == NULL)
  245.         errmssg(ERR_ABORT, 0, "out of memory [malloc failed]");
  246.     return s;
  247. }
  248.  
  249.  
  250. PTRTYPE *xrealloc(s, n)
  251. PTRTYPE *s;
  252. unsigned n;
  253. {
  254.     if ((s = realloc(s, n)) == NULL)
  255.         errmssg(ERR_ABORT, 0, "out of memory [malloc failed]");
  256.     return s;
  257. }
  258.  
  259.  
  260. /*
  261.  * errmssg - Error reporting routine.  If "err" is nonzero then the
  262.  * sys_errlist[] text will be included in the message.  If "severe" is
  263.  * non-zero then the program will abort after displaying the message.
  264.  * Non-fatal errors will be displayed only if "Do_print_errors" is TRUE.
  265.  */
  266. /*VARARGS*/
  267. #ifdef USE_STDARG
  268. void errmssg(int severe, int err, char *fmt, ...)
  269. #else
  270. void errmssg(va_alist)
  271. va_dcl
  272. #endif
  273. {
  274.     va_list args;
  275. #ifndef USE_STDARG
  276.     int severe, err;
  277.     char *fmt;
  278. #endif
  279.     extern char *sys_errlist[];
  280.  
  281. #ifdef USE_STDARG
  282.     va_start(args, fmt);
  283. #else
  284.     va_start(args);
  285.     severe = va_arg(args, int);
  286.     err = va_arg(args, int);
  287.     fmt = va_arg(args, char *);
  288. #endif
  289.  
  290.     if (severe || Do_print_errors) {
  291.         fprintf(stderr, "%s: ", Progname);
  292.         vfprintf(stderr, fmt, args);
  293.         if (err > 0)
  294.             fprintf(stderr, " [%s]", sys_errlist[err]);
  295.         putc('\n', stderr);
  296.     }
  297.  
  298.     va_end(args);
  299.  
  300.     if (severe)
  301.         exit(1);
  302. }
  303.  
  304.  
  305. /*
  306.  * Disk Usage Functions - Disk usage is accumulated (struct dusage) and
  307.  * is used to track both disk usage and file counts chronologically.
  308.  * The following routines manipulate this information.
  309.  */
  310.  
  311.  
  312. /*
  313.  * Reset usage information to zero.
  314.  */
  315. void zero_usage(usage)
  316. struct dusage *usage;
  317. {
  318.     register int *f, i;
  319.     register long *b;
  320.  
  321.     b = usage->blocks;
  322.     f = usage->files;
  323.     i = Num_break;
  324.     while (--i >= 0) {
  325.         *b++ = 0L;
  326.         *f++ = 0;
  327.     }
  328. }
  329.  
  330. /*
  331.  * Load usage information from file size and age.
  332.  */
  333. void set_usage(usage, mtime, nblocks)
  334. struct dusage *usage;
  335. time_t mtime;
  336. long nblocks;
  337. {
  338.     register int *f, i;
  339.     register long *b;
  340.     int ndays, *brk;
  341.  
  342.     /*
  343.      * There is a race condition here which luckily works out OK.  If a file
  344.      * is created after "du" is started, the "Curr_time-sbufp->st_mtime" value
  345.      * will be a small negative number, however dividing by "60*60*24" will
  346.      * truncate the result to zero, which is the result we want.
  347.      */
  348.     ndays = (int)((Curr_time-mtime) / (60L*60L*24L/*seconds*/));
  349.  
  350.     b = usage->blocks;
  351.     f = usage->files;
  352.     brk = Breakdown;
  353.     i = Num_break;
  354.     while (--i >= 0) {
  355.         if (*brk++ <= ndays) {
  356.             *b++ = nblocks;
  357.             *f++ = 1;
  358.         } else {
  359.             *b++ = 0L;
  360.             *f++ = 0;
  361.         }
  362.     }
  363. }
  364.  
  365. /*
  366.  * Accumulate usage information.
  367.  */
  368. void add_usage(tot_usage, ent_usage)
  369. register struct dusage *tot_usage, *ent_usage;
  370. {
  371.     register int i;
  372.  
  373.     i = Num_break;
  374.     while (--i >= 0) {
  375.         tot_usage->blocks[i] += ent_usage->blocks[i];
  376.         tot_usage->files[i] += ent_usage->files[i];
  377.     }
  378. }
  379.  
  380. /*
  381.  * Display usage information.
  382.  */
  383. void print_usage(name, usage)
  384. char *name;
  385. struct dusage *usage;
  386. {
  387.     int i;
  388.     for (i = 0 ; i < Num_break ; ++i) {
  389.         if (Do_file_counts)
  390.             printf("%ld\t%d\t", usage->blocks[i], usage->files[i]);
  391.         else
  392.             printf("%ld\t", usage->blocks[i]);
  393.     }
  394.     printf("%s\n", name);
  395. }
  396.  
  397.