174462Salfred/* $NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $ */ 274462Salfred/* $FreeBSD: releng/10.3/usr.sbin/rpc.lockd/lockd.c 277859 2015-01-28 21:51:34Z rstone $ */ 374462Salfred 414123Speter/* 514123Speter * Copyright (c) 1995 614123Speter * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved. 714123Speter * 814123Speter * Redistribution and use in source and binary forms, with or without 914123Speter * modification, are permitted provided that the following conditions 1014123Speter * are met: 1114123Speter * 1. Redistributions of source code must retain the above copyright 1214123Speter * notice, this list of conditions and the following disclaimer. 1314123Speter * 2. Redistributions in binary form must reproduce the above copyright 1414123Speter * notice, this list of conditions and the following disclaimer in the 1514123Speter * documentation and/or other materials provided with the distribution. 1614123Speter * 3. All advertising materials mentioning features or use of this software 1714123Speter * must display the following acknowledgement: 1814123Speter * This product includes software developed for the FreeBSD project 1914123Speter * 4. Neither the name of the author nor the names of any co-contributors 2014123Speter * may be used to endorse or promote products derived from this software 2114123Speter * without specific prior written permission. 2214123Speter * 2314123Speter * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND 2414123Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2514123Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2614123Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2714123Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2814123Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2914123Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3014123Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3114123Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3214123Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3314123Speter * SUCH DAMAGE. 3414123Speter * 3514123Speter */ 3614123Speter 3774462Salfred#include <sys/cdefs.h> 3830376Scharnier#ifndef lint 3974462Salfred__RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $"); 4074462Salfred#endif 4114123Speter 4274462Salfred/* 4374462Salfred * main() function for NFS lock daemon. Most of the code in this 4474462Salfred * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x. 4574462Salfred * 4674462Salfred * The actual program logic is in the file lock_proc.c 4774462Salfred */ 4814123Speter 49177662Sdfr#include <sys/param.h> 50177662Sdfr#include <sys/linker.h> 51177662Sdfr#include <sys/module.h> 5274462Salfred#include <sys/socket.h> 53177633Sdfr#include <sys/stat.h> 5474462Salfred 55173281Smatteo#include <netinet/in.h> 56173281Smatteo#include <arpa/inet.h> 57173281Smatteo 5830376Scharnier#include <err.h> 5974462Salfred#include <stdio.h> 6030376Scharnier#include <stdlib.h> 6174462Salfred#include <errno.h> 6274462Salfred#include <syslog.h> 6374462Salfred#include <signal.h> 6430376Scharnier#include <string.h> 6574462Salfred#include <unistd.h> 6674462Salfred#include <libutil.h> 6774462Salfred#include <netconfig.h> 68173281Smatteo#include <netdb.h> 6974462Salfred 7030376Scharnier#include <rpc/rpc.h> 71109363Smbr#include <rpc/rpc_com.h> 7274462Salfred#include <rpcsvc/sm_inter.h> 7374462Salfred 7414123Speter#include "lockd.h" 7574462Salfred#include <rpcsvc/nlm_prot.h> 7614123Speter 77222624Srmacklem#define GETPORT_MAXTRY 20 /* Max tries to get a port # */ 78222624Srmacklem 7974462Salfredint debug_level = 0; /* 0 = no debugging syslog() calls */ 8074462Salfredint _rpcsvcdirty = 0; 8114123Speter 8274462Salfredint grace_expired; 8375631Salfredint nsm_state; 84177633Sdfrint kernel_lockd; 85180025Sdfrint kernel_lockd_client; 8675631Salfredpid_t client_pid; 8775631Salfredstruct mon mon_host; 88173281Smatteochar **hosts, *svcport_str = NULL; 89222624Srmacklemstatic int mallocd_svcport = 0; 90222624Srmacklemstatic int *sock_fd; 91222624Srmacklemstatic int sock_fdcnt; 92222624Srmacklemstatic int sock_fdpos; 93173281Smatteoint nhosts = 0; 94173281Smatteoint xcreated = 0; 95177633Sdfrchar **addrs; /* actually (netid, uaddr) pairs */ 96177633Sdfrint naddrs; /* count of how many (netid, uaddr) pairs */ 97216603Suqschar localhost[] = "localhost"; 9814123Speter 99222624Srmacklemstatic int create_service(struct netconfig *nconf); 100222624Srmacklemstatic void complete_service(struct netconfig *nconf, char *port_str); 101222624Srmacklemstatic void clearout_service(void); 102177633Sdfrvoid lookup_addresses(struct netconfig *nconf); 10375631Salfredvoid init_nsm(void); 10492909Salfredvoid nlm_prog_0(struct svc_req *, SVCXPRT *); 10592909Salfredvoid nlm_prog_1(struct svc_req *, SVCXPRT *); 10692909Salfredvoid nlm_prog_3(struct svc_req *, SVCXPRT *); 10792909Salfredvoid nlm_prog_4(struct svc_req *, SVCXPRT *); 108173281Smatteovoid out_of_mem(void); 10992909Salfredvoid usage(void); 11074462Salfred 11192909Salfredvoid sigalarm_handler(void); 11274462Salfred 113177633Sdfr/* 114177633Sdfr * XXX move to some header file. 115177633Sdfr */ 116177633Sdfr#define _PATH_RPCLOCKDSOCK "/var/run/rpclockd.sock" 117177633Sdfr 11830376Scharnierint 119173281Smatteomain(int argc, char **argv) 12014123Speter{ 121173281Smatteo int ch, i, s; 122173281Smatteo void *nc_handle; 123173281Smatteo char *endptr, **hosts_bak; 12487096Salfred struct sigaction sigalarm; 12574462Salfred int grace_period = 30; 12674462Salfred struct netconfig *nconf; 127173281Smatteo int have_v6 = 1; 128109363Smbr int maxrec = RPC_MAXDATASIZE; 129168324Smatteo in_port_t svcport = 0; 130222624Srmacklem int attempt_cnt, port_len, port_pos, ret; 131222624Srmacklem char **port_list; 13214123Speter 133177662Sdfr while ((ch = getopt(argc, argv, "d:g:h:p:")) != (-1)) { 13474462Salfred switch (ch) { 13574462Salfred case 'd': 13674462Salfred debug_level = atoi(optarg); 13774462Salfred if (!debug_level) { 13874462Salfred usage(); 13974462Salfred /* NOTREACHED */ 14074462Salfred } 14174462Salfred break; 14274462Salfred case 'g': 14374462Salfred grace_period = atoi(optarg); 14474462Salfred if (!grace_period) { 14574462Salfred usage(); 14674462Salfred /* NOTREACHED */ 14774462Salfred } 14874462Salfred break; 149173281Smatteo case 'h': 150173281Smatteo ++nhosts; 151173281Smatteo hosts_bak = hosts; 152173281Smatteo hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 153173281Smatteo if (hosts_bak == NULL) { 154173281Smatteo if (hosts != NULL) { 155173281Smatteo for (i = 0; i < nhosts; i++) 156173281Smatteo free(hosts[i]); 157173281Smatteo free(hosts); 158173281Smatteo out_of_mem(); 159173281Smatteo } 160173281Smatteo } 161173281Smatteo hosts = hosts_bak; 162173281Smatteo hosts[nhosts - 1] = strdup(optarg); 163173281Smatteo if (hosts[nhosts - 1] == NULL) { 164173281Smatteo for (i = 0; i < (nhosts - 1); i++) 165173281Smatteo free(hosts[i]); 166173281Smatteo free(hosts); 167173281Smatteo out_of_mem(); 168173281Smatteo } 169173281Smatteo break; 170168324Smatteo case 'p': 171168324Smatteo endptr = NULL; 172168324Smatteo svcport = (in_port_t)strtoul(optarg, &endptr, 10); 173168324Smatteo if (endptr == NULL || *endptr != '\0' || 174168324Smatteo svcport == 0 || svcport >= IPPORT_MAX) 175168324Smatteo usage(); 176173281Smatteo svcport_str = strdup(optarg); 177168324Smatteo break; 17874462Salfred default: 17974462Salfred case '?': 18074462Salfred usage(); 18174462Salfred /* NOTREACHED */ 18274462Salfred } 18374462Salfred } 18474462Salfred if (geteuid()) { /* This command allowed only to root */ 18574462Salfred fprintf(stderr, "Sorry. You are not superuser\n"); 18674462Salfred exit(1); 18774462Salfred } 18814123Speter 189177662Sdfr kernel_lockd = FALSE; 190180025Sdfr kernel_lockd_client = FALSE; 191177662Sdfr if (modfind("nfslockd") < 0) { 192177662Sdfr if (kldload("nfslockd") < 0) { 193177662Sdfr fprintf(stderr, "Can't find or load kernel support for rpc.lockd - using non-kernel implementation\n"); 194178066Sdfr } else { 195178066Sdfr kernel_lockd = TRUE; 196177662Sdfr } 197177662Sdfr } else { 198177662Sdfr kernel_lockd = TRUE; 199177662Sdfr } 200180025Sdfr if (kernel_lockd) { 201180025Sdfr if (getosreldate() >= 800040) 202180025Sdfr kernel_lockd_client = TRUE; 203180025Sdfr } 204177662Sdfr 20574462Salfred (void)rpcb_unset(NLM_PROG, NLM_SM, NULL); 20674462Salfred (void)rpcb_unset(NLM_PROG, NLM_VERS, NULL); 20774462Salfred (void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL); 20874462Salfred (void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL); 20914123Speter 21074462Salfred /* 21174462Salfred * Check if IPv6 support is present. 21274462Salfred */ 21374462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 21474462Salfred if (s < 0) 215173281Smatteo have_v6 = 0; 216173281Smatteo else 21774462Salfred close(s); 21814123Speter 219173281Smatteo rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 220168324Smatteo 221173281Smatteo /* 222173281Smatteo * If no hosts were specified, add a wildcard entry to bind to 223173281Smatteo * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 224173281Smatteo * list. 225173281Smatteo */ 226173281Smatteo if (nhosts == 0) { 227173281Smatteo hosts = malloc(sizeof(char**)); 228173281Smatteo if (hosts == NULL) 229173281Smatteo out_of_mem(); 230168324Smatteo 231173281Smatteo hosts[0] = "*"; 232173281Smatteo nhosts = 1; 233173281Smatteo } else { 234173281Smatteo hosts_bak = hosts; 235173281Smatteo if (have_v6) { 236173281Smatteo hosts_bak = realloc(hosts, (nhosts + 2) * 237173281Smatteo sizeof(char *)); 238173281Smatteo if (hosts_bak == NULL) { 239173281Smatteo for (i = 0; i < nhosts; i++) 240173281Smatteo free(hosts[i]); 241173281Smatteo free(hosts); 242173281Smatteo out_of_mem(); 243173281Smatteo } else 244173281Smatteo hosts = hosts_bak; 245109363Smbr 246173281Smatteo nhosts += 2; 247173281Smatteo hosts[nhosts - 2] = "::1"; 248173281Smatteo } else { 249173281Smatteo hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 250173281Smatteo if (hosts_bak == NULL) { 251173281Smatteo for (i = 0; i < nhosts; i++) 252173281Smatteo free(hosts[i]); 25314123Speter 254173281Smatteo free(hosts); 255173281Smatteo out_of_mem(); 256173281Smatteo } else { 257173281Smatteo nhosts += 1; 258173281Smatteo hosts = hosts_bak; 259168324Smatteo } 260168324Smatteo } 261173281Smatteo hosts[nhosts - 1] = "127.0.0.1"; 262173281Smatteo } 263168324Smatteo 264177633Sdfr if (kernel_lockd) { 265180025Sdfr if (!kernel_lockd_client) { 266180025Sdfr /* 267180025Sdfr * For the case where we have a kernel lockd but it 268180025Sdfr * doesn't provide client locking, we run a cut-down 269180025Sdfr * RPC service on a local-domain socket. The kernel's 270180025Sdfr * RPC server will pass what it can't handle (mainly 271180025Sdfr * client replies) down to us. 272180025Sdfr */ 273180025Sdfr struct sockaddr_un sun; 274180025Sdfr int fd, oldmask; 275180025Sdfr SVCXPRT *xprt; 276177633Sdfr 277180025Sdfr memset(&sun, 0, sizeof sun); 278180025Sdfr sun.sun_family = AF_LOCAL; 279180025Sdfr unlink(_PATH_RPCLOCKDSOCK); 280180025Sdfr strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK); 281180025Sdfr sun.sun_len = SUN_LEN(&sun); 282180025Sdfr fd = socket(AF_LOCAL, SOCK_STREAM, 0); 283180025Sdfr if (!fd) { 284180025Sdfr err(1, "Can't create local lockd socket"); 285180025Sdfr } 286180025Sdfr oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO); 287180025Sdfr if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) { 288180025Sdfr err(1, "Can't bind local lockd socket"); 289180025Sdfr } 290180025Sdfr umask(oldmask); 291180025Sdfr if (listen(fd, SOMAXCONN) < 0) { 292180025Sdfr err(1, "Can't listen on local lockd socket"); 293180025Sdfr } 294180025Sdfr xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 295180025Sdfr if (!xprt) { 296180025Sdfr err(1, "Can't create transport for local lockd socket"); 297180025Sdfr } 298180025Sdfr if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) { 299180025Sdfr err(1, "Can't register service for local lockd socket"); 300180025Sdfr } 301177633Sdfr } 302177633Sdfr 303177633Sdfr /* 304177633Sdfr * We need to look up the addresses so that we can 305177633Sdfr * hand uaddrs (ascii encoded address+port strings) to 306177633Sdfr * the kernel. 307177633Sdfr */ 308177633Sdfr nc_handle = setnetconfig(); 309177633Sdfr while ((nconf = getnetconfig(nc_handle))) { 310177633Sdfr /* We want to listen only on udp6, tcp6, udp, tcp transports */ 311177633Sdfr if (nconf->nc_flag & NC_VISIBLE) { 312177633Sdfr /* Skip if there's no IPv6 support */ 313177633Sdfr if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 314177633Sdfr /* DO NOTHING */ 315177633Sdfr } else { 316177633Sdfr lookup_addresses(nconf); 317177633Sdfr } 318173281Smatteo } 31974462Salfred } 320177633Sdfr endnetconfig(nc_handle); 321177633Sdfr } else { 322222624Srmacklem attempt_cnt = 1; 323222624Srmacklem sock_fdcnt = 0; 324222624Srmacklem sock_fd = NULL; 325222624Srmacklem port_list = NULL; 326222624Srmacklem port_len = 0; 327177633Sdfr nc_handle = setnetconfig(); 328177633Sdfr while ((nconf = getnetconfig(nc_handle))) { 329177633Sdfr /* We want to listen only on udp6, tcp6, udp, tcp transports */ 330177633Sdfr if (nconf->nc_flag & NC_VISIBLE) { 331177633Sdfr /* Skip if there's no IPv6 support */ 332177633Sdfr if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 333177633Sdfr /* DO NOTHING */ 334177633Sdfr } else { 335222624Srmacklem ret = create_service(nconf); 336222624Srmacklem if (ret == 1) 337222624Srmacklem /* Ignore this call */ 338222624Srmacklem continue; 339222624Srmacklem if (ret < 0) { 340222624Srmacklem /* 341222624Srmacklem * Failed to bind port, so close 342222624Srmacklem * off all sockets created and 343222624Srmacklem * try again if the port# was 344222624Srmacklem * dynamically assigned via 345222624Srmacklem * bind(2). 346222624Srmacklem */ 347222624Srmacklem clearout_service(); 348222624Srmacklem if (mallocd_svcport != 0 && 349222624Srmacklem attempt_cnt < 350222624Srmacklem GETPORT_MAXTRY) { 351222624Srmacklem free(svcport_str); 352222624Srmacklem svcport_str = NULL; 353222624Srmacklem mallocd_svcport = 0; 354222624Srmacklem } else { 355222624Srmacklem errno = EADDRINUSE; 356222624Srmacklem syslog(LOG_ERR, 357222624Srmacklem "bindresvport_sa: %m"); 358222624Srmacklem exit(1); 359222624Srmacklem } 360222624Srmacklem 361222624Srmacklem /* 362222624Srmacklem * Start over at the first 363222624Srmacklem * service. 364222624Srmacklem */ 365222624Srmacklem free(sock_fd); 366222624Srmacklem sock_fdcnt = 0; 367222624Srmacklem sock_fd = NULL; 368222624Srmacklem nc_handle = setnetconfig(); 369222624Srmacklem attempt_cnt++; 370222624Srmacklem } else if (mallocd_svcport != 0 && 371222624Srmacklem attempt_cnt == GETPORT_MAXTRY) { 372222624Srmacklem /* 373222624Srmacklem * For the last attempt, allow 374222624Srmacklem * different port #s for each 375222624Srmacklem * nconf by saving the 376222624Srmacklem * svcport_str and setting it 377222624Srmacklem * back to NULL. 378222624Srmacklem */ 379222624Srmacklem port_list = realloc(port_list, 380222624Srmacklem (port_len + 1) * 381222624Srmacklem sizeof(char *)); 382222624Srmacklem if (port_list == NULL) 383222624Srmacklem out_of_mem(); 384222624Srmacklem port_list[port_len++] = 385222624Srmacklem svcport_str; 386222624Srmacklem svcport_str = NULL; 387222624Srmacklem mallocd_svcport = 0; 388222624Srmacklem } 389177633Sdfr } 390177633Sdfr } 391177633Sdfr } 392222624Srmacklem 393222624Srmacklem /* 394222624Srmacklem * Successfully bound the ports, so call complete_service() to 395222624Srmacklem * do the rest of the setup on the service(s). 396222624Srmacklem */ 397222624Srmacklem sock_fdpos = 0; 398222624Srmacklem port_pos = 0; 399222624Srmacklem nc_handle = setnetconfig(); 400222624Srmacklem while ((nconf = getnetconfig(nc_handle))) { 401222624Srmacklem /* We want to listen only on udp6, tcp6, udp, tcp transports */ 402222624Srmacklem if (nconf->nc_flag & NC_VISIBLE) { 403222624Srmacklem /* Skip if there's no IPv6 support */ 404222624Srmacklem if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 405222624Srmacklem /* DO NOTHING */ 406222624Srmacklem } else if (port_list != NULL) { 407222624Srmacklem if (port_pos >= port_len) { 408222624Srmacklem syslog(LOG_ERR, 409222624Srmacklem "too many port#s"); 410222624Srmacklem exit(1); 411222624Srmacklem } 412222624Srmacklem complete_service(nconf, 413222624Srmacklem port_list[port_pos++]); 414222624Srmacklem } else 415222624Srmacklem complete_service(nconf, svcport_str); 416222624Srmacklem } 417222624Srmacklem } 418177633Sdfr endnetconfig(nc_handle); 419222624Srmacklem free(sock_fd); 420222624Srmacklem if (port_list != NULL) { 421222624Srmacklem for (port_pos = 0; port_pos < port_len; port_pos++) 422222624Srmacklem free(port_list[port_pos]); 423222624Srmacklem free(port_list); 424222624Srmacklem } 42574462Salfred } 42614123Speter 42774462Salfred /* 42874462Salfred * Note that it is NOT sensible to run this program from inetd - the 42974462Salfred * protocol assumes that it will run immediately at boot time. 43074462Salfred */ 431132254Smr if (daemon(0, debug_level > 0)) { 43274462Salfred err(1, "cannot fork"); 43374462Salfred /* NOTREACHED */ 43474462Salfred } 43574462Salfred 43674462Salfred openlog("rpc.lockd", 0, LOG_DAEMON); 43774462Salfred if (debug_level) 43874462Salfred syslog(LOG_INFO, "Starting, debug level %d", debug_level); 43974462Salfred else 44074462Salfred syslog(LOG_INFO, "Starting"); 44174462Salfred 44286319Salfred sigalarm.sa_handler = (sig_t) sigalarm_handler; 44374462Salfred sigemptyset(&sigalarm.sa_mask); 44474462Salfred sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */ 44574462Salfred sigalarm.sa_flags |= SA_RESTART; 44674462Salfred if (sigaction(SIGALRM, &sigalarm, NULL) != 0) { 44774462Salfred syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s", 44874462Salfred strerror(errno)); 44974462Salfred exit(1); 45074462Salfred } 45174462Salfred 452177633Sdfr if (kernel_lockd) { 453180025Sdfr if (!kernel_lockd_client) { 454180025Sdfr init_nsm(); 455180025Sdfr client_pid = client_request(); 45675631Salfred 457180025Sdfr /* 458180025Sdfr * Create a child process to enter the kernel and then 459180025Sdfr * wait for RPCs on our local domain socket. 460180025Sdfr */ 461180025Sdfr if (!fork()) 462180025Sdfr nlm_syscall(debug_level, grace_period, 463180025Sdfr naddrs, addrs); 464180025Sdfr else 465180025Sdfr svc_run(); 466180025Sdfr } else { 467180025Sdfr /* 468180025Sdfr * The kernel lockd implementation provides 469180025Sdfr * both client and server so we don't need to 470180025Sdfr * do anything else. 471180025Sdfr */ 472177633Sdfr nlm_syscall(debug_level, grace_period, naddrs, addrs); 473180025Sdfr } 474177633Sdfr } else { 475177633Sdfr grace_expired = 0; 476177633Sdfr alarm(grace_period); 47775631Salfred 478177633Sdfr init_nsm(); 479177633Sdfr 480177633Sdfr client_pid = client_request(); 481177633Sdfr 482177633Sdfr svc_run(); /* Should never return */ 483177633Sdfr } 48474462Salfred exit(1); 48514123Speter} 48630376Scharnier 487173281Smatteo/* 488173281Smatteo * This routine creates and binds sockets on the appropriate 489222624Srmacklem * addresses. It gets called one time for each transport. 490222624Srmacklem * It returns 0 upon success, 1 for ingore the call and -1 to indicate 491222624Srmacklem * bind failed with EADDRINUSE. 492222624Srmacklem * Any file descriptors that have been created are stored in sock_fd and 493222624Srmacklem * the total count of them is maintained in sock_fdcnt. 494173281Smatteo */ 495222624Srmacklemstatic int 496173281Smatteocreate_service(struct netconfig *nconf) 497173281Smatteo{ 498173281Smatteo struct addrinfo hints, *res = NULL; 499173281Smatteo struct sockaddr_in *sin; 500173281Smatteo struct sockaddr_in6 *sin6; 501173281Smatteo struct __rpc_sockinfo si; 502173281Smatteo int aicode; 503173281Smatteo int fd; 504173281Smatteo int nhostsbak; 505173281Smatteo int r; 506173281Smatteo u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 507222624Srmacklem int mallocd_res; 508173281Smatteo 509173281Smatteo if ((nconf->nc_semantics != NC_TPI_CLTS) && 510173281Smatteo (nconf->nc_semantics != NC_TPI_COTS) && 511173281Smatteo (nconf->nc_semantics != NC_TPI_COTS_ORD)) 512222624Srmacklem return (1); /* not my type */ 513173281Smatteo 514173281Smatteo /* 515173281Smatteo * XXX - using RPC library internal functions. 516173281Smatteo */ 517173281Smatteo if (!__rpc_nconf2sockinfo(nconf, &si)) { 518173281Smatteo syslog(LOG_ERR, "cannot get information for %s", 519173281Smatteo nconf->nc_netid); 520222624Srmacklem return (1); 521173281Smatteo } 522173281Smatteo 523173281Smatteo /* Get rpc.statd's address on this transport */ 524173281Smatteo memset(&hints, 0, sizeof hints); 525173281Smatteo hints.ai_family = si.si_af; 526173281Smatteo hints.ai_socktype = si.si_socktype; 527173281Smatteo hints.ai_protocol = si.si_proto; 528173281Smatteo 529173281Smatteo /* 530173281Smatteo * Bind to specific IPs if asked to 531173281Smatteo */ 532173281Smatteo nhostsbak = nhosts; 533173281Smatteo while (nhostsbak > 0) { 534173281Smatteo --nhostsbak; 535222624Srmacklem sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); 536222624Srmacklem if (sock_fd == NULL) 537222624Srmacklem out_of_mem(); 538222624Srmacklem sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ 539222624Srmacklem mallocd_res = 0; 540277859Srstone hints.ai_flags = AI_PASSIVE; 541173281Smatteo 542173281Smatteo /* 543173281Smatteo * XXX - using RPC library internal functions. 544173281Smatteo */ 545173281Smatteo if ((fd = __rpc_nconf2fd(nconf)) < 0) { 546173281Smatteo syslog(LOG_ERR, "cannot create socket for %s", 547173281Smatteo nconf->nc_netid); 548173281Smatteo continue; 549173281Smatteo } 550173281Smatteo 551173281Smatteo switch (hints.ai_family) { 552173281Smatteo case AF_INET: 553173281Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 554173281Smatteo host_addr) == 1) { 555222624Srmacklem hints.ai_flags |= AI_NUMERICHOST; 556173281Smatteo } else { 557173281Smatteo /* 558173281Smatteo * Skip if we have an AF_INET6 address. 559173281Smatteo */ 560173281Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 561173281Smatteo host_addr) == 1) { 562173281Smatteo close(fd); 563173281Smatteo continue; 564173281Smatteo } 565173281Smatteo } 566173281Smatteo break; 567173281Smatteo case AF_INET6: 568173281Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 569173281Smatteo host_addr) == 1) { 570222624Srmacklem hints.ai_flags |= AI_NUMERICHOST; 571173281Smatteo } else { 572173281Smatteo /* 573173281Smatteo * Skip if we have an AF_INET address. 574173281Smatteo */ 575173281Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 576173281Smatteo host_addr) == 1) { 577173281Smatteo close(fd); 578173281Smatteo continue; 579173281Smatteo } 580173281Smatteo } 581173281Smatteo break; 582173281Smatteo default: 583173281Smatteo break; 584173281Smatteo } 585173281Smatteo 586173281Smatteo /* 587173281Smatteo * If no hosts were specified, just bind to INADDR_ANY 588173281Smatteo */ 589173281Smatteo if (strcmp("*", hosts[nhostsbak]) == 0) { 590173281Smatteo if (svcport_str == NULL) { 591173281Smatteo res = malloc(sizeof(struct addrinfo)); 592173281Smatteo if (res == NULL) 593173281Smatteo out_of_mem(); 594222624Srmacklem mallocd_res = 1; 595173281Smatteo res->ai_flags = hints.ai_flags; 596173281Smatteo res->ai_family = hints.ai_family; 597173281Smatteo res->ai_protocol = hints.ai_protocol; 598173281Smatteo switch (res->ai_family) { 599173281Smatteo case AF_INET: 600173281Smatteo sin = malloc(sizeof(struct sockaddr_in)); 601173281Smatteo if (sin == NULL) 602173281Smatteo out_of_mem(); 603173281Smatteo sin->sin_family = AF_INET; 604173281Smatteo sin->sin_port = htons(0); 605173281Smatteo sin->sin_addr.s_addr = htonl(INADDR_ANY); 606173281Smatteo res->ai_addr = (struct sockaddr*) sin; 607173281Smatteo res->ai_addrlen = (socklen_t) 608222624Srmacklem sizeof(struct sockaddr_in); 609173281Smatteo break; 610173281Smatteo case AF_INET6: 611173281Smatteo sin6 = malloc(sizeof(struct sockaddr_in6)); 612173411Smatteo if (sin6 == NULL) 613173281Smatteo out_of_mem(); 614173281Smatteo sin6->sin6_family = AF_INET6; 615173281Smatteo sin6->sin6_port = htons(0); 616173281Smatteo sin6->sin6_addr = in6addr_any; 617173281Smatteo res->ai_addr = (struct sockaddr*) sin6; 618222624Srmacklem res->ai_addrlen = (socklen_t) 619222624Srmacklem sizeof(struct sockaddr_in6); 620173281Smatteo break; 621173281Smatteo default: 622222624Srmacklem syslog(LOG_ERR, 623222624Srmacklem "bad addr fam %d", 624222624Srmacklem res->ai_family); 625222624Srmacklem exit(1); 626173281Smatteo } 627173281Smatteo } else { 628173281Smatteo if ((aicode = getaddrinfo(NULL, svcport_str, 629173281Smatteo &hints, &res)) != 0) { 630173281Smatteo syslog(LOG_ERR, 631173281Smatteo "cannot get local address for %s: %s", 632173281Smatteo nconf->nc_netid, 633173281Smatteo gai_strerror(aicode)); 634222624Srmacklem close(fd); 635173281Smatteo continue; 636173281Smatteo } 637173281Smatteo } 638173281Smatteo } else { 639173281Smatteo if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 640173281Smatteo &hints, &res)) != 0) { 641173281Smatteo syslog(LOG_ERR, 642173281Smatteo "cannot get local address for %s: %s", 643173281Smatteo nconf->nc_netid, gai_strerror(aicode)); 644222624Srmacklem close(fd); 645173281Smatteo continue; 646173281Smatteo } 647173281Smatteo } 648173281Smatteo 649222624Srmacklem 650222624Srmacklem /* Store the fd. */ 651222624Srmacklem sock_fd[sock_fdcnt - 1] = fd; 652222624Srmacklem 653222624Srmacklem /* Now, attempt the bind. */ 654173281Smatteo r = bindresvport_sa(fd, res->ai_addr); 655173281Smatteo if (r != 0) { 656222624Srmacklem if (errno == EADDRINUSE && mallocd_svcport != 0) { 657222624Srmacklem if (mallocd_res != 0) { 658222624Srmacklem free(res->ai_addr); 659222624Srmacklem free(res); 660222624Srmacklem } else 661222624Srmacklem freeaddrinfo(res); 662222624Srmacklem return (-1); 663222624Srmacklem } 664173281Smatteo syslog(LOG_ERR, "bindresvport_sa: %m"); 665173281Smatteo exit(1); 666173281Smatteo } 667173281Smatteo 668222624Srmacklem if (svcport_str == NULL) { 669222624Srmacklem svcport_str = malloc(NI_MAXSERV * sizeof(char)); 670222624Srmacklem if (svcport_str == NULL) 671222624Srmacklem out_of_mem(); 672222624Srmacklem mallocd_svcport = 1; 673222624Srmacklem 674222624Srmacklem if (getnameinfo(res->ai_addr, 675222624Srmacklem res->ai_addr->sa_len, NULL, NI_MAXHOST, 676222624Srmacklem svcport_str, NI_MAXSERV * sizeof(char), 677222624Srmacklem NI_NUMERICHOST | NI_NUMERICSERV)) 678222624Srmacklem errx(1, "Cannot get port number"); 679222624Srmacklem } 680222624Srmacklem if (mallocd_res != 0) { 681222624Srmacklem free(res->ai_addr); 682222624Srmacklem free(res); 683222624Srmacklem } else 684222624Srmacklem freeaddrinfo(res); 685222624Srmacklem res = NULL; 686222624Srmacklem } 687222624Srmacklem return (0); 688222624Srmacklem} 689222624Srmacklem 690222624Srmacklem/* 691222624Srmacklem * Called after all the create_service() calls have succeeded, to complete 692222624Srmacklem * the setup and registration. 693222624Srmacklem */ 694222624Srmacklemstatic void 695222624Srmacklemcomplete_service(struct netconfig *nconf, char *port_str) 696222624Srmacklem{ 697222624Srmacklem struct addrinfo hints, *res = NULL; 698222624Srmacklem struct __rpc_sockinfo si; 699222624Srmacklem struct netbuf servaddr; 700222624Srmacklem SVCXPRT *transp = NULL; 701222624Srmacklem int aicode, fd, nhostsbak; 702222624Srmacklem int registered = 0; 703222624Srmacklem 704222624Srmacklem if ((nconf->nc_semantics != NC_TPI_CLTS) && 705222624Srmacklem (nconf->nc_semantics != NC_TPI_COTS) && 706222624Srmacklem (nconf->nc_semantics != NC_TPI_COTS_ORD)) 707222624Srmacklem return; /* not my type */ 708222624Srmacklem 709222624Srmacklem /* 710222624Srmacklem * XXX - using RPC library internal functions. 711222624Srmacklem */ 712222624Srmacklem if (!__rpc_nconf2sockinfo(nconf, &si)) { 713222624Srmacklem syslog(LOG_ERR, "cannot get information for %s", 714222624Srmacklem nconf->nc_netid); 715222624Srmacklem return; 716222624Srmacklem } 717222624Srmacklem 718222624Srmacklem nhostsbak = nhosts; 719222624Srmacklem while (nhostsbak > 0) { 720222624Srmacklem --nhostsbak; 721222624Srmacklem if (sock_fdpos >= sock_fdcnt) { 722222624Srmacklem /* Should never happen. */ 723222624Srmacklem syslog(LOG_ERR, "Ran out of socket fd's"); 724222624Srmacklem return; 725222624Srmacklem } 726222624Srmacklem fd = sock_fd[sock_fdpos++]; 727222624Srmacklem if (fd < 0) 728222624Srmacklem continue; 729222624Srmacklem 730177950Sdfr if (nconf->nc_semantics != NC_TPI_CLTS) 731177950Sdfr listen(fd, SOMAXCONN); 732177950Sdfr 733173281Smatteo transp = svc_tli_create(fd, nconf, NULL, 734173281Smatteo RPC_MAXDATASIZE, RPC_MAXDATASIZE); 735173281Smatteo 736173281Smatteo if (transp != (SVCXPRT *) NULL) { 737173281Smatteo if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0, 738173281Smatteo NULL)) 739173281Smatteo syslog(LOG_ERR, 740173281Smatteo "can't register %s NLM_PROG, NLM_SM service", 741173281Smatteo nconf->nc_netid); 742173281Smatteo 743173281Smatteo if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1, 744173281Smatteo NULL)) 745173281Smatteo syslog(LOG_ERR, 746173281Smatteo "can't register %s NLM_PROG, NLM_VERS service", 747173281Smatteo nconf->nc_netid); 748173281Smatteo 749173281Smatteo if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, 750173281Smatteo NULL)) 751173281Smatteo syslog(LOG_ERR, 752173281Smatteo "can't register %s NLM_PROG, NLM_VERSX service", 753173281Smatteo nconf->nc_netid); 754173281Smatteo 755173281Smatteo if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, 756173281Smatteo NULL)) 757173281Smatteo syslog(LOG_ERR, 758173281Smatteo "can't register %s NLM_PROG, NLM_VERS4 service", 759173281Smatteo nconf->nc_netid); 760173281Smatteo 761173281Smatteo } else 762173281Smatteo syslog(LOG_WARNING, "can't create %s services", 763173281Smatteo nconf->nc_netid); 764173281Smatteo 765173281Smatteo if (registered == 0) { 766173281Smatteo registered = 1; 767173281Smatteo memset(&hints, 0, sizeof hints); 768173281Smatteo hints.ai_flags = AI_PASSIVE; 769173281Smatteo hints.ai_family = si.si_af; 770173281Smatteo hints.ai_socktype = si.si_socktype; 771173281Smatteo hints.ai_protocol = si.si_proto; 772173281Smatteo 773222624Srmacklem if ((aicode = getaddrinfo(NULL, port_str, &hints, 774173281Smatteo &res)) != 0) { 775173281Smatteo syslog(LOG_ERR, "cannot get local address: %s", 776173281Smatteo gai_strerror(aicode)); 777173281Smatteo exit(1); 778173281Smatteo } 779173281Smatteo 780173281Smatteo servaddr.buf = malloc(res->ai_addrlen); 781173281Smatteo memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 782173281Smatteo servaddr.len = res->ai_addrlen; 783173281Smatteo 784173281Smatteo rpcb_set(NLM_PROG, NLM_SM, nconf, &servaddr); 785173281Smatteo rpcb_set(NLM_PROG, NLM_VERS, nconf, &servaddr); 786173281Smatteo rpcb_set(NLM_PROG, NLM_VERSX, nconf, &servaddr); 787173281Smatteo rpcb_set(NLM_PROG, NLM_VERS4, nconf, &servaddr); 788173281Smatteo 789173281Smatteo xcreated++; 790173281Smatteo freeaddrinfo(res); 791173281Smatteo } 792173281Smatteo } /* end while */ 793173281Smatteo} 794173281Smatteo 795177633Sdfr/* 796222624Srmacklem * Clear out sockets after a failure to bind one of them, so that the 797222624Srmacklem * cycle of socket creation/binding can start anew. 798222624Srmacklem */ 799222624Srmacklemstatic void 800222624Srmacklemclearout_service(void) 801222624Srmacklem{ 802222624Srmacklem int i; 803222624Srmacklem 804222624Srmacklem for (i = 0; i < sock_fdcnt; i++) { 805222624Srmacklem if (sock_fd[i] >= 0) { 806222624Srmacklem shutdown(sock_fd[i], SHUT_RDWR); 807222624Srmacklem close(sock_fd[i]); 808222624Srmacklem } 809222624Srmacklem } 810222624Srmacklem} 811222624Srmacklem 812222624Srmacklem/* 813177633Sdfr * Look up addresses for the kernel to create transports for. 814177633Sdfr */ 815173281Smatteovoid 816177633Sdfrlookup_addresses(struct netconfig *nconf) 817177633Sdfr{ 818177633Sdfr struct addrinfo hints, *res = NULL; 819177633Sdfr struct sockaddr_in *sin; 820177633Sdfr struct sockaddr_in6 *sin6; 821177633Sdfr struct __rpc_sockinfo si; 822177633Sdfr struct netbuf servaddr; 823177633Sdfr int aicode; 824177633Sdfr int nhostsbak; 825177633Sdfr u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 826177633Sdfr char *uaddr; 827177633Sdfr 828177633Sdfr if ((nconf->nc_semantics != NC_TPI_CLTS) && 829177633Sdfr (nconf->nc_semantics != NC_TPI_COTS) && 830177633Sdfr (nconf->nc_semantics != NC_TPI_COTS_ORD)) 831177633Sdfr return; /* not my type */ 832177633Sdfr 833177633Sdfr /* 834177633Sdfr * XXX - using RPC library internal functions. 835177633Sdfr */ 836177633Sdfr if (!__rpc_nconf2sockinfo(nconf, &si)) { 837177633Sdfr syslog(LOG_ERR, "cannot get information for %s", 838177633Sdfr nconf->nc_netid); 839177633Sdfr return; 840177633Sdfr } 841177633Sdfr 842177633Sdfr /* Get rpc.statd's address on this transport */ 843177633Sdfr memset(&hints, 0, sizeof hints); 844177633Sdfr hints.ai_flags = AI_PASSIVE; 845177633Sdfr hints.ai_family = si.si_af; 846177633Sdfr hints.ai_socktype = si.si_socktype; 847177633Sdfr hints.ai_protocol = si.si_proto; 848177633Sdfr 849177633Sdfr /* 850177633Sdfr * Bind to specific IPs if asked to 851177633Sdfr */ 852177633Sdfr nhostsbak = nhosts; 853177633Sdfr while (nhostsbak > 0) { 854177633Sdfr --nhostsbak; 855177633Sdfr 856177633Sdfr switch (hints.ai_family) { 857177633Sdfr case AF_INET: 858177633Sdfr if (inet_pton(AF_INET, hosts[nhostsbak], 859177633Sdfr host_addr) == 1) { 860177633Sdfr hints.ai_flags &= AI_NUMERICHOST; 861177633Sdfr } else { 862177633Sdfr /* 863177633Sdfr * Skip if we have an AF_INET6 address. 864177633Sdfr */ 865177633Sdfr if (inet_pton(AF_INET6, hosts[nhostsbak], 866177633Sdfr host_addr) == 1) { 867177633Sdfr continue; 868177633Sdfr } 869177633Sdfr } 870177633Sdfr break; 871177633Sdfr case AF_INET6: 872177633Sdfr if (inet_pton(AF_INET6, hosts[nhostsbak], 873177633Sdfr host_addr) == 1) { 874177633Sdfr hints.ai_flags &= AI_NUMERICHOST; 875177633Sdfr } else { 876177633Sdfr /* 877177633Sdfr * Skip if we have an AF_INET address. 878177633Sdfr */ 879177633Sdfr if (inet_pton(AF_INET, hosts[nhostsbak], 880177633Sdfr host_addr) == 1) { 881177633Sdfr continue; 882177633Sdfr } 883177633Sdfr } 884177633Sdfr break; 885177633Sdfr default: 886177633Sdfr break; 887177633Sdfr } 888177633Sdfr 889177633Sdfr /* 890177633Sdfr * If no hosts were specified, just bind to INADDR_ANY 891177633Sdfr */ 892177633Sdfr if (strcmp("*", hosts[nhostsbak]) == 0) { 893177633Sdfr if (svcport_str == NULL) { 894177633Sdfr res = malloc(sizeof(struct addrinfo)); 895177633Sdfr if (res == NULL) 896177633Sdfr out_of_mem(); 897177633Sdfr res->ai_flags = hints.ai_flags; 898177633Sdfr res->ai_family = hints.ai_family; 899177633Sdfr res->ai_protocol = hints.ai_protocol; 900177633Sdfr switch (res->ai_family) { 901177633Sdfr case AF_INET: 902177633Sdfr sin = malloc(sizeof(struct sockaddr_in)); 903177633Sdfr if (sin == NULL) 904177633Sdfr out_of_mem(); 905177633Sdfr sin->sin_family = AF_INET; 906177633Sdfr sin->sin_port = htons(0); 907177633Sdfr sin->sin_addr.s_addr = htonl(INADDR_ANY); 908177633Sdfr res->ai_addr = (struct sockaddr*) sin; 909177633Sdfr res->ai_addrlen = (socklen_t) 910177633Sdfr sizeof(res->ai_addr); 911177633Sdfr break; 912177633Sdfr case AF_INET6: 913177633Sdfr sin6 = malloc(sizeof(struct sockaddr_in6)); 914177633Sdfr if (sin6 == NULL) 915177633Sdfr out_of_mem(); 916177633Sdfr sin6->sin6_family = AF_INET6; 917177633Sdfr sin6->sin6_port = htons(0); 918177633Sdfr sin6->sin6_addr = in6addr_any; 919177633Sdfr res->ai_addr = (struct sockaddr*) sin6; 920177633Sdfr res->ai_addrlen = (socklen_t) sizeof(res->ai_addr); 921177633Sdfr break; 922177633Sdfr default: 923177633Sdfr break; 924177633Sdfr } 925177633Sdfr } else { 926177633Sdfr if ((aicode = getaddrinfo(NULL, svcport_str, 927177633Sdfr &hints, &res)) != 0) { 928177633Sdfr syslog(LOG_ERR, 929177633Sdfr "cannot get local address for %s: %s", 930177633Sdfr nconf->nc_netid, 931177633Sdfr gai_strerror(aicode)); 932177633Sdfr continue; 933177633Sdfr } 934177633Sdfr } 935177633Sdfr } else { 936177633Sdfr if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 937177633Sdfr &hints, &res)) != 0) { 938177633Sdfr syslog(LOG_ERR, 939177633Sdfr "cannot get local address for %s: %s", 940177633Sdfr nconf->nc_netid, gai_strerror(aicode)); 941177633Sdfr continue; 942177633Sdfr } 943177633Sdfr } 944177633Sdfr 945177633Sdfr servaddr.len = servaddr.maxlen = res->ai_addr->sa_len; 946177633Sdfr servaddr.buf = res->ai_addr; 947177633Sdfr uaddr = taddr2uaddr(nconf, &servaddr); 948177633Sdfr 949177633Sdfr addrs = realloc(addrs, 2 * (naddrs + 1) * sizeof(char *)); 950177633Sdfr if (!addrs) 951177633Sdfr out_of_mem(); 952177633Sdfr addrs[2 * naddrs] = strdup(nconf->nc_netid); 953177633Sdfr addrs[2 * naddrs + 1] = uaddr; 954177633Sdfr naddrs++; 955177633Sdfr } /* end while */ 956177633Sdfr} 957177633Sdfr 958177633Sdfrvoid 95986319Salfredsigalarm_handler(void) 96074462Salfred{ 96186319Salfred 96274462Salfred grace_expired = 1; 96374462Salfred} 96474462Salfred 96574462Salfredvoid 96630376Scharnierusage() 96730376Scharnier{ 968177666Sdfr errx(1, "usage: rpc.lockd [-d <debuglevel>]" 969173281Smatteo " [-g <grace period>] [-h <bindip>] [-p <port>]"); 97030376Scharnier} 97175631Salfred 97275631Salfred/* 97375631Salfred * init_nsm -- 97475631Salfred * Reset the NSM state-of-the-world and acquire its state. 97575631Salfred */ 97675631Salfredvoid 97775631Salfredinit_nsm(void) 97875631Salfred{ 97975631Salfred enum clnt_stat ret; 98075631Salfred my_id id; 98175631Salfred sm_stat stat; 98292978Salfred char name[] = "NFS NLM"; 98375631Salfred 98475631Salfred /* 98575631Salfred * !!! 98675631Salfred * The my_id structure isn't used by the SM_UNMON_ALL call, as far 98775631Salfred * as I know. Leave it empty for now. 98875631Salfred */ 98975631Salfred memset(&id, 0, sizeof(id)); 99092978Salfred id.my_name = name; 99175631Salfred 99275631Salfred /* 99375631Salfred * !!! 99475631Salfred * The statd program must already be registered when lockd runs. 99575631Salfred */ 99675631Salfred do { 99775631Salfred ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL, 998121558Speter (xdrproc_t)xdr_my_id, &id, (xdrproc_t)xdr_sm_stat, &stat); 99975631Salfred if (ret == RPC_PROGUNAVAIL) { 1000113971Sghelmer syslog(LOG_WARNING, "%lu %s", SM_PROG, 1001113971Sghelmer clnt_sperrno(ret)); 100275631Salfred sleep(2); 100375631Salfred continue; 100475631Salfred } 100575631Salfred break; 100675631Salfred } while (0); 100775631Salfred 100875631Salfred if (ret != 0) { 1009113971Sghelmer syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret)); 1010113971Sghelmer exit(1); 101175631Salfred } 101275631Salfred 101375631Salfred nsm_state = stat.state; 101475631Salfred 101575631Salfred /* setup constant data for SM_MON calls */ 101692978Salfred mon_host.mon_id.my_id.my_name = localhost; 101775631Salfred mon_host.mon_id.my_id.my_prog = NLM_PROG; 101875631Salfred mon_host.mon_id.my_id.my_vers = NLM_SM; 101975631Salfred mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY; /* bsdi addition */ 102075631Salfred} 1021173281Smatteo 1022173281Smatteo/* 1023173281Smatteo * Out of memory, fatal 1024173281Smatteo */ 1025173281Smatteovoid out_of_mem() 1026173281Smatteo{ 1027173281Smatteo syslog(LOG_ERR, "out of memory"); 1028173281Smatteo exit(2); 1029173281Smatteo} 1030