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