1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 22 * Use is subject to license terms. 23 * 24 * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T 25 * All Rights Reserved 26 * 27 * Portions of this source code were derived from Berkeley 28 * 4.3 BSD under license from the Regents of the University of 29 * California. 30 */ 31 /* 32 * Copyright (c) 2016 by Delphix. All rights reserved. 33 */ 34 #pragma ident "%Z%%M% %I% %E% SMI" 35 36 #define _SVID_GETTOD 37 #include <sys/time.h> 38 extern int gettimeofday(struct timeval *); 39 40 #include <sys/types.h> 41 #include <stdio.h> 42 #include <string.h> 43 #include <malloc.h> 44 #include <errno.h> 45 #include <signal.h> 46 #include <limits.h> 47 #include <stdlib.h> 48 #include <unistd.h> 49 #include <sys/types.h> 50 #include <sys/wait.h> 51 #include <sys/stat.h> 52 #include <ctype.h> 53 #include <dirent.h> 54 #include <rpc/rpc.h> 55 #include <rpc/nettype.h> 56 #include <rpc/rpcb_prot.h> 57 #include <rpc/rpcb_clnt.h> 58 #include <sys/systeminfo.h> 59 #include <sys/select.h> 60 #include "ypsym.h" 61 #include "ypdefs.h" 62 #include "yp_b.h" 63 #include "shim.h" 64 #include "yptol.h" 65 66 67 #ifdef DEBUG 68 #undef YPPROG 69 #define YPPROG ((ulong_t)109999) 70 #undef YPBINDPROG 71 #define YPBINDPROG ((ulong_t)109998) 72 #endif 73 74 #define INTER_TRY 12 /* Seconds between tries */ 75 #define PORTMAP_TIME 30 /* Seconds before decide its down */ 76 #define TIMEOUT INTER_TRY*4 /* Total time for timeout */ 77 #define CUR_PAR 4 /* Total parallal yppushes */ 78 #define MIN_GRACE 25 /* select timeout and minimum grace */ 79 #define GRACE_PERIOD 800 /* Total seconds we'll wait for */ 80 /* responses from ypxfrs, yes */ 81 /* virginia yp map transfers */ 82 /* can take a long time, we */ 83 /* only worry if the slave */ 84 /* crashes ... */ 85 86 USE_YPDBPATH 87 static char *pusage; 88 static char *domain = NULL; 89 static char *host = NULL; 90 static char my_name[YPMAXPEER +1]; 91 static char default_domain_name[YPMAXDOMAIN]; 92 static char domain_alias[MAXNAMLEN]; /* nickname for domain - */ 93 /* used in sysv filesystems */ 94 static char map_alias[MAXNAMLEN]; /* nickname for map - */ 95 /* used in sysv filesystems */ 96 static char *map = NULL; 97 static bool verbose = FALSE; 98 static bool onehost = FALSE; 99 static bool oldxfr = FALSE; 100 static bool callback_timeout = FALSE; /* set when a callback times out */ 101 int grace_period = GRACE_PERIOD; 102 int curpar = CUR_PAR; /* should be set by other stuff */ 103 static char ypmapname[1024]; /* Used to check for map's existence */ 104 105 static struct timeval intertry = { 106 INTER_TRY, /* Seconds */ 107 0 /* Microseconds */ 108 }; 109 static struct timeval timeout = { 110 TIMEOUT, /* Seconds */ 111 0 /* Microseconds */ 112 }; 113 static SVCXPRT *transport4; 114 static SVCXPRT *transport6; 115 struct server { 116 struct server *pnext; 117 struct dom_binding domb; 118 char svc_name[YPMAXPEER+1]; 119 unsigned long xactid; 120 unsigned short state; 121 unsigned long status; 122 bool oldvers; 123 int start_time; 124 }; 125 #define n_conf dom_binding->ypbind_nconf 126 #define svc_addr dom_binding->ypbind_svcaddr 127 static struct server *server_list = (struct server *)NULL; 128 static struct server *active_list = (struct server *)NULL; 129 130 /* State values for server.state field */ 131 132 #define SSTAT_INIT 0 133 #define SSTAT_CALLED 1 134 #define SSTAT_RESPONDED 2 135 #define SSTAT_PROGNOTREG 3 136 #define SSTAT_RPC 4 137 #define SSTAT_RSCRC 5 138 #define SSTAT_SYSTEM 6 139 140 static char err_usage[] = 141 "Usage:\n\typpush [-p <par>] [-d <domainname>] [-h <hostname>] [-v] map\n"; 142 static char err_bad_args[] = 143 "The %s argument is bad.\n"; 144 static char err_cant_get_kname[] = 145 "Can't get %s from system call.\n"; 146 static char err_null_kname[] = 147 "The %s hasn't been set on this machine.\n"; 148 static char err_bad_domainname[] = "domainname"; 149 static char err_cant_bind[] = 150 "Can't find a yp server for domain %s. Reason: %s.\n"; 151 static char err_cant_build_serverlist[] = 152 "Can't build server list from map \"ypservers\". Reason: %s.\n"; 153 static char err_cant_find_host[] = 154 "Can't find host %s in map \"ypservers\".\n"; 155 /* 156 * State_duple table. All messages should take 1 arg - the node name. 157 */ 158 struct state_duple { 159 int state; 160 char *state_msg; 161 }; 162 static struct state_duple state_duples[] = { 163 {SSTAT_INIT, "Internal error trying to talk to %s."}, 164 {SSTAT_CALLED, "%s has been called."}, 165 {SSTAT_RESPONDED, "%s (v1 ypserv) sent an old-style request."}, 166 {SSTAT_PROGNOTREG, "nis server not registered at %s."}, 167 {SSTAT_RPC, "RPC error to %s: "}, 168 {SSTAT_RSCRC, "Local resource allocation failure - can't talk to %s."}, 169 {SSTAT_SYSTEM, "System error talking to %s: "}, 170 {0, (char *)NULL} 171 }; 172 /* 173 * Status_duple table. No messages should require any args. 174 */ 175 struct status_duple { 176 long status; 177 char *status_msg; 178 }; 179 static struct status_duple status_duples[] = { 180 {YPPUSH_SUCC, "Map successfully transferred."}, 181 {YPPUSH_AGE, 182 "Transfer not done: master's version isn't newer."}, 183 {YPPUSH_NOMAP, "Failed - ypxfr there can't find a server for map."}, 184 {YPPUSH_NODOM, "Failed - domain isn't supported."}, 185 {YPPUSH_RSRC, "Failed - local resource allocation failure."}, 186 {YPPUSH_RPC, "Failed - ypxfr had an RPC failure"}, 187 {YPPUSH_MADDR, "Failed - ypxfr couldn't get the map master's address."}, 188 {YPPUSH_YPERR, "Failed - nis server or map format error."}, 189 {YPPUSH_BADARGS, "Failed - args to ypxfr were bad."}, 190 {YPPUSH_DBM, "Failed - dbm operation on map failed."}, 191 {YPPUSH_FILE, "Failed - file I/O operation on map failed"}, 192 {YPPUSH_SKEW, "Failed - map version skew during transfer."}, 193 {YPPUSH_CLEAR, 194 "Map successfully transferred, but ypxfr \ 195 couldn't send \"Clear map\" to ypserv "}, 196 {YPPUSH_FORCE, 197 "Failed - no local order number in map - use -f flag to ypxfr."}, 198 {YPPUSH_XFRERR, "Failed - ypxfr internal error."}, 199 {YPPUSH_REFUSED, "Failed - Transfer request refused."}, 200 {YPPUSH_NOALIAS, 201 "Failed - System V domain/map alias not in alias file."}, 202 {0, (char *)NULL} 203 }; 204 /* 205 * rpcerr_duple table 206 */ 207 struct rpcerr_duple { 208 enum clnt_stat rpc_stat; 209 char *rpc_msg; 210 }; 211 static struct rpcerr_duple rpcerr_duples[] = { 212 {RPC_SUCCESS, "RPC success"}, 213 {RPC_CANTENCODEARGS, "RPC Can't encode args"}, 214 {RPC_CANTDECODERES, "RPC Can't decode results"}, 215 {RPC_CANTSEND, "RPC Can't send"}, 216 {RPC_CANTRECV, "RPC Can't recv"}, 217 {RPC_TIMEDOUT, "NIS server registered, but does not respond"}, 218 {RPC_VERSMISMATCH, "RPC version mismatch"}, 219 {RPC_AUTHERROR, "RPC auth error"}, 220 {RPC_PROGUNAVAIL, "RPC remote program unavailable"}, 221 {RPC_PROGVERSMISMATCH, "RPC program mismatch"}, 222 {RPC_PROCUNAVAIL, "RPC unknown procedure"}, 223 {RPC_CANTDECODEARGS, "RPC Can't decode args"}, 224 {RPC_UNKNOWNHOST, "unknown host"}, 225 {RPC_RPCBFAILURE, "rpcbind failure (host is down?)"}, 226 {RPC_PROGNOTREGISTERED, "RPC prog not registered"}, 227 {RPC_SYSTEMERROR, "RPC system error"}, 228 {RPC_SUCCESS, (char *)NULL} /* Duplicate rpc_stat */ 229 /* unused in list-end */ 230 /* entry */ 231 }; 232 233 static void get_default_domain_name(void); 234 static void get_command_line_args(int argc, char **argv); 235 static unsigned short send_message(struct server *ps, 236 unsigned long program, long *err); 237 static void make_server_list(void); 238 static void one_host_list(void); 239 static void add_server(char *sname, int namelen); 240 static int generate_callback(unsigned long *program); 241 static void xactid_seed(unsigned long *xactid); 242 static void main_loop(unsigned long program); 243 static void listener_exit(unsigned long program, int stat); 244 static void listener_dispatch(struct svc_req *rqstp, SVCXPRT *transp); 245 static void print_state_msg(struct server *s, long e); 246 static void print_callback_msg(struct server *s); 247 static void rpcerr_msg(enum clnt_stat e); 248 static void get_xfr_response(SVCXPRT *transp); 249 250 #ifdef SYSVCONFIG 251 extern void sysvconfig(void); 252 #endif 253 extern int yp_getalias(char *key, char *key_alias, int maxlen); 254 extern int getdomainname(char *, int); 255 256 extern struct rpc_createerr rpc_createerr; 257 extern CLIENT *__yp_clnt_create_rsvdport(); 258 259 int 260 main(int argc, char **argv) 261 { 262 unsigned long program; 263 struct stat64 sbuf; 264 265 get_command_line_args(argc, argv); 266 267 if (!domain) { 268 get_default_domain_name(); 269 } 270 271 #ifdef SYSVCONFIG 272 sysvconfig(); 273 #endif 274 275 if (yp_getalias(domain, domain_alias, NAME_MAX) != 0) 276 fprintf(stderr, "domain alias for %s not found\n", domain); 277 if (yp_getalias(map, map_alias, MAXALIASLEN) != 0) 278 fprintf(stderr, "map alias for %s not found\n", map); 279 280 /* check to see if the map exists in this domain */ 281 if (is_yptol_mode()) 282 sprintf(ypmapname, "%s/%s/%s%s.dir", ypdbpath, domain_alias, 283 NTOL_PREFIX, map_alias); 284 else 285 sprintf(ypmapname, "%s/%s/%s.dir", ypdbpath, domain_alias, 286 map_alias); 287 if (stat64(ypmapname, &sbuf) < 0) { 288 fprintf(stderr, "yppush: Map does not exist.\n"); 289 exit(1); 290 } 291 292 if (onehost) { 293 one_host_list(); 294 } else { 295 make_server_list(); 296 } 297 298 /* 299 * All process exits after the call to generate_callback should be 300 * through listener_exit(program, status), not exit(status), so the 301 * transient server can get unregistered with the portmapper. 302 */ 303 304 if (!generate_callback(&program)) { 305 fprintf(stderr, "Can't set up transient callback server.\n"); 306 } 307 308 main_loop(program); 309 310 listener_exit(program, 0); 311 312 /* NOTREACHED */ 313 return (0); 314 } 315 316 /* 317 * This does the command line parsing. 318 */ 319 static void 320 get_command_line_args(int argc, char **argv) 321 { 322 pusage = err_usage; 323 argv++; 324 325 if (argc < 2) { 326 fprintf(stderr, pusage); 327 exit(1); 328 } 329 330 while (--argc) { 331 if ((*argv)[0] == '-') { 332 switch ((*argv)[1]) { 333 case 'v': 334 verbose = TRUE; 335 argv++; 336 break; 337 case 'd': 338 if (argc > 1) { 339 argv++; 340 argc--; 341 domain = *argv; 342 argv++; 343 if (((int)strlen(domain)) > 344 YPMAXDOMAIN) { 345 fprintf(stderr, 346 err_bad_args, 347 err_bad_domainname); 348 exit(1); 349 } 350 } else { 351 fprintf(stderr, pusage); 352 exit(1); 353 } 354 break; 355 case 'h': 356 if (argc > 1) { 357 onehost = TRUE; 358 argv++; 359 argc--; 360 host = *argv; 361 argv++; 362 } else { 363 fprintf(stderr, pusage); 364 exit(1); 365 } 366 break; 367 368 case 'p': 369 370 if (argc > 1) { 371 argv++; 372 argc--; 373 if (sscanf(*argv, "%d", &curpar) != 1) { 374 (void) fprintf(stderr, pusage); 375 exit(1); 376 } 377 argv++; 378 if (curpar < 1) { 379 (void) fprintf(stderr, pusage); 380 exit(1); 381 } 382 } else { 383 (void) fprintf(stderr, pusage); 384 exit(1); 385 } 386 break; 387 388 default: 389 fprintf(stderr, pusage); 390 exit(1); 391 } 392 } else { 393 if (!map) { 394 map = *argv; 395 } else { 396 fprintf(stderr, pusage); 397 exit(1); 398 } 399 argv++; 400 } 401 } 402 403 if (!map) { 404 fprintf(stderr, pusage); 405 exit(1); 406 } 407 } 408 409 /* 410 * This gets the local kernel domainname, and sets the global domain to it. 411 */ 412 static void 413 get_default_domain_name(void) 414 { 415 if (!getdomainname(default_domain_name, YPMAXDOMAIN)) { 416 domain = default_domain_name; 417 } else { 418 fprintf(stderr, err_cant_get_kname, err_bad_domainname); 419 exit(1); 420 } 421 422 if ((int)strlen(domain) == 0) { 423 fprintf(stderr, err_null_kname, err_bad_domainname); 424 exit(1); 425 } 426 } 427 428 /* 429 * This verifies that the hostname supplied by the user is in the map 430 * "ypservers" then calls add_server to make it the only entry on the 431 * list of servers. 432 */ 433 static void 434 one_host_list(void) 435 { 436 char *key; 437 int keylen; 438 char *val; 439 int vallen; 440 int err; 441 char *ypservers = "ypservers"; 442 443 if (verbose) { 444 printf("Verifying YP server: %s\n", host); 445 fflush(stdout); 446 } 447 448 if (err = yp_bind(domain_alias)) { 449 fprintf(stderr, err_cant_bind, domain, yperr_string(err)); 450 exit(1); 451 } 452 453 keylen = strlen(host); 454 455 if (yp_match(domain_alias, ypservers, host, keylen, 456 &val, &vallen)) { 457 fprintf(stderr, err_cant_find_host, host); 458 exit(1); 459 } 460 461 add_server(host, keylen); 462 } 463 464 /* 465 * This uses yp operations to retrieve each server name in the map 466 * "ypservers". add_server is called for each one to add it to the list of 467 * servers. 468 */ 469 static void 470 make_server_list(void) 471 { 472 char *key; 473 int keylen; 474 char *outkey; 475 int outkeylen; 476 char *val; 477 int vallen; 478 int err; 479 char *ypservers = "ypservers"; 480 int count; 481 482 if (verbose) { 483 printf("Finding YP servers: "); 484 fflush(stdout); 485 count = 4; 486 } 487 488 if (err = yp_bind(domain_alias)) { 489 fprintf(stderr, err_cant_bind, domain, yperr_string(err)); 490 exit(1); 491 } 492 493 if (err = yp_first(domain_alias, ypservers, &outkey, &outkeylen, 494 &val, &vallen)) { 495 fprintf(stderr, err_cant_build_serverlist, yperr_string(err)); 496 exit(1); 497 } 498 499 for (;;) { 500 add_server(outkey, outkeylen); 501 if (verbose) { 502 printf(" %s", outkey); 503 fflush(stdout); 504 if (count++ == 8) { 505 printf("\n"); 506 count = 0; 507 } 508 } 509 free(val); 510 key = outkey; 511 keylen = outkeylen; 512 513 if (err = yp_next(domain_alias, ypservers, key, keylen, 514 &outkey, &outkeylen, &val, &vallen)) { 515 516 if (err == YPERR_NOMORE) { 517 break; 518 } else { 519 fprintf(stderr, err_cant_build_serverlist, 520 yperr_string(err)); 521 exit(1); 522 } 523 } 524 525 free(key); 526 } 527 if (count != 0) { 528 if (verbose) 529 printf("\n"); 530 } 531 } 532 533 /* 534 * This adds a single server to the server list. 535 */ 536 static void 537 add_server(char *sname, int namelen) 538 { 539 struct server *ps; 540 static unsigned long seq; 541 static unsigned long xactid = 0; 542 543 if (strcmp(sname, my_name) == 0) 544 return; 545 546 if (xactid == 0) { 547 xactid_seed(&xactid); 548 } 549 550 if ((ps = (struct server *)malloc((unsigned)sizeof (struct server))) 551 == (struct server *)NULL) { 552 perror("yppush: malloc failure"); 553 exit(1); 554 } 555 556 sname[namelen] = '\0'; 557 strcpy(ps->svc_name, sname); 558 ps->state = SSTAT_INIT; 559 ps->status = 0; 560 ps->oldvers = FALSE; 561 ps->xactid = xactid + seq++; 562 ps->pnext = server_list; 563 server_list = ps; 564 } 565 566 /* 567 * This sets the base range for the transaction ids used in speaking the the 568 * server ypxfr processes. 569 */ 570 static void 571 xactid_seed(unsigned long *xactid) 572 { 573 struct timeval t; 574 575 if (gettimeofday(&t) == -1) { 576 perror("yppush gettimeofday failure"); 577 *xactid = 1234567; 578 } else { 579 *xactid = t.tv_sec; 580 } 581 } 582 583 /* 584 * This generates the channel which will be used as the listener process' 585 * service rendezvous point, and comes up with a transient program number 586 * for the use of the RPC messages from the ypxfr processes. 587 */ 588 static int 589 generate_callback(unsigned long *program) 590 { 591 unsigned long prognum = 0x40000000, maxprognum; 592 union { 593 unsigned long p; 594 unsigned char b[sizeof (unsigned long)]; 595 } u; 596 int ret, i; 597 struct netconfig *nc4, *nc6, *nc; 598 SVCXPRT *trans; 599 600 nc4 = getnetconfigent("udp"); 601 nc6 = getnetconfigent("udp6"); 602 if (nc4 == 0 && nc6 == 0) { 603 fprintf(stderr, 604 "yppush: Could not get udp or udp6 netconfig entry\n"); 605 exit(1); 606 } 607 608 transport4 = (nc4 == 0) ? 0 : svc_tli_create(RPC_ANYFD, nc4, 0, 0, 0); 609 transport6 = (nc6 == 0) ? 0 : svc_tli_create(RPC_ANYFD, nc6, 0, 0, 0); 610 if (transport4 == 0 && transport6 == 0) { 611 fprintf(stderr, "yppush: Could not create server handle(s)\n"); 612 exit(1); 613 } 614 615 /* Find the maximum possible program number using an unsigned long */ 616 for (i = 0; i < sizeof (u.b); i++) 617 u.b[i] = 0xff; 618 maxprognum = u.p; 619 620 if (transport4 != 0) { 621 trans = transport4; 622 nc = nc4; 623 } else { 624 trans = transport6; 625 nc = nc6; 626 } 627 while (prognum < maxprognum && (ret = 628 rpcb_set(prognum, YPPUSHVERS, nc, &trans->xp_ltaddr)) == 0) 629 prognum++; 630 631 if (ret == 0) { 632 fprintf(stderr, "yppush: Could not create callback service\n"); 633 exit(1); 634 } else { 635 if (trans == transport4 && transport6 != 0) { 636 ret = rpcb_set(prognum, YPPUSHVERS, nc6, 637 &transport6->xp_ltaddr); 638 if (ret == 0) { 639 fprintf(stderr, 640 "yppush: Could not create udp6 callback service\n"); 641 exit(1); 642 } 643 } 644 *program = prognum; 645 } 646 647 return (ret); 648 } 649 650 /* 651 * This is the main loop. Send messages to each server, 652 * and then wait for a response. 653 */ 654 655 656 int 657 add_to_active() 658 { 659 struct server *ps; 660 ps = server_list; 661 if (ps == NULL) 662 return (0); 663 server_list = server_list->pnext; /* delete from server_list */ 664 ps->pnext = active_list; 665 active_list = ps; 666 return (1); 667 } 668 669 int 670 delete_active(in) 671 struct server *in; 672 { 673 struct server *p; 674 struct server *n; 675 if (in == active_list) { 676 active_list = active_list->pnext; 677 return (1); 678 } 679 p = active_list; 680 for (n = active_list; n; n = n->pnext) { 681 if (in == n) { 682 p->pnext = n->pnext; 683 return (0); 684 685 } 686 p = n; 687 } 688 return (-1); 689 } 690 691 void 692 main_loop(program) 693 unsigned long program; 694 { 695 pollfd_t *pollset = NULL; 696 int npollfds = 0; 697 int pollret; 698 struct server *ps; 699 long error; 700 int hpar; /* this times par count */ 701 int i; 702 int j; 703 int time_now; 704 int docb; 705 int actives = 0; 706 int dead = 0; 707 708 if (grace_period < MIN_GRACE) 709 grace_period = MIN_GRACE; 710 if (transport4 != 0) { 711 if (!svc_reg(transport4, program, YPPUSHVERS, 712 listener_dispatch, 0)) { 713 fprintf(stderr, 714 "Can't set up transient udp callback server.\n"); 715 } 716 } 717 if (transport6 != 0) { 718 if (!svc_reg(transport6, program, YPPUSHVERS, 719 listener_dispatch, 0)) { 720 fprintf(stderr, 721 "Can't set up transient udp6 callback server.\n"); 722 } 723 } 724 for (;;) { 725 time_now = time(0); 726 if (server_list == NULL) { 727 actives = 0; 728 dead = 0; 729 for (ps = active_list; ps; ps = ps->pnext) 730 if (ps->state == SSTAT_CALLED) { 731 if ((time_now - ps->start_time) < 732 grace_period) 733 actives++; 734 else 735 dead++; 736 } 737 if (actives == 0) { 738 if (verbose) { 739 printf("terminating %d dead\n", dead); 740 fflush(stdout); 741 } 742 743 for (ps = active_list; ps; ps = ps->pnext) 744 if (ps->state == SSTAT_CALLED) { 745 if ((time_now - ps->start_time) 746 >= grace_period) { 747 if (verbose) { 748 printf( 749 "no response from %s -- grace of %d seconds expired.\n", 750 ps->svc_name, grace_period); 751 fflush(stdout); 752 } 753 fprintf(stderr, 754 "No response from ypxfr on %s\n", ps->svc_name); 755 } 756 } 757 break; 758 } 759 } 760 actives = 0; 761 for (ps = active_list; ps; ps = ps->pnext) { 762 if (ps->state == SSTAT_CALLED) { 763 if ((time_now - ps->start_time) 764 < grace_period) { 765 actives++; 766 767 if (verbose) { 768 printf( 769 "No response yet from ypxfr on %s\n", ps->svc_name); 770 fflush(stdout); 771 } 772 } 773 } else { 774 if (verbose) { 775 printf("Deactivating %s\n", 776 ps->svc_name); 777 fflush(stdout); 778 } 779 delete_active(ps); 780 } 781 } 782 783 /* add someone to the active list keep up with curpar */ 784 for (i = 0; i < (curpar - actives); i++) { 785 if (add_to_active()) { 786 ps = active_list; 787 ps->state = send_message(ps, program, &error); 788 print_state_msg(ps, error); 789 if (ps->state != SSTAT_CALLED) 790 delete_active(ps); /* zorch it */ 791 else 792 ps->start_time = time(0); /* set time */ 793 } 794 } 795 docb = 0; 796 for (ps = active_list; ps; ps = ps->pnext) 797 if (ps->state == SSTAT_CALLED) { 798 docb = 1; 799 break; 800 } 801 if (docb == 0) { 802 if (verbose) { 803 printf("No one to wait for this pass.\n"); 804 fflush(stdout); 805 } 806 continue; /* try curpar more */ 807 } 808 809 if (npollfds != svc_max_pollfd) { 810 pollset = realloc(pollset, 811 sizeof (pollfd_t) * svc_max_pollfd); 812 npollfds = svc_max_pollfd; 813 } 814 815 /* 816 * Get existing array of pollfd's, should really compress 817 * this but it shouldn't get very large (or sparse). 818 */ 819 (void) memcpy(pollset, svc_pollfd, 820 sizeof (pollfd_t) * svc_max_pollfd); 821 822 errno = 0; 823 switch (pollret = poll(pollset, npollfds, MIN_GRACE * 1000)) { 824 case -1: 825 if (errno != EINTR) { 826 (void) perror("main loop select"); 827 } 828 break; 829 830 case 0: 831 if (verbose) { 832 (void) printf("timeout in main loop select.\n"); 833 fflush(stdout); 834 } 835 break; 836 837 default: 838 svc_getreq_poll(pollset, pollret); 839 break; 840 } /* switch */ 841 } /* for */ 842 } 843 844 /* 845 * This does the listener process cleanup and process exit. 846 */ 847 static void 848 listener_exit(unsigned long program, int stat) 849 { 850 svc_unreg(program, YPPUSHVERS); 851 exit(stat); 852 } 853 854 /* 855 * This is the listener process' RPC service dispatcher. 856 */ 857 static void 858 listener_dispatch(struct svc_req *rqstp, SVCXPRT *transp) 859 { 860 switch (rqstp->rq_proc) { 861 862 case YPPUSHPROC_NULL: 863 if (!svc_sendreply(transp, xdr_void, 0)) { 864 fprintf(stderr, "Can't reply to rpc call.\n"); 865 } 866 break; 867 868 case YPPUSHPROC_XFRRESP: 869 get_xfr_response(transp); 870 break; 871 872 default: 873 svcerr_noproc(transp); 874 break; 875 } 876 } 877 878 879 /* 880 * This dumps a server state message to stdout. It is called in cases where 881 * we have no expectation of receiving a callback from the remote ypxfr. 882 */ 883 static void 884 print_state_msg(struct server *s, long e) 885 { 886 struct state_duple *sd; 887 888 if (s->state == SSTAT_SYSTEM) 889 return; /* already printed */ 890 891 if (!verbose && (s->state == SSTAT_RESPONDED || 892 s->state == SSTAT_CALLED)) 893 return; 894 895 for (sd = state_duples; sd->state_msg; sd++) { 896 if (sd->state == s->state) { 897 printf(sd->state_msg, s->svc_name); 898 899 if (s->state == SSTAT_RPC) { 900 rpcerr_msg((enum clnt_stat) e); 901 } 902 903 printf("\n"); 904 fflush(stdout); 905 return; 906 } 907 } 908 909 fprintf(stderr, "yppush: Bad server state value %d.\n", s->state); 910 } 911 912 /* 913 * This dumps a transfer status message to stdout. It is called in 914 * response to a received RPC message from the called ypxfr. 915 */ 916 static void 917 print_callback_msg(struct server *s) 918 { 919 register struct status_duple *sd; 920 921 if (!verbose && 922 (s->status == YPPUSH_AGE) || 923 (s->status == YPPUSH_SUCC)) 924 925 return; 926 927 for (sd = status_duples; sd->status_msg; sd++) { 928 929 if (sd->status == s->status) { 930 printf("Status received from ypxfr on %s:\n\t%s\n", 931 s->svc_name, sd->status_msg); 932 fflush(stdout); 933 return; 934 } 935 } 936 937 fprintf(stderr, "yppush listener: Garbage transaction " 938 "status (value %d) from ypxfr on %s.\n", 939 (int)s->status, s->svc_name); 940 } 941 942 /* 943 * This dumps an RPC error message to stdout. This is basically a rewrite 944 * of clnt_perrno, but writes to stdout instead of stderr. 945 */ 946 static void 947 rpcerr_msg(enum clnt_stat e) 948 { 949 struct rpcerr_duple *rd; 950 951 for (rd = rpcerr_duples; rd->rpc_msg; rd++) { 952 953 if (rd->rpc_stat == e) { 954 printf(rd->rpc_msg); 955 return; 956 } 957 } 958 959 fprintf(stderr, "Bad error code passed to rpcerr_msg: %d.\n", e); 960 } 961 962 /* 963 * This picks up the response from the ypxfr process which has been started 964 * up on the remote node. The response status must be non-zero, otherwise 965 * the status will be set to "ypxfr error". 966 */ 967 static void 968 get_xfr_response(SVCXPRT *transp) 969 { 970 struct yppushresp_xfr resp; 971 register struct server *s; 972 973 if (!svc_getargs(transp, (xdrproc_t)xdr_yppushresp_xfr, 974 (caddr_t)&resp)) { 975 svcerr_decode(transp); 976 return; 977 } 978 979 if (!svc_sendreply(transp, xdr_void, 0)) { 980 (void) fprintf(stderr, "Can't reply to rpc call.\n"); 981 } 982 983 for (s = active_list; s; s = s->pnext) { 984 985 if (s->xactid == resp.transid) { 986 s->status = resp.status ? resp.status: YPPUSH_XFRERR; 987 print_callback_msg(s); 988 s->state = SSTAT_RESPONDED; 989 return; 990 } 991 } 992 } 993 994 /* 995 * This sends a message to a single ypserv process. The return value is 996 * a state value. If the RPC call fails because of a version 997 * mismatch, we'll assume that we're talking to a version 1 ypserv process, 998 * and will send it an old "YPPROC_GET" request, as was defined in the 999 * earlier version of yp_prot.h 1000 */ 1001 static unsigned short 1002 send_message(struct server *ps, unsigned long program, long *err) 1003 { 1004 struct ypreq_newxfr req; 1005 struct ypreq_xfr oldreq; 1006 enum clnt_stat s; 1007 struct rpc_err rpcerr; 1008 1009 if ((ps->domb.dom_client = __yp_clnt_create_rsvdport(ps->svc_name, 1010 YPPROG, YPVERS, (char *)NULL, 0, 0)) == NULL) { 1011 1012 if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) { 1013 return (SSTAT_PROGNOTREG); 1014 } else { 1015 printf("Error talking to %s: ", ps->svc_name); 1016 rpcerr_msg(rpc_createerr.cf_stat); 1017 printf("\n"); 1018 fflush(stdout); 1019 return (SSTAT_SYSTEM); 1020 } 1021 } 1022 1023 if (sysinfo(SI_HOSTNAME, my_name, sizeof (my_name)) == -1) { 1024 return (SSTAT_RSCRC); 1025 } 1026 1027 if (!oldxfr) { 1028 req.ypxfr_domain = domain; 1029 req.ypxfr_map = map; 1030 req.ypxfr_ordernum = 0; 1031 req.ypxfr_owner = my_name; 1032 req.name = ps->svc_name; 1033 /* 1034 * the creation of field req.name, instead of ypreq_xfr (old) 1035 * req.port, does not make any sense. it doesn't give any 1036 * information to receiving ypserv except its own name !! 1037 * new ypserv duplicates work for YPPROC_XFR and YPPROC_NEWXFR 1038 */ 1039 req.transid = ps->xactid; 1040 req.proto = program; 1041 s = (enum clnt_stat) clnt_call(ps->domb.dom_client, 1042 YPPROC_NEWXFR, (xdrproc_t)xdr_ypreq_newxfr, (caddr_t)&req, 1043 xdr_void, 0, timeout); 1044 } 1045 1046 clnt_geterr(ps->domb.dom_client, &rpcerr); 1047 1048 if (s == RPC_PROCUNAVAIL) { 1049 oldreq.ypxfr_domain = domain; 1050 oldreq.ypxfr_map = map; 1051 oldreq.ypxfr_ordernum = 0; 1052 oldreq.ypxfr_owner = my_name; 1053 oldreq.transid = ps->xactid; 1054 oldreq.proto = program; 1055 oldreq.port = 0; 1056 s = (enum clnt_stat) clnt_call(ps->domb.dom_client, 1057 YPPROC_XFR, (xdrproc_t)xdr_ypreq_xfr, (caddr_t)&oldreq, 1058 xdr_void, 0, timeout); 1059 clnt_geterr(ps->domb.dom_client, &rpcerr); 1060 } 1061 1062 clnt_destroy(ps->domb.dom_client); 1063 1064 if (s == RPC_SUCCESS) { 1065 return (SSTAT_CALLED); 1066 } else { 1067 *err = (long)rpcerr.re_status; 1068 return (SSTAT_RPC); 1069 } 1070 /*NOTREACHED*/ 1071 } 1072 1073 /* 1074 * FUNCTION: is_yptol_mode(); 1075 * 1076 * DESCRIPTION: Determines if we should run in N2L or traditional mode based 1077 * on the presence of the N2L mapping file. 1078 * 1079 * This is a copy of a function from libnisdb. If more than this 1080 * one function become required it may be worth linking the 1081 * entire lib. 1082 * 1083 * INPUTS: Nothing 1084 * 1085 * OUTPUTS: TRUE = Run in N2L mode 1086 * FALSE = Run in traditional mode. 1087 */ 1088 bool_t 1089 is_yptol_mode() 1090 { 1091 struct stat filestat; 1092 1093 if (stat(NTOL_MAP_FILE, &filestat) != -1) 1094 return (TRUE); 1095 1096 return (FALSE); 1097 } 1098