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