114125Speter/*
214125Speter * Copyright (c) 1995
314125Speter *	A.R. Gordon (andrew.gordon@net-tel.co.uk).  All rights reserved.
414125Speter *
514125Speter * Redistribution and use in source and binary forms, with or without
614125Speter * modification, are permitted provided that the following conditions
714125Speter * are met:
814125Speter * 1. Redistributions of source code must retain the above copyright
914125Speter *    notice, this list of conditions and the following disclaimer.
1014125Speter * 2. Redistributions in binary form must reproduce the above copyright
1114125Speter *    notice, this list of conditions and the following disclaimer in the
1214125Speter *    documentation and/or other materials provided with the distribution.
1314125Speter * 3. All advertising materials mentioning features or use of this software
1414125Speter *    must display the following acknowledgement:
1514125Speter *	This product includes software developed for the FreeBSD project
1614125Speter * 4. Neither the name of the author nor the names of any co-contributors
1714125Speter *    may be used to endorse or promote products derived from this software
1814125Speter *    without specific prior written permission.
1914125Speter *
2014125Speter * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
2114125Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2214125Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2314125Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2414125Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2514125Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2614125Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2714125Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2814125Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2914125Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3014125Speter * SUCH DAMAGE.
3114125Speter *
3214125Speter */
3314125Speter
3414125Speter/* main() function for status monitor daemon.  Some of the code in this	*/
3514125Speter/* file was generated by running rpcgen /usr/include/rpcsvc/sm_inter.x	*/
3614125Speter/* The actual program logic is in the file procs.c			*/
3714125Speter
38127861Scharnier#include <sys/cdefs.h>
39127861Scharnier__FBSDID("$FreeBSD$");
40127861Scharnier
4130376Scharnier#include <err.h>
42222627Srmacklem#include <errno.h>
4314125Speter#include <stdio.h>
4430376Scharnier#include <stdlib.h>
4514125Speter#include <rpc/rpc.h>
46109363Smbr#include <rpc/rpc_com.h>
4799787Salfred#include <string.h>
4814125Speter#include <syslog.h>
4914125Speter#include <sys/types.h>
50173263Smatteo#include <sys/socket.h>
5114125Speter#include <sys/wait.h>
52173263Smatteo#include <netinet/in.h>
53173263Smatteo#include <arpa/inet.h>
54173263Smatteo#include <netdb.h>
5514125Speter#include <signal.h>
56127861Scharnier#include <unistd.h>
5714125Speter#include "statd.h"
5814125Speter
59222627Srmacklem#define	GETPORT_MAXTRY	20	/* Max tries to get a port # */
60222627Srmacklem
6114125Speterint debug = 0;		/* Controls syslog() calls for debug messages	*/
6214125Speter
63173263Smatteochar **hosts, *svcport_str = NULL;
64173263Smatteoint nhosts = 0;
65173263Smatteoint xcreated = 0;
66222627Srmacklemstatic int	mallocd_svcport = 0;
67222627Srmacklemstatic int	*sock_fd;
68222627Srmacklemstatic int	sock_fdcnt;
69222627Srmacklemstatic int	sock_fdpos;
70173263Smatteo
71222627Srmacklemstatic int	create_service(struct netconfig *nconf);
72222627Srmacklemstatic void	complete_service(struct netconfig *nconf, char *port_str);
73222627Srmacklemstatic void	clearout_service(void);
7499798Salfredstatic void handle_sigchld(int sig);
75173263Smatteovoid out_of_mem(void);
76173263Smatteo
7799798Salfredstatic void usage(void);
7814125Speter
7930376Scharnierint
8014125Spetermain(int argc, char **argv)
8114125Speter{
8214125Speter  struct sigaction sa;
83168325Smatteo  struct netconfig *nconf;
84173263Smatteo  void *nc_handle;
85173263Smatteo  in_port_t svcport;
86173263Smatteo  int ch, i, s;
87173263Smatteo  char *endptr, **hosts_bak;
88173263Smatteo  int have_v6 = 1;
89109363Smbr  int maxrec = RPC_MAXDATASIZE;
90222627Srmacklem  int attempt_cnt, port_len, port_pos, ret;
91222627Srmacklem  char **port_list;
9214125Speter
93173263Smatteo  while ((ch = getopt(argc, argv, "dh:p:")) != -1)
94127861Scharnier    switch (ch) {
95127861Scharnier    case 'd':
96127861Scharnier      debug = 1;
97127861Scharnier      break;
98173263Smatteo    case 'h':
99173263Smatteo      ++nhosts;
100173263Smatteo      hosts_bak = hosts;
101173263Smatteo      hosts_bak = realloc(hosts, nhosts * sizeof(char *));
102173263Smatteo      if (hosts_bak == NULL) {
103173263Smatteo	      if (hosts != NULL) {
104173263Smatteo		      for (i = 0; i < nhosts; i++)
105173263Smatteo			      free(hosts[i]);
106173263Smatteo		      free(hosts);
107173263Smatteo		      out_of_mem();
108173263Smatteo	      }
109173263Smatteo      }
110173263Smatteo      hosts = hosts_bak;
111173263Smatteo      hosts[nhosts - 1] = strdup(optarg);
112173263Smatteo      if (hosts[nhosts - 1] == NULL) {
113173263Smatteo	      for (i = 0; i < (nhosts - 1); i++)
114173263Smatteo		      free(hosts[i]);
115173263Smatteo	      free(hosts);
116173263Smatteo	      out_of_mem();
117173263Smatteo      }
118173263Smatteo      break;
119168325Smatteo    case 'p':
120168325Smatteo      endptr = NULL;
121168325Smatteo      svcport = (in_port_t)strtoul(optarg, &endptr, 10);
122168325Smatteo      if (endptr == NULL || *endptr != '\0' || svcport == 0 ||
123168325Smatteo          svcport >= IPPORT_MAX)
124168325Smatteo	usage();
125173263Smatteo
126173263Smatteo      svcport_str = strdup(optarg);
127168325Smatteo      break;
128127861Scharnier    default:
129127861Scharnier      usage();
130127861Scharnier    }
131127861Scharnier  argc -= optind;
132127861Scharnier  argv += optind;
13314125Speter
134100120Salfred  (void)rpcb_unset(SM_PROG, SM_VERS, NULL);
13514125Speter
136168325Smatteo  /*
137168325Smatteo   * Check if IPv6 support is present.
138168325Smatteo   */
139168325Smatteo  s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
140168325Smatteo  if (s < 0)
141173263Smatteo      have_v6 = 0;
142173263Smatteo  else
143168325Smatteo      close(s);
144168325Smatteo
145173263Smatteo  rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
146168325Smatteo
147173263Smatteo  /*
148173263Smatteo   * If no hosts were specified, add a wildcard entry to bind to
149173263Smatteo   * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
150173263Smatteo   * list.
151173263Smatteo   */
152173263Smatteo  if (nhosts == 0) {
153173263Smatteo	  hosts = malloc(sizeof(char**));
154173263Smatteo	  if (hosts == NULL)
155173263Smatteo		  out_of_mem();
156168325Smatteo
157173263Smatteo	  hosts[0] = "*";
158173263Smatteo	  nhosts = 1;
159173263Smatteo  } else {
160173263Smatteo	  hosts_bak = hosts;
161173263Smatteo	  if (have_v6) {
162173263Smatteo		  hosts_bak = realloc(hosts, (nhosts + 2) *
163173263Smatteo		      sizeof(char *));
164173263Smatteo		  if (hosts_bak == NULL) {
165173263Smatteo			  for (i = 0; i < nhosts; i++)
166173263Smatteo				  free(hosts[i]);
167173263Smatteo			  free(hosts);
168173263Smatteo			  out_of_mem();
169173263Smatteo		  } else
170173263Smatteo			  hosts = hosts_bak;
171109363Smbr
172173263Smatteo		  nhosts += 2;
173173263Smatteo		  hosts[nhosts - 2] = "::1";
174173263Smatteo	  } else {
175173263Smatteo		  hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
176173263Smatteo		  if (hosts_bak == NULL) {
177173263Smatteo			  for (i = 0; i < nhosts; i++)
178173263Smatteo				  free(hosts[i]);
17914125Speter
180173263Smatteo			  free(hosts);
181173263Smatteo			  out_of_mem();
182173263Smatteo		  } else {
183173263Smatteo			  nhosts += 1;
184173263Smatteo			  hosts = hosts_bak;
185168325Smatteo		  }
186173263Smatteo	  }
187173263Smatteo	  hosts[nhosts - 1] = "127.0.0.1";
188173263Smatteo  }
189173263Smatteo
190222627Srmacklem  attempt_cnt = 1;
191222627Srmacklem  sock_fdcnt = 0;
192222627Srmacklem  sock_fd = NULL;
193222627Srmacklem  port_list = NULL;
194222627Srmacklem  port_len = 0;
195173263Smatteo  nc_handle = setnetconfig();
196173263Smatteo  while ((nconf = getnetconfig(nc_handle))) {
197173263Smatteo	  /* We want to listen only on udp6, tcp6, udp, tcp transports */
198173263Smatteo	  if (nconf->nc_flag & NC_VISIBLE) {
199173263Smatteo		  /* Skip if there's no IPv6 support */
200173263Smatteo		  if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
201173263Smatteo	      /* DO NOTHING */
202173263Smatteo		  } else {
203222627Srmacklem			ret = create_service(nconf);
204222627Srmacklem			if (ret == 1)
205222627Srmacklem				/* Ignore this call */
206222627Srmacklem				continue;
207222627Srmacklem			if (ret < 0) {
208222627Srmacklem				/*
209222627Srmacklem				 * Failed to bind port, so close off
210222627Srmacklem				 * all sockets created and try again
211222627Srmacklem				 * if the port# was dynamically
212222627Srmacklem				 * assigned via bind(2).
213222627Srmacklem				 */
214222627Srmacklem				clearout_service();
215222627Srmacklem				if (mallocd_svcport != 0 &&
216222627Srmacklem				    attempt_cnt < GETPORT_MAXTRY) {
217222627Srmacklem					free(svcport_str);
218222627Srmacklem					svcport_str = NULL;
219222627Srmacklem					mallocd_svcport = 0;
220222627Srmacklem				} else {
221222627Srmacklem					errno = EADDRINUSE;
222222627Srmacklem					syslog(LOG_ERR,
223222627Srmacklem					    "bindresvport_sa: %m");
224222627Srmacklem					exit(1);
225222627Srmacklem				}
226222627Srmacklem
227222627Srmacklem				/* Start over at the first service. */
228222627Srmacklem				free(sock_fd);
229222627Srmacklem				sock_fdcnt = 0;
230222627Srmacklem				sock_fd = NULL;
231222627Srmacklem				nc_handle = setnetconfig();
232222627Srmacklem				attempt_cnt++;
233222627Srmacklem			} else if (mallocd_svcport != 0 &&
234222627Srmacklem			    attempt_cnt == GETPORT_MAXTRY) {
235222627Srmacklem				/*
236222627Srmacklem				 * For the last attempt, allow
237222627Srmacklem				 * different port #s for each nconf
238222627Srmacklem				 * by saving the svcport_str and
239222627Srmacklem				 * setting it back to NULL.
240222627Srmacklem				 */
241222627Srmacklem				port_list = realloc(port_list,
242222627Srmacklem				    (port_len + 1) * sizeof(char *));
243222627Srmacklem				if (port_list == NULL)
244222627Srmacklem					out_of_mem();
245222627Srmacklem				port_list[port_len++] = svcport_str;
246222627Srmacklem				svcport_str = NULL;
247222627Srmacklem				mallocd_svcport = 0;
248222627Srmacklem			}
249168325Smatteo		  }
250168325Smatteo	  }
251168325Smatteo  }
252222627Srmacklem
253222627Srmacklem  /*
254222627Srmacklem   * Successfully bound the ports, so call complete_service() to
255222627Srmacklem   * do the rest of the setup on the service(s).
256222627Srmacklem   */
257222627Srmacklem  sock_fdpos = 0;
258222627Srmacklem  port_pos = 0;
259222627Srmacklem  nc_handle = setnetconfig();
260222627Srmacklem  while ((nconf = getnetconfig(nc_handle))) {
261222627Srmacklem	  /* We want to listen only on udp6, tcp6, udp, tcp transports */
262222627Srmacklem	  if (nconf->nc_flag & NC_VISIBLE) {
263222627Srmacklem		  /* Skip if there's no IPv6 support */
264222627Srmacklem		  if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
265222627Srmacklem	      /* DO NOTHING */
266222627Srmacklem		  } else if (port_list != NULL) {
267222627Srmacklem			if (port_pos >= port_len) {
268222627Srmacklem				syslog(LOG_ERR, "too many port#s");
269222627Srmacklem				exit(1);
270222627Srmacklem			}
271222627Srmacklem			complete_service(nconf, port_list[port_pos++]);
272222627Srmacklem		  } else
273222627Srmacklem			complete_service(nconf, svcport_str);
274222627Srmacklem	  }
275222627Srmacklem  }
276173263Smatteo  endnetconfig(nc_handle);
277222627Srmacklem  free(sock_fd);
278222627Srmacklem  if (port_list != NULL) {
279222627Srmacklem  	for (port_pos = 0; port_pos < port_len; port_pos++)
280222627Srmacklem  		free(port_list[port_pos]);
281222627Srmacklem  	free(port_list);
282222627Srmacklem  }
283222627Srmacklem
284171733Struckman  init_file("/var/db/statd.status");
285168325Smatteo
28614125Speter  /* Note that it is NOT sensible to run this program from inetd - the 	*/
28714125Speter  /* protocol assumes that it will run immediately at boot time.	*/
28814125Speter  daemon(0, 0);
28914125Speter  openlog("rpc.statd", 0, LOG_DAEMON);
29014125Speter  if (debug) syslog(LOG_INFO, "Starting - debug enabled");
29114125Speter  else syslog(LOG_INFO, "Starting");
29214125Speter
29314125Speter  /* Install signal handler to collect exit status of child processes	*/
29414125Speter  sa.sa_handler = handle_sigchld;
29514125Speter  sigemptyset(&sa.sa_mask);
29614125Speter  sigaddset(&sa.sa_mask, SIGCHLD);
29714125Speter  sa.sa_flags = SA_RESTART;
29814125Speter  sigaction(SIGCHLD, &sa, NULL);
29914125Speter
30014125Speter  /* Initialisation now complete - start operating			*/
30114125Speter  notify_hosts();	/* Forks a process (if necessary) to do the	*/
30214125Speter			/* SM_NOTIFY calls, which may be slow.		*/
30314125Speter
30414125Speter  svc_run();	/* Should never return					*/
30514125Speter  exit(1);
30614125Speter}
30714125Speter
308173263Smatteo/*
309173263Smatteo * This routine creates and binds sockets on the appropriate
310222627Srmacklem * addresses. It gets called one time for each transport.
311222627Srmacklem * It returns 0 upon success, 1 for ingore the call and -1 to indicate
312222627Srmacklem * bind failed with EADDRINUSE.
313222627Srmacklem * Any file descriptors that have been created are stored in sock_fd and
314222627Srmacklem * the total count of them is maintained in sock_fdcnt.
315173263Smatteo */
316222627Srmacklemstatic int
317173263Smatteocreate_service(struct netconfig *nconf)
318173263Smatteo{
319173263Smatteo	struct addrinfo hints, *res = NULL;
320173263Smatteo	struct sockaddr_in *sin;
321173263Smatteo	struct sockaddr_in6 *sin6;
322173263Smatteo	struct __rpc_sockinfo si;
323173263Smatteo	int aicode;
324173263Smatteo	int fd;
325173263Smatteo	int nhostsbak;
326173263Smatteo	int r;
327173263Smatteo	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
328222627Srmacklem	int mallocd_res;
329173263Smatteo
330173263Smatteo	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
331173263Smatteo	    (nconf->nc_semantics != NC_TPI_COTS) &&
332173263Smatteo	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
333222627Srmacklem		return (1);	/* not my type */
334173263Smatteo
335173263Smatteo	/*
336173263Smatteo	 * XXX - using RPC library internal functions.
337173263Smatteo	 */
338173263Smatteo	if (!__rpc_nconf2sockinfo(nconf, &si)) {
339173263Smatteo		syslog(LOG_ERR, "cannot get information for %s",
340173263Smatteo		    nconf->nc_netid);
341222627Srmacklem		return (1);
342173263Smatteo	}
343173263Smatteo
344173263Smatteo	/* Get rpc.statd's address on this transport */
345173263Smatteo	memset(&hints, 0, sizeof hints);
346173263Smatteo	hints.ai_flags = AI_PASSIVE;
347173263Smatteo	hints.ai_family = si.si_af;
348173263Smatteo	hints.ai_socktype = si.si_socktype;
349173263Smatteo	hints.ai_protocol = si.si_proto;
350173263Smatteo
351173263Smatteo	/*
352173263Smatteo	 * Bind to specific IPs if asked to
353173263Smatteo	 */
354173263Smatteo	nhostsbak = nhosts;
355173263Smatteo	while (nhostsbak > 0) {
356173263Smatteo		--nhostsbak;
357222627Srmacklem		sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int));
358222627Srmacklem		if (sock_fd == NULL)
359222627Srmacklem			out_of_mem();
360222627Srmacklem		sock_fd[sock_fdcnt++] = -1;	/* Set invalid for now. */
361222627Srmacklem		mallocd_res = 0;
362173263Smatteo
363173263Smatteo		/*
364173263Smatteo		 * XXX - using RPC library internal functions.
365173263Smatteo		 */
366173263Smatteo		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
367173263Smatteo			syslog(LOG_ERR, "cannot create socket for %s",
368173263Smatteo			    nconf->nc_netid);
369173263Smatteo			continue;
370173263Smatteo		}
371173263Smatteo		switch (hints.ai_family) {
372173263Smatteo		case AF_INET:
373173263Smatteo			if (inet_pton(AF_INET, hosts[nhostsbak],
374173263Smatteo			    host_addr) == 1) {
375222627Srmacklem				hints.ai_flags |= AI_NUMERICHOST;
376173263Smatteo			} else {
377173263Smatteo				/*
378173263Smatteo				 * Skip if we have an AF_INET6 address.
379173263Smatteo				 */
380173263Smatteo				if (inet_pton(AF_INET6, hosts[nhostsbak],
381173263Smatteo				    host_addr) == 1) {
382173263Smatteo					close(fd);
383173263Smatteo					continue;
384173263Smatteo				}
385173263Smatteo			}
386173263Smatteo			break;
387173263Smatteo		case AF_INET6:
388173263Smatteo			if (inet_pton(AF_INET6, hosts[nhostsbak],
389173263Smatteo			    host_addr) == 1) {
390222627Srmacklem				hints.ai_flags |= AI_NUMERICHOST;
391173263Smatteo			} else {
392173263Smatteo				/*
393173263Smatteo				 * Skip if we have an AF_INET address.
394173263Smatteo				 */
395173263Smatteo				if (inet_pton(AF_INET, hosts[nhostsbak],
396173263Smatteo				    host_addr) == 1) {
397173263Smatteo					close(fd);
398173263Smatteo					continue;
399173263Smatteo				}
400173263Smatteo			}
401173263Smatteo			break;
402173263Smatteo		default:
403173263Smatteo			break;
404173263Smatteo		}
405173263Smatteo
406173263Smatteo		/*
407173263Smatteo		 * If no hosts were specified, just bind to INADDR_ANY
408173263Smatteo		 */
409173263Smatteo		if (strcmp("*", hosts[nhostsbak]) == 0) {
410173263Smatteo			if (svcport_str == NULL) {
411173263Smatteo				res = malloc(sizeof(struct addrinfo));
412173263Smatteo				if (res == NULL)
413173263Smatteo					out_of_mem();
414222627Srmacklem				mallocd_res = 1;
415173263Smatteo				res->ai_flags = hints.ai_flags;
416173263Smatteo				res->ai_family = hints.ai_family;
417173263Smatteo				res->ai_protocol = hints.ai_protocol;
418173263Smatteo				switch (res->ai_family) {
419173263Smatteo				case AF_INET:
420173263Smatteo					sin = malloc(sizeof(struct sockaddr_in));
421173263Smatteo					if (sin == NULL)
422173263Smatteo						out_of_mem();
423173263Smatteo					sin->sin_family = AF_INET;
424173263Smatteo					sin->sin_port = htons(0);
425173263Smatteo					sin->sin_addr.s_addr = htonl(INADDR_ANY);
426173263Smatteo					res->ai_addr = (struct sockaddr*) sin;
427173263Smatteo					res->ai_addrlen = (socklen_t)
428222627Srmacklem					    sizeof(struct sockaddr_in);
429173263Smatteo					break;
430173263Smatteo				case AF_INET6:
431173263Smatteo					sin6 = malloc(sizeof(struct sockaddr_in6));
432173411Smatteo					if (sin6 == NULL)
433173263Smatteo						out_of_mem();
434173263Smatteo					sin6->sin6_family = AF_INET6;
435173263Smatteo					sin6->sin6_port = htons(0);
436173263Smatteo					sin6->sin6_addr = in6addr_any;
437173263Smatteo					res->ai_addr = (struct sockaddr*) sin6;
438222627Srmacklem					res->ai_addrlen = (socklen_t)
439222627Srmacklem					    sizeof(struct sockaddr_in6);
440173263Smatteo					break;
441173263Smatteo				default:
442222627Srmacklem					syslog(LOG_ERR, "bad addr fam %d",
443222627Srmacklem					    res->ai_family);
444222627Srmacklem					exit(1);
445173263Smatteo				}
446173263Smatteo			} else {
447173263Smatteo				if ((aicode = getaddrinfo(NULL, svcport_str,
448173263Smatteo				    &hints, &res)) != 0) {
449173263Smatteo					syslog(LOG_ERR,
450173263Smatteo					    "cannot get local address for %s: %s",
451173263Smatteo					    nconf->nc_netid,
452173263Smatteo					    gai_strerror(aicode));
453222627Srmacklem					close(fd);
454173263Smatteo					continue;
455173263Smatteo				}
456173263Smatteo			}
457173263Smatteo		} else {
458173263Smatteo			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
459173263Smatteo			    &hints, &res)) != 0) {
460173263Smatteo				syslog(LOG_ERR,
461173263Smatteo				    "cannot get local address for %s: %s",
462173263Smatteo				    nconf->nc_netid, gai_strerror(aicode));
463222627Srmacklem				close(fd);
464173263Smatteo				continue;
465173263Smatteo			}
466173263Smatteo		}
467173263Smatteo
468222627Srmacklem		/* Store the fd. */
469222627Srmacklem		sock_fd[sock_fdcnt - 1] = fd;
470222627Srmacklem
471222627Srmacklem		/* Now, attempt the bind. */
472173263Smatteo		r = bindresvport_sa(fd, res->ai_addr);
473173263Smatteo		if (r != 0) {
474222627Srmacklem			if (errno == EADDRINUSE && mallocd_svcport != 0) {
475222627Srmacklem				if (mallocd_res != 0) {
476222627Srmacklem					free(res->ai_addr);
477222627Srmacklem					free(res);
478222627Srmacklem				} else
479222627Srmacklem					freeaddrinfo(res);
480222627Srmacklem				return (-1);
481222627Srmacklem			}
482173263Smatteo			syslog(LOG_ERR, "bindresvport_sa: %m");
483173263Smatteo			exit(1);
484173263Smatteo		}
485173263Smatteo
486222627Srmacklem		if (svcport_str == NULL) {
487222627Srmacklem			svcport_str = malloc(NI_MAXSERV * sizeof(char));
488222627Srmacklem			if (svcport_str == NULL)
489222627Srmacklem				out_of_mem();
490222627Srmacklem			mallocd_svcport = 1;
491222627Srmacklem
492222627Srmacklem			if (getnameinfo(res->ai_addr,
493222627Srmacklem			    res->ai_addr->sa_len, NULL, NI_MAXHOST,
494222627Srmacklem			    svcport_str, NI_MAXSERV * sizeof(char),
495222627Srmacklem			    NI_NUMERICHOST | NI_NUMERICSERV))
496222627Srmacklem				errx(1, "Cannot get port number");
497222627Srmacklem		}
498222627Srmacklem		if (mallocd_res != 0) {
499222627Srmacklem			free(res->ai_addr);
500222627Srmacklem			free(res);
501222627Srmacklem		} else
502222627Srmacklem			freeaddrinfo(res);
503222627Srmacklem		res = NULL;
504222627Srmacklem	}
505222627Srmacklem	return (0);
506222627Srmacklem}
507222627Srmacklem
508222627Srmacklem/*
509222627Srmacklem * Called after all the create_service() calls have succeeded, to complete
510222627Srmacklem * the setup and registration.
511222627Srmacklem */
512222627Srmacklemstatic void
513222627Srmacklemcomplete_service(struct netconfig *nconf, char *port_str)
514222627Srmacklem{
515222627Srmacklem	struct addrinfo hints, *res = NULL;
516222627Srmacklem	struct __rpc_sockinfo si;
517222627Srmacklem	struct netbuf servaddr;
518222627Srmacklem	SVCXPRT	*transp = NULL;
519222627Srmacklem	int aicode, fd, nhostsbak;
520222627Srmacklem	int registered = 0;
521222627Srmacklem
522222627Srmacklem	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
523222627Srmacklem	    (nconf->nc_semantics != NC_TPI_COTS) &&
524222627Srmacklem	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
525222627Srmacklem		return;	/* not my type */
526222627Srmacklem
527222627Srmacklem	/*
528222627Srmacklem	 * XXX - using RPC library internal functions.
529222627Srmacklem	 */
530222627Srmacklem	if (!__rpc_nconf2sockinfo(nconf, &si)) {
531222627Srmacklem		syslog(LOG_ERR, "cannot get information for %s",
532222627Srmacklem		    nconf->nc_netid);
533222627Srmacklem		return;
534222627Srmacklem	}
535222627Srmacklem
536222627Srmacklem	nhostsbak = nhosts;
537222627Srmacklem	while (nhostsbak > 0) {
538222627Srmacklem		--nhostsbak;
539222627Srmacklem		if (sock_fdpos >= sock_fdcnt) {
540222627Srmacklem			/* Should never happen. */
541222627Srmacklem			syslog(LOG_ERR, "Ran out of socket fd's");
542222627Srmacklem			return;
543222627Srmacklem		}
544222627Srmacklem		fd = sock_fd[sock_fdpos++];
545222627Srmacklem		if (fd < 0)
546222627Srmacklem			continue;
547222627Srmacklem
548177950Sdfr		if (nconf->nc_semantics != NC_TPI_CLTS)
549177963Skan			listen(fd, SOMAXCONN);
550177950Sdfr
551173263Smatteo		transp = svc_tli_create(fd, nconf, NULL,
552173263Smatteo		RPC_MAXDATASIZE, RPC_MAXDATASIZE);
553173263Smatteo
554173263Smatteo		if (transp != (SVCXPRT *) NULL) {
555173263Smatteo			if (!svc_register(transp, SM_PROG, SM_VERS,
556173263Smatteo			    sm_prog_1, 0)) {
557173263Smatteo				syslog(LOG_ERR, "can't register on %s",
558173263Smatteo				    nconf->nc_netid);
559173263Smatteo			} else {
560173263Smatteo				if (!svc_reg(transp, SM_PROG, SM_VERS,
561173263Smatteo				    sm_prog_1, NULL))
562173263Smatteo					syslog(LOG_ERR,
563173263Smatteo					    "can't register %s SM_PROG service",
564173263Smatteo					    nconf->nc_netid);
565173263Smatteo			}
566173263Smatteo		} else
567173263Smatteo			syslog(LOG_WARNING, "can't create %s services",
568173263Smatteo			    nconf->nc_netid);
569173263Smatteo
570173263Smatteo		if (registered == 0) {
571173263Smatteo			registered = 1;
572173263Smatteo			memset(&hints, 0, sizeof hints);
573173263Smatteo			hints.ai_flags = AI_PASSIVE;
574173263Smatteo			hints.ai_family = si.si_af;
575173263Smatteo			hints.ai_socktype = si.si_socktype;
576173263Smatteo			hints.ai_protocol = si.si_proto;
577173263Smatteo
578173263Smatteo
579222627Srmacklem			if ((aicode = getaddrinfo(NULL, port_str, &hints,
580173263Smatteo			    &res)) != 0) {
581173263Smatteo				syslog(LOG_ERR, "cannot get local address: %s",
582173263Smatteo				    gai_strerror(aicode));
583173263Smatteo				exit(1);
584173263Smatteo			}
585173263Smatteo
586173263Smatteo			servaddr.buf = malloc(res->ai_addrlen);
587173263Smatteo			memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
588173263Smatteo			servaddr.len = res->ai_addrlen;
589173263Smatteo
590173263Smatteo			rpcb_set(SM_PROG, SM_VERS, nconf, &servaddr);
591173263Smatteo
592173263Smatteo			xcreated++;
593173263Smatteo			freeaddrinfo(res);
594173263Smatteo		}
595173263Smatteo	} /* end while */
596173263Smatteo}
597173263Smatteo
598222627Srmacklem/*
599222627Srmacklem * Clear out sockets after a failure to bind one of them, so that the
600222627Srmacklem * cycle of socket creation/binding can start anew.
601222627Srmacklem */
60230376Scharnierstatic void
603222627Srmacklemclearout_service(void)
604222627Srmacklem{
605222627Srmacklem	int i;
606222627Srmacklem
607222627Srmacklem	for (i = 0; i < sock_fdcnt; i++) {
608222627Srmacklem		if (sock_fd[i] >= 0) {
609222627Srmacklem			shutdown(sock_fd[i], SHUT_RDWR);
610222627Srmacklem			close(sock_fd[i]);
611222627Srmacklem		}
612222627Srmacklem	}
613222627Srmacklem}
614222627Srmacklem
615222627Srmacklemstatic void
61630376Scharnierusage()
61730376Scharnier{
618173263Smatteo      fprintf(stderr, "usage: rpc.statd [-d] [-h <bindip>] [-p <port>]\n");
61930376Scharnier      exit(1);
62030376Scharnier}
62114125Speter
62214125Speter/* handle_sigchld ---------------------------------------------------------- */
62314125Speter/*
62414125Speter   Purpose:	Catch SIGCHLD and collect process status
62514125Speter   Retruns:	Nothing.
62614125Speter   Notes:	No special action required, other than to collect the
62714125Speter		process status and hence allow the child to die:
62814125Speter		we only use child processes for asynchronous transmission
62914125Speter		of SM_NOTIFY to other systems, so it is normal for the
63014125Speter		children to exit when they have done their work.
63114125Speter*/
63214125Speter
63399798Salfredstatic void handle_sigchld(int sig __unused)
63414125Speter{
63514125Speter  int pid, status;
63614125Speter  pid = wait4(-1, &status, WNOHANG, (struct rusage*)0);
63714125Speter  if (!pid) syslog(LOG_ERR, "Phantom SIGCHLD??");
63814125Speter  else if (status == 0)
63914125Speter  {
64014125Speter    if (debug) syslog(LOG_DEBUG, "Child %d exited OK", pid);
64114125Speter  }
64214125Speter  else syslog(LOG_ERR, "Child %d failed with status %d", pid,
64314125Speter    WEXITSTATUS(status));
64414125Speter}
64514125Speter
646173263Smatteo/*
647173263Smatteo * Out of memory, fatal
648173263Smatteo */
649173263Smatteovoid
650173263Smatteoout_of_mem()
651173263Smatteo{
652173263Smatteo
653173263Smatteo	syslog(LOG_ERR, "out of memory");
654173263Smatteo	exit(2);
655173263Smatteo}
656