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
main(int argc,char ** argv)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
get_command_line_args(int argc,char ** argv)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
get_default_domain_name(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
one_host_list(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
make_server_list(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
add_server(char * sname,int namelen)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
xactid_seed(unsigned long * xactid)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
generate_callback(unsigned long * program)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
add_to_active()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
delete_active(in)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
main_loop(program)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
listener_exit(unsigned long program,int stat)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
listener_dispatch(struct svc_req * rqstp,SVCXPRT * transp)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
print_state_msg(struct server * s,long e)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
print_callback_msg(struct server * s)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
rpcerr_msg(enum clnt_stat e)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
get_xfr_response(SVCXPRT * transp)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
send_message(struct server * ps,unsigned long program,long * err)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
is_yptol_mode()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