1 /* 2 * Copyright (c) 1998-2002 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 #include <sm/gen.h> 16 17 SM_IDSTR(copyright, 18 "@(#) Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.\n\ 19 All rights reserved.\n\ 20 Copyright (c) 1988, 1993\n\ 21 The Regents of the University of California. All rights reserved.\n") 22 23 SM_IDSTR(id, "@(#)$Id: mailstats.c,v 8.100 2002/06/27 23:24:06 gshapiro Exp $") 24 25 #include <unistd.h> 26 #include <stddef.h> 27 #include <stdlib.h> 28 #include <ctype.h> 29 #include <string.h> 30 #include <time.h> 31 #ifdef EX_OK 32 # undef EX_OK /* unistd.h may have another use for this */ 33 #endif /* EX_OK */ 34 #include <sysexits.h> 35 36 #include <sm/errstring.h> 37 #include <sm/limits.h> 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 int 46 main(argc, argv) 47 int argc; 48 char **argv; 49 { 50 register int i; 51 int mno; 52 int save_errno; 53 int ch, fd; 54 char *sfile; 55 char *cfile; 56 SM_FILE_T *cfp; 57 bool mnames; 58 bool progmode; 59 bool trunc; 60 long frmsgs = 0, frbytes = 0, tomsgs = 0, tobytes = 0, rejmsgs = 0; 61 long dismsgs = 0; 62 long quarmsgs = 0; 63 time_t now; 64 char mtable[MAXMAILERS][MNAMELEN + 1]; 65 char sfilebuf[MAXPATHLEN]; 66 char buf[MAXLINE]; 67 struct statistics stats; 68 extern char *ctime(); 69 extern char *optarg; 70 extern int optind; 71 72 cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL); 73 sfile = NULL; 74 mnames = true; 75 progmode = false; 76 trunc = false; 77 while ((ch = getopt(argc, argv, "cC:f:opP")) != -1) 78 { 79 switch (ch) 80 { 81 case 'c': 82 cfile = getcfname(0, 0, SM_GET_SUBMIT_CF, NULL); 83 break; 84 85 case 'C': 86 cfile = optarg; 87 break; 88 89 case 'f': 90 sfile = optarg; 91 break; 92 93 case 'o': 94 mnames = false; 95 break; 96 97 case 'p': 98 trunc = true; 99 /* FALLTHROUGH */ 100 101 case 'P': 102 progmode = true; 103 break; 104 105 case '?': 106 default: 107 usage: 108 (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, 109 "usage: mailstats [-C cffile] [-c] [-P] [-f stfile] [-o] [-p]\n"); 110 exit(EX_USAGE); 111 } 112 } 113 argc -= optind; 114 argv += optind; 115 116 if (argc != 0) 117 goto usage; 118 119 if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY, 120 NULL)) == NULL) 121 { 122 save_errno = errno; 123 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "mailstats: "); 124 errno = save_errno; 125 sm_perror(cfile); 126 exit(EX_NOINPUT); 127 } 128 129 mno = 0; 130 (void) sm_strlcpy(mtable[mno++], "prog", MNAMELEN + 1); 131 (void) sm_strlcpy(mtable[mno++], "*file*", MNAMELEN + 1); 132 (void) sm_strlcpy(mtable[mno++], "*include*", MNAMELEN + 1); 133 134 while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL) 135 { 136 register char *b; 137 char *s; 138 register char *m; 139 140 b = strchr(buf, '#'); 141 if (b == NULL) 142 b = strchr(buf, '\n'); 143 if (b == NULL) 144 b = &buf[strlen(buf)]; 145 while (isascii(*--b) && isspace(*b)) 146 continue; 147 *++b = '\0'; 148 149 b = buf; 150 switch (*b++) 151 { 152 case 'M': /* mailer definition */ 153 break; 154 155 case 'O': /* option -- see if .st file */ 156 if (sm_strncasecmp(b, " StatusFile", 11) == 0 && 157 !(isascii(b[11]) && isalnum(b[11]))) 158 { 159 /* new form -- find value */ 160 b = strchr(b, '='); 161 if (b == NULL) 162 continue; 163 while (isascii(*++b) && isspace(*b)) 164 continue; 165 } 166 else if (*b++ != 'S') 167 { 168 /* something else boring */ 169 continue; 170 } 171 172 /* this is the S or StatusFile option -- save it */ 173 if (sm_strlcpy(sfilebuf, b, sizeof sfilebuf) >= 174 sizeof sfilebuf) 175 { 176 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 177 "StatusFile filename too long: %.30s...\n", 178 b); 179 exit(EX_CONFIG); 180 } 181 if (sfile == NULL) 182 sfile = sfilebuf; 183 /* FALLTHROUGH */ 184 185 default: 186 continue; 187 } 188 189 if (mno >= MAXMAILERS) 190 { 191 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 192 "Too many mailers defined, %d max.\n", 193 MAXMAILERS); 194 exit(EX_SOFTWARE); 195 } 196 m = mtable[mno]; 197 s = m + MNAMELEN; /* is [MNAMELEN + 1] */ 198 while (*b != ',' && !(isascii(*b) && isspace(*b)) && 199 *b != '\0' && m < s) 200 *m++ = *b++; 201 *m = '\0'; 202 for (i = 0; i < mno; i++) 203 { 204 if (strcmp(mtable[i], mtable[mno]) == 0) 205 break; 206 } 207 if (i == mno) 208 mno++; 209 } 210 (void) sm_io_close(cfp, SM_TIME_DEFAULT); 211 for (; mno < MAXMAILERS; mno++) 212 mtable[mno][0] = '\0'; 213 214 if (sfile == NULL) 215 { 216 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 217 "mailstats: no statistics file located\n"); 218 exit(EX_OSFILE); 219 } 220 221 fd = open(sfile, O_RDONLY, 0600); 222 if ((fd < 0) || (i = read(fd, &stats, sizeof stats)) < 0) 223 { 224 save_errno = errno; 225 (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, "mailstats: "); 226 errno = save_errno; 227 sm_perror(sfile); 228 exit(EX_NOINPUT); 229 } 230 if (i == 0) 231 { 232 (void) sleep(1); 233 if ((i = read(fd, &stats, sizeof stats)) < 0) 234 { 235 save_errno = errno; 236 (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, 237 "mailstats: "); 238 errno = save_errno; 239 sm_perror(sfile); 240 exit(EX_NOINPUT); 241 } 242 else if (i == 0) 243 { 244 memset((ARBPTR_T) &stats, '\0', sizeof stats); 245 (void) time(&stats.stat_itime); 246 } 247 } 248 if (i != 0) 249 { 250 if (stats.stat_magic != STAT_MAGIC) 251 { 252 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 253 "mailstats: incorrect magic number in %s\n", 254 sfile); 255 exit(EX_OSERR); 256 } 257 else if (stats.stat_version != STAT_VERSION) 258 { 259 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 260 "mailstats version (%d) incompatible with %s version (%d)\n", 261 STAT_VERSION, sfile, 262 stats.stat_version); 263 264 exit(EX_OSERR); 265 } 266 else if (i != sizeof stats || stats.stat_size != sizeof(stats)) 267 { 268 (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, 269 "mailstats: file size changed.\n"); 270 exit(EX_OSERR); 271 } 272 } 273 274 if (progmode) 275 { 276 (void) time(&now); 277 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%ld %ld\n", 278 (long) stats.stat_itime, (long) now); 279 } 280 else 281 { 282 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 283 "Statistics from %s", 284 ctime(&stats.stat_itime)); 285 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 286 " M msgsfr bytes_from msgsto bytes_to msgsrej msgsdis"); 287 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " msgsqur"); 288 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", 289 mnames ? " Mailer" : ""); 290 } 291 for (i = 0; i < MAXMAILERS; i++) 292 { 293 if (stats.stat_nf[i] || stats.stat_nt[i] || 294 stats.stat_nq[i] || 295 stats.stat_nr[i] || stats.stat_nd[i]) 296 { 297 char *format; 298 299 if (progmode) 300 format = "%2d %8ld %10ld %8ld %10ld %6ld %6ld"; 301 else 302 format = "%2d %8ld %10ldK %8ld %10ldK %6ld %6ld"; 303 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 304 format, i, 305 stats.stat_nf[i], 306 stats.stat_bf[i], 307 stats.stat_nt[i], 308 stats.stat_bt[i], 309 stats.stat_nr[i], 310 stats.stat_nd[i]); 311 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 312 " %6ld", stats.stat_nq[i]); 313 if (mnames) 314 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 315 " %s", 316 mtable[i]); 317 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); 318 frmsgs += stats.stat_nf[i]; 319 frbytes += stats.stat_bf[i]; 320 tomsgs += stats.stat_nt[i]; 321 tobytes += stats.stat_bt[i]; 322 rejmsgs += stats.stat_nr[i]; 323 dismsgs += stats.stat_nd[i]; 324 quarmsgs += stats.stat_nq[i]; 325 } 326 } 327 if (progmode) 328 { 329 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 330 " T %8ld %10ld %8ld %10ld %6ld %6ld", 331 frmsgs, frbytes, tomsgs, tobytes, rejmsgs, 332 dismsgs); 333 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 334 " %6ld", quarmsgs); 335 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); 336 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 337 " C %8ld %8ld %6ld\n", 338 stats.stat_cf, stats.stat_ct, 339 stats.stat_cr); 340 (void) close(fd); 341 if (trunc) 342 { 343 fd = open(sfile, O_RDWR | O_TRUNC, 0600); 344 if (fd >= 0) 345 (void) close(fd); 346 } 347 } 348 else 349 { 350 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 351 "============================================================="); 352 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "========"); 353 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); 354 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 355 " T %8ld %10ldK %8ld %10ldK %6ld %6ld", 356 frmsgs, frbytes, tomsgs, tobytes, rejmsgs, 357 dismsgs); 358 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 359 " %6ld", quarmsgs); 360 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); 361 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 362 " C %8ld %10s %8ld %10s %6ld\n", 363 stats.stat_cf, "", stats.stat_ct, "", 364 stats.stat_cr); 365 } 366 exit(EX_OK); 367 /* NOTREACHED */ 368 return EX_OK; 369 } 370