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