cobwebs - mailbox size/age report
Don Gworek
uggworek at sunybcs.UUCP
Sun Jun 23 03:35:52 AEST 1985
Here is a program which reports unusually large, or unusually
old, mailboxes in /usr/spool/mail.
When the user file system is under disc quota, the mail system
can often be used as "secondary" storage. This program points
out users with unusually large amounts of unread mail.
The program will report for specific usernames, and sort either
alphabetically, by mailbox size, or mailbox age. A quiet option
supresses the top banner.
# This is a shell archive. Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".
#
# This archive contains:
# cobwebs.1 cobwebs.c
echo x - cobwebs.1
sed -e 's/^X//' > "cobwebs.1" << '//E*O*F cobwebs.1//'
X.TH COBWEBS 1 "21 June 1985"
X.SH NAME
Xcobwebs
X\- check for unusually large or old mailboxes
X.SH SYNOPSIS
X.B cobwebs
X[
X-agq
X]
X[
X-d days
X]
X[
X-s size
X]
X[
Xusername ...
X]
X.PP
X.SH DESCRIPTION
X.I Cobwebs
Xreports the size and age of mailboxes in /usr/spool/mail,
Xplus the last login of the mailbox owners. The default
Xis to report mailboxes which are quite large -- larger than
Xthe default size, 20000 bytes.
X.PP
XWith the -d option,
X.I cobwebs
Xreports mailboxes that are unusually old --
Xthe default time is 30 days.
X.I Cobwebs
Xalso reports the mailbox status for usernames (command line
Xor piped). And the program makes a general report of all
Xmailboxes, with the -g option.
X.SH OPTIONS
X.PP
X-a Sort alphabetically. Use this option with -d or -s.
X.PP
X-d Sort and/or search by age in days. The default is
X30 days, or the number argument is used.
X.PP
X-g General report \-- status of all mailboxes. By
Xdefault, this report is alphabetic. -d or -s will allow
Xsort by age or size.
X.PP
X-q Quiet option \-- no top banner.
X.PP
X-s Sort and/or search by size in bytes. Default is
X20000 bytes, or the number argument is used.
X.SH FILES
X/usr/spool/mail /etc/passwd /usr/adm/lastlog
X.SH AUTHOR
XDon Gworek
//E*O*F cobwebs.1//
ls -l cobwebs.1
echo x - cobwebs.c
sed -e 's/^X//' > "cobwebs.c" << '//E*O*F cobwebs.c//'
X/*
X * cobwebs [-agq] [-d Days] [-s Size] [username ...]
X *
X * -a alphabetic sort
X * -d sort and/or search by age (default DEF_DAYS)
X * -g all mailboxes
X * -q quiet option -- no top banner
X * -s sort and/or search by size (default DEF_SIZE)
X *
X * Default: cobwebs -s
X *
X * In case of multiple flags:
X * Sort priority -- alpha > days > size
X * Search priority -- general > usernames > days > size
X *
X */
X
X#include <sys/param.h>
X#include <stdio.h>
X#include <sys/dir.h>
X#include <sys/stat.h>
X#include <lastlog.h>
X#include <pwd.h>
X
X#define DEF_SIZE 20000 /* default mbox size limit */
X#define DEF_DAYS 30 /* default mbox age limit */
X#define MAXSTRING 30
X#define MAXUSERNAMES 400
X#define MAXPACKS 1000
X#define TRUE 1
X#define FALSE 0
X
X#define NMAX 10
X
Xstruct packet
X{
X char name[NMAX];
X off_t size;
X time_t filetime;
X};
X
Xstruct packet *calloc ();
Xstruct packet *packs[MAXPACKS];
Xstruct packet **packp;
Xstruct stat stbuf;
X
Xchar *malloc ();
Xchar usernames[MAXUSERNAMES][NMAX];
Xint num_unames = 0; /* number of usernames */
Xint now;
Xint pack_count = 0;
Xint mbox_size = DEF_SIZE; /* default mbox constraint */
Xint mbox_days = DEF_DAYS; /* default mailbox age */
Xlong int mbox_clock = 0; /* convert above to seconds */
Xlong int size_accum = 0;
Xlong int age_diff_accum = 0;
Xint mbox_total = 0;
Xint rep_names = FALSE; /* name search flag */
Xint rep_alpha = FALSE; /* alphabetic sort flag */
Xint rep_gen = FALSE; /* all mailboxes flag */
Xint rep_size = FALSE; /* sort and/or search by size */
Xint rep_days = FALSE; /* sort and/or search by age */
Xint rep_quiet = FALSE; /* print the top banner */
X
Xscmp (p, q)
Xchar *p, *q;
X{
X return (strcmp (p, q));
X}
X
Xmain (argc, argv)
Xint argc;
Xchar *argv[];
X{
X int i;
X (void) time (&now);
X while ((argc-- > 0) && (*(*++argv) == '-'))
X switch (*(*argv + 1))
X {
X case 's':
X if (*(*argv + 2) != '\0')
X str_to_int (*argv, 2, &mbox_size);
X else
X if ((argc>1) && (**(argv+1) >= '0') && (**(argv+1) <= '9'))
X {
X str_to_int (*++argv, 0, &mbox_size);
X argc--;
X }
X rep_size = TRUE;
X break;
X case 'd':
X if (*(*argv + 2) != '\0')
X str_to_int (*argv, 2, &mbox_days);
X else
X if ((argc>1) && (**(argv+1) >= '0') && (**(argv+1) <= '9'))
X {
X str_to_int (*++argv, 0, &mbox_days);
X argc--;
X }
X mbox_clock = now - 86400 * mbox_days;
X rep_days = TRUE;
X break;
X default :
X i = 1;
X do
X switch (*(*argv + i))
X {
X case 'a' : rep_alpha = TRUE; break;
X case 'g' : rep_gen = TRUE; break;
X case 'q' : rep_quiet = TRUE; break;
X default : usage ();
X }
X while (*(*argv + (++i)) != '\0');
X break;
X }
X if ((argc > 0) && !rep_gen)
X {
X while ((argc-- > 0) && (num_unames < MAXUSERNAMES))
X (void) strcpy (usernames[num_unames++], *argv++);
X if (num_unames >= MAXUSERNAMES)
X fatal ("Error: MAXUSERNAMES %d reached\n", MAXUSERNAMES);
X rep_names = TRUE;
X }
X if (!isatty (0) && !rep_gen)
X {
X while (getname (usernames[num_unames++], NMAX) > 0);
X if (num_unames >= MAXUSERNAMES)
X fatal ("Error: MAXUSERNAMES %d reached\n", MAXUSERNAMES);
X rep_names = TRUE;
X }
X if (rep_names)
X {
X qsort (usernames, num_unames, sizeof usernames[0], scmp);
X if (!rep_size && !rep_days)
X rep_alpha = TRUE;
X }
X else
X if (rep_gen && !rep_days && !rep_size)
X rep_alpha = TRUE; /* -g default */
X else
X if (rep_days)
X rep_size = FALSE; /* no conflict */
X else
X rep_size = TRUE; /* default */
X check_mailboxes ();
X}
X
Xsize_cmp (p, q)
Xstruct packet **p, **q;
X{
X if ((*p)->size == (*q)->size)
X return (0);
X if ((*p)->size > (*q)->size)
X return (-1);
X return (1);
X}
X
Xalpha_cmp (p, q)
Xstruct packet **p, **q;
X{
X return (strcmp ((*p)->name, (*q)->name));
X}
X
Xfiletime_cmp (p, q)
Xstruct packet **p, **q;
X{
X if ((*p)->filetime == (*q)->filetime)
X return (0);
X if ((*p)->filetime > (*q)->filetime)
X return (1);
X return (-1);
X}
X
Xcheck_mailboxes ()
X{
X DIR * etc;
X struct direct *dp;
X if (chdir ("/usr/spool/mail") < 0) {
X perror ("/usr/spool/mail"); exit (1);
X }
X if ((etc = opendir (".")) == NULL) {
X perror ("/usr/spool/mail"); exit (1);
X }
X packp = packs;
X while (dp = readdir (etc))
X {
X if (dp->d_ino == 0)
X continue;
X if (stat (dp->d_name, &stbuf) < 0)
X continue;
X if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
X continue;
X if (pack_count >= MAXPACKS)
X fatal ("%d MAXPACKS reached -- report aborted\n", MAXPACKS);
X if (rep_names)
X {
X if (binsearch (dp->d_name))
X {
X take_note (dp->d_name);
X if (pack_count >= num_unames)
X goto sortpacks; /* all names found */
X }
X continue;
X }
X mbox_total++;
X age_diff_accum += (stbuf.st_ctime - now);
X size_accum += stbuf.st_size;
X if ((rep_gen)
X || (rep_days && (stbuf.st_ctime < mbox_clock))
X || (rep_size && (stbuf.st_size > mbox_size)))
X take_note (dp->d_name);
X }
Xsortpacks:
X if (rep_alpha)
X qsort (packs, packp - packs, sizeof packs[0], alpha_cmp);
X else
X if (rep_days)
X qsort (packs, packp - packs, sizeof packs[0], filetime_cmp);
X else
X qsort (packs, packp - packs, sizeof packs[0], size_cmp);
X printout ();
X}
X
Xtake_note (name)
Xchar *name;
X{
X pack_count++;
X *packp = calloc (1, sizeof (struct packet));
X (void) strcpy ((*packp)->name, name);
X (*packp)->size = stbuf.st_size;
X (*packp)->filetime = stbuf.st_ctime;
X packp++;
X}
X
Xchar *
Xage_is (period)
Xlong int period;
X{
X int days, hours;
X char *string, temp[MAXSTRING];
X string = malloc (16);
X *string = '\0';
X days = period / 86400;
X hours = (period % 86400) / 3600;
X switch (days)
X {
X case 0:
X (void) sprintf (string, " ");
X break;
X case 1:
X (void) sprintf (string, "%3d Day ", days);
X break;
X default:
X (void) sprintf (string, "%3d Days ", days);
X }
X switch (hours)
X {
X case 0:
X (void) sprintf (temp, "%2d Mins ",
X (((period % 86400) % 3600) / 60));
X break;
X case 1:
X (void) sprintf (temp, "%2d Hour ", hours);
X break;
X default:
X (void) sprintf (temp, "%2d Hours", hours);
X break;
X }
X (void) strcat (string, temp);
X return (string);
X}
X
Xprintout ()
X{
X register struct packet **p;
X int f;
X struct passwd *pwd;
X struct lastlog ll;
X int i;
X char *s, host[10];
X if ((f = open ("/usr/adm/lastlog", 0)) < 0) {
X perror ("/usr/adm/lastlog"); exit (1);
X }
X if (!rep_quiet)
X {
X if (pack_count == 0)
X {
X printf ("No Report.\n");
X return;
X }
X for (i = 65; i-- > 0; putchar ('-'));
X putchar ('\n');
X (void) gethostname (host, 10);
X s = (char *) ctime (&now);
X printf ("%10s %.12s ", host, (s + 4));
X if (pack_count == 1)
X printf ("%d Mailbox", pack_count);
X else
X printf ("%d Mailboxes", pack_count);
X if (rep_names && (num_unames != pack_count))
X printf (" Found For %d Names", num_unames);
X else
X if (!rep_gen && !rep_names)
X {
X if (rep_days)
X printf (" Older Than %d Days", mbox_days);
X else
X if (rep_size)
X printf (" Larger Than %d", mbox_size);
X }
X if (!rep_names)
X printf ("\n\nTotal: %d Average Size: %d Average Age:%-16s",
X mbox_total, (size_accum/mbox_total),
X age_is ((age_diff_accum + now) / mbox_total));
X printf ("\n\n NAME MAILBOX SIZE");
X printf (" MAILBOX AGE LAST LOGIN\n");
X for (i = 65; i-- > 0; putchar ('-'));
X putchar ('\n');
X }
X for (p = packs; p < packp; p++)
X {
X printf ("%-8s", (*p)->name);
X printf (" %6d ", (*p)->size);
X printf ("%-16s", age_is (now - (*p)->filetime));
X if (((pwd = getpwnam ((*p)->name)) != NULL)
X && (lseek (f, (long) pwd->pw_uid * sizeof (struct lastlog), 0) >= 0)
X && (read (f, (char *) & ll, sizeof ll) == sizeof ll)
X && (ll.ll_time <= 0))
X printf (" no login record\n");
X else
X {
X s = (char *) ctime (&ll.ll_time);
X printf (" %.*s,%.*s\n", 24 - 18, (s + 4), 5, (s + 19));
X }
X }
X (void) close (f);
X}
X
Xbinsearch (target)
Xchar *target;
X{
X int hi, lo, mid, val;
X lo = 0;
X hi = num_unames - 1;
X while (TRUE)
X if (hi < lo)
X return (FALSE);
X else
X if ((val = strcmp (target, usernames[(mid = (lo + hi) / 2)])) == 0)
X return (TRUE);
X else
X if (val > 0)
X lo = mid + 1;
X else
X hi = mid - 1;
X}
X
Xstr_to_int (string, offset, num)
Xchar string[];
Xint offset, *num;
X{
X int i, place, sum;
X for (place = 1, sum = 0, i = strlen (string); i-- > offset; place *= 10)
X {
X if ((string [i] < '0') || (string [i] > '9'))
X usage ();
X else
X sum = sum + (string [i] - '0') * place;
X }
X *num = sum;
X}
X
Xgetname (line, lengthlim)
Xchar line[];
Xint lengthlim;
X{
X int i;
X char ch;
X for (i=0; i < lengthlim-1 && ((ch = getchar ()) != EOF)
X && (ch != '\n') && (ch != ' ') && (ch != '\t');)
X line[i++] = ch;
X line[i] = '\0';
X return (i);
X}
X
Xusage ()
X{
X fprintf (stderr, "Usage: cobwebs [-agq] [-d days] ");
X fprintf (stderr, "[-s size] [username ...]\n");
X exit (1);
X}
X
Xfatal (format, argument)
Xchar *format, *argument;
X{
X fprintf (stderr, format, argument);
X exit (1);
X}
//E*O*F cobwebs.c//
ls -l cobwebs.c
exit 0
More information about the Comp.sources.unix
mailing list