17c478bd9Sstevel@tonic-gate /* 2*058561cbSjbeck * Copyright (c) 1998-2004, 2006 Sendmail, Inc. and its suppliers. 37c478bd9Sstevel@tonic-gate * All rights reserved. 47c478bd9Sstevel@tonic-gate * 57c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 67c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 77c478bd9Sstevel@tonic-gate * the sendmail distribution. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate */ 107c478bd9Sstevel@tonic-gate 117c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 127c478bd9Sstevel@tonic-gate 137c478bd9Sstevel@tonic-gate #include <sendmail.h> 147c478bd9Sstevel@tonic-gate 15*058561cbSjbeck SM_RCSID("@(#)$Id: control.c,v 8.128 2006/08/15 23:24:56 ca Exp $") 167c478bd9Sstevel@tonic-gate 177c478bd9Sstevel@tonic-gate #include <sm/fdset.h> 187c478bd9Sstevel@tonic-gate 197c478bd9Sstevel@tonic-gate /* values for cmd_code */ 207c478bd9Sstevel@tonic-gate #define CMDERROR 0 /* bad command */ 217c478bd9Sstevel@tonic-gate #define CMDRESTART 1 /* restart daemon */ 227c478bd9Sstevel@tonic-gate #define CMDSHUTDOWN 2 /* end daemon */ 237c478bd9Sstevel@tonic-gate #define CMDHELP 3 /* help */ 247c478bd9Sstevel@tonic-gate #define CMDSTATUS 4 /* daemon status */ 257c478bd9Sstevel@tonic-gate #define CMDMEMDUMP 5 /* dump memory, to find memory leaks */ 267c478bd9Sstevel@tonic-gate #define CMDMSTAT 6 /* daemon status, more info, tagged data */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate struct cmd 297c478bd9Sstevel@tonic-gate { 307c478bd9Sstevel@tonic-gate char *cmd_name; /* command name */ 317c478bd9Sstevel@tonic-gate int cmd_code; /* internal code, see below */ 327c478bd9Sstevel@tonic-gate }; 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate static struct cmd CmdTab[] = 357c478bd9Sstevel@tonic-gate { 367c478bd9Sstevel@tonic-gate { "help", CMDHELP }, 377c478bd9Sstevel@tonic-gate { "restart", CMDRESTART }, 387c478bd9Sstevel@tonic-gate { "shutdown", CMDSHUTDOWN }, 397c478bd9Sstevel@tonic-gate { "status", CMDSTATUS }, 407c478bd9Sstevel@tonic-gate { "memdump", CMDMEMDUMP }, 417c478bd9Sstevel@tonic-gate { "mstat", CMDMSTAT }, 427c478bd9Sstevel@tonic-gate { NULL, CMDERROR } 437c478bd9Sstevel@tonic-gate }; 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate static void controltimeout __P((int)); 487c478bd9Sstevel@tonic-gate int ControlSocket = -1; 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* 517c478bd9Sstevel@tonic-gate ** OPENCONTROLSOCKET -- create/open the daemon control named socket 527c478bd9Sstevel@tonic-gate ** 537c478bd9Sstevel@tonic-gate ** Creates and opens a named socket for external control over 547c478bd9Sstevel@tonic-gate ** the sendmail daemon. 557c478bd9Sstevel@tonic-gate ** 567c478bd9Sstevel@tonic-gate ** Parameters: 577c478bd9Sstevel@tonic-gate ** none. 587c478bd9Sstevel@tonic-gate ** 597c478bd9Sstevel@tonic-gate ** Returns: 607c478bd9Sstevel@tonic-gate ** 0 if successful, -1 otherwise 617c478bd9Sstevel@tonic-gate */ 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate int 647c478bd9Sstevel@tonic-gate opencontrolsocket() 657c478bd9Sstevel@tonic-gate { 667c478bd9Sstevel@tonic-gate # if NETUNIX 677c478bd9Sstevel@tonic-gate int save_errno; 687c478bd9Sstevel@tonic-gate int rval; 697c478bd9Sstevel@tonic-gate long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN; 707c478bd9Sstevel@tonic-gate struct sockaddr_un controladdr; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate if (ControlSocketName == NULL || *ControlSocketName == '\0') 737c478bd9Sstevel@tonic-gate return 0; 747c478bd9Sstevel@tonic-gate 75*058561cbSjbeck if (strlen(ControlSocketName) >= sizeof(controladdr.sun_path)) 767c478bd9Sstevel@tonic-gate { 777c478bd9Sstevel@tonic-gate errno = ENAMETOOLONG; 787c478bd9Sstevel@tonic-gate return -1; 797c478bd9Sstevel@tonic-gate } 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate rval = safefile(ControlSocketName, RunAsUid, RunAsGid, RunAsUserName, 827c478bd9Sstevel@tonic-gate sff, S_IRUSR|S_IWUSR, NULL); 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate /* if not safe, don't create */ 857c478bd9Sstevel@tonic-gate if (rval != 0) 867c478bd9Sstevel@tonic-gate { 877c478bd9Sstevel@tonic-gate errno = rval; 887c478bd9Sstevel@tonic-gate return -1; 897c478bd9Sstevel@tonic-gate } 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate ControlSocket = socket(AF_UNIX, SOCK_STREAM, 0); 927c478bd9Sstevel@tonic-gate if (ControlSocket < 0) 937c478bd9Sstevel@tonic-gate return -1; 947c478bd9Sstevel@tonic-gate if (SM_FD_SETSIZE > 0 && ControlSocket >= SM_FD_SETSIZE) 957c478bd9Sstevel@tonic-gate { 967c478bd9Sstevel@tonic-gate clrcontrol(); 977c478bd9Sstevel@tonic-gate errno = EINVAL; 987c478bd9Sstevel@tonic-gate return -1; 997c478bd9Sstevel@tonic-gate } 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate (void) unlink(ControlSocketName); 102*058561cbSjbeck memset(&controladdr, '\0', sizeof(controladdr)); 1037c478bd9Sstevel@tonic-gate controladdr.sun_family = AF_UNIX; 1047c478bd9Sstevel@tonic-gate (void) sm_strlcpy(controladdr.sun_path, ControlSocketName, 105*058561cbSjbeck sizeof(controladdr.sun_path)); 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate if (bind(ControlSocket, (struct sockaddr *) &controladdr, 108*058561cbSjbeck sizeof(controladdr)) < 0) 1097c478bd9Sstevel@tonic-gate { 1107c478bd9Sstevel@tonic-gate save_errno = errno; 1117c478bd9Sstevel@tonic-gate clrcontrol(); 1127c478bd9Sstevel@tonic-gate errno = save_errno; 1137c478bd9Sstevel@tonic-gate return -1; 1147c478bd9Sstevel@tonic-gate } 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate if (geteuid() == 0) 1177c478bd9Sstevel@tonic-gate { 1187c478bd9Sstevel@tonic-gate uid_t u = 0; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate if (RunAsUid != 0) 1217c478bd9Sstevel@tonic-gate u = RunAsUid; 1227c478bd9Sstevel@tonic-gate else if (TrustedUid != 0) 1237c478bd9Sstevel@tonic-gate u = TrustedUid; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate if (u != 0 && 1267c478bd9Sstevel@tonic-gate chown(ControlSocketName, u, -1) < 0) 1277c478bd9Sstevel@tonic-gate { 1287c478bd9Sstevel@tonic-gate save_errno = errno; 1297c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, NOQID, 1307c478bd9Sstevel@tonic-gate "ownership change on %s to uid %d failed: %s", 1317c478bd9Sstevel@tonic-gate ControlSocketName, (int) u, 1327c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 1337c478bd9Sstevel@tonic-gate message("050 ownership change on %s to uid %d failed: %s", 1347c478bd9Sstevel@tonic-gate ControlSocketName, (int) u, 1357c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 1367c478bd9Sstevel@tonic-gate closecontrolsocket(true); 1377c478bd9Sstevel@tonic-gate errno = save_errno; 1387c478bd9Sstevel@tonic-gate return -1; 1397c478bd9Sstevel@tonic-gate } 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate if (chmod(ControlSocketName, S_IRUSR|S_IWUSR) < 0) 1437c478bd9Sstevel@tonic-gate { 1447c478bd9Sstevel@tonic-gate save_errno = errno; 1457c478bd9Sstevel@tonic-gate closecontrolsocket(true); 1467c478bd9Sstevel@tonic-gate errno = save_errno; 1477c478bd9Sstevel@tonic-gate return -1; 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate if (listen(ControlSocket, 8) < 0) 1517c478bd9Sstevel@tonic-gate { 1527c478bd9Sstevel@tonic-gate save_errno = errno; 1537c478bd9Sstevel@tonic-gate closecontrolsocket(true); 1547c478bd9Sstevel@tonic-gate errno = save_errno; 1557c478bd9Sstevel@tonic-gate return -1; 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate # endif /* NETUNIX */ 1587c478bd9Sstevel@tonic-gate return 0; 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate /* 1617c478bd9Sstevel@tonic-gate ** CLOSECONTROLSOCKET -- close the daemon control named socket 1627c478bd9Sstevel@tonic-gate ** 1637c478bd9Sstevel@tonic-gate ** Close a named socket. 1647c478bd9Sstevel@tonic-gate ** 1657c478bd9Sstevel@tonic-gate ** Parameters: 1667c478bd9Sstevel@tonic-gate ** fullclose -- if set, close the socket and remove it; 1677c478bd9Sstevel@tonic-gate ** otherwise, just remove it 1687c478bd9Sstevel@tonic-gate ** 1697c478bd9Sstevel@tonic-gate ** Returns: 1707c478bd9Sstevel@tonic-gate ** none. 1717c478bd9Sstevel@tonic-gate */ 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate void 1747c478bd9Sstevel@tonic-gate closecontrolsocket(fullclose) 1757c478bd9Sstevel@tonic-gate bool fullclose; 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate # if NETUNIX 1787c478bd9Sstevel@tonic-gate long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN; 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate if (ControlSocket >= 0) 1817c478bd9Sstevel@tonic-gate { 1827c478bd9Sstevel@tonic-gate int rval; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate if (fullclose) 1857c478bd9Sstevel@tonic-gate { 1867c478bd9Sstevel@tonic-gate (void) close(ControlSocket); 1877c478bd9Sstevel@tonic-gate ControlSocket = -1; 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate rval = safefile(ControlSocketName, RunAsUid, RunAsGid, 1917c478bd9Sstevel@tonic-gate RunAsUserName, sff, S_IRUSR|S_IWUSR, NULL); 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate /* if not safe, don't unlink */ 1947c478bd9Sstevel@tonic-gate if (rval != 0) 1957c478bd9Sstevel@tonic-gate return; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate if (unlink(ControlSocketName) < 0) 1987c478bd9Sstevel@tonic-gate { 1997c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 2007c478bd9Sstevel@tonic-gate "Could not remove control socket: %s", 2017c478bd9Sstevel@tonic-gate sm_errstring(errno)); 2027c478bd9Sstevel@tonic-gate return; 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate # endif /* NETUNIX */ 2067c478bd9Sstevel@tonic-gate return; 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate /* 2097c478bd9Sstevel@tonic-gate ** CLRCONTROL -- reset the control connection 2107c478bd9Sstevel@tonic-gate ** 2117c478bd9Sstevel@tonic-gate ** Parameters: 2127c478bd9Sstevel@tonic-gate ** none. 2137c478bd9Sstevel@tonic-gate ** 2147c478bd9Sstevel@tonic-gate ** Returns: 2157c478bd9Sstevel@tonic-gate ** none. 2167c478bd9Sstevel@tonic-gate ** 2177c478bd9Sstevel@tonic-gate ** Side Effects: 2187c478bd9Sstevel@tonic-gate ** releases any resources used by the control interface. 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate void 2227c478bd9Sstevel@tonic-gate clrcontrol() 2237c478bd9Sstevel@tonic-gate { 2247c478bd9Sstevel@tonic-gate # if NETUNIX 2257c478bd9Sstevel@tonic-gate if (ControlSocket >= 0) 2267c478bd9Sstevel@tonic-gate (void) close(ControlSocket); 2277c478bd9Sstevel@tonic-gate ControlSocket = -1; 2287c478bd9Sstevel@tonic-gate # endif /* NETUNIX */ 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate ** CONTROL_COMMAND -- read and process command from named socket 2327c478bd9Sstevel@tonic-gate ** 2337c478bd9Sstevel@tonic-gate ** Read and process the command from the opened socket. 2347c478bd9Sstevel@tonic-gate ** Exits when done since it is running in a forked child. 2357c478bd9Sstevel@tonic-gate ** 2367c478bd9Sstevel@tonic-gate ** Parameters: 2377c478bd9Sstevel@tonic-gate ** sock -- the opened socket from getrequests() 2387c478bd9Sstevel@tonic-gate ** e -- the current envelope 2397c478bd9Sstevel@tonic-gate ** 2407c478bd9Sstevel@tonic-gate ** Returns: 2417c478bd9Sstevel@tonic-gate ** none. 2427c478bd9Sstevel@tonic-gate */ 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate static jmp_buf CtxControlTimeout; 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 2477c478bd9Sstevel@tonic-gate static void 2487c478bd9Sstevel@tonic-gate controltimeout(timeout) 2497c478bd9Sstevel@tonic-gate int timeout; 2507c478bd9Sstevel@tonic-gate { 2517c478bd9Sstevel@tonic-gate /* 2527c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 2537c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 2547c478bd9Sstevel@tonic-gate ** DOING. 2557c478bd9Sstevel@tonic-gate */ 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 2587c478bd9Sstevel@tonic-gate longjmp(CtxControlTimeout, 1); 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate void 2627c478bd9Sstevel@tonic-gate control_command(sock, e) 2637c478bd9Sstevel@tonic-gate int sock; 2647c478bd9Sstevel@tonic-gate ENVELOPE *e; 2657c478bd9Sstevel@tonic-gate { 2667c478bd9Sstevel@tonic-gate volatile int exitstat = EX_OK; 2677c478bd9Sstevel@tonic-gate SM_FILE_T *s = NULL; 2687c478bd9Sstevel@tonic-gate SM_EVENT *ev = NULL; 2697c478bd9Sstevel@tonic-gate SM_FILE_T *traffic; 2707c478bd9Sstevel@tonic-gate SM_FILE_T *oldout; 2717c478bd9Sstevel@tonic-gate char *cmd; 2727c478bd9Sstevel@tonic-gate char *p; 2737c478bd9Sstevel@tonic-gate struct cmd *c; 2747c478bd9Sstevel@tonic-gate char cmdbuf[MAXLINE]; 2757c478bd9Sstevel@tonic-gate char inp[MAXLINE]; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate sm_setproctitle(false, e, "control cmd read"); 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate if (TimeOuts.to_control > 0) 2807c478bd9Sstevel@tonic-gate { 2817c478bd9Sstevel@tonic-gate /* handle possible input timeout */ 2827c478bd9Sstevel@tonic-gate if (setjmp(CtxControlTimeout) != 0) 2837c478bd9Sstevel@tonic-gate { 2847c478bd9Sstevel@tonic-gate if (LogLevel > 2) 2857c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id, 2867c478bd9Sstevel@tonic-gate "timeout waiting for input during control command"); 2877c478bd9Sstevel@tonic-gate exit(EX_IOERR); 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate ev = sm_setevent(TimeOuts.to_control, controltimeout, 2907c478bd9Sstevel@tonic-gate TimeOuts.to_control); 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate s = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, (void *) &sock, 2947c478bd9Sstevel@tonic-gate SM_IO_RDWR, NULL); 2957c478bd9Sstevel@tonic-gate if (s == NULL) 2967c478bd9Sstevel@tonic-gate { 2977c478bd9Sstevel@tonic-gate int save_errno = errno; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate (void) close(sock); 3007c478bd9Sstevel@tonic-gate errno = save_errno; 3017c478bd9Sstevel@tonic-gate exit(EX_IOERR); 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate (void) sm_io_setvbuf(s, SM_TIME_DEFAULT, NULL, 3047c478bd9Sstevel@tonic-gate SM_IO_NBF, SM_IO_BUFSIZ); 3057c478bd9Sstevel@tonic-gate 306*058561cbSjbeck if (sm_io_fgets(s, SM_TIME_DEFAULT, inp, sizeof(inp)) == NULL) 3077c478bd9Sstevel@tonic-gate { 3087c478bd9Sstevel@tonic-gate (void) sm_io_close(s, SM_TIME_DEFAULT); 3097c478bd9Sstevel@tonic-gate exit(EX_IOERR); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate (void) sm_io_flush(s, SM_TIME_DEFAULT); 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate /* clean up end of line */ 3147c478bd9Sstevel@tonic-gate fixcrlf(inp, true); 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate sm_setproctitle(false, e, "control: %s", inp); 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate /* break off command */ 3197c478bd9Sstevel@tonic-gate for (p = inp; isascii(*p) && isspace(*p); p++) 3207c478bd9Sstevel@tonic-gate continue; 3217c478bd9Sstevel@tonic-gate cmd = cmdbuf; 3227c478bd9Sstevel@tonic-gate while (*p != '\0' && 3237c478bd9Sstevel@tonic-gate !(isascii(*p) && isspace(*p)) && 324*058561cbSjbeck cmd < &cmdbuf[sizeof(cmdbuf) - 2]) 3257c478bd9Sstevel@tonic-gate *cmd++ = *p++; 3267c478bd9Sstevel@tonic-gate *cmd = '\0'; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* throw away leading whitespace */ 3297c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p)) 3307c478bd9Sstevel@tonic-gate p++; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* decode command */ 3337c478bd9Sstevel@tonic-gate for (c = CmdTab; c->cmd_name != NULL; c++) 3347c478bd9Sstevel@tonic-gate { 3357c478bd9Sstevel@tonic-gate if (sm_strcasecmp(c->cmd_name, cmdbuf) == 0) 3367c478bd9Sstevel@tonic-gate break; 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate switch (c->cmd_code) 3407c478bd9Sstevel@tonic-gate { 3417c478bd9Sstevel@tonic-gate case CMDHELP: /* get help */ 3427c478bd9Sstevel@tonic-gate traffic = TrafficLogFile; 3437c478bd9Sstevel@tonic-gate TrafficLogFile = NULL; 3447c478bd9Sstevel@tonic-gate oldout = OutChannel; 3457c478bd9Sstevel@tonic-gate OutChannel = s; 3467c478bd9Sstevel@tonic-gate help("control", e); 3477c478bd9Sstevel@tonic-gate TrafficLogFile = traffic; 3487c478bd9Sstevel@tonic-gate OutChannel = oldout; 3497c478bd9Sstevel@tonic-gate break; 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate case CMDRESTART: /* restart the daemon */ 3527c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(s, SM_TIME_DEFAULT, "OK\r\n"); 3537c478bd9Sstevel@tonic-gate exitstat = EX_RESTART; 3547c478bd9Sstevel@tonic-gate break; 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate case CMDSHUTDOWN: /* kill the daemon */ 3577c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(s, SM_TIME_DEFAULT, "OK\r\n"); 3587c478bd9Sstevel@tonic-gate exitstat = EX_SHUTDOWN; 3597c478bd9Sstevel@tonic-gate break; 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate case CMDSTATUS: /* daemon status */ 3627c478bd9Sstevel@tonic-gate proc_list_probe(); 3637c478bd9Sstevel@tonic-gate { 3647c478bd9Sstevel@tonic-gate int qgrp; 3657c478bd9Sstevel@tonic-gate long bsize; 3667c478bd9Sstevel@tonic-gate long free; 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* XXX need to deal with different partitions */ 3697c478bd9Sstevel@tonic-gate qgrp = e->e_qgrp; 3707c478bd9Sstevel@tonic-gate if (!ISVALIDQGRP(qgrp)) 3717c478bd9Sstevel@tonic-gate qgrp = 0; 3727c478bd9Sstevel@tonic-gate free = freediskspace(Queue[qgrp]->qg_qdir, &bsize); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate ** Prevent overflow and don't lose 3767c478bd9Sstevel@tonic-gate ** precision (if bsize == 512) 3777c478bd9Sstevel@tonic-gate */ 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate if (free > 0) 3807c478bd9Sstevel@tonic-gate free = (long)((double) free * 3817c478bd9Sstevel@tonic-gate ((double) bsize / 1024)); 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(s, SM_TIME_DEFAULT, 3847c478bd9Sstevel@tonic-gate "%d/%d/%ld/%d\r\n", 3857c478bd9Sstevel@tonic-gate CurChildren, MaxChildren, 3867c478bd9Sstevel@tonic-gate free, getla()); 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate proc_list_display(s, ""); 3897c478bd9Sstevel@tonic-gate break; 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate case CMDMSTAT: /* daemon status, extended, tagged format */ 3927c478bd9Sstevel@tonic-gate proc_list_probe(); 3937c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(s, SM_TIME_DEFAULT, 3947c478bd9Sstevel@tonic-gate "C:%d\r\nM:%d\r\nL:%d\r\n", 3957c478bd9Sstevel@tonic-gate CurChildren, MaxChildren, 3967c478bd9Sstevel@tonic-gate getla()); 3977c478bd9Sstevel@tonic-gate printnqe(s, "Q:"); 3987c478bd9Sstevel@tonic-gate disk_status(s, "D:"); 3997c478bd9Sstevel@tonic-gate proc_list_display(s, "P:"); 4007c478bd9Sstevel@tonic-gate break; 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate case CMDMEMDUMP: /* daemon memory dump, to find memory leaks */ 4037c478bd9Sstevel@tonic-gate # if SM_HEAP_CHECK 4047c478bd9Sstevel@tonic-gate /* dump the heap, if we are checking for memory leaks */ 4057c478bd9Sstevel@tonic-gate if (sm_debug_active(&SmHeapCheck, 2)) 4067c478bd9Sstevel@tonic-gate { 4077c478bd9Sstevel@tonic-gate sm_heap_report(s, sm_debug_level(&SmHeapCheck) - 1); 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate else 4107c478bd9Sstevel@tonic-gate { 4117c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(s, SM_TIME_DEFAULT, 4127c478bd9Sstevel@tonic-gate "Memory dump unavailable.\r\n"); 4137c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(s, SM_TIME_DEFAULT, 4147c478bd9Sstevel@tonic-gate "To fix, run sendmail with -dsm_check_heap.4\r\n"); 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate # else /* SM_HEAP_CHECK */ 4177c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(s, SM_TIME_DEFAULT, 4187c478bd9Sstevel@tonic-gate "Memory dump unavailable.\r\n"); 4197c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(s, SM_TIME_DEFAULT, 4207c478bd9Sstevel@tonic-gate "To fix, rebuild with -DSM_HEAP_CHECK\r\n"); 4217c478bd9Sstevel@tonic-gate # endif /* SM_HEAP_CHECK */ 4227c478bd9Sstevel@tonic-gate break; 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate case CMDERROR: /* unknown command */ 4257c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(s, SM_TIME_DEFAULT, 4267c478bd9Sstevel@tonic-gate "Bad command (%s)\r\n", cmdbuf); 4277c478bd9Sstevel@tonic-gate break; 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate (void) sm_io_close(s, SM_TIME_DEFAULT); 4307c478bd9Sstevel@tonic-gate if (ev != NULL) 4317c478bd9Sstevel@tonic-gate sm_clrevent(ev); 4327c478bd9Sstevel@tonic-gate exit(exitstat); 4337c478bd9Sstevel@tonic-gate } 434