1065a643dSPeter Wemm /*
25dd76dd0SGregory Neil Shapiro * Copyright (c) 1998-2004, 2006 Proofpoint, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro * All rights reserved.
4065a643dSPeter Wemm *
5065a643dSPeter Wemm * By using this file, you agree to the terms and conditions set
6065a643dSPeter Wemm * forth in the LICENSE file which can be found at the top level of
7065a643dSPeter Wemm * the sendmail distribution.
8065a643dSPeter Wemm *
9065a643dSPeter Wemm */
10065a643dSPeter Wemm
1106f25ae9SGregory Neil Shapiro #include <sendmail.h>
1206f25ae9SGregory Neil Shapiro
134313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: control.c,v 8.130 2013-11-22 20:51:55 ca Exp $")
1413bd1963SGregory Neil Shapiro
15*2fb4f839SGregory Neil Shapiro #include <sm/sendmail.h>
1613bd1963SGregory Neil Shapiro #include <sm/fdset.h>
1740266059SGregory Neil Shapiro
188774250cSGregory Neil Shapiro /* values for cmd_code */
198774250cSGregory Neil Shapiro #define CMDERROR 0 /* bad command */
208774250cSGregory Neil Shapiro #define CMDRESTART 1 /* restart daemon */
218774250cSGregory Neil Shapiro #define CMDSHUTDOWN 2 /* end daemon */
228774250cSGregory Neil Shapiro #define CMDHELP 3 /* help */
238774250cSGregory Neil Shapiro #define CMDSTATUS 4 /* daemon status */
2440266059SGregory Neil Shapiro #define CMDMEMDUMP 5 /* dump memory, to find memory leaks */
2540266059SGregory Neil Shapiro #define CMDMSTAT 6 /* daemon status, more info, tagged data */
268774250cSGregory Neil Shapiro
278774250cSGregory Neil Shapiro struct cmd
288774250cSGregory Neil Shapiro {
298774250cSGregory Neil Shapiro char *cmd_name; /* command name */
308774250cSGregory Neil Shapiro int cmd_code; /* internal code, see below */
318774250cSGregory Neil Shapiro };
328774250cSGregory Neil Shapiro
338774250cSGregory Neil Shapiro static struct cmd CmdTab[] =
348774250cSGregory Neil Shapiro {
358774250cSGregory Neil Shapiro { "help", CMDHELP },
368774250cSGregory Neil Shapiro { "restart", CMDRESTART },
378774250cSGregory Neil Shapiro { "shutdown", CMDSHUTDOWN },
388774250cSGregory Neil Shapiro { "status", CMDSTATUS },
3940266059SGregory Neil Shapiro { "memdump", CMDMEMDUMP },
4040266059SGregory Neil Shapiro { "mstat", CMDMSTAT },
418774250cSGregory Neil Shapiro { NULL, CMDERROR }
428774250cSGregory Neil Shapiro };
438774250cSGregory Neil Shapiro
44b6bacd31SGregory Neil Shapiro static void controltimeout __P((int));
45065a643dSPeter Wemm int ControlSocket = -1;
46065a643dSPeter Wemm
4740266059SGregory Neil Shapiro /*
48065a643dSPeter Wemm ** OPENCONTROLSOCKET -- create/open the daemon control named socket
49065a643dSPeter Wemm **
50065a643dSPeter Wemm ** Creates and opens a named socket for external control over
51065a643dSPeter Wemm ** the sendmail daemon.
52065a643dSPeter Wemm **
53065a643dSPeter Wemm ** Parameters:
54065a643dSPeter Wemm ** none.
55065a643dSPeter Wemm **
56065a643dSPeter Wemm ** Returns:
57065a643dSPeter Wemm ** 0 if successful, -1 otherwise
58065a643dSPeter Wemm */
59065a643dSPeter Wemm
60065a643dSPeter Wemm int
opencontrolsocket()61065a643dSPeter Wemm opencontrolsocket()
62065a643dSPeter Wemm {
6306f25ae9SGregory Neil Shapiro #if NETUNIX
6406f25ae9SGregory Neil Shapiro int save_errno;
65065a643dSPeter Wemm int rval;
6606f25ae9SGregory Neil Shapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
67065a643dSPeter Wemm struct sockaddr_un controladdr;
68065a643dSPeter Wemm
69*2fb4f839SGregory Neil Shapiro if (SM_IS_EMPTY(ControlSocketName))
70065a643dSPeter Wemm return 0;
71065a643dSPeter Wemm
72d0cef73dSGregory Neil Shapiro if (strlen(ControlSocketName) >= sizeof(controladdr.sun_path))
73065a643dSPeter Wemm {
74065a643dSPeter Wemm errno = ENAMETOOLONG;
75065a643dSPeter Wemm return -1;
76065a643dSPeter Wemm }
77065a643dSPeter Wemm
78065a643dSPeter Wemm rval = safefile(ControlSocketName, RunAsUid, RunAsGid, RunAsUserName,
79065a643dSPeter Wemm sff, S_IRUSR|S_IWUSR, NULL);
80065a643dSPeter Wemm
81065a643dSPeter Wemm /* if not safe, don't create */
82065a643dSPeter Wemm if (rval != 0)
83065a643dSPeter Wemm {
84065a643dSPeter Wemm errno = rval;
85065a643dSPeter Wemm return -1;
86065a643dSPeter Wemm }
87065a643dSPeter Wemm
88065a643dSPeter Wemm ControlSocket = socket(AF_UNIX, SOCK_STREAM, 0);
89065a643dSPeter Wemm if (ControlSocket < 0)
90065a643dSPeter Wemm return -1;
9113bd1963SGregory Neil Shapiro if (SM_FD_SETSIZE > 0 && ControlSocket >= SM_FD_SETSIZE)
9213bd1963SGregory Neil Shapiro {
9313bd1963SGregory Neil Shapiro clrcontrol();
9413bd1963SGregory Neil Shapiro errno = EINVAL;
9513bd1963SGregory Neil Shapiro return -1;
9613bd1963SGregory Neil Shapiro }
97065a643dSPeter Wemm
9806f25ae9SGregory Neil Shapiro (void) unlink(ControlSocketName);
99d0cef73dSGregory Neil Shapiro memset(&controladdr, '\0', sizeof(controladdr));
100065a643dSPeter Wemm controladdr.sun_family = AF_UNIX;
10140266059SGregory Neil Shapiro (void) sm_strlcpy(controladdr.sun_path, ControlSocketName,
102d0cef73dSGregory Neil Shapiro sizeof(controladdr.sun_path));
103065a643dSPeter Wemm
104065a643dSPeter Wemm if (bind(ControlSocket, (struct sockaddr *) &controladdr,
105d0cef73dSGregory Neil Shapiro sizeof(controladdr)) < 0)
106065a643dSPeter Wemm {
10706f25ae9SGregory Neil Shapiro save_errno = errno;
1082e43090eSPeter Wemm clrcontrol();
109065a643dSPeter Wemm errno = save_errno;
110065a643dSPeter Wemm return -1;
111065a643dSPeter Wemm }
112065a643dSPeter Wemm
113193538b7SGregory Neil Shapiro if (geteuid() == 0)
114065a643dSPeter Wemm {
115193538b7SGregory Neil Shapiro uid_t u = 0;
116193538b7SGregory Neil Shapiro
117193538b7SGregory Neil Shapiro if (RunAsUid != 0)
118193538b7SGregory Neil Shapiro u = RunAsUid;
119193538b7SGregory Neil Shapiro else if (TrustedUid != 0)
120193538b7SGregory Neil Shapiro u = TrustedUid;
121193538b7SGregory Neil Shapiro
122193538b7SGregory Neil Shapiro if (u != 0 &&
123193538b7SGregory Neil Shapiro chown(ControlSocketName, u, -1) < 0)
124065a643dSPeter Wemm {
12506f25ae9SGregory Neil Shapiro save_errno = errno;
126065a643dSPeter Wemm sm_syslog(LOG_ALERT, NOQID,
127193538b7SGregory Neil Shapiro "ownership change on %s to uid %d failed: %s",
128193538b7SGregory Neil Shapiro ControlSocketName, (int) u,
12940266059SGregory Neil Shapiro sm_errstring(save_errno));
130193538b7SGregory Neil Shapiro message("050 ownership change on %s to uid %d failed: %s",
131193538b7SGregory Neil Shapiro ControlSocketName, (int) u,
13240266059SGregory Neil Shapiro sm_errstring(save_errno));
13340266059SGregory Neil Shapiro closecontrolsocket(true);
134065a643dSPeter Wemm errno = save_errno;
135065a643dSPeter Wemm return -1;
136065a643dSPeter Wemm }
137065a643dSPeter Wemm }
138065a643dSPeter Wemm
139065a643dSPeter Wemm if (chmod(ControlSocketName, S_IRUSR|S_IWUSR) < 0)
140065a643dSPeter Wemm {
14106f25ae9SGregory Neil Shapiro save_errno = errno;
14240266059SGregory Neil Shapiro closecontrolsocket(true);
143065a643dSPeter Wemm errno = save_errno;
144065a643dSPeter Wemm return -1;
145065a643dSPeter Wemm }
146065a643dSPeter Wemm
147065a643dSPeter Wemm if (listen(ControlSocket, 8) < 0)
148065a643dSPeter Wemm {
14906f25ae9SGregory Neil Shapiro save_errno = errno;
15040266059SGregory Neil Shapiro closecontrolsocket(true);
151065a643dSPeter Wemm errno = save_errno;
152065a643dSPeter Wemm return -1;
153065a643dSPeter Wemm }
15406f25ae9SGregory Neil Shapiro #endif /* NETUNIX */
155065a643dSPeter Wemm return 0;
156065a643dSPeter Wemm }
15740266059SGregory Neil Shapiro /*
158065a643dSPeter Wemm ** CLOSECONTROLSOCKET -- close the daemon control named socket
159065a643dSPeter Wemm **
160065a643dSPeter Wemm ** Close a named socket.
161065a643dSPeter Wemm **
162065a643dSPeter Wemm ** Parameters:
163065a643dSPeter Wemm ** fullclose -- if set, close the socket and remove it;
164065a643dSPeter Wemm ** otherwise, just remove it
165065a643dSPeter Wemm **
166065a643dSPeter Wemm ** Returns:
167065a643dSPeter Wemm ** none.
168065a643dSPeter Wemm */
169065a643dSPeter Wemm
170065a643dSPeter Wemm void
closecontrolsocket(fullclose)171065a643dSPeter Wemm closecontrolsocket(fullclose)
172065a643dSPeter Wemm bool fullclose;
173065a643dSPeter Wemm {
17406f25ae9SGregory Neil Shapiro #if NETUNIX
17506f25ae9SGregory Neil Shapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
176065a643dSPeter Wemm
177065a643dSPeter Wemm if (ControlSocket >= 0)
178065a643dSPeter Wemm {
179065a643dSPeter Wemm int rval;
180065a643dSPeter Wemm
181065a643dSPeter Wemm if (fullclose)
182065a643dSPeter Wemm {
183065a643dSPeter Wemm (void) close(ControlSocket);
184065a643dSPeter Wemm ControlSocket = -1;
185065a643dSPeter Wemm }
186065a643dSPeter Wemm
187193538b7SGregory Neil Shapiro rval = safefile(ControlSocketName, RunAsUid, RunAsGid,
188193538b7SGregory Neil Shapiro RunAsUserName, sff, S_IRUSR|S_IWUSR, NULL);
189065a643dSPeter Wemm
190065a643dSPeter Wemm /* if not safe, don't unlink */
191065a643dSPeter Wemm if (rval != 0)
192065a643dSPeter Wemm return;
193065a643dSPeter Wemm
194065a643dSPeter Wemm if (unlink(ControlSocketName) < 0)
195065a643dSPeter Wemm {
196065a643dSPeter Wemm sm_syslog(LOG_WARNING, NOQID,
197065a643dSPeter Wemm "Could not remove control socket: %s",
19840266059SGregory Neil Shapiro sm_errstring(errno));
199065a643dSPeter Wemm return;
200065a643dSPeter Wemm }
201065a643dSPeter Wemm }
20206f25ae9SGregory Neil Shapiro #endif /* NETUNIX */
203065a643dSPeter Wemm return;
204065a643dSPeter Wemm }
20540266059SGregory Neil Shapiro /*
206065a643dSPeter Wemm ** CLRCONTROL -- reset the control connection
207065a643dSPeter Wemm **
208065a643dSPeter Wemm ** Parameters:
209065a643dSPeter Wemm ** none.
210065a643dSPeter Wemm **
211065a643dSPeter Wemm ** Returns:
212065a643dSPeter Wemm ** none.
213065a643dSPeter Wemm **
214065a643dSPeter Wemm ** Side Effects:
215065a643dSPeter Wemm ** releases any resources used by the control interface.
216065a643dSPeter Wemm */
217065a643dSPeter Wemm
218065a643dSPeter Wemm void
clrcontrol()219065a643dSPeter Wemm clrcontrol()
220065a643dSPeter Wemm {
22106f25ae9SGregory Neil Shapiro #if NETUNIX
222065a643dSPeter Wemm if (ControlSocket >= 0)
223065a643dSPeter Wemm (void) close(ControlSocket);
224065a643dSPeter Wemm ControlSocket = -1;
22506f25ae9SGregory Neil Shapiro #endif /* NETUNIX */
226065a643dSPeter Wemm }
22740266059SGregory Neil Shapiro /*
228065a643dSPeter Wemm ** CONTROL_COMMAND -- read and process command from named socket
229065a643dSPeter Wemm **
230065a643dSPeter Wemm ** Read and process the command from the opened socket.
23106f25ae9SGregory Neil Shapiro ** Exits when done since it is running in a forked child.
232065a643dSPeter Wemm **
233065a643dSPeter Wemm ** Parameters:
234065a643dSPeter Wemm ** sock -- the opened socket from getrequests()
235065a643dSPeter Wemm ** e -- the current envelope
236065a643dSPeter Wemm **
237065a643dSPeter Wemm ** Returns:
238065a643dSPeter Wemm ** none.
239065a643dSPeter Wemm */
240065a643dSPeter Wemm
24106f25ae9SGregory Neil Shapiro static jmp_buf CtxControlTimeout;
24206f25ae9SGregory Neil Shapiro
24340266059SGregory Neil Shapiro /* ARGSUSED0 */
24406f25ae9SGregory Neil Shapiro static void
controltimeout(timeout)24506f25ae9SGregory Neil Shapiro controltimeout(timeout)
246b6bacd31SGregory Neil Shapiro int timeout;
24706f25ae9SGregory Neil Shapiro {
2488774250cSGregory Neil Shapiro /*
2498774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
2508774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2518774250cSGregory Neil Shapiro ** DOING.
2528774250cSGregory Neil Shapiro */
2538774250cSGregory Neil Shapiro
2548774250cSGregory Neil Shapiro errno = ETIMEDOUT;
25506f25ae9SGregory Neil Shapiro longjmp(CtxControlTimeout, 1);
25606f25ae9SGregory Neil Shapiro }
25706f25ae9SGregory Neil Shapiro
258065a643dSPeter Wemm void
control_command(sock,e)259065a643dSPeter Wemm control_command(sock, e)
260065a643dSPeter Wemm int sock;
261065a643dSPeter Wemm ENVELOPE *e;
262065a643dSPeter Wemm {
26306f25ae9SGregory Neil Shapiro volatile int exitstat = EX_OK;
26440266059SGregory Neil Shapiro SM_FILE_T *s = NULL;
26540266059SGregory Neil Shapiro SM_EVENT *ev = NULL;
26640266059SGregory Neil Shapiro SM_FILE_T *traffic;
26740266059SGregory Neil Shapiro SM_FILE_T *oldout;
268065a643dSPeter Wemm char *cmd;
269065a643dSPeter Wemm char *p;
270065a643dSPeter Wemm struct cmd *c;
271065a643dSPeter Wemm char cmdbuf[MAXLINE];
272065a643dSPeter Wemm char inp[MAXLINE];
273065a643dSPeter Wemm
27440266059SGregory Neil Shapiro sm_setproctitle(false, e, "control cmd read");
27506f25ae9SGregory Neil Shapiro
27606f25ae9SGregory Neil Shapiro if (TimeOuts.to_control > 0)
27706f25ae9SGregory Neil Shapiro {
27806f25ae9SGregory Neil Shapiro /* handle possible input timeout */
27906f25ae9SGregory Neil Shapiro if (setjmp(CtxControlTimeout) != 0)
28006f25ae9SGregory Neil Shapiro {
28106f25ae9SGregory Neil Shapiro if (LogLevel > 2)
28206f25ae9SGregory Neil Shapiro sm_syslog(LOG_NOTICE, e->e_id,
28306f25ae9SGregory Neil Shapiro "timeout waiting for input during control command");
28406f25ae9SGregory Neil Shapiro exit(EX_IOERR);
28506f25ae9SGregory Neil Shapiro }
28640266059SGregory Neil Shapiro ev = sm_setevent(TimeOuts.to_control, controltimeout,
28706f25ae9SGregory Neil Shapiro TimeOuts.to_control);
28806f25ae9SGregory Neil Shapiro }
289065a643dSPeter Wemm
29040266059SGregory Neil Shapiro s = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &sock,
29140266059SGregory Neil Shapiro SM_IO_RDWR, NULL);
292065a643dSPeter Wemm if (s == NULL)
293065a643dSPeter Wemm {
294065a643dSPeter Wemm int save_errno = errno;
295065a643dSPeter Wemm
29606f25ae9SGregory Neil Shapiro (void) close(sock);
297065a643dSPeter Wemm errno = save_errno;
29806f25ae9SGregory Neil Shapiro exit(EX_IOERR);
299065a643dSPeter Wemm }
30040266059SGregory Neil Shapiro (void) sm_io_setvbuf(s, SM_TIME_DEFAULT, NULL,
30140266059SGregory Neil Shapiro SM_IO_NBF, SM_IO_BUFSIZ);
302065a643dSPeter Wemm
303552d4955SGregory Neil Shapiro if (sm_io_fgets(s, SM_TIME_DEFAULT, inp, sizeof(inp)) < 0)
304065a643dSPeter Wemm {
30540266059SGregory Neil Shapiro (void) sm_io_close(s, SM_TIME_DEFAULT);
30606f25ae9SGregory Neil Shapiro exit(EX_IOERR);
307065a643dSPeter Wemm }
30840266059SGregory Neil Shapiro (void) sm_io_flush(s, SM_TIME_DEFAULT);
309065a643dSPeter Wemm
310065a643dSPeter Wemm /* clean up end of line */
31140266059SGregory Neil Shapiro fixcrlf(inp, true);
312065a643dSPeter Wemm
31340266059SGregory Neil Shapiro sm_setproctitle(false, e, "control: %s", inp);
314065a643dSPeter Wemm
315065a643dSPeter Wemm /* break off command */
3165b0945b5SGregory Neil Shapiro for (p = inp; SM_ISSPACE(*p); p++)
317065a643dSPeter Wemm continue;
318065a643dSPeter Wemm cmd = cmdbuf;
319065a643dSPeter Wemm while (*p != '\0' &&
3205b0945b5SGregory Neil Shapiro !(SM_ISSPACE(*p)) && cmd < &cmdbuf[sizeof(cmdbuf) - 2])
321065a643dSPeter Wemm *cmd++ = *p++;
322065a643dSPeter Wemm *cmd = '\0';
323065a643dSPeter Wemm
324065a643dSPeter Wemm /* throw away leading whitespace */
3255b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p))
326065a643dSPeter Wemm p++;
327065a643dSPeter Wemm
328065a643dSPeter Wemm /* decode command */
32906f25ae9SGregory Neil Shapiro for (c = CmdTab; c->cmd_name != NULL; c++)
330065a643dSPeter Wemm {
331*2fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(c->cmd_name, cmdbuf))
332065a643dSPeter Wemm break;
333065a643dSPeter Wemm }
334065a643dSPeter Wemm
33506f25ae9SGregory Neil Shapiro switch (c->cmd_code)
336065a643dSPeter Wemm {
337065a643dSPeter Wemm case CMDHELP: /* get help */
338065a643dSPeter Wemm traffic = TrafficLogFile;
339065a643dSPeter Wemm TrafficLogFile = NULL;
340065a643dSPeter Wemm oldout = OutChannel;
341065a643dSPeter Wemm OutChannel = s;
34206f25ae9SGregory Neil Shapiro help("control", e);
343065a643dSPeter Wemm TrafficLogFile = traffic;
344065a643dSPeter Wemm OutChannel = oldout;
345065a643dSPeter Wemm break;
346065a643dSPeter Wemm
347065a643dSPeter Wemm case CMDRESTART: /* restart the daemon */
34840266059SGregory Neil Shapiro (void) sm_io_fprintf(s, SM_TIME_DEFAULT, "OK\r\n");
34906f25ae9SGregory Neil Shapiro exitstat = EX_RESTART;
350065a643dSPeter Wemm break;
351065a643dSPeter Wemm
352065a643dSPeter Wemm case CMDSHUTDOWN: /* kill the daemon */
35340266059SGregory Neil Shapiro (void) sm_io_fprintf(s, SM_TIME_DEFAULT, "OK\r\n");
35406f25ae9SGregory Neil Shapiro exitstat = EX_SHUTDOWN;
355065a643dSPeter Wemm break;
356065a643dSPeter Wemm
357065a643dSPeter Wemm case CMDSTATUS: /* daemon status */
358065a643dSPeter Wemm proc_list_probe();
35906f25ae9SGregory Neil Shapiro {
36040266059SGregory Neil Shapiro int qgrp;
36106f25ae9SGregory Neil Shapiro long bsize;
36206f25ae9SGregory Neil Shapiro long free;
36306f25ae9SGregory Neil Shapiro
36440266059SGregory Neil Shapiro /* XXX need to deal with different partitions */
36540266059SGregory Neil Shapiro qgrp = e->e_qgrp;
36640266059SGregory Neil Shapiro if (!ISVALIDQGRP(qgrp))
36740266059SGregory Neil Shapiro qgrp = 0;
36840266059SGregory Neil Shapiro free = freediskspace(Queue[qgrp]->qg_qdir, &bsize);
36906f25ae9SGregory Neil Shapiro
37006f25ae9SGregory Neil Shapiro /*
37106f25ae9SGregory Neil Shapiro ** Prevent overflow and don't lose
37206f25ae9SGregory Neil Shapiro ** precision (if bsize == 512)
37306f25ae9SGregory Neil Shapiro */
37406f25ae9SGregory Neil Shapiro
37540266059SGregory Neil Shapiro if (free > 0)
37640266059SGregory Neil Shapiro free = (long)((double) free *
37740266059SGregory Neil Shapiro ((double) bsize / 1024));
37806f25ae9SGregory Neil Shapiro
37940266059SGregory Neil Shapiro (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
38040266059SGregory Neil Shapiro "%d/%d/%ld/%d\r\n",
38106f25ae9SGregory Neil Shapiro CurChildren, MaxChildren,
38240266059SGregory Neil Shapiro free, getla());
38306f25ae9SGregory Neil Shapiro }
38440266059SGregory Neil Shapiro proc_list_display(s, "");
38540266059SGregory Neil Shapiro break;
38640266059SGregory Neil Shapiro
38740266059SGregory Neil Shapiro case CMDMSTAT: /* daemon status, extended, tagged format */
38840266059SGregory Neil Shapiro proc_list_probe();
38940266059SGregory Neil Shapiro (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
39040266059SGregory Neil Shapiro "C:%d\r\nM:%d\r\nL:%d\r\n",
39140266059SGregory Neil Shapiro CurChildren, MaxChildren,
39240266059SGregory Neil Shapiro getla());
39340266059SGregory Neil Shapiro printnqe(s, "Q:");
39440266059SGregory Neil Shapiro disk_status(s, "D:");
39540266059SGregory Neil Shapiro proc_list_display(s, "P:");
39640266059SGregory Neil Shapiro break;
39740266059SGregory Neil Shapiro
39840266059SGregory Neil Shapiro case CMDMEMDUMP: /* daemon memory dump, to find memory leaks */
39940266059SGregory Neil Shapiro #if SM_HEAP_CHECK
40040266059SGregory Neil Shapiro /* dump the heap, if we are checking for memory leaks */
40140266059SGregory Neil Shapiro if (sm_debug_active(&SmHeapCheck, 2))
40240266059SGregory Neil Shapiro {
40340266059SGregory Neil Shapiro sm_heap_report(s, sm_debug_level(&SmHeapCheck) - 1);
40440266059SGregory Neil Shapiro }
40540266059SGregory Neil Shapiro else
40640266059SGregory Neil Shapiro {
40740266059SGregory Neil Shapiro (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
40840266059SGregory Neil Shapiro "Memory dump unavailable.\r\n");
40940266059SGregory Neil Shapiro (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
41040266059SGregory Neil Shapiro "To fix, run sendmail with -dsm_check_heap.4\r\n");
41140266059SGregory Neil Shapiro }
41240266059SGregory Neil Shapiro #else /* SM_HEAP_CHECK */
41340266059SGregory Neil Shapiro (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
41440266059SGregory Neil Shapiro "Memory dump unavailable.\r\n");
41540266059SGregory Neil Shapiro (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
41640266059SGregory Neil Shapiro "To fix, rebuild with -DSM_HEAP_CHECK\r\n");
41740266059SGregory Neil Shapiro #endif /* SM_HEAP_CHECK */
418065a643dSPeter Wemm break;
419065a643dSPeter Wemm
420065a643dSPeter Wemm case CMDERROR: /* unknown command */
42140266059SGregory Neil Shapiro (void) sm_io_fprintf(s, SM_TIME_DEFAULT,
42240266059SGregory Neil Shapiro "Bad command (%s)\r\n", cmdbuf);
423065a643dSPeter Wemm break;
424065a643dSPeter Wemm }
42540266059SGregory Neil Shapiro (void) sm_io_close(s, SM_TIME_DEFAULT);
42606f25ae9SGregory Neil Shapiro if (ev != NULL)
42740266059SGregory Neil Shapiro sm_clrevent(ev);
42806f25ae9SGregory Neil Shapiro exit(exitstat);
429065a643dSPeter Wemm }
430