1 /* 2 * Copyright (c) 1995 3 * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed for the FreeBSD project 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33 34 /* main() function for status monitor daemon. Some of the code in this */ 35 /* file was generated by running rpcgen /usr/include/rpcsvc/sm_inter.x */ 36 /* The actual program logic is in the file procs.c */ 37 38 #include <sys/cdefs.h> 39 __FBSDID("$FreeBSD$"); 40 41 #include <err.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <rpc/rpc.h> 45 #include <rpc/rpc_com.h> 46 #include <string.h> 47 #include <syslog.h> 48 #include <sys/types.h> 49 #include <sys/wait.h> 50 #include <signal.h> 51 #include <unistd.h> 52 #include "statd.h" 53 54 int debug = 0; /* Controls syslog() calls for debug messages */ 55 56 static void handle_sigchld(int sig); 57 static void usage(void); 58 59 const char *transports[] = { "udp", "tcp", "udp6", "tcp6" }; 60 61 int 62 main(int argc, char **argv) 63 { 64 SVCXPRT *transp; 65 struct sigaction sa; 66 struct netconfig *nconf; 67 struct sockaddr_in sin; 68 struct sockaddr_in6 sin6; 69 int ch, i, maxindex, r, s, sock; 70 char *endptr; 71 int maxrec = RPC_MAXDATASIZE; 72 in_port_t svcport = 0; 73 74 while ((ch = getopt(argc, argv, "dp:")) != -1) 75 switch (ch) { 76 case 'd': 77 debug = 1; 78 break; 79 case 'p': 80 endptr = NULL; 81 svcport = (in_port_t)strtoul(optarg, &endptr, 10); 82 if (endptr == NULL || *endptr != '\0' || svcport == 0 || 83 svcport >= IPPORT_MAX) 84 usage(); 85 break; 86 default: 87 usage(); 88 } 89 argc -= optind; 90 argv += optind; 91 92 (void)rpcb_unset(SM_PROG, SM_VERS, NULL); 93 94 /* 95 * Check if IPv6 support is present. 96 */ 97 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 98 if (s < 0) 99 maxindex = 2; 100 else { 101 close(s); 102 maxindex = 4; 103 } 104 105 if (svcport != 0) { 106 bzero(&sin, sizeof(struct sockaddr_in)); 107 sin.sin_len = sizeof(struct sockaddr_in); 108 sin.sin_family = AF_INET; 109 sin.sin_port = htons(svcport); 110 111 bzero(&sin6, sizeof(struct sockaddr_in6)); 112 sin6.sin6_len = sizeof(struct sockaddr_in6); 113 sin6.sin6_family = AF_INET6; 114 sin6.sin6_port = htons(svcport); 115 } 116 117 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 118 119 for (i = 0; i < maxindex; i++) { 120 nconf = getnetconfigent(transports[i]); 121 if (nconf == NULL) 122 errx(1, "cannot get %s netconf: %s.", transports[i], 123 nc_sperror()); 124 125 if (svcport != 0) { 126 if (strcmp(nconf->nc_netid, "udp6") == 0) { 127 sock = socket(AF_INET6, SOCK_DGRAM, 128 IPPROTO_UDP); 129 if (sock != -1) { 130 r = bindresvport_sa(sock, 131 (struct sockaddr *)&sin6); 132 if (r != 0) { 133 syslog(LOG_ERR, "bindresvport: %m"); 134 exit(1); 135 } 136 } 137 } else if (strcmp(nconf->nc_netid, "udp") == 0) { 138 sock = socket(AF_INET, SOCK_DGRAM, 139 IPPROTO_UDP); 140 if (sock != -1) { 141 r = bindresvport(sock, &sin); 142 if (r != 0) { 143 syslog(LOG_ERR, "bindresvport: %m"); 144 exit(1); 145 } 146 } 147 } else if (strcmp(nconf->nc_netid, "tcp6") == 0) { 148 sock = socket(AF_INET6, SOCK_STREAM, 149 IPPROTO_TCP); 150 if (sock != -1) { 151 r = bindresvport_sa(sock, 152 (struct sockaddr *)&sin6); 153 if (r != 0) { 154 syslog(LOG_ERR, "bindresvport: %m"); 155 exit(1); 156 } 157 } 158 } else if (strcmp(nconf->nc_netid, "tcp") == 0) { 159 sock = socket(AF_INET, SOCK_STREAM, 160 IPPROTO_TCP); 161 if (sock != -1) { 162 r = bindresvport(sock, &sin); 163 if (r != 0) { 164 syslog(LOG_ERR, "bindresvport: %m"); 165 exit(1); 166 } 167 } 168 } 169 170 transp = svc_tli_create(sock, nconf, NULL, 171 RPC_MAXDATASIZE, RPC_MAXDATASIZE); 172 } else { 173 transp = svc_tli_create(RPC_ANYFD, nconf, NULL, 174 RPC_MAXDATASIZE, RPC_MAXDATASIZE); 175 } 176 177 if (transp == NULL) { 178 errx(1, "cannot create %s service.", transports[i]); 179 /* NOTREACHED */ 180 } 181 if (!svc_reg(transp, SM_PROG, SM_VERS, sm_prog_1, nconf)) { 182 errx(1, "unable to register (SM_PROG, NLM_SM, %s)", 183 transports[i]); 184 /* NOTREACHED */ 185 } 186 freenetconfigent(nconf); 187 } 188 init_file("/var/db/statd.status"); 189 190 /* Note that it is NOT sensible to run this program from inetd - the */ 191 /* protocol assumes that it will run immediately at boot time. */ 192 daemon(0, 0); 193 openlog("rpc.statd", 0, LOG_DAEMON); 194 if (debug) syslog(LOG_INFO, "Starting - debug enabled"); 195 else syslog(LOG_INFO, "Starting"); 196 197 /* Install signal handler to collect exit status of child processes */ 198 sa.sa_handler = handle_sigchld; 199 sigemptyset(&sa.sa_mask); 200 sigaddset(&sa.sa_mask, SIGCHLD); 201 sa.sa_flags = SA_RESTART; 202 sigaction(SIGCHLD, &sa, NULL); 203 204 /* Initialisation now complete - start operating */ 205 notify_hosts(); /* Forks a process (if necessary) to do the */ 206 /* SM_NOTIFY calls, which may be slow. */ 207 208 svc_run(); /* Should never return */ 209 exit(1); 210 } 211 212 static void 213 usage() 214 { 215 fprintf(stderr, "usage: rpc.statd [-d] [-p <port>]\n"); 216 exit(1); 217 } 218 219 /* handle_sigchld ---------------------------------------------------------- */ 220 /* 221 Purpose: Catch SIGCHLD and collect process status 222 Retruns: Nothing. 223 Notes: No special action required, other than to collect the 224 process status and hence allow the child to die: 225 we only use child processes for asynchronous transmission 226 of SM_NOTIFY to other systems, so it is normal for the 227 children to exit when they have done their work. 228 */ 229 230 static void handle_sigchld(int sig __unused) 231 { 232 int pid, status; 233 pid = wait4(-1, &status, WNOHANG, (struct rusage*)0); 234 if (!pid) syslog(LOG_ERR, "Phantom SIGCHLD??"); 235 else if (status == 0) 236 { 237 if (debug) syslog(LOG_DEBUG, "Child %d exited OK", pid); 238 } 239 else syslog(LOG_ERR, "Child %d failed with status %d", pid, 240 WEXITSTATUS(status)); 241 } 242 243