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