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