cmd-inet/usr.sbin: remove -Wno-implicit-function-declaration
[unleashed.git] / usr / src / cmd / ypcmd / yppush.c
blob9d9f554038f91068912afced48b34d0659909cef
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
21 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
22 * Use is subject to license terms.
24 * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
25 * All Rights Reserved
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.
32 * Copyright (c) 2016 by Delphix. All rights reserved.
34 #pragma ident "%Z%%M% %I% %E% SMI"
36 #define _SVID_GETTOD
37 #include <sys/time.h>
38 extern int gettimeofday(struct timeval *);
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"
67 #ifdef DEBUG
68 #undef YPPROG
69 #define YPPROG ((ulong_t)109999)
70 #undef YPBINDPROG
71 #define YPBINDPROG ((ulong_t)109998)
72 #endif
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 ... */
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 */
105 static struct timeval intertry = {
106 INTER_TRY, /* Seconds */
107 0 /* Microseconds */
109 static struct timeval timeout = {
110 TIMEOUT, /* Seconds */
111 0 /* Microseconds */
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;
125 #define n_conf dom_binding->ypbind_nconf
126 #define svc_addr dom_binding->ypbind_svcaddr
127 static struct server *server_list = NULL;
128 static struct server *active_list = NULL;
130 /* State values for server.state field */
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
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";
156 * State_duple table. All messages should take 1 arg - the node name.
158 struct state_duple {
159 int state;
160 char *state_msg;
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, NULL}
173 * Status_duple table. No messages should require any args.
175 struct status_duple {
176 long status;
177 char *status_msg;
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, NULL}
205 * rpcerr_duple table
207 struct rpcerr_duple {
208 enum clnt_stat rpc_stat;
209 char *rpc_msg;
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, NULL} /* Duplicate rpc_stat */
229 /* unused in list-end */
230 /* entry */
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);
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);
256 extern CLIENT *__yp_clnt_create_rsvdport();
259 main(int argc, char **argv)
261 unsigned long program;
262 struct stat64 sbuf;
264 get_command_line_args(argc, argv);
266 if (!domain) {
267 get_default_domain_name();
270 #ifdef SYSVCONFIG
271 sysvconfig();
272 #endif
274 if (yp_getalias(domain, domain_alias, NAME_MAX) != 0)
275 fprintf(stderr, "domain alias for %s not found\n", domain);
276 if (yp_getalias(map, map_alias, MAXALIASLEN) != 0)
277 fprintf(stderr, "map alias for %s not found\n", map);
279 /* check to see if the map exists in this domain */
280 if (is_yptol_mode())
281 sprintf(ypmapname, "%s/%s/%s%s.dir", ypdbpath, domain_alias,
282 NTOL_PREFIX, map_alias);
283 else
284 sprintf(ypmapname, "%s/%s/%s.dir", ypdbpath, domain_alias,
285 map_alias);
286 if (stat64(ypmapname, &sbuf) < 0) {
287 fprintf(stderr, "yppush: Map does not exist.\n");
288 exit(1);
291 if (onehost) {
292 one_host_list();
293 } else {
294 make_server_list();
298 * All process exits after the call to generate_callback should be
299 * through listener_exit(program, status), not exit(status), so the
300 * transient server can get unregistered with the portmapper.
303 if (!generate_callback(&program)) {
304 fprintf(stderr, "Can't set up transient callback server.\n");
307 main_loop(program);
309 listener_exit(program, 0);
311 /* NOTREACHED */
312 return (0);
316 * This does the command line parsing.
318 static void
319 get_command_line_args(int argc, char **argv)
321 pusage = err_usage;
322 argv++;
324 if (argc < 2) {
325 fprintf(stderr, pusage);
326 exit(1);
329 while (--argc) {
330 if ((*argv)[0] == '-') {
331 switch ((*argv)[1]) {
332 case 'v':
333 verbose = TRUE;
334 argv++;
335 break;
336 case 'd':
337 if (argc > 1) {
338 argv++;
339 argc--;
340 domain = *argv;
341 argv++;
342 if (((int)strlen(domain)) >
343 YPMAXDOMAIN) {
344 fprintf(stderr,
345 err_bad_args,
346 err_bad_domainname);
347 exit(1);
349 } else {
350 fprintf(stderr, pusage);
351 exit(1);
353 break;
354 case 'h':
355 if (argc > 1) {
356 onehost = TRUE;
357 argv++;
358 argc--;
359 host = *argv;
360 argv++;
361 } else {
362 fprintf(stderr, pusage);
363 exit(1);
365 break;
367 case 'p':
369 if (argc > 1) {
370 argv++;
371 argc--;
372 if (sscanf(*argv, "%d", &curpar) != 1) {
373 (void) fprintf(stderr, pusage);
374 exit(1);
376 argv++;
377 if (curpar < 1) {
378 (void) fprintf(stderr, pusage);
379 exit(1);
381 } else {
382 (void) fprintf(stderr, pusage);
383 exit(1);
385 break;
387 default:
388 fprintf(stderr, pusage);
389 exit(1);
391 } else {
392 if (!map) {
393 map = *argv;
394 } else {
395 fprintf(stderr, pusage);
396 exit(1);
398 argv++;
402 if (!map) {
403 fprintf(stderr, pusage);
404 exit(1);
409 * This gets the local kernel domainname, and sets the global domain to it.
411 static void
412 get_default_domain_name(void)
414 if (!getdomainname(default_domain_name, YPMAXDOMAIN)) {
415 domain = default_domain_name;
416 } else {
417 fprintf(stderr, err_cant_get_kname, err_bad_domainname);
418 exit(1);
421 if ((int)strlen(domain) == 0) {
422 fprintf(stderr, err_null_kname, err_bad_domainname);
423 exit(1);
428 * This verifies that the hostname supplied by the user is in the map
429 * "ypservers" then calls add_server to make it the only entry on the
430 * list of servers.
432 static void
433 one_host_list(void)
435 char *key;
436 int keylen;
437 char *val;
438 int vallen;
439 int err;
440 char *ypservers = "ypservers";
442 if (verbose) {
443 printf("Verifying YP server: %s\n", host);
444 fflush(stdout);
447 if (err = yp_bind(domain_alias)) {
448 fprintf(stderr, err_cant_bind, domain, yperr_string(err));
449 exit(1);
452 keylen = strlen(host);
454 if (yp_match(domain_alias, ypservers, host, keylen,
455 &val, &vallen)) {
456 fprintf(stderr, err_cant_find_host, host);
457 exit(1);
460 add_server(host, keylen);
464 * This uses yp operations to retrieve each server name in the map
465 * "ypservers". add_server is called for each one to add it to the list of
466 * servers.
468 static void
469 make_server_list(void)
471 char *key;
472 int keylen;
473 char *outkey;
474 int outkeylen;
475 char *val;
476 int vallen;
477 int err;
478 char *ypservers = "ypservers";
479 int count;
481 if (verbose) {
482 printf("Finding YP servers: ");
483 fflush(stdout);
484 count = 4;
487 if (err = yp_bind(domain_alias)) {
488 fprintf(stderr, err_cant_bind, domain, yperr_string(err));
489 exit(1);
492 if (err = yp_first(domain_alias, ypservers, &outkey, &outkeylen,
493 &val, &vallen)) {
494 fprintf(stderr, err_cant_build_serverlist, yperr_string(err));
495 exit(1);
498 for (;;) {
499 add_server(outkey, outkeylen);
500 if (verbose) {
501 printf(" %s", outkey);
502 fflush(stdout);
503 if (count++ == 8) {
504 printf("\n");
505 count = 0;
508 free(val);
509 key = outkey;
510 keylen = outkeylen;
512 if (err = yp_next(domain_alias, ypservers, key, keylen,
513 &outkey, &outkeylen, &val, &vallen)) {
515 if (err == YPERR_NOMORE) {
516 break;
517 } else {
518 fprintf(stderr, err_cant_build_serverlist,
519 yperr_string(err));
520 exit(1);
524 free(key);
526 if (count != 0) {
527 if (verbose)
528 printf("\n");
533 * This adds a single server to the server list.
535 static void
536 add_server(char *sname, int namelen)
538 struct server *ps;
539 static unsigned long seq;
540 static unsigned long xactid = 0;
542 if (strcmp(sname, my_name) == 0)
543 return;
545 if (xactid == 0) {
546 xactid_seed(&xactid);
549 if ((ps = (struct server *)malloc((unsigned)sizeof (struct server)))
550 == NULL) {
551 perror("yppush: malloc failure");
552 exit(1);
555 sname[namelen] = '\0';
556 strcpy(ps->svc_name, sname);
557 ps->state = SSTAT_INIT;
558 ps->status = 0;
559 ps->oldvers = FALSE;
560 ps->xactid = xactid + seq++;
561 ps->pnext = server_list;
562 server_list = ps;
566 * This sets the base range for the transaction ids used in speaking the the
567 * server ypxfr processes.
569 static void
570 xactid_seed(unsigned long *xactid)
572 struct timeval t;
574 if (gettimeofday(&t) == -1) {
575 perror("yppush gettimeofday failure");
576 *xactid = 1234567;
577 } else {
578 *xactid = t.tv_sec;
583 * This generates the channel which will be used as the listener process'
584 * service rendezvous point, and comes up with a transient program number
585 * for the use of the RPC messages from the ypxfr processes.
587 static int
588 generate_callback(unsigned long *program)
590 unsigned long prognum = 0x40000000, maxprognum;
591 union {
592 unsigned long p;
593 unsigned char b[sizeof (unsigned long)];
594 } u;
595 int ret, i;
596 struct netconfig *nc4, *nc6, *nc;
597 SVCXPRT *trans;
599 nc4 = getnetconfigent("udp");
600 nc6 = getnetconfigent("udp6");
601 if (nc4 == 0 && nc6 == 0) {
602 fprintf(stderr,
603 "yppush: Could not get udp or udp6 netconfig entry\n");
604 exit(1);
607 transport4 = (nc4 == 0) ? 0 : svc_tli_create(RPC_ANYFD, nc4, 0, 0, 0);
608 transport6 = (nc6 == 0) ? 0 : svc_tli_create(RPC_ANYFD, nc6, 0, 0, 0);
609 if (transport4 == 0 && transport6 == 0) {
610 fprintf(stderr, "yppush: Could not create server handle(s)\n");
611 exit(1);
614 /* Find the maximum possible program number using an unsigned long */
615 for (i = 0; i < sizeof (u.b); i++)
616 u.b[i] = 0xff;
617 maxprognum = u.p;
619 if (transport4 != 0) {
620 trans = transport4;
621 nc = nc4;
622 } else {
623 trans = transport6;
624 nc = nc6;
626 while (prognum < maxprognum && (ret =
627 rpcb_set(prognum, YPPUSHVERS, nc, &trans->xp_ltaddr)) == 0)
628 prognum++;
630 if (ret == 0) {
631 fprintf(stderr, "yppush: Could not create callback service\n");
632 exit(1);
633 } else {
634 if (trans == transport4 && transport6 != 0) {
635 ret = rpcb_set(prognum, YPPUSHVERS, nc6,
636 &transport6->xp_ltaddr);
637 if (ret == 0) {
638 fprintf(stderr,
639 "yppush: Could not create udp6 callback service\n");
640 exit(1);
643 *program = prognum;
646 return (ret);
650 * This is the main loop. Send messages to each server,
651 * and then wait for a response.
656 add_to_active()
658 struct server *ps;
659 ps = server_list;
660 if (ps == NULL)
661 return (0);
662 server_list = server_list->pnext; /* delete from server_list */
663 ps->pnext = active_list;
664 active_list = ps;
665 return (1);
669 delete_active(in)
670 struct server *in;
672 struct server *p;
673 struct server *n;
674 if (in == active_list) {
675 active_list = active_list->pnext;
676 return (1);
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);
685 p = n;
687 return (-1);
690 void
691 main_loop(program)
692 unsigned long program;
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;
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");
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");
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++;
736 if (actives == 0) {
737 if (verbose) {
738 printf("terminating %d dead\n", dead);
739 fflush(stdout);
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);
752 fprintf(stderr,
753 "No response from ypxfr on %s\n", ps->svc_name);
756 break;
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++;
766 if (verbose) {
767 printf(
768 "No response yet from ypxfr on %s\n", ps->svc_name);
769 fflush(stdout);
772 } else {
773 if (verbose) {
774 printf("Deactivating %s\n",
775 ps->svc_name);
776 fflush(stdout);
778 delete_active(ps);
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 */
794 docb = 0;
795 for (ps = active_list; ps; ps = ps->pnext)
796 if (ps->state == SSTAT_CALLED) {
797 docb = 1;
798 break;
800 if (docb == 0) {
801 if (verbose) {
802 printf("No one to wait for this pass.\n");
803 fflush(stdout);
805 continue; /* try curpar more */
808 if (npollfds != svc_max_pollfd) {
809 pollset = reallocarray(pollset, svc_max_pollfd,
810 sizeof (pollfd_t));
811 npollfds = svc_max_pollfd;
815 * Get existing array of pollfd's, should really compress
816 * this but it shouldn't get very large (or sparse).
818 (void) memcpy(pollset, svc_pollfd,
819 sizeof (pollfd_t) * svc_max_pollfd);
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");
827 break;
829 case 0:
830 if (verbose) {
831 (void) printf("timeout in main loop select.\n");
832 fflush(stdout);
834 break;
836 default:
837 svc_getreq_poll(pollset, pollret);
838 break;
839 } /* switch */
840 } /* for */
844 * This does the listener process cleanup and process exit.
846 static void
847 listener_exit(unsigned long program, int stat)
849 svc_unreg(program, YPPUSHVERS);
850 exit(stat);
854 * This is the listener process' RPC service dispatcher.
856 static void
857 listener_dispatch(struct svc_req *rqstp, SVCXPRT *transp)
859 switch (rqstp->rq_proc) {
861 case YPPUSHPROC_NULL:
862 if (!svc_sendreply(transp, xdr_void, 0)) {
863 fprintf(stderr, "Can't reply to rpc call.\n");
865 break;
867 case YPPUSHPROC_XFRRESP:
868 get_xfr_response(transp);
869 break;
871 default:
872 svcerr_noproc(transp);
873 break;
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.
882 static void
883 print_state_msg(struct server *s, long e)
885 struct state_duple *sd;
887 if (s->state == SSTAT_SYSTEM)
888 return; /* already printed */
890 if (!verbose && (s->state == SSTAT_RESPONDED ||
891 s->state == SSTAT_CALLED))
892 return;
894 for (sd = state_duples; sd->state_msg; sd++) {
895 if (sd->state == s->state) {
896 printf(sd->state_msg, s->svc_name);
898 if (s->state == SSTAT_RPC) {
899 rpcerr_msg((enum clnt_stat) e);
902 printf("\n");
903 fflush(stdout);
904 return;
908 fprintf(stderr, "yppush: Bad server state value %d.\n", s->state);
912 * This dumps a transfer status message to stdout. It is called in
913 * response to a received RPC message from the called ypxfr.
915 static void
916 print_callback_msg(struct server *s)
918 register struct status_duple *sd;
920 if (!verbose &&
921 (s->status == YPPUSH_AGE) ||
922 (s->status == YPPUSH_SUCC))
924 return;
926 for (sd = status_duples; sd->status_msg; sd++) {
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;
936 fprintf(stderr, "yppush listener: Garbage transaction "
937 "status (value %d) from ypxfr on %s.\n",
938 (int)s->status, s->svc_name);
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.
945 static void
946 rpcerr_msg(enum clnt_stat e)
948 struct rpcerr_duple *rd;
950 for (rd = rpcerr_duples; rd->rpc_msg; rd++) {
952 if (rd->rpc_stat == e) {
953 printf(rd->rpc_msg);
954 return;
958 fprintf(stderr, "Bad error code passed to rpcerr_msg: %d.\n", e);
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".
966 static void
967 get_xfr_response(SVCXPRT *transp)
969 struct yppushresp_xfr resp;
970 register struct server *s;
972 if (!svc_getargs(transp, (xdrproc_t)xdr_yppushresp_xfr,
973 (caddr_t)&resp)) {
974 svcerr_decode(transp);
975 return;
978 if (!svc_sendreply(transp, xdr_void, 0)) {
979 (void) fprintf(stderr, "Can't reply to rpc call.\n");
982 for (s = active_list; s; s = s->pnext) {
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;
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 it an old "YPPROC_GET" request, as was defined in the
998 * earlier version of yp_prot.h
1000 static unsigned short
1001 send_message(struct server *ps, unsigned long program, long *err)
1003 struct ypreq_newxfr req;
1004 struct ypreq_xfr oldreq;
1005 enum clnt_stat s;
1006 struct rpc_err rpcerr;
1008 if ((ps->domb.dom_client = __yp_clnt_create_rsvdport(ps->svc_name,
1009 YPPROG, YPVERS, NULL, 0, 0)) == NULL) {
1011 if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) {
1012 return (SSTAT_PROGNOTREG);
1013 } else {
1014 printf("Error talking to %s: ", ps->svc_name);
1015 rpcerr_msg(rpc_createerr.cf_stat);
1016 printf("\n");
1017 fflush(stdout);
1018 return (SSTAT_SYSTEM);
1022 if (sysinfo(SI_HOSTNAME, my_name, sizeof (my_name)) == -1) {
1023 return (SSTAT_RSCRC);
1026 if (!oldxfr) {
1027 req.ypxfr_domain = domain;
1028 req.ypxfr_map = map;
1029 req.ypxfr_ordernum = 0;
1030 req.ypxfr_owner = my_name;
1031 req.name = ps->svc_name;
1033 * the creation of field req.name, instead of ypreq_xfr (old)
1034 * req.port, does not make any sense. it doesn't give any
1035 * information to receiving ypserv except its own name !!
1036 * new ypserv duplicates work for YPPROC_XFR and YPPROC_NEWXFR
1038 req.transid = ps->xactid;
1039 req.proto = program;
1040 s = (enum clnt_stat) clnt_call(ps->domb.dom_client,
1041 YPPROC_NEWXFR, (xdrproc_t)xdr_ypreq_newxfr, (caddr_t)&req,
1042 xdr_void, 0, timeout);
1045 clnt_geterr(ps->domb.dom_client, &rpcerr);
1047 if (s == RPC_PROCUNAVAIL) {
1048 oldreq.ypxfr_domain = domain;
1049 oldreq.ypxfr_map = map;
1050 oldreq.ypxfr_ordernum = 0;
1051 oldreq.ypxfr_owner = my_name;
1052 oldreq.transid = ps->xactid;
1053 oldreq.proto = program;
1054 oldreq.port = 0;
1055 s = (enum clnt_stat) clnt_call(ps->domb.dom_client,
1056 YPPROC_XFR, (xdrproc_t)xdr_ypreq_xfr, (caddr_t)&oldreq,
1057 xdr_void, 0, timeout);
1058 clnt_geterr(ps->domb.dom_client, &rpcerr);
1061 clnt_destroy(ps->domb.dom_client);
1063 if (s == RPC_SUCCESS) {
1064 return (SSTAT_CALLED);
1065 } else {
1066 *err = (long)rpcerr.re_status;
1067 return (SSTAT_RPC);
1069 /*NOTREACHED*/
1073 * FUNCTION: is_yptol_mode();
1075 * DESCRIPTION: Determines if we should run in N2L or traditional mode based
1076 * on the presence of the N2L mapping file.
1078 * This is a copy of a function from libnisdb. If more than this
1079 * one function become required it may be worth linking the
1080 * entire lib.
1082 * INPUTS: Nothing
1084 * OUTPUTS: TRUE = Run in N2L mode
1085 * FALSE = Run in traditional mode.
1087 bool_t
1088 is_yptol_mode()
1090 struct stat filestat;
1092 if (stat(NTOL_MAP_FILE, &filestat) != -1)
1093 return (TRUE);
1095 return (FALSE);