xref: /freebsd/contrib/sendmail/src/stats.c (revision e0c4386e7e71d93b0edc0c8fa156263fc4a8b0b6)
1 /*
2  * Copyright (c) 1998-2002 Proofpoint, Inc. and its suppliers.
3  *	All rights reserved.
4  * Copyright (c) 1983, 1995-1997 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 #include <sendmail.h>
15 
16 SM_RCSID("@(#)$Id: stats.c,v 8.58 2013-11-22 20:51:56 ca Exp $")
17 
18 #include <sendmail/mailstats.h>
19 
20 static struct statistics	Stat;
21 
22 static bool	GotStats = false;	/* set when we have stats to merge */
23 
24 /* See http://physics.nist.gov/cuu/Units/binary.html */
25 #define ONE_K		1000		/* one thousand (twenty-four?) */
26 #define KBYTES(x)	(((x) + (ONE_K - 1)) / ONE_K)
27 /*
28 **  MARKSTATS -- mark statistics
29 **
30 **	Parameters:
31 **		e -- the envelope.
32 **		to -- to address.
33 **		type -- type of stats this represents.
34 **
35 **	Returns:
36 **		none.
37 **
38 **	Side Effects:
39 **		changes static Stat structure
40 */
41 
42 void
43 markstats(e, to, type)
44 	register ENVELOPE *e;
45 	register ADDRESS *to;
46 	int type;
47 {
48 	switch (type)
49 	{
50 	  case STATS_QUARANTINE:
51 		if (e->e_from.q_mailer != NULL)
52 			Stat.stat_nq[e->e_from.q_mailer->m_mno]++;
53 		break;
54 
55 	  case STATS_REJECT:
56 		if (e->e_from.q_mailer != NULL)
57 		{
58 			if (bitset(EF_DISCARD, e->e_flags))
59 				Stat.stat_nd[e->e_from.q_mailer->m_mno]++;
60 			else
61 				Stat.stat_nr[e->e_from.q_mailer->m_mno]++;
62 		}
63 		Stat.stat_cr++;
64 		break;
65 
66 	  case STATS_CONNECT:
67 		if (to == NULL)
68 			Stat.stat_cf++;
69 		else
70 			Stat.stat_ct++;
71 		break;
72 
73 	  case STATS_NORMAL:
74 		if (to == NULL)
75 		{
76 			if (e->e_from.q_mailer != NULL)
77 			{
78 				Stat.stat_nf[e->e_from.q_mailer->m_mno]++;
79 				Stat.stat_bf[e->e_from.q_mailer->m_mno] +=
80 					KBYTES(e->e_msgsize);
81 			}
82 		}
83 		else
84 		{
85 			Stat.stat_nt[to->q_mailer->m_mno]++;
86 			Stat.stat_bt[to->q_mailer->m_mno] += KBYTES(e->e_msgsize);
87 		}
88 		break;
89 
90 	  default:
91 		/* Silently ignore bogus call */
92 		return;
93 	}
94 
95 
96 	GotStats = true;
97 }
98 /*
99 **  CLEARSTATS -- clear statistics structure
100 **
101 **	Parameters:
102 **		none.
103 **
104 **	Returns:
105 **		none.
106 **
107 **	Side Effects:
108 **		clears the Stat structure.
109 */
110 
111 void
112 clearstats()
113 {
114 	/* clear the structure to avoid future disappointment */
115 	memset(&Stat, '\0', sizeof(Stat));
116 	GotStats = false;
117 }
118 /*
119 **  POSTSTATS -- post statistics in the statistics file
120 **
121 **	Parameters:
122 **		sfile -- the name of the statistics file.
123 **
124 **	Returns:
125 **		none.
126 **
127 **	Side Effects:
128 **		merges the Stat structure with the sfile file.
129 */
130 
131 void
132 poststats(sfile)
133 	char *sfile;
134 {
135 	int fd;
136 	static bool entered = false;
137 	long sff = SFF_REGONLY|SFF_OPENASROOT;
138 	struct statistics stats;
139 	extern off_t lseek __P((int, off_t, int));
140 
141 	if (sfile == NULL || *sfile == '\0' || !GotStats || entered)
142 		return;
143 	entered = true;
144 
145 	(void) time(&Stat.stat_itime);
146 	Stat.stat_size = sizeof(Stat);
147 	Stat.stat_magic = STAT_MAGIC;
148 	Stat.stat_version = STAT_VERSION;
149 
150 	if (!bitnset(DBS_WRITESTATSTOSYMLINK, DontBlameSendmail))
151 		sff |= SFF_NOSLINK;
152 	if (!bitnset(DBS_WRITESTATSTOHARDLINK, DontBlameSendmail))
153 		sff |= SFF_NOHLINK;
154 
155 	fd = safeopen(sfile, O_RDWR, 0600, sff);
156 	if (fd < 0)
157 	{
158 		if (LogLevel > 12)
159 			sm_syslog(LOG_INFO, NOQID, "poststats: %s: %s",
160 				  sfile, sm_errstring(errno));
161 		errno = 0;
162 		entered = false;
163 		return;
164 	}
165 	if (read(fd, (char *) &stats, sizeof(stats)) == sizeof(stats) &&
166 	    stats.stat_size == sizeof(stats) &&
167 	    stats.stat_magic == Stat.stat_magic &&
168 	    stats.stat_version == Stat.stat_version)
169 	{
170 		/* merge current statistics into statfile */
171 		register int i;
172 
173 		for (i = 0; i < MAXMAILERS; i++)
174 		{
175 			stats.stat_nf[i] += Stat.stat_nf[i];
176 			stats.stat_bf[i] += Stat.stat_bf[i];
177 			stats.stat_nt[i] += Stat.stat_nt[i];
178 			stats.stat_bt[i] += Stat.stat_bt[i];
179 			stats.stat_nr[i] += Stat.stat_nr[i];
180 			stats.stat_nd[i] += Stat.stat_nd[i];
181 			stats.stat_nq[i] += Stat.stat_nq[i];
182 		}
183 		stats.stat_cr += Stat.stat_cr;
184 		stats.stat_ct += Stat.stat_ct;
185 		stats.stat_cf += Stat.stat_cf;
186 	}
187 	else
188 		memmove((char *) &stats, (char *) &Stat, sizeof(stats));
189 
190 	/* write out results */
191 	(void) lseek(fd, (off_t) 0, 0);
192 	(void) write(fd, (char *) &stats, sizeof(stats));
193 	(void) close(fd);
194 
195 	/* clear the structure to avoid future disappointment */
196 	clearstats();
197 	entered = false;
198 }
199