home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char SCCSID[] = "@(#) du.c 1.16 93/08/18 00:09:01";
- #endif
- static char Copyright[] = "@(#) Copyright 1990-1993, Unicom Systems Development, Inc. All rights reserved.";
-
- /*
- * "du" enhanced disk usage summary - version 2.
- *
- * Copyright 1990-1993, Unicom Systems Development. All rights reserved.
- * See accompanying README file for terms of distribution and use.
- *
- * Edit at tabstops=4.
- */
-
- #define USAGE "usage: %s [ options ] [ path ... ] (try \"-h\" for help)\n"
-
- #include "config.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <pwd.h>
- #include <time.h>
- #ifdef TIMEOUT
- # include <signal.h>
- #endif
- #ifdef USE_STDARG
- # include <stdarg.h>
- #else
- # include <varargs.h>
- #endif
- #include <sys/types.h>
- #include <sys/stat.h>
- #define INTERN
- #include "du.h"
- #include "patchlevel.h"
-
- static void do_help __ARGS((void));
- static void set_breakdown __ARGS((char *));
- static int get_userid __ARGS((char *));
-
-
- #ifdef TIMEOUT
- /*ARGSUSED*/
- void alarm_catcher(n)
- int n;
- {
- errmssg(ERR_ABORT, 0, "timeout occurred -- giving up");
- /*NOTREACHED*/
- }
- #endif
-
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int i;
- struct dusage tot_usage, ent_usage;
- extern char *optarg;
- extern int optind;
-
- Progname = argv[0];
-
- /*
- * Crack command line options.
- */
- while ((i = getopt(argc, argv, "abB:c:CDdfFhiklLrstuU:")) != EOF) {
- switch (i) {
- case 'a': Handle_output = PR_EVERYTHING; break;
- case 'b': Report_blksize = 1; break;
- case 'B': Report_blksize = atoi(optarg); break;
- case 'c': set_breakdown(optarg); break;
- case 'C': Do_file_counts = TRUE; break;
- #ifdef OBSOLETEOPT
- case 'd': Do_descend_dirs = FALSE; break;
- #endif
- case 'f': Handle_filesys = FS_NEVER_CROSS; break;
- case 'F': Handle_filesys = FS_LOCAL_ONLY; break;
- case 'h': do_help(); exit(0);
- case 'i': Do_accum_subdirs = FALSE; break;
- case 'k': Report_blksize = 1024; break;
- case 'l': Handle_links = LK_COUNT_ALL; break;
- case 'L': Handle_links = LK_COUNT_AVERAGE; break;
- case 'r': Do_print_errors = TRUE; break;
- case 's': Handle_output = PR_TOTALS_ONLY; break;
- case 't': Do_print_grand_total = TRUE; break;
- case 'u': Handle_links = LK_COUNT_NONE; break;
- case 'U': Selected_user = get_userid(optarg); break;
- #ifdef DEBUG
- case 'D': Debug = TRUE; break;
- #endif
- default: fprintf(stderr, USAGE, Progname);
- exit(1);
- }
- }
-
- #ifdef TIMEOUT
- /*
- * Install the handler to trap timeouts.
- */
- (void) signal(SIGALRM, alarm_catcher);
- #endif
-
- /*
- * Initialize the filesystem information tables.
- */
- fs_initinfo();
-
- /*
- * Get the time so we can do the breakdown of usage by age.
- */
- (void) time(&Curr_time);
-
- /*
- * Go get the usage.
- */
- if (argc == optind) {
- du_entry(".", &tot_usage);
- } else {
- zero_usage(&tot_usage);
- for (i = optind ; i < argc ; ++i) {
- du_entry(argv[i], &ent_usage);
- add_usage(&tot_usage, &ent_usage);
- }
- }
-
- if (Do_print_grand_total)
- print_usage("TOTAL", &tot_usage);
- exit(0);
- /*NOTREACHED*/
- }
-
-
- static char *help_text[] = {
- "du - version %V",
- " %C",
- "Usage:",
- " %P [ options ] [ path ... ]",
- "Options:",
- " -a Report all entries, i.e. files as well as directories.",
- " -b Equivalent to \"-B 1\".",
- " -B n Report in blocks of \"n\" bytes (default %B).",
- " (Use \"0\" to report in native filesystem blocks.)",
- " -c n,n,... Breakdown by age, one col for each \"n\" days or older.",
- " -C Display file counts as well as disk usage.",
- #ifdef OBSOLETEOPT
- " -d Do not descend into directories.",
- #endif
- " -f Do not cross any filesystem mount points.",
- " -F Do not cross remote filesystem mount points.",
- " -h Display this help message.",
- " -i Do not accumulate subdirectory usages into parent dir.",
- " -k Equivalent to \"-B 1024\".",
- " -l Count multiply linked files each time encountered.",
- " -L Average usage of multiply linked files across the links.",
- #ifndef PRINT_ERRORS
- " -r Print (do not suppress) errors which occur during scan.",
- #endif
- " -s Only report a total for each argument on command line.",
- " -t Report a grand total of all items.",
- " -u Skip (do not count) multiply linked files entirely.",
- " -U user Report only usage by given user (specify name or id num).",
- NULL
- };
-
-
- static void do_help()
- {
- char *s, *p;
- int i;
-
- for (i = 0 ; help_text[i] != NULL ; ++i) {
- for (s = help_text[i] ; *s != '\0' ; ++s) {
- if (*s != '%') {
- putchar(*s);
- } else {
- switch (*++s) {
- case 'B':
- printf("%d", REPORT_BLKSIZE);
- break;
- case 'C':
- for (p = Copyright ; *p != ' ' ; ++p)
- ;
- fputs(p+1, stdout);
- break;
- case 'P':
- fputs(Progname, stdout);
- break;
- case 'V':
- fputs(VERSION, stdout);
- break;
- default:
- putchar('%');
- putchar(*s);
- break;
- }
- }
- }
- putchar('\n');
- }
- exit(0);
- }
-
-
- static void set_breakdown(str)
- char *str;
- {
- char *s;
- Num_break = 0;
- while ((s = strtok(str, " \t,")) != NULL) {
- str = NULL;
- if (Num_break >= MAX_BREAK)
- errmssg(ERR_ABORT, 0, "too many breakdown catagories");
- if ((Breakdown[Num_break++] = atoi(s)) <= 0 && strcmp(s, "0") != 0)
- errmssg(ERR_ABORT, 0, "bad breakdown value \"%s\"", s);
- }
- if (Num_break == 0)
- errmssg(ERR_ABORT, 0, "no breakdown catagories specified");
- }
-
-
- static int get_userid(id)
- char *id;
- {
- int n;
- struct passwd *pw;
- extern struct passwd *getpwnam();
-
- if ((n = atoi(id)) != 0 || strcmp(id, "0") == 0)
- return n;
- pw = getpwnam(id);
- endpwent();
- if (pw != NULL)
- return pw->pw_uid;
- errmssg(ERR_ABORT, 0, "bad user id \"%s\" specified", id);
- /*NOTREACHED*/
- }
-
-
- PTRTYPE *xmalloc(n)
- unsigned n;
- {
- PTRTYPE *s;
- if ((s = malloc(n)) == NULL)
- errmssg(ERR_ABORT, 0, "out of memory [malloc failed]");
- return s;
- }
-
-
- PTRTYPE *xrealloc(s, n)
- PTRTYPE *s;
- unsigned n;
- {
- if ((s = realloc(s, n)) == NULL)
- errmssg(ERR_ABORT, 0, "out of memory [malloc failed]");
- return s;
- }
-
-
- /*
- * errmssg - Error reporting routine. If "err" is nonzero then the
- * sys_errlist[] text will be included in the message. If "severe" is
- * non-zero then the program will abort after displaying the message.
- * Non-fatal errors will be displayed only if "Do_print_errors" is TRUE.
- */
- /*VARARGS*/
- #ifdef USE_STDARG
- void errmssg(int severe, int err, char *fmt, ...)
- #else
- void errmssg(va_alist)
- va_dcl
- #endif
- {
- va_list args;
- #ifndef USE_STDARG
- int severe, err;
- char *fmt;
- #endif
- extern char *sys_errlist[];
-
- #ifdef USE_STDARG
- va_start(args, fmt);
- #else
- va_start(args);
- severe = va_arg(args, int);
- err = va_arg(args, int);
- fmt = va_arg(args, char *);
- #endif
-
- if (severe || Do_print_errors) {
- fprintf(stderr, "%s: ", Progname);
- vfprintf(stderr, fmt, args);
- if (err > 0)
- fprintf(stderr, " [%s]", sys_errlist[err]);
- putc('\n', stderr);
- }
-
- va_end(args);
-
- if (severe)
- exit(1);
- }
-
-
- /*
- * Disk Usage Functions - Disk usage is accumulated (struct dusage) and
- * is used to track both disk usage and file counts chronologically.
- * The following routines manipulate this information.
- */
-
-
- /*
- * Reset usage information to zero.
- */
- void zero_usage(usage)
- struct dusage *usage;
- {
- register int *f, i;
- register long *b;
-
- b = usage->blocks;
- f = usage->files;
- i = Num_break;
- while (--i >= 0) {
- *b++ = 0L;
- *f++ = 0;
- }
- }
-
- /*
- * Load usage information from file size and age.
- */
- void set_usage(usage, mtime, nblocks)
- struct dusage *usage;
- time_t mtime;
- long nblocks;
- {
- register int *f, i;
- register long *b;
- int ndays, *brk;
-
- /*
- * There is a race condition here which luckily works out OK. If a file
- * is created after "du" is started, the "Curr_time-sbufp->st_mtime" value
- * will be a small negative number, however dividing by "60*60*24" will
- * truncate the result to zero, which is the result we want.
- */
- ndays = (int)((Curr_time-mtime) / (60L*60L*24L/*seconds*/));
-
- b = usage->blocks;
- f = usage->files;
- brk = Breakdown;
- i = Num_break;
- while (--i >= 0) {
- if (*brk++ <= ndays) {
- *b++ = nblocks;
- *f++ = 1;
- } else {
- *b++ = 0L;
- *f++ = 0;
- }
- }
- }
-
- /*
- * Accumulate usage information.
- */
- void add_usage(tot_usage, ent_usage)
- register struct dusage *tot_usage, *ent_usage;
- {
- register int i;
-
- i = Num_break;
- while (--i >= 0) {
- tot_usage->blocks[i] += ent_usage->blocks[i];
- tot_usage->files[i] += ent_usage->files[i];
- }
- }
-
- /*
- * Display usage information.
- */
- void print_usage(name, usage)
- char *name;
- struct dusage *usage;
- {
- int i;
- for (i = 0 ; i < Num_break ; ++i) {
- if (Do_file_counts)
- printf("%ld\t%d\t", usage->blocks[i], usage->files[i]);
- else
- printf("%ld\t", usage->blocks[i]);
- }
- printf("%s\n", name);
- }
-
-