rpcbind.c revision 133789
1/*	$NetBSD: rpcbind.c,v 1.3 2002/11/08 00:16:40 fvdl Exp $	*/
2/*	$FreeBSD: head/usr.sbin/rpcbind/rpcbind.c 133789 2004-08-16 00:20:31Z mbr $ */
3
4/*
5 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
6 * unrestricted use provided that this legend is included on all tape
7 * media and as a part of the software program in whole or part.  Users
8 * may copy or modify Sun RPC without charge, but are not authorized
9 * to license or distribute it to anyone else except as part of a product or
10 * program developed by the user.
11 *
12 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
13 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
14 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
15 *
16 * Sun RPC is provided with no support and without any obligation on the
17 * part of Sun Microsystems, Inc. to assist in its use, correction,
18 * modification or enhancement.
19 *
20 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
21 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
22 * OR ANY PART THEREOF.
23 *
24 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
25 * or profits or other special, indirect and consequential damages, even if
26 * Sun has been advised of the possibility of such damages.
27 *
28 * Sun Microsystems, Inc.
29 * 2550 Garcia Avenue
30 * Mountain View, California  94043
31 */
32/*
33 * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc.
34 */
35
36/* #ident	"@(#)rpcbind.c	1.19	94/04/25 SMI" */
37
38#if 0
39#ifndef lint
40static	char sccsid[] = "@(#)rpcbind.c 1.35 89/04/21 Copyr 1984 Sun Micro";
41#endif
42#endif
43
44/*
45 * rpcbind.c
46 * Implements the program, version to address mapping for rpc.
47 *
48 */
49
50#include <sys/types.h>
51#include <sys/stat.h>
52#include <sys/errno.h>
53#include <sys/time.h>
54#include <sys/resource.h>
55#include <sys/wait.h>
56#include <sys/signal.h>
57#include <sys/socket.h>
58#include <sys/un.h>
59#include <rpc/rpc.h>
60#include <rpc/rpc_com.h>
61#ifdef PORTMAP
62#include <netinet/in.h>
63#endif
64#include <arpa/inet.h>
65#include <fcntl.h>
66#include <netdb.h>
67#include <stdio.h>
68#include <netconfig.h>
69#include <stdlib.h>
70#include <unistd.h>
71#include <syslog.h>
72#include <err.h>
73#include <libutil.h>
74#include <pwd.h>
75#include <string.h>
76#include <errno.h>
77#include "rpcbind.h"
78
79/* Global variables */
80int debugging = 0;	/* Tell me what's going on */
81int doabort = 0;	/* When debugging, do an abort on errors */
82rpcblist_ptr list_rbl;	/* A list of version 3/4 rpcbind services */
83
84/* who to suid to if -s is given */
85#define RUN_AS  "daemon"
86
87#define RPCBINDDLOCK "/var/run/rpcbind.lock"
88
89int runasdaemon = 0;
90int insecure = 0;
91int oldstyle_local = 0;
92int verboselog = 0;
93
94char **hosts = NULL;
95int nhosts = 0;
96int on = 1;
97int rpcbindlockfd;
98
99#ifdef WARMSTART
100/* Local Variable */
101static int warmstart = 0;	/* Grab an old copy of registrations. */
102#endif
103
104#ifdef PORTMAP
105struct pmaplist *list_pml;	/* A list of version 2 rpcbind services */
106char *udptrans;		/* Name of UDP transport */
107char *tcptrans;		/* Name of TCP transport */
108char *udp_uaddr;	/* Universal UDP address */
109char *tcp_uaddr;	/* Universal TCP address */
110#endif
111static char servname[] = "rpcbind";
112static char superuser[] = "superuser";
113
114int main __P((int, char *[]));
115
116static int init_transport __P((struct netconfig *));
117static void rbllist_add __P((rpcprog_t, rpcvers_t, struct netconfig *,
118			     struct netbuf *));
119static void terminate __P((int));
120static void parseargs __P((int, char *[]));
121
122int
123main(int argc, char *argv[])
124{
125	struct netconfig *nconf;
126	void *nc_handle;	/* Net config handle */
127	struct rlimit rl;
128	int maxrec = RPC_MAXDATASIZE;
129
130	parseargs(argc, argv);
131
132	/* Check that another rpcbind isn't already running. */
133	if ((rpcbindlockfd = (open(RPCBINDDLOCK,
134	    O_RDONLY|O_CREAT, 0444))) == -1)
135		err(1, "%s", RPCBINDDLOCK);
136
137	if(flock(rpcbindlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK)
138		errx(1, "another rpcbind is already running. Aborting");
139
140	getrlimit(RLIMIT_NOFILE, &rl);
141	if (rl.rlim_cur < 128) {
142		if (rl.rlim_max <= 128)
143			rl.rlim_cur = rl.rlim_max;
144		else
145			rl.rlim_cur = 128;
146		setrlimit(RLIMIT_NOFILE, &rl);
147	}
148	openlog("rpcbind", LOG_CONS, LOG_DAEMON);
149	if (geteuid()) { /* This command allowed only to root */
150		fprintf(stderr, "Sorry. You are not superuser\n");
151		exit(1);
152	}
153	nc_handle = setnetconfig(); 	/* open netconfig file */
154	if (nc_handle == NULL) {
155		syslog(LOG_ERR, "could not read /etc/netconfig");
156		exit(1);
157	}
158#ifdef PORTMAP
159	udptrans = "";
160	tcptrans = "";
161#endif
162
163	nconf = getnetconfigent("local");
164	if (nconf == NULL)
165		nconf = getnetconfigent("unix");
166	if (nconf == NULL) {
167		syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]);
168		exit(1);
169	}
170
171	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
172
173	init_transport(nconf);
174
175	while ((nconf = getnetconfig(nc_handle))) {
176		if (nconf->nc_flag & NC_VISIBLE)
177			init_transport(nconf);
178	}
179	endnetconfig(nc_handle);
180
181	/* catch the usual termination signals for graceful exit */
182	(void) signal(SIGCHLD, reap);
183	(void) signal(SIGINT, terminate);
184	(void) signal(SIGTERM, terminate);
185	(void) signal(SIGQUIT, terminate);
186	/* ignore others that could get sent */
187	(void) signal(SIGPIPE, SIG_IGN);
188	(void) signal(SIGHUP, SIG_IGN);
189	(void) signal(SIGUSR1, SIG_IGN);
190	(void) signal(SIGUSR2, SIG_IGN);
191#ifdef WARMSTART
192	if (warmstart) {
193		read_warmstart();
194	}
195#endif
196	if (debugging) {
197		printf("rpcbind debugging enabled.");
198		if (doabort) {
199			printf("  Will abort on errors!\n");
200		} else {
201			printf("\n");
202		}
203	} else {
204		if (daemon(0, 0))
205			err(1, "fork failed");
206	}
207
208	if (runasdaemon) {
209		struct passwd *p;
210
211		if((p = getpwnam(RUN_AS)) == NULL) {
212			syslog(LOG_ERR, "cannot get uid of daemon: %m");
213			exit(1);
214		}
215		if (setuid(p->pw_uid) == -1) {
216			syslog(LOG_ERR, "setuid to daemon failed: %m");
217			exit(1);
218		}
219	}
220
221	network_init();
222
223	my_svc_run();
224	syslog(LOG_ERR, "svc_run returned unexpectedly");
225	rpcbind_abort();
226	/* NOTREACHED */
227
228	return 0;
229}
230
231/*
232 * Adds the entry into the rpcbind database.
233 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
234 * Returns 0 if succeeds, else fails
235 */
236static int
237init_transport(struct netconfig *nconf)
238{
239	int fd;
240	struct t_bind taddr;
241	struct addrinfo hints, *res = NULL;
242	struct __rpc_sockinfo si;
243	SVCXPRT	*my_xprt;
244	int status;	/* bound checking ? */
245	int aicode;
246	int addrlen;
247	int nhostsbak;
248	int checkbind;
249	struct sockaddr *sa;
250	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
251	struct sockaddr_un sun;
252	mode_t oldmask;
253
254	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
255		(nconf->nc_semantics != NC_TPI_COTS) &&
256		(nconf->nc_semantics != NC_TPI_COTS_ORD))
257		return (1);	/* not my type */
258#ifdef ND_DEBUG
259	if (debugging) {
260		int i;
261		char **s;
262
263		(void) fprintf(stderr, "%s: %ld lookup routines :\n",
264			nconf->nc_netid, nconf->nc_nlookups);
265		for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups;
266		     i++, s++)
267			fprintf(stderr, "[%d] - %s\n", i, *s);
268	}
269#endif
270
271	/*
272	 * XXX - using RPC library internal functions. For NC_TPI_CLTS
273	 * we call this later, for each socket we like to bind.
274	 */
275	if (nconf->nc_semantics != NC_TPI_CLTS) {
276		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
277			int non_fatal = 0;
278
279			if (errno == EPROTONOSUPPORT)
280				non_fatal = 1;
281			syslog(non_fatal?LOG_DEBUG:LOG_ERR, "cannot create socket for %s",
282			    nconf->nc_netid);
283			return (1);
284		}
285	}
286
287	if (!__rpc_nconf2sockinfo(nconf, &si)) {
288		syslog(LOG_ERR, "cannot get information for %s",
289		    nconf->nc_netid);
290		return (1);
291	}
292
293	if ((strcmp(nconf->nc_netid, "local") == 0) ||
294	    (strcmp(nconf->nc_netid, "unix") == 0)) {
295		memset(&sun, 0, sizeof sun);
296		sun.sun_family = AF_LOCAL;
297		unlink(_PATH_RPCBINDSOCK);
298		strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
299		sun.sun_len = SUN_LEN(&sun);
300		addrlen = sizeof (struct sockaddr_un);
301		sa = (struct sockaddr *)&sun;
302	} else {
303		/* Get rpcbind's address on this transport */
304
305		memset(&hints, 0, sizeof hints);
306		hints.ai_flags = AI_PASSIVE;
307		hints.ai_family = si.si_af;
308		hints.ai_socktype = si.si_socktype;
309		hints.ai_protocol = si.si_proto;
310	}
311	if (nconf->nc_semantics == NC_TPI_CLTS) {
312		/*
313		 * If no hosts were specified, just bind to INADDR_ANY.  Otherwise
314		 * make sure 127.0.0.1 is added to the list.
315		 */
316		nhostsbak = nhosts;
317		nhostsbak++;
318		hosts = realloc(hosts, nhostsbak * sizeof(char *));
319		if (nhostsbak == 1)
320			hosts[0] = "*";
321		else {
322			if (hints.ai_family == AF_INET) {
323				hosts[nhostsbak - 1] = "127.0.0.1";
324			} else if (hints.ai_family == AF_INET6) {
325				hosts[nhostsbak - 1] = "::1";
326			} else
327				return 1;
328		}
329
330	       /*
331		* Bind to specific IPs if asked to
332		*/
333		checkbind = 1;
334		while (nhostsbak > 0) {
335			--nhostsbak;
336			/*
337			 * XXX - using RPC library internal functions.
338			 */
339			if ((fd = __rpc_nconf2fd(nconf)) < 0) {
340				syslog(LOG_ERR, "cannot create socket for %s",
341				    nconf->nc_netid);
342				return (1);
343			}
344			switch (hints.ai_family) {
345			case AF_INET:
346				if (inet_pton(AF_INET, hosts[nhostsbak],
347				    host_addr) == 1) {
348					hints.ai_flags &= AI_NUMERICHOST;
349				} else {
350					/*
351					 * Skip if we have an AF_INET6 adress.
352					 */
353					if (inet_pton(AF_INET6,
354					    hosts[nhostsbak], host_addr) == 1)
355						continue;
356				}
357				break;
358			case AF_INET6:
359				if (inet_pton(AF_INET6, hosts[nhostsbak],
360				    host_addr) == 1) {
361					hints.ai_flags &= AI_NUMERICHOST;
362				} else {
363					/*
364					 * Skip if we have an AF_INET adress.
365					 */
366					if (inet_pton(AF_INET, hosts[nhostsbak],
367					    host_addr) == 1)
368						continue;
369				}
370				if (setsockopt(fd, IPPROTO_IPV6,
371                                    IPV6_V6ONLY, &on, sizeof on) < 0) {
372                                        syslog(LOG_ERR,
373					    "can't set v6-only binding for "
374                                            "udp6 socket: %m");
375					continue;
376				}
377				break;
378			default:
379				break;
380			}
381
382			/*
383			 * If no hosts were specified, just bind to INADDR_ANY
384			 */
385			if (strcmp("*", hosts[nhostsbak]) == 0)
386				hosts[nhostsbak] = NULL;
387
388			if ((aicode = getaddrinfo(hosts[nhostsbak],
389			    servname, &hints, &res)) != 0) {
390				syslog(LOG_ERR,
391				    "cannot get local address for %s: %s",
392				    nconf->nc_netid, gai_strerror(aicode));
393				continue;
394			}
395			addrlen = res->ai_addrlen;
396			sa = (struct sockaddr *)res->ai_addr;
397			oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
398			if (bind(fd, sa, addrlen) != 0) {
399				syslog(LOG_ERR, "cannot bind %s on %s: %m",
400					(hosts[nhostsbak] == NULL) ? "*" :
401					hosts[nhostsbak], nconf->nc_netid);
402				if (res != NULL)
403					freeaddrinfo(res);
404				continue;
405			} else
406				checkbind++;
407			(void) umask(oldmask);
408
409			/* Copy the address */
410			taddr.addr.len = taddr.addr.maxlen = addrlen;
411			taddr.addr.buf = malloc(addrlen);
412			if (taddr.addr.buf == NULL) {
413				syslog(LOG_ERR,
414				    "cannot allocate memory for %s address",
415				    nconf->nc_netid);
416				if (res != NULL)
417					freeaddrinfo(res);
418				return 1;
419			}
420			memcpy(taddr.addr.buf, sa, addrlen);
421#ifdef ND_DEBUG
422			if (debugging) {
423				/*
424				 * for debugging print out our universal
425				 * address
426				 */
427				char *uaddr;
428				struct netbuf nb;
429
430				nb.buf = sa;
431				nb.len = nb.maxlen = sa->sa_len;
432				uaddr = taddr2uaddr(nconf, &nb);
433				(void) fprintf(stderr,
434				    "rpcbind : my address is %s\n", uaddr);
435				(void) free(uaddr);
436			}
437#endif
438
439			if (nconf->nc_semantics != NC_TPI_CLTS)
440				listen(fd, SOMAXCONN);
441
442			my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr,
443			    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
444			if (my_xprt == (SVCXPRT *)NULL) {
445				syslog(LOG_ERR, "%s: could not create service",
446					nconf->nc_netid);
447				goto error;
448			}
449		}
450		if (!checkbind)
451			return 1;
452	} else {
453		if ((strcmp(nconf->nc_netid, "local") != 0) &&
454		    (strcmp(nconf->nc_netid, "unix") != 0)) {
455			if ((aicode = getaddrinfo(NULL, servname, &hints, &res))
456			    != 0) {
457				syslog(LOG_ERR,
458				    "cannot get local address for %s: %s",
459				    nconf->nc_netid, gai_strerror(aicode));
460				return 1;
461			}
462			addrlen = res->ai_addrlen;
463			sa = (struct sockaddr *)res->ai_addr;
464		}
465		oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
466		if (bind(fd, sa, addrlen) < 0) {
467			syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid);
468			if (res != NULL)
469				freeaddrinfo(res);
470			return 1;
471		}
472		(void) umask(oldmask);
473
474		/* Copy the address */
475		taddr.addr.len = taddr.addr.maxlen = addrlen;
476		taddr.addr.buf = malloc(addrlen);
477		if (taddr.addr.buf == NULL) {
478			syslog(LOG_ERR, "cannot allocate memory for %s address",
479			    nconf->nc_netid);
480			if (res != NULL)
481				freeaddrinfo(res);
482			return 1;
483		}
484		memcpy(taddr.addr.buf, sa, addrlen);
485#ifdef ND_DEBUG
486		if (debugging) {
487			/* for debugging print out our universal address */
488			char *uaddr;
489			struct netbuf nb;
490
491			nb.buf = sa;
492			nb.len = nb.maxlen = sa->sa_len;
493			uaddr = taddr2uaddr(nconf, &nb);
494			(void) fprintf(stderr, "rpcbind : my address is %s\n",
495			    uaddr);
496			(void) free(uaddr);
497		}
498#endif
499
500		if (nconf->nc_semantics != NC_TPI_CLTS)
501			listen(fd, SOMAXCONN);
502
503		my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
504		if (my_xprt == (SVCXPRT *)NULL) {
505			syslog(LOG_ERR, "%s: could not create service",
506					nconf->nc_netid);
507			goto error;
508		}
509	}
510
511#ifdef PORTMAP
512	/*
513	 * Register both the versions for tcp/ip, udp/ip and local.
514	 */
515	if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 &&
516		(strcmp(nconf->nc_proto, NC_TCP) == 0 ||
517		strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
518		(strcmp(nconf->nc_netid, "unix") == 0) ||
519		(strcmp(nconf->nc_netid, "local") == 0)) {
520		struct pmaplist *pml;
521
522		if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
523			pmap_service, 0)) {
524			syslog(LOG_ERR, "could not register on %s",
525					nconf->nc_netid);
526			goto error;
527		}
528		pml = malloc(sizeof (struct pmaplist));
529		if (pml == NULL) {
530			syslog(LOG_ERR, "no memory!");
531			exit(1);
532		}
533		pml->pml_map.pm_prog = PMAPPROG;
534		pml->pml_map.pm_vers = PMAPVERS;
535		pml->pml_map.pm_port = PMAPPORT;
536		if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
537			if (tcptrans[0]) {
538				syslog(LOG_ERR,
539				"cannot have more than one TCP transport");
540				goto error;
541			}
542			tcptrans = strdup(nconf->nc_netid);
543			pml->pml_map.pm_prot = IPPROTO_TCP;
544
545			/* Let's snarf the universal address */
546			/* "h1.h2.h3.h4.p1.p2" */
547			tcp_uaddr = taddr2uaddr(nconf, &taddr.addr);
548		} else if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
549			if (udptrans[0]) {
550				syslog(LOG_ERR,
551				"cannot have more than one UDP transport");
552				goto error;
553			}
554			udptrans = strdup(nconf->nc_netid);
555			pml->pml_map.pm_prot = IPPROTO_UDP;
556
557			/* Let's snarf the universal address */
558			/* "h1.h2.h3.h4.p1.p2" */
559			udp_uaddr = taddr2uaddr(nconf, &taddr.addr);
560		} else if (strcmp(nconf->nc_netid, "local") == 0)
561			pml->pml_map.pm_prot = IPPROTO_ST;
562		else if (strcmp(nconf->nc_netid, "unix") == 0)
563			pml->pml_map.pm_prot = IPPROTO_ST;
564		pml->pml_next = list_pml;
565		list_pml = pml;
566
567		/* Add version 3 information */
568		pml = malloc(sizeof (struct pmaplist));
569		if (pml == NULL) {
570			syslog(LOG_ERR, "no memory!");
571			exit(1);
572		}
573		pml->pml_map = list_pml->pml_map;
574		pml->pml_map.pm_vers = RPCBVERS;
575		pml->pml_next = list_pml;
576		list_pml = pml;
577
578		/* Add version 4 information */
579		pml = malloc (sizeof (struct pmaplist));
580		if (pml == NULL) {
581			syslog(LOG_ERR, "no memory!");
582			exit(1);
583		}
584		pml->pml_map = list_pml->pml_map;
585		pml->pml_map.pm_vers = RPCBVERS4;
586		pml->pml_next = list_pml;
587		list_pml = pml;
588
589		/* Also add version 2 stuff to rpcbind list */
590		rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr);
591	}
592#endif
593
594	/* version 3 registration */
595	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
596		syslog(LOG_ERR, "could not register %s version 3",
597				nconf->nc_netid);
598		goto error;
599	}
600	rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr);
601
602	/* version 4 registration */
603	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
604		syslog(LOG_ERR, "could not register %s version 4",
605				nconf->nc_netid);
606		goto error;
607	}
608	rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr);
609
610	/* decide if bound checking works for this transport */
611	status = add_bndlist(nconf, &taddr.addr);
612#ifdef BIND_DEBUG
613	if (debugging) {
614		if (status < 0) {
615			fprintf(stderr, "Error in finding bind status for %s\n",
616				nconf->nc_netid);
617		} else if (status == 0) {
618			fprintf(stderr, "check binding for %s\n",
619				nconf->nc_netid);
620		} else if (status > 0) {
621			fprintf(stderr, "No check binding for %s\n",
622				nconf->nc_netid);
623		}
624	}
625#endif
626	/*
627	 * rmtcall only supported on CLTS transports for now.
628	 */
629	if (nconf->nc_semantics == NC_TPI_CLTS) {
630		status = create_rmtcall_fd(nconf);
631
632#ifdef BIND_DEBUG
633		if (debugging) {
634			if (status < 0) {
635				fprintf(stderr,
636				    "Could not create rmtcall fd for %s\n",
637					nconf->nc_netid);
638			} else {
639				fprintf(stderr, "rmtcall fd for %s is %d\n",
640					nconf->nc_netid, status);
641			}
642		}
643#endif
644	}
645	return (0);
646error:
647	close(fd);
648	return (1);
649}
650
651static void
652rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
653	    struct netbuf *addr)
654{
655	rpcblist_ptr rbl;
656
657	rbl = malloc(sizeof (rpcblist));
658	if (rbl == NULL) {
659		syslog(LOG_ERR, "no memory!");
660		exit(1);
661	}
662
663	rbl->rpcb_map.r_prog = prog;
664	rbl->rpcb_map.r_vers = vers;
665	rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
666	rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
667	rbl->rpcb_map.r_owner = strdup(superuser);
668	rbl->rpcb_next = list_rbl;	/* Attach to global list */
669	list_rbl = rbl;
670}
671
672/*
673 * Catch the signal and die
674 */
675static void
676terminate(int dummy __unused)
677{
678	close(rpcbindlockfd);
679#ifdef WARMSTART
680	syslog(LOG_ERR,
681		"rpcbind terminating on signal. Restart with \"rpcbind -w\"");
682	write_warmstart();	/* Dump yourself */
683#endif
684	exit(2);
685}
686
687void
688rpcbind_abort()
689{
690#ifdef WARMSTART
691	write_warmstart();	/* Dump yourself */
692#endif
693	abort();
694}
695
696/* get command line options */
697static void
698parseargs(int argc, char *argv[])
699{
700	int c;
701
702	while ((c = getopt(argc, argv, "dwah:ilLs")) != -1) {
703		switch (c) {
704		case 'a':
705			doabort = 1;	/* when debugging, do an abort on */
706			break;		/* errors; for rpcbind developers */
707					/* only! */
708		case 'd':
709			debugging = 1;
710			break;
711		case 'h':
712			++nhosts;
713			hosts = realloc(hosts, nhosts * sizeof(char *));
714			if (hosts == NULL)
715				errx(1, "Out of memory");
716			hosts[nhosts - 1] = strdup(optarg);
717			if (hosts[nhosts - 1] == NULL)
718				errx(1, "Out of memory");
719			break;
720		case 'i':
721			insecure = 1;
722			break;
723		case 'L':
724			oldstyle_local = 1;
725			break;
726		case 'l':
727			verboselog = 1;
728			break;
729		case 's':
730			runasdaemon = 1;
731			break;
732#ifdef WARMSTART
733		case 'w':
734			warmstart = 1;
735			break;
736#endif
737		default:	/* error */
738			fprintf(stderr,	"usage: rpcbind [-Idwils]\n");
739			exit (1);
740		}
741	}
742	if (doabort && !debugging) {
743	    fprintf(stderr,
744		"-a (abort) specified without -d (debugging) -- ignored.\n");
745	    doabort = 0;
746	}
747}
748
749void
750reap(int dummy __unused)
751{
752	int save_errno = errno;
753
754	while (wait3(NULL, WNOHANG, NULL) > 0)
755		;
756	errno = save_errno;
757}
758
759void
760toggle_verboselog(int dummy __unused)
761{
762	verboselog = !verboselog;
763}
764