stats.c revision 64562
1/*
2 * Copyright (c) 1998, 1999 Sendmail, 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#ifndef lint
15static char id[] = "@(#)$Id: stats.c,v 8.36.14.2 2000/05/25 23:33:34 gshapiro Exp $";
16#endif /* ! lint */
17
18#include <sendmail.h>
19#include <sendmail/mailstats.h>
20
21
22static struct statistics	Stat;
23
24static bool	GotStats = FALSE;	/* set when we have stats to merge */
25
26/* See http://physics.nist.gov/cuu/Units/binary.html */
27#define ONE_K		1000		/* one thousand (twenty-four?) */
28#define KBYTES(x)	(((x) + (ONE_K - 1)) / ONE_K)
29/*
30**  MARKSTATS -- mark statistics
31**
32**	Parameters:
33**		e -- the envelope.
34**		to -- to address.
35**		reject -- whether this is a rejection.
36**
37**	Returns:
38**		none.
39**
40**	Side Effects:
41**		changes static Stat structure
42*/
43
44void
45markstats(e, to, reject)
46	register ENVELOPE *e;
47	register ADDRESS *to;
48	bool reject;
49{
50	if (reject)
51	{
52		if (e->e_from.q_mailer != NULL)
53		{
54			if (bitset(EF_DISCARD, e->e_flags))
55				Stat.stat_nd[e->e_from.q_mailer->m_mno]++;
56			else
57				Stat.stat_nr[e->e_from.q_mailer->m_mno]++;
58		}
59		Stat.stat_cr++;
60	}
61	else if (to == NULL)
62	{
63		Stat.stat_cf++;
64		if (e->e_from.q_mailer != NULL)
65		{
66			Stat.stat_nf[e->e_from.q_mailer->m_mno]++;
67			Stat.stat_bf[e->e_from.q_mailer->m_mno] +=
68				KBYTES(e->e_msgsize);
69		}
70	}
71	else
72	{
73		Stat.stat_ct++;
74		Stat.stat_nt[to->q_mailer->m_mno]++;
75		Stat.stat_bt[to->q_mailer->m_mno] += KBYTES(e->e_msgsize);
76	}
77
78
79	GotStats = TRUE;
80}
81/*
82**  CLEARSTATS -- clear statistics structure
83**
84**	Parameters:
85**		none.
86**
87**	Returns:
88**		none.
89**
90**	Side Effects:
91**		clears the Stat structure.
92*/
93
94void
95clearstats()
96{
97	/* clear the structure to avoid future disappointment */
98	memset(&Stat, '\0', sizeof Stat);
99	GotStats = FALSE;
100}
101/*
102**  POSTSTATS -- post statistics in the statistics file
103**
104**	Parameters:
105**		sfile -- the name of the statistics file.
106**
107**	Returns:
108**		none.
109**
110**	Side Effects:
111**		merges the Stat structure with the sfile file.
112*/
113
114void
115poststats(sfile)
116	char *sfile;
117{
118	register int fd;
119	long sff = SFF_REGONLY|SFF_OPENASROOT;
120	struct statistics stats;
121	extern off_t lseek();
122
123	if (sfile == NULL || !GotStats)
124		return;
125
126	(void) time(&Stat.stat_itime);
127	Stat.stat_size = sizeof Stat;
128	Stat.stat_magic = STAT_MAGIC;
129	Stat.stat_version = STAT_VERSION;
130
131	if (!bitnset(DBS_WRITESTATSTOSYMLINK, DontBlameSendmail))
132		sff |= SFF_NOSLINK;
133	if (!bitnset(DBS_WRITESTATSTOHARDLINK, DontBlameSendmail))
134		sff |= SFF_NOHLINK;
135
136	fd = safeopen(sfile, O_RDWR, 0644, sff);
137	if (fd < 0)
138	{
139		if (LogLevel > 12)
140			sm_syslog(LOG_INFO, NOQID, "poststats: %s: %s",
141				  sfile, errstring(errno));
142		errno = 0;
143		return;
144	}
145	if (read(fd, (char *) &stats, sizeof stats) == sizeof stats &&
146	    stats.stat_size == sizeof stats &&
147	    stats.stat_magic == Stat.stat_magic &&
148	    stats.stat_version == Stat.stat_version)
149	{
150		/* merge current statistics into statfile */
151		register int i;
152
153		for (i = 0; i < MAXMAILERS; i++)
154		{
155			stats.stat_nf[i] += Stat.stat_nf[i];
156			stats.stat_bf[i] += Stat.stat_bf[i];
157			stats.stat_nt[i] += Stat.stat_nt[i];
158			stats.stat_bt[i] += Stat.stat_bt[i];
159			stats.stat_nr[i] += Stat.stat_nr[i];
160			stats.stat_nd[i] += Stat.stat_nd[i];
161		}
162		stats.stat_cr += Stat.stat_cr;
163		stats.stat_ct += Stat.stat_ct;
164		stats.stat_cf += Stat.stat_cf;
165	}
166	else
167		memmove((char *) &stats, (char *) &Stat, sizeof stats);
168
169	/* write out results */
170	(void) lseek(fd, (off_t) 0, 0);
171	(void) write(fd, (char *) &stats, sizeof stats);
172	(void) close(fd);
173
174	/* clear the structure to avoid future disappointment */
175	clearstats();
176}
177