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