mailstats.c revision 77352
118334Speter/*
252284Sobrien * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
318334Speter *	All rights reserved.
418334Speter * Copyright (c) 1983 Eric P. Allman.  All rights reserved.
518334Speter * Copyright (c) 1988, 1993
618334Speter *	The Regents of the University of California.  All rights reserved.
718334Speter *
818334Speter * By using this file, you agree to the terms and conditions set
918334Speter * forth in the LICENSE file which can be found at the top level of
1018334Speter * the sendmail distribution.
1118334Speter *
1218334Speter *
1318334Speter */
1418334Speter
1518334Speter#ifndef lint
1618334Speterstatic char copyright[] =
1718334Speter"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
1818334Speter	All rights reserved.\n\
1918334Speter     Copyright (c) 1988, 1993\n\
2018334Speter	The Regents of the University of California.  All rights reserved.\n";
2118334Speter#endif /* ! lint */
2218334Speter
2318334Speter#ifndef lint
2418334Speterstatic char id[] = "@(#)$Id: mailstats.c,v 8.53.16.13 2001/05/07 22:06:38 gshapiro Exp $";
2518334Speter#endif /* ! lint */
2618334Speter
2718334Speter/* $FreeBSD: head/contrib/sendmail/mailstats/mailstats.c 77352 2001-05-28 17:10:35Z gshapiro $ */
2818334Speter
2918334Speter#include <unistd.h>
3018334Speter#include <stddef.h>
3118334Speter#include <stdlib.h>
3218334Speter#include <ctype.h>
3350397Sobrien#include <string.h>
3450397Sobrien#include <time.h>
3518334Speter#ifdef EX_OK
3618334Speter# undef EX_OK		/* unistd.h may have another use for this */
3718334Speter#endif /* EX_OK */
3818334Speter#include <sysexits.h>
3918334Speter
4018334Speter#include <sendmail/sendmail.h>
4118334Speter#include <sendmail/mailstats.h>
4218334Speter#include <sendmail/pathnames.h>
4318334Speter
4418334Speter
4518334Speter#define MNAMELEN	20	/* max length of mailer name */
4618334Speter
4718334Speter
4818334Speterint
4950397Sobrienmain(argc, argv)
5050397Sobrien	int argc;
5118334Speter	char **argv;
5250397Sobrien{
5350397Sobrien	register int i;
5450397Sobrien	int mno;
5518334Speter	int save_errno;
5650397Sobrien	int ch, fd;
5750397Sobrien	char *sfile;
5850397Sobrien	char *cfile;
5950397Sobrien	FILE *cfp;
6050397Sobrien	bool mnames;
6150397Sobrien	bool progmode;
6250397Sobrien	long frmsgs = 0, frbytes = 0, tomsgs = 0, tobytes = 0, rejmsgs = 0;
6350397Sobrien	long dismsgs = 0;
6450397Sobrien	time_t now;
6550397Sobrien	char mtable[MAXMAILERS][MNAMELEN + 1];
6650397Sobrien	char sfilebuf[MAXLINE];
6750397Sobrien	char buf[MAXLINE];
6850397Sobrien	struct statistics stats;
6950397Sobrien	extern char *ctime();
7050397Sobrien	extern char *optarg;
7118334Speter	extern int optind;
7218334Speter
7318334Speter
7418334Speter	cfile = _PATH_SENDMAILCF;
7518334Speter	sfile = NULL;
7618334Speter	mnames = TRUE;
7718334Speter	progmode = FALSE;
7818334Speter	while ((ch = getopt(argc, argv, "C:f:op")) != -1)
7918334Speter	{
8018334Speter		switch (ch)
8118334Speter		{
8218334Speter		  case 'C':
8318334Speter			cfile = optarg;
8418334Speter			break;
8518334Speter
8618334Speter		  case 'f':
8718334Speter			sfile = optarg;
8818334Speter			break;
8918334Speter
9018334Speter		  case 'o':
9118334Speter			mnames = FALSE;
9218334Speter			break;
9318334Speter
9452284Sobrien		  case 'p':
9552284Sobrien			progmode = TRUE;
9652284Sobrien			break;
9752284Sobrien
9852284Sobrien		  case '?':
9952284Sobrien		  default:
10052284Sobrien  usage:
10152284Sobrien			(void) fputs("usage: mailstats [-C cffile] [-f stfile] [-o] [-p]\n",
10252284Sobrien				     stderr);
10352284Sobrien			exit(EX_USAGE);
10452284Sobrien		}
10552284Sobrien	}
10652284Sobrien	argc -= optind;
10752284Sobrien	argv += optind;
10852284Sobrien
10952284Sobrien	if (argc != 0)
11052284Sobrien		goto usage;
11152284Sobrien
11252284Sobrien	if ((cfp = fopen(cfile, "r")) == NULL)
11318334Speter	{
11418334Speter		save_errno = errno;
11552284Sobrien		fprintf(stderr, "mailstats: ");
11652284Sobrien		errno = save_errno;
11752284Sobrien		perror(cfile);
11852284Sobrien		exit(EX_NOINPUT);
11952284Sobrien	}
12052284Sobrien
12152284Sobrien	mno = 0;
12252284Sobrien	(void) strlcpy(mtable[mno++], "prog", MNAMELEN + 1);
12318334Speter	(void) strlcpy(mtable[mno++], "*file*", MNAMELEN + 1);
12418334Speter	(void) strlcpy(mtable[mno++], "*include*", MNAMELEN + 1);
12518334Speter
12618334Speter	while (fgets(buf, sizeof(buf), cfp) != NULL)
12752284Sobrien	{
12852284Sobrien		register char *b;
12952284Sobrien		char *s;
13018334Speter		register char *m;
13118334Speter
13252284Sobrien		b = buf;
13318334Speter		switch (*b++)
13418334Speter		{
13518334Speter		  case 'M':		/* mailer definition */
13618334Speter			break;
13718334Speter
13818334Speter		  case 'O':		/* option -- see if .st file */
13918334Speter			if (strncasecmp(b, " StatusFile", 11) == 0 &&
14018334Speter			    !(isascii(b[11]) && isalnum(b[11])))
14118334Speter			{
14218334Speter				/* new form -- find value */
14318334Speter				b = strchr(b, '=');
14418334Speter				if (b == NULL)
14518334Speter					continue;
14618334Speter				while (isascii(*++b) && isspace(*b))
14718334Speter					continue;
14818334Speter			}
14918334Speter			else if (*b++ != 'S')
15018334Speter			{
15118334Speter				/* something else boring */
15218334Speter				continue;
15318334Speter			}
15418334Speter
15518334Speter			/* this is the S or StatusFile option -- save it */
15618334Speter			if (strlcpy(sfilebuf, b, sizeof sfilebuf) >=
15750397Sobrien			    sizeof sfilebuf)
15850397Sobrien			{
15950397Sobrien				fprintf(stderr,
16050397Sobrien					"StatusFile filename too long: %.30s...\n",
16118334Speter					b);
16218334Speter				exit(EX_CONFIG);
16318334Speter			}
16418334Speter			b = strchr(sfilebuf, '#');
16518334Speter			if (b == NULL)
16618334Speter				b = strchr(sfilebuf, '\n');
16718334Speter			if (b == NULL)
16850397Sobrien				b = &sfilebuf[strlen(sfilebuf)];
16918334Speter			while (isascii(*--b) && isspace(*b))
17018334Speter				continue;
17118334Speter			*++b = '\0';
17218334Speter			if (sfile == NULL)
17318334Speter				sfile = sfilebuf;
17418334Speter
17518334Speter		  default:
17618334Speter			continue;
17718334Speter		}
17818334Speter
17918334Speter		if (mno >= MAXMAILERS)
18018334Speter		{
18118334Speter			fprintf(stderr,
18218334Speter				"Too many mailers defined, %d max.\n",
18318334Speter				MAXMAILERS);
18418334Speter			exit(EX_SOFTWARE);
18518334Speter		}
18618334Speter		m = mtable[mno];
18718334Speter		s = m + MNAMELEN;		/* is [MNAMELEN + 1] */
18818334Speter		while (*b != ',' && !(isascii(*b) && isspace(*b)) &&
18918334Speter		       *b != '\0' && m < s)
19018334Speter			*m++ = *b++;
19118334Speter		*m = '\0';
19218334Speter		for (i = 0; i < mno; i++)
19318334Speter		{
19418334Speter			if (strcmp(mtable[i], mtable[mno]) == 0)
19518334Speter				break;
19618334Speter		}
19718334Speter		if (i == mno)
19850397Sobrien			mno++;
19918334Speter	}
20018334Speter	(void) fclose(cfp);
20118334Speter	for (; mno < MAXMAILERS; mno++)
20218334Speter		mtable[mno][0]='\0';
20318334Speter
20418334Speter	if (sfile == NULL)
20518334Speter	{
20618334Speter		fprintf(stderr, "mailstats: no statistics file located\n");
20718334Speter		exit (EX_OSFILE);
20818334Speter	}
20918334Speter
21018334Speter	fd = open(sfile, O_RDONLY);
21118334Speter	if ((fd < 0) || (i = read(fd, &stats, sizeof stats)) < 0)
21218334Speter	{
21318334Speter		save_errno = errno;
21418334Speter		(void) fputs("mailstats: ", stderr);
21518334Speter		errno = save_errno;
21618334Speter		perror(sfile);
21718334Speter		exit(EX_NOINPUT);
21818334Speter	}
21918334Speter	if (i == 0)
22018334Speter	{
22118334Speter		(void) sleep(1);
22218334Speter		if ((i = read(fd, &stats, sizeof stats)) < 0)
22318334Speter		{
22418334Speter			save_errno = errno;
22518334Speter			(void) fputs("mailstats: ", stderr);
22618334Speter			errno = save_errno;
22718334Speter			perror(sfile);
22818334Speter			exit(EX_NOINPUT);
22918334Speter		}
23050397Sobrien		else if (i == 0)
23150397Sobrien		{
23250397Sobrien			memset((ARBPTR_T) &stats, '\0', sizeof stats);
23350397Sobrien			(void) time(&stats.stat_itime);
23450397Sobrien		}
23552284Sobrien	}
23652284Sobrien	if (i != 0)
23752284Sobrien	{
23852284Sobrien		if (stats.stat_magic != STAT_MAGIC)
23952284Sobrien		{
24052284Sobrien			fprintf(stderr,
24152284Sobrien				"mailstats: incorrect magic number in %s\n",
24252284Sobrien				sfile);
24352284Sobrien			exit(EX_OSERR);
24452284Sobrien		}
24552284Sobrien		else if (stats.stat_version != STAT_VERSION)
24618334Speter		{
24718334Speter			fprintf(stderr,
24818334Speter				"mailstats version (%d) incompatible with %s version (%d)\n",
24918334Speter				STAT_VERSION, sfile, stats.stat_version);
25018334Speter			exit(EX_OSERR);
25118334Speter		}
25218334Speter		else if (i != sizeof stats || stats.stat_size != sizeof(stats))
25318334Speter		{
25418334Speter			(void) fputs("mailstats: file size changed.\n", stderr);
25518334Speter			exit(EX_OSERR);
25618334Speter		}
25718334Speter	}
25818334Speter
25918334Speter	if (progmode)
26018334Speter	{
26118334Speter		(void) time(&now);
26250397Sobrien		printf("%ld %ld\n", (long) stats.stat_itime, (long) now);
26318334Speter	}
26418334Speter	else
26518334Speter	{
26618334Speter		printf("Statistics from %s", ctime(&stats.stat_itime));
26718334Speter		printf(" M   msgsfr  bytes_from   msgsto    bytes_to  msgsrej msgsdis%s\n",
26818334Speter			mnames ? "  Mailer" : "");
26918334Speter	}
27018334Speter	for (i = 0; i < MAXMAILERS; i++)
27118334Speter	{
27218334Speter		if (stats.stat_nf[i] || stats.stat_nt[i] ||
27350397Sobrien		    stats.stat_nr[i] || stats.stat_nd[i])
27418334Speter		{
27518334Speter			char *format;
27618334Speter
27718334Speter			if (progmode)
27818334Speter				format = "%2d %8ld %10ld %8ld %10ld   %6ld  %6ld";
27918334Speter			else
28018334Speter				format = "%2d %8ld %10ldK %8ld %10ldK   %6ld  %6ld";
28150397Sobrien			printf(format, i,
28250397Sobrien			    stats.stat_nf[i], stats.stat_bf[i],
28350397Sobrien			    stats.stat_nt[i], stats.stat_bt[i],
28450397Sobrien			    stats.stat_nr[i], stats.stat_nd[i]);
28550397Sobrien			if (mnames)
28650397Sobrien				printf("  %s", mtable[i]);
28750397Sobrien			printf("\n");
28850397Sobrien			frmsgs += stats.stat_nf[i];
28950397Sobrien			frbytes += stats.stat_bf[i];
29050397Sobrien			tomsgs += stats.stat_nt[i];
29150397Sobrien			tobytes += stats.stat_bt[i];
29250397Sobrien			rejmsgs += stats.stat_nr[i];
29350397Sobrien			dismsgs += stats.stat_nd[i];
29450397Sobrien		}
29550397Sobrien	}
29650397Sobrien	if (progmode)
29750397Sobrien	{
29850397Sobrien		printf(" T %8ld %10ld %8ld %10ld   %6ld  %6ld\n",
29950397Sobrien		       frmsgs, frbytes, tomsgs, tobytes, rejmsgs, dismsgs);
30050397Sobrien		printf(" C %8ld %8ld %6ld\n",
30150397Sobrien		       stats.stat_cf, stats.stat_ct, stats.stat_cr);
30250397Sobrien		(void) close(fd);
30350397Sobrien		fd = open(sfile, O_RDWR | O_TRUNC);
30450397Sobrien		if (fd >= 0)
30550397Sobrien			(void) close(fd);
30650397Sobrien	}
30750397Sobrien	else
30850397Sobrien	{
30950397Sobrien		printf("=============================================================\n");
31050397Sobrien		printf(" T %8ld %10ldK %8ld %10ldK   %6ld  %6ld\n",
31150397Sobrien			frmsgs, frbytes, tomsgs, tobytes, rejmsgs, dismsgs);
31250397Sobrien		printf(" C %8ld %10s  %8ld %10s    %6ld\n",
31350397Sobrien		       stats.stat_cf, "", stats.stat_ct, "", stats.stat_cr);
31450397Sobrien	}
31550397Sobrien	exit(EX_OK);
31650397Sobrien	/* NOTREACHED */
31750397Sobrien	return EX_OK;
31850397Sobrien}
31950397Sobrien