xref: /freebsd/contrib/sendmail/mailstats/mailstats.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 /*
2  * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3  * Copyright (c) 1983 Eric P. Allman.  All rights reserved.
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * By using this file, you agree to the terms and conditions set
8  * forth in the LICENSE file which can be found at the top level of
9  * the sendmail distribution.
10  *
11  *
12  */
13 
14 #ifndef lint
15 static char copyright[] =
16 "@(#) Copyright (c) 1988, 1993\n\
17 	The Regents of the University of California.  All rights reserved.\n";
18 #endif /* not lint */
19 
20 #ifndef lint
21 static char sccsid[] = "@(#)mailstats.c	8.29 (Berkeley) 1/25/1999";
22 #endif /* not lint */
23 
24 #ifndef NOT_SENDMAIL
25 # define NOT_SENDMAIL
26 #endif
27 #include <sendmail.h>
28 #include <mailstats.h>
29 #include <pathnames.h>
30 
31 #define MNAMELEN	20	/* max length of mailer name */
32 
33 int
34 main(argc, argv)
35 	int argc;
36 	char **argv;
37 {
38 	extern char *optarg;
39 	extern int optind;
40 	struct statistics stat;
41 	register int i;
42 	int mno;
43 	int ch, fd;
44 	char *sfile;
45 	char *cfile;
46 	FILE *cfp;
47 	bool mnames;
48 	bool progmode;
49 	long frmsgs = 0, frbytes = 0, tomsgs = 0, tobytes = 0, rejmsgs = 0;
50 	long dismsgs = 0;
51 	char mtable[MAXMAILERS][MNAMELEN+1];
52 	char sfilebuf[MAXLINE];
53 	char buf[MAXLINE];
54 	time_t now;
55 	extern char *ctime();
56 
57 	cfile = _PATH_SENDMAILCF;
58 	sfile = NULL;
59 	mnames = TRUE;
60 	progmode = FALSE;
61 	while ((ch = getopt(argc, argv, "C:f:op")) != -1)
62 	{
63 		switch (ch)
64 		{
65 		  case 'C':
66 			cfile = optarg;
67 			break;
68 
69 		  case 'f':
70 			sfile = optarg;
71 			break;
72 
73 		  case 'o':
74 			mnames = FALSE;
75 			break;
76 
77 #if _FFR_MAILSTATS_PROGMODE
78 		  case 'p':
79 			progmode = TRUE;
80 			break;
81 #endif
82 
83 		  case '?':
84 		  default:
85   usage:
86 #if _FFR_MAILSTATS_PROGMODE
87 			fputs("usage: mailstats [-o] [-C cffile] [-f stfile] -o -p\n",
88 				stderr);
89 #else
90 			fputs("usage: mailstats [-o] [-C cffile] [-f stfile] -o \n",
91 				stderr);
92 #endif
93 			exit(EX_USAGE);
94 		}
95 	}
96 	argc -= optind;
97 	argv += optind;
98 
99 	if (argc != 0)
100 		goto usage;
101 
102 	if ((cfp = fopen(cfile, "r")) == NULL)
103 	{
104 		fprintf(stderr, "mailstats: ");
105 		perror(cfile);
106 		exit(EX_NOINPUT);
107 	}
108 
109 	mno = 0;
110 	(void) strcpy(mtable[mno++], "prog");
111 	(void) strcpy(mtable[mno++], "*file*");
112 	(void) strcpy(mtable[mno++], "*include*");
113 
114 	while (fgets(buf, sizeof(buf), cfp) != NULL)
115 	{
116 		register char *b;
117 		char *s;
118 		register char *m;
119 
120 		b = buf;
121 		switch (*b++)
122 		{
123 		  case 'M':		/* mailer definition */
124 			break;
125 
126 		  case 'O':		/* option -- see if .st file */
127 			if (strncasecmp(b, " StatusFile", 11) == 0 &&
128 			    !(isascii(b[11]) && isalnum(b[11])))
129 			{
130 				/* new form -- find value */
131 				b = strchr(b, '=');
132 				if (b == NULL)
133 					continue;
134 				while (isascii(*++b) && isspace(*b))
135 					continue;
136 			}
137 			else if (*b++ != 'S')
138 			{
139 				/* something else boring */
140 				continue;
141 			}
142 
143 			/* this is the S or StatusFile option -- save it */
144 			if (strlen(b) >= sizeof sfilebuf)
145 			{
146 				fprintf(stderr,
147 					"StatusFile filename too long: %.30s...\n",
148 					b);
149 				exit(EX_CONFIG);
150 			}
151 			strcpy(sfilebuf, b);
152 			b = strchr(sfilebuf, '#');
153 			if (b == NULL)
154 				b = strchr(sfilebuf, '\n');
155 			if (b == NULL)
156 				b = &sfilebuf[strlen(sfilebuf)];
157 			while (isascii(*--b) && isspace(*b))
158 				continue;
159 			*++b = '\0';
160 			if (sfile == NULL)
161 				sfile = sfilebuf;
162 
163 		  default:
164 			continue;
165 		}
166 
167 		if (mno >= MAXMAILERS)
168 		{
169 			fprintf(stderr,
170 				"Too many mailers defined, %d max.\n",
171 				MAXMAILERS);
172 			exit(EX_SOFTWARE);
173 		}
174 		m = mtable[mno];
175 		s = m + MNAMELEN;		/* is [MNAMELEN+1] */
176 		while (*b != ',' && !(isascii(*b) && isspace(*b)) &&
177 		       *b != '\0' && m < s)
178 			*m++ = *b++;
179 		*m = '\0';
180 		for (i = 0; i < mno; i++)
181 		{
182 			if (strcmp(mtable[i], mtable[mno]) == 0)
183 				break;
184 		}
185 		if (i == mno)
186 			mno++;
187 	}
188 	(void) fclose(cfp);
189 	for (; mno < MAXMAILERS; mno++)
190 		mtable[mno][0]='\0';
191 
192 	if (sfile == NULL)
193 	{
194 		fprintf(stderr, "mailstats: no statistics file located\n");
195 		exit (EX_OSFILE);
196 	}
197 
198 	if ((fd = open(sfile, O_RDONLY)) < 0 ||
199 	    (i = read(fd, &stat, sizeof stat)) < 0)
200 	{
201 		fputs("mailstats: ", stderr);
202 		perror(sfile);
203 		exit(EX_NOINPUT);
204 	}
205 	if (i == 0)
206 	{
207 		sleep(1);
208 		if ((i = read(fd, &stat, sizeof stat)) < 0)
209 		{
210 			fputs("mailstats: ", stderr);
211 			perror(sfile);
212 			exit(EX_NOINPUT);
213 		}
214 		else if (i == 0)
215 		{
216 			bzero((ARBPTR_T) &stat, sizeof stat);
217 			(void) time(&stat.stat_itime);
218 		}
219 	}
220 	if (i != 0)
221 	{
222 		if (stat.stat_magic != STAT_MAGIC)
223 		{
224 			fprintf(stderr,
225 				"mailstats: incorrect magic number in %s\n",
226 				sfile);
227 			exit(EX_OSERR);
228 		}
229 		else if (stat.stat_version != STAT_VERSION)
230 		{
231 			fprintf(stderr,
232 				"mailstats version (%d) incompatible with %s version(%d)\n",
233 				STAT_VERSION, sfile, stat.stat_version);
234 			exit(EX_OSERR);
235 		}
236 		else if (i != sizeof stat || stat.stat_size != sizeof(stat))
237 		{
238 			fputs("mailstats: file size changed.\n", stderr);
239 			exit(EX_OSERR);
240 		}
241 	}
242 
243 	if (progmode)
244 	{
245 		time(&now);
246 		printf("%ld %ld\n", (long) stat.stat_itime, (long) now);
247 	}
248 	else
249 	{
250 		printf("Statistics from %s", ctime(&stat.stat_itime));
251 		printf(" M   msgsfr  bytes_from   msgsto    bytes_to  msgsrej msgsdis%s\n",
252 			mnames ? "  Mailer" : "");
253 	}
254 	for (i = 0; i < MAXMAILERS; i++)
255 	{
256 		if (stat.stat_nf[i] || stat.stat_nt[i] ||
257 		    stat.stat_nr[i] || stat.stat_nd[i])
258 		{
259 			char *format;
260 
261 			if (progmode)
262 				format = "%2d %8ld %10ld %8ld %10ld   %6ld  %6ld";
263 			else
264 				format = "%2d %8ld %10ldK %8ld %10ldK   %6ld  %6ld";
265 			printf(format, i,
266 			    stat.stat_nf[i], stat.stat_bf[i],
267 			    stat.stat_nt[i], stat.stat_bt[i],
268 			    stat.stat_nr[i], stat.stat_nd[i]);
269 			if (mnames)
270 				printf("  %s", mtable[i]);
271 			printf("\n");
272 			frmsgs += stat.stat_nf[i];
273 			frbytes += stat.stat_bf[i];
274 			tomsgs += stat.stat_nt[i];
275 			tobytes += stat.stat_bt[i];
276 			rejmsgs += stat.stat_nr[i];
277 			dismsgs += stat.stat_nd[i];
278 		}
279 	}
280 	if (progmode)
281 	{
282 		printf(" T %8ld %10ld %8ld %10ld   %6ld  %6ld\n",
283 		       frmsgs, frbytes, tomsgs, tobytes, rejmsgs, dismsgs);
284 		close(fd);
285 		fd = open(sfile, O_RDWR | O_TRUNC);
286 		if (fd >= 0)
287 			close(fd);
288 	}
289 	else
290 	{
291 		printf("=============================================================\n");
292 		printf(" T %8ld %10ldK %8ld %10ldK   %6ld  %6ld\n",
293 			frmsgs, frbytes, tomsgs, tobytes, rejmsgs, dismsgs);
294 	}
295 	exit(EX_OK);
296 }
297