8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / ypcmd / yppush.c
blobf24eb7c6d88b4b1b156556127b41b2123ada6ec0
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 = (struct server *)NULL;
128 static struct server *active_list = (struct server *)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, (char *)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, (char *)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, (char *)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 struct rpc_createerr rpc_createerr;
257 extern CLIENT *__yp_clnt_create_rsvdport();
260 main(int argc, char **argv)
262 unsigned long program;
263 struct stat64 sbuf;
265 get_command_line_args(argc, argv);
267 if (!domain) {
268 get_default_domain_name();
271 #ifdef SYSVCONFIG
272 sysvconfig();
273 #endif
275 if (yp_getalias(domain, domain_alias, NAME_MAX) != 0)
276 fprintf(stderr, "domain alias for %s not found\n", domain);
277 if (yp_getalias(map, map_alias, MAXALIASLEN) != 0)
278 fprintf(stderr, "map alias for %s not found\n", map);
280 /* check to see if the map exists in this domain */
281 if (is_yptol_mode())
282 sprintf(ypmapname, "%s/%s/%s%s.dir", ypdbpath, domain_alias,
283 NTOL_PREFIX, map_alias);
284 else
285 sprintf(ypmapname, "%s/%s/%s.dir", ypdbpath, domain_alias,
286 map_alias);
287 if (stat64(ypmapname, &sbuf) < 0) {
288 fprintf(stderr, "yppush: Map does not exist.\n");
289 exit(1);
292 if (onehost) {
293 one_host_list();
294 } else {
295 make_server_list();
299 * All process exits after the call to generate_callback should be
300 * through listener_exit(program, status), not exit(status), so the
301 * transient server can get unregistered with the portmapper.
304 if (!generate_callback(&program)) {
305 fprintf(stderr, "Can't set up transient callback server.\n");
308 main_loop(program);
310 listener_exit(program, 0);
312 /* NOTREACHED */
313 return (0);
317 * This does the command line parsing.
319 static void
320 get_command_line_args(int argc, char **argv)
322 pusage = err_usage;
323 argv++;
325 if (argc < 2) {
326 fprintf(stderr, pusage);
327 exit(1);
330 while (--argc) {
331 if ((*argv)[0] == '-') {
332 switch ((*argv)[1]) {
333 case 'v':
334 verbose = TRUE;
335 argv++;
336 break;
337 case 'd':
338 if (argc > 1) {
339 argv++;
340 argc--;
341 domain = *argv;
342 argv++;
343 if (((int)strlen(domain)) >
344 YPMAXDOMAIN) {
345 fprintf(stderr,
346 err_bad_args,
347 err_bad_domainname);
348 exit(1);
350 } else {
351 fprintf(stderr, pusage);
352 exit(1);
354 break;
355 case 'h':
356 if (argc > 1) {
357 onehost = TRUE;
358 argv++;
359 argc--;
360 host = *argv;
361 argv++;
362 } else {
363 fprintf(stderr, pusage);
364 exit(1);
366 break;
368 case 'p':
370 if (argc > 1) {
371 argv++;
372 argc--;
373 if (sscanf(*argv, "%d", &curpar) != 1) {
374 (void) fprintf(stderr, pusage);
375 exit(1);
377 argv++;
378 if (curpar < 1) {
379 (void) fprintf(stderr, pusage);
380 exit(1);
382 } else {
383 (void) fprintf(stderr, pusage);
384 exit(1);
386 break;
388 default:
389 fprintf(stderr, pusage);
390 exit(1);
392 } else {
393 if (!map) {
394 map = *argv;
395 } else {
396 fprintf(stderr, pusage);
397 exit(1);
399 argv++;
403 if (!map) {
404 fprintf(stderr, pusage);
405 exit(1);
410 * This gets the local kernel domainname, and sets the global domain to it.
412 static void
413 get_default_domain_name(void)
415 if (!getdomainname(default_domain_name, YPMAXDOMAIN)) {
416 domain = default_domain_name;
417 } else {
418 fprintf(stderr, err_cant_get_kname, err_bad_domainname);
419 exit(1);
422 if ((int)strlen(domain) == 0) {
423 fprintf(stderr, err_null_kname, err_bad_domainname);
424 exit(1);
429 * This verifies that the hostname supplied by the user is in the map
430 * "ypservers" then calls add_server to make it the only entry on the
431 * list of servers.
433 static void
434 one_host_list(void)
436 char *key;
437 int keylen;
438 char *val;
439 int vallen;
440 int err;
441 char *ypservers = "ypservers";
443 if (verbose) {
444 printf("Verifying YP server: %s\n", host);
445 fflush(stdout);
448 if (err = yp_bind(domain_alias)) {
449 fprintf(stderr, err_cant_bind, domain, yperr_string(err));
450 exit(1);
453 keylen = strlen(host);
455 if (yp_match(domain_alias, ypservers, host, keylen,
456 &val, &vallen)) {
457 fprintf(stderr, err_cant_find_host, host);
458 exit(1);
461 add_server(host, keylen);
465 * This uses yp operations to retrieve each server name in the map
466 * "ypservers". add_server is called for each one to add it to the list of
467 * servers.
469 static void
470 make_server_list(void)
472 char *key;
473 int keylen;
474 char *outkey;
475 int outkeylen;
476 char *val;
477 int vallen;
478 int err;
479 char *ypservers = "ypservers";
480 int count;
482 if (verbose) {
483 printf("Finding YP servers: ");
484 fflush(stdout);
485 count = 4;
488 if (err = yp_bind(domain_alias)) {
489 fprintf(stderr, err_cant_bind, domain, yperr_string(err));
490 exit(1);
493 if (err = yp_first(domain_alias, ypservers, &outkey, &outkeylen,
494 &val, &vallen)) {
495 fprintf(stderr, err_cant_build_serverlist, yperr_string(err));
496 exit(1);
499 for (;;) {
500 add_server(outkey, outkeylen);
501 if (verbose) {
502 printf(" %s", outkey);
503 fflush(stdout);
504 if (count++ == 8) {
505 printf("\n");
506 count = 0;
509 free(val);
510 key = outkey;
511 keylen = outkeylen;
513 if (err = yp_next(domain_alias, ypservers, key, keylen,
514 &outkey, &outkeylen, &val, &vallen)) {
516 if (err == YPERR_NOMORE) {
517 break;
518 } else {
519 fprintf(stderr, err_cant_build_serverlist,
520 yperr_string(err));
521 exit(1);
525 free(key);
527 if (count != 0) {
528 if (verbose)
529 printf("\n");
534 * This adds a single server to the server list.
536 static void
537 add_server(char *sname, int namelen)
539 struct server *ps;
540 static unsigned long seq;
541 static unsigned long xactid = 0;
543 if (strcmp(sname, my_name) == 0)
544 return;
546 if (xactid == 0) {
547 xactid_seed(&xactid);
550 if ((ps = (struct server *)malloc((unsigned)sizeof (struct server)))
551 == (struct server *)NULL) {
552 perror("yppush: malloc failure");
553 exit(1);
556 sname[namelen] = '\0';
557 strcpy(ps->svc_name, sname);
558 ps->state = SSTAT_INIT;
559 ps->status = 0;
560 ps->oldvers = FALSE;
561 ps->xactid = xactid + seq++;
562 ps->pnext = server_list;
563 server_list = ps;
567 * This sets the base range for the transaction ids used in speaking the the
568 * server ypxfr processes.
570 static void
571 xactid_seed(unsigned long *xactid)
573 struct timeval t;
575 if (gettimeofday(&t) == -1) {
576 perror("yppush gettimeofday failure");
577 *xactid = 1234567;
578 } else {
579 *xactid = t.tv_sec;
584 * This generates the channel which will be used as the listener process'
585 * service rendezvous point, and comes up with a transient program number
586 * for the use of the RPC messages from the ypxfr processes.
588 static int
589 generate_callback(unsigned long *program)
591 unsigned long prognum = 0x40000000, maxprognum;
592 union {
593 unsigned long p;
594 unsigned char b[sizeof (unsigned long)];
595 } u;
596 int ret, i;
597 struct netconfig *nc4, *nc6, *nc;
598 SVCXPRT *trans;
600 nc4 = getnetconfigent("udp");
601 nc6 = getnetconfigent("udp6");
602 if (nc4 == 0 && nc6 == 0) {
603 fprintf(stderr,
604 "yppush: Could not get udp or udp6 netconfig entry\n");
605 exit(1);
608 transport4 = (nc4 == 0) ? 0 : svc_tli_create(RPC_ANYFD, nc4, 0, 0, 0);
609 transport6 = (nc6 == 0) ? 0 : svc_tli_create(RPC_ANYFD, nc6, 0, 0, 0);
610 if (transport4 == 0 && transport6 == 0) {
611 fprintf(stderr, "yppush: Could not create server handle(s)\n");
612 exit(1);
615 /* Find the maximum possible program number using an unsigned long */
616 for (i = 0; i < sizeof (u.b); i++)
617 u.b[i] = 0xff;
618 maxprognum = u.p;
620 if (transport4 != 0) {
621 trans = transport4;
622 nc = nc4;
623 } else {
624 trans = transport6;
625 nc = nc6;
627 while (prognum < maxprognum && (ret =
628 rpcb_set(prognum, YPPUSHVERS, nc, &trans->xp_ltaddr)) == 0)
629 prognum++;
631 if (ret == 0) {
632 fprintf(stderr, "yppush: Could not create callback service\n");
633 exit(1);
634 } else {
635 if (trans == transport4 && transport6 != 0) {
636 ret = rpcb_set(prognum, YPPUSHVERS, nc6,
637 &transport6->xp_ltaddr);
638 if (ret == 0) {
639 fprintf(stderr,
640 "yppush: Could not create udp6 callback service\n");
641 exit(1);
644 *program = prognum;
647 return (ret);
651 * This is the main loop. Send messages to each server,
652 * and then wait for a response.
657 add_to_active()
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);
670 delete_active(in)
671 struct server *in;
673 struct server *p;
674 struct server *n;
675 if (in == active_list) {
676 active_list = active_list->pnext;
677 return (1);
679 p = active_list;
680 for (n = active_list; n; n = n->pnext) {
681 if (in == n) {
682 p->pnext = n->pnext;
683 return (0);
686 p = n;
688 return (-1);
691 void
692 main_loop(program)
693 unsigned long program;
695 pollfd_t *pollset = NULL;
696 int npollfds = 0;
697 int pollret;
698 struct server *ps;
699 long error;
700 int hpar; /* this times par count */
701 int i;
702 int j;
703 int time_now;
704 int docb;
705 int actives = 0;
706 int dead = 0;
708 if (grace_period < MIN_GRACE)
709 grace_period = MIN_GRACE;
710 if (transport4 != 0) {
711 if (!svc_reg(transport4, program, YPPUSHVERS,
712 listener_dispatch, 0)) {
713 fprintf(stderr,
714 "Can't set up transient udp callback server.\n");
717 if (transport6 != 0) {
718 if (!svc_reg(transport6, program, YPPUSHVERS,
719 listener_dispatch, 0)) {
720 fprintf(stderr,
721 "Can't set up transient udp6 callback server.\n");
724 for (;;) {
725 time_now = time(0);
726 if (server_list == NULL) {
727 actives = 0;
728 dead = 0;
729 for (ps = active_list; ps; ps = ps->pnext)
730 if (ps->state == SSTAT_CALLED) {
731 if ((time_now - ps->start_time) <
732 grace_period)
733 actives++;
734 else
735 dead++;
737 if (actives == 0) {
738 if (verbose) {
739 printf("terminating %d dead\n", dead);
740 fflush(stdout);
743 for (ps = active_list; ps; ps = ps->pnext)
744 if (ps->state == SSTAT_CALLED) {
745 if ((time_now - ps->start_time)
746 >= grace_period) {
747 if (verbose) {
748 printf(
749 "no response from %s -- grace of %d seconds expired.\n",
750 ps->svc_name, grace_period);
751 fflush(stdout);
753 fprintf(stderr,
754 "No response from ypxfr on %s\n", ps->svc_name);
757 break;
760 actives = 0;
761 for (ps = active_list; ps; ps = ps->pnext) {
762 if (ps->state == SSTAT_CALLED) {
763 if ((time_now - ps->start_time)
764 < grace_period) {
765 actives++;
767 if (verbose) {
768 printf(
769 "No response yet from ypxfr on %s\n", ps->svc_name);
770 fflush(stdout);
773 } else {
774 if (verbose) {
775 printf("Deactivating %s\n",
776 ps->svc_name);
777 fflush(stdout);
779 delete_active(ps);
783 /* add someone to the active list keep up with curpar */
784 for (i = 0; i < (curpar - actives); i++) {
785 if (add_to_active()) {
786 ps = active_list;
787 ps->state = send_message(ps, program, &error);
788 print_state_msg(ps, error);
789 if (ps->state != SSTAT_CALLED)
790 delete_active(ps); /* zorch it */
791 else
792 ps->start_time = time(0); /* set time */
795 docb = 0;
796 for (ps = active_list; ps; ps = ps->pnext)
797 if (ps->state == SSTAT_CALLED) {
798 docb = 1;
799 break;
801 if (docb == 0) {
802 if (verbose) {
803 printf("No one to wait for this pass.\n");
804 fflush(stdout);
806 continue; /* try curpar more */
809 if (npollfds != svc_max_pollfd) {
810 pollset = realloc(pollset,
811 sizeof (pollfd_t) * svc_max_pollfd);
812 npollfds = svc_max_pollfd;
816 * Get existing array of pollfd's, should really compress
817 * this but it shouldn't get very large (or sparse).
819 (void) memcpy(pollset, svc_pollfd,
820 sizeof (pollfd_t) * svc_max_pollfd);
822 errno = 0;
823 switch (pollret = poll(pollset, npollfds, MIN_GRACE * 1000)) {
824 case -1:
825 if (errno != EINTR) {
826 (void) perror("main loop select");
828 break;
830 case 0:
831 if (verbose) {
832 (void) printf("timeout in main loop select.\n");
833 fflush(stdout);
835 break;
837 default:
838 svc_getreq_poll(pollset, pollret);
839 break;
840 } /* switch */
841 } /* for */
845 * This does the listener process cleanup and process exit.
847 static void
848 listener_exit(unsigned long program, int stat)
850 svc_unreg(program, YPPUSHVERS);
851 exit(stat);
855 * This is the listener process' RPC service dispatcher.
857 static void
858 listener_dispatch(struct svc_req *rqstp, SVCXPRT *transp)
860 switch (rqstp->rq_proc) {
862 case YPPUSHPROC_NULL:
863 if (!svc_sendreply(transp, xdr_void, 0)) {
864 fprintf(stderr, "Can't reply to rpc call.\n");
866 break;
868 case YPPUSHPROC_XFRRESP:
869 get_xfr_response(transp);
870 break;
872 default:
873 svcerr_noproc(transp);
874 break;
880 * This dumps a server state message to stdout. It is called in cases where
881 * we have no expectation of receiving a callback from the remote ypxfr.
883 static void
884 print_state_msg(struct server *s, long e)
886 struct state_duple *sd;
888 if (s->state == SSTAT_SYSTEM)
889 return; /* already printed */
891 if (!verbose && (s->state == SSTAT_RESPONDED ||
892 s->state == SSTAT_CALLED))
893 return;
895 for (sd = state_duples; sd->state_msg; sd++) {
896 if (sd->state == s->state) {
897 printf(sd->state_msg, s->svc_name);
899 if (s->state == SSTAT_RPC) {
900 rpcerr_msg((enum clnt_stat) e);
903 printf("\n");
904 fflush(stdout);
905 return;
909 fprintf(stderr, "yppush: Bad server state value %d.\n", s->state);
913 * This dumps a transfer status message to stdout. It is called in
914 * response to a received RPC message from the called ypxfr.
916 static void
917 print_callback_msg(struct server *s)
919 register struct status_duple *sd;
921 if (!verbose &&
922 (s->status == YPPUSH_AGE) ||
923 (s->status == YPPUSH_SUCC))
925 return;
927 for (sd = status_duples; sd->status_msg; sd++) {
929 if (sd->status == s->status) {
930 printf("Status received from ypxfr on %s:\n\t%s\n",
931 s->svc_name, sd->status_msg);
932 fflush(stdout);
933 return;
937 fprintf(stderr, "yppush listener: Garbage transaction "
938 "status (value %d) from ypxfr on %s.\n",
939 (int)s->status, s->svc_name);
943 * This dumps an RPC error message to stdout. This is basically a rewrite
944 * of clnt_perrno, but writes to stdout instead of stderr.
946 static void
947 rpcerr_msg(enum clnt_stat e)
949 struct rpcerr_duple *rd;
951 for (rd = rpcerr_duples; rd->rpc_msg; rd++) {
953 if (rd->rpc_stat == e) {
954 printf(rd->rpc_msg);
955 return;
959 fprintf(stderr, "Bad error code passed to rpcerr_msg: %d.\n", e);
963 * This picks up the response from the ypxfr process which has been started
964 * up on the remote node. The response status must be non-zero, otherwise
965 * the status will be set to "ypxfr error".
967 static void
968 get_xfr_response(SVCXPRT *transp)
970 struct yppushresp_xfr resp;
971 register struct server *s;
973 if (!svc_getargs(transp, (xdrproc_t)xdr_yppushresp_xfr,
974 (caddr_t)&resp)) {
975 svcerr_decode(transp);
976 return;
979 if (!svc_sendreply(transp, xdr_void, 0)) {
980 (void) fprintf(stderr, "Can't reply to rpc call.\n");
983 for (s = active_list; s; s = s->pnext) {
985 if (s->xactid == resp.transid) {
986 s->status = resp.status ? resp.status: YPPUSH_XFRERR;
987 print_callback_msg(s);
988 s->state = SSTAT_RESPONDED;
989 return;
995 * This sends a message to a single ypserv process. The return value is
996 * a state value. If the RPC call fails because of a version
997 * mismatch, we'll assume that we're talking to a version 1 ypserv process,
998 * and will send it an old "YPPROC_GET" request, as was defined in the
999 * earlier version of yp_prot.h
1001 static unsigned short
1002 send_message(struct server *ps, unsigned long program, long *err)
1004 struct ypreq_newxfr req;
1005 struct ypreq_xfr oldreq;
1006 enum clnt_stat s;
1007 struct rpc_err rpcerr;
1009 if ((ps->domb.dom_client = __yp_clnt_create_rsvdport(ps->svc_name,
1010 YPPROG, YPVERS, (char *)NULL, 0, 0)) == NULL) {
1012 if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) {
1013 return (SSTAT_PROGNOTREG);
1014 } else {
1015 printf("Error talking to %s: ", ps->svc_name);
1016 rpcerr_msg(rpc_createerr.cf_stat);
1017 printf("\n");
1018 fflush(stdout);
1019 return (SSTAT_SYSTEM);
1023 if (sysinfo(SI_HOSTNAME, my_name, sizeof (my_name)) == -1) {
1024 return (SSTAT_RSCRC);
1027 if (!oldxfr) {
1028 req.ypxfr_domain = domain;
1029 req.ypxfr_map = map;
1030 req.ypxfr_ordernum = 0;
1031 req.ypxfr_owner = my_name;
1032 req.name = ps->svc_name;
1034 * the creation of field req.name, instead of ypreq_xfr (old)
1035 * req.port, does not make any sense. it doesn't give any
1036 * information to receiving ypserv except its own name !!
1037 * new ypserv duplicates work for YPPROC_XFR and YPPROC_NEWXFR
1039 req.transid = ps->xactid;
1040 req.proto = program;
1041 s = (enum clnt_stat) clnt_call(ps->domb.dom_client,
1042 YPPROC_NEWXFR, (xdrproc_t)xdr_ypreq_newxfr, (caddr_t)&req,
1043 xdr_void, 0, timeout);
1046 clnt_geterr(ps->domb.dom_client, &rpcerr);
1048 if (s == RPC_PROCUNAVAIL) {
1049 oldreq.ypxfr_domain = domain;
1050 oldreq.ypxfr_map = map;
1051 oldreq.ypxfr_ordernum = 0;
1052 oldreq.ypxfr_owner = my_name;
1053 oldreq.transid = ps->xactid;
1054 oldreq.proto = program;
1055 oldreq.port = 0;
1056 s = (enum clnt_stat) clnt_call(ps->domb.dom_client,
1057 YPPROC_XFR, (xdrproc_t)xdr_ypreq_xfr, (caddr_t)&oldreq,
1058 xdr_void, 0, timeout);
1059 clnt_geterr(ps->domb.dom_client, &rpcerr);
1062 clnt_destroy(ps->domb.dom_client);
1064 if (s == RPC_SUCCESS) {
1065 return (SSTAT_CALLED);
1066 } else {
1067 *err = (long)rpcerr.re_status;
1068 return (SSTAT_RPC);
1070 /*NOTREACHED*/
1074 * FUNCTION: is_yptol_mode();
1076 * DESCRIPTION: Determines if we should run in N2L or traditional mode based
1077 * on the presence of the N2L mapping file.
1079 * This is a copy of a function from libnisdb. If more than this
1080 * one function become required it may be worth linking the
1081 * entire lib.
1083 * INPUTS: Nothing
1085 * OUTPUTS: TRUE = Run in N2L mode
1086 * FALSE = Run in traditional mode.
1088 bool_t
1089 is_yptol_mode()
1091 struct stat filestat;
1093 if (stat(NTOL_MAP_FILE, &filestat) != -1)
1094 return (TRUE);
1096 return (FALSE);