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