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