diff options
Diffstat (limited to 'usr/src/cmd/ypcmd/yppush.c')
| -rw-r--r-- | usr/src/cmd/ypcmd/yppush.c | 1102 |
1 files changed, 1102 insertions, 0 deletions
diff --git a/usr/src/cmd/ypcmd/yppush.c b/usr/src/cmd/ypcmd/yppush.c new file mode 100644 index 0000000000..441e546763 --- /dev/null +++ b/usr/src/cmd/ypcmd/yppush.c @@ -0,0 +1,1102 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T + * All Rights Reserved + * + * Portions of this source code were derived from Berkeley + * 4.3 BSD under license from the Regents of the University of + * California. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#define _SVID_GETTOD +#include <sys/time.h> +extern int gettimeofday(struct timeval *); + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <malloc.h> +#include <errno.h> +#include <signal.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <ctype.h> +#include <dirent.h> +#include <rpc/rpc.h> +#include <rpc/nettype.h> +#include <rpc/rpcb_prot.h> +#include <rpc/rpcb_clnt.h> +#include <sys/systeminfo.h> +#include <sys/select.h> +#include "ypsym.h" +#include "ypdefs.h" +#include "yp_b.h" +#include "shim.h" +#include "yptol.h" + + +#ifdef DEBUG +#undef YPPROG +#define YPPROG ((ulong_t)109999) +#undef YPBINDPROG +#define YPBINDPROG ((ulong_t)109998) +#endif + +#define INTER_TRY 12 /* Seconds between tries */ +#define PORTMAP_TIME 30 /* Seconds before decide its down */ +#define TIMEOUT INTER_TRY*4 /* Total time for timeout */ +#define CUR_PAR 4 /* Total parallal yppushes */ +#define MIN_GRACE 25 /* select timeout and minimum grace */ +#define GRACE_PERIOD 800 /* Total seconds we'll wait for */ + /* responses from ypxfrs, yes */ + /* virginia yp map transfers */ + /* can take a long time, we */ + /* only worry if the slave */ + /* crashes ... */ + +USE_YPDBPATH +static char *pusage; +static char *domain = NULL; +static char *host = NULL; +static char my_name[YPMAXPEER +1]; +static char default_domain_name[YPMAXDOMAIN]; +static char domain_alias[MAXNAMLEN]; /* nickname for domain - */ + /* used in sysv filesystems */ +static char map_alias[MAXNAMLEN]; /* nickname for map - */ + /* used in sysv filesystems */ +static char *map = NULL; +static bool verbose = FALSE; +static bool onehost = FALSE; +static bool oldxfr = FALSE; +static bool callback_timeout = FALSE; /* set when a callback times out */ +int grace_period = GRACE_PERIOD; +int curpar = CUR_PAR; /* should be set by other stuff */ +static char ypmapname[1024]; /* Used to check for map's existence */ + +static struct timeval intertry = { + INTER_TRY, /* Seconds */ + 0 /* Microseconds */ +}; +static struct timeval timeout = { + TIMEOUT, /* Seconds */ + 0 /* Microseconds */ +}; +static SVCXPRT *transport4; +static SVCXPRT *transport6; +struct server { + struct server *pnext; + struct dom_binding domb; + char svc_name[YPMAXPEER+1]; + unsigned long xactid; + unsigned short state; + unsigned long status; + bool oldvers; + int start_time; +}; +#define n_conf dom_binding->ypbind_nconf +#define svc_addr dom_binding->ypbind_svcaddr +static struct server *server_list = (struct server *)NULL; +static struct server *active_list = (struct server *)NULL; + +/* State values for server.state field */ + +#define SSTAT_INIT 0 +#define SSTAT_CALLED 1 +#define SSTAT_RESPONDED 2 +#define SSTAT_PROGNOTREG 3 +#define SSTAT_RPC 4 +#define SSTAT_RSCRC 5 +#define SSTAT_SYSTEM 6 + +static char err_usage[] = +"Usage:\n\typpush [-p <par>] [-d <domainname>] [-h <hostname>] [-v] map\n"; +static char err_bad_args[] = + "The %s argument is bad.\n"; +static char err_cant_get_kname[] = + "Can't get %s from system call.\n"; +static char err_null_kname[] = + "The %s hasn't been set on this machine.\n"; +static char err_bad_domainname[] = "domainname"; +static char err_cant_bind[] = + "Can't find a yp server for domain %s. Reason: %s.\n"; +static char err_cant_build_serverlist[] = + "Can't build server list from map \"ypservers\". Reason: %s.\n"; +static char err_cant_find_host[] = + "Can't find host %s in map \"ypservers\".\n"; +/* + * State_duple table. All messages should take 1 arg - the node name. + */ +struct state_duple { + int state; + char *state_msg; +}; +static struct state_duple state_duples[] = { + {SSTAT_INIT, "Internal error trying to talk to %s."}, + {SSTAT_CALLED, "%s has been called."}, + {SSTAT_RESPONDED, "%s (v1 ypserv) sent an old-style request."}, + {SSTAT_PROGNOTREG, "nis server not registered at %s."}, + {SSTAT_RPC, "RPC error to %s: "}, + {SSTAT_RSCRC, "Local resource allocation failure - can't talk to %s."}, + {SSTAT_SYSTEM, "System error talking to %s: "}, + {0, (char *)NULL} +}; +/* + * Status_duple table. No messages should require any args. + */ +static struct status_duple { + long status; + char *status_msg; +}; +static struct status_duple status_duples[] = { + {YPPUSH_SUCC, "Map successfully transferred."}, + {YPPUSH_AGE, + "Transfer not done: master's version isn't newer."}, + {YPPUSH_NOMAP, "Failed - ypxfr there can't find a server for map."}, + {YPPUSH_NODOM, "Failed - domain isn't supported."}, + {YPPUSH_RSRC, "Failed - local resource allocation failure."}, + {YPPUSH_RPC, "Failed - ypxfr had an RPC failure"}, + {YPPUSH_MADDR, "Failed - ypxfr couldn't get the map master's address."}, + {YPPUSH_YPERR, "Failed - nis server or map format error."}, + {YPPUSH_BADARGS, "Failed - args to ypxfr were bad."}, + {YPPUSH_DBM, "Failed - dbm operation on map failed."}, + {YPPUSH_FILE, "Failed - file I/O operation on map failed"}, + {YPPUSH_SKEW, "Failed - map version skew during transfer."}, + {YPPUSH_CLEAR, + "Map successfully transferred, but ypxfr \ + couldn't send \"Clear map\" to ypserv "}, + {YPPUSH_FORCE, + "Failed - no local order number in map - use -f flag to ypxfr."}, + {YPPUSH_XFRERR, "Failed - ypxfr internal error."}, + {YPPUSH_REFUSED, "Failed - Transfer request refused."}, + {YPPUSH_NOALIAS, + "Failed - System V domain/map alias not in alias file."}, + {0, (char *)NULL} +}; +/* + * rpcerr_duple table + */ +static struct rpcerr_duple { + enum clnt_stat rpc_stat; + char *rpc_msg; +}; +static struct rpcerr_duple rpcerr_duples[] = { + {RPC_SUCCESS, "RPC success"}, + {RPC_CANTENCODEARGS, "RPC Can't encode args"}, + {RPC_CANTDECODERES, "RPC Can't decode results"}, + {RPC_CANTSEND, "RPC Can't send"}, + {RPC_CANTRECV, "RPC Can't recv"}, + {RPC_TIMEDOUT, "NIS server registered, but does not respond"}, + {RPC_VERSMISMATCH, "RPC version mismatch"}, + {RPC_AUTHERROR, "RPC auth error"}, + {RPC_PROGUNAVAIL, "RPC remote program unavailable"}, + {RPC_PROGVERSMISMATCH, "RPC program mismatch"}, + {RPC_PROCUNAVAIL, "RPC unknown procedure"}, + {RPC_CANTDECODEARGS, "RPC Can't decode args"}, + {RPC_UNKNOWNHOST, "unknown host"}, + {RPC_RPCBFAILURE, "rpcbind failure (host is down?)"}, + {RPC_PROGNOTREGISTERED, "RPC prog not registered"}, + {RPC_SYSTEMERROR, "RPC system error"}, + {RPC_SUCCESS, (char *)NULL} /* Duplicate rpc_stat */ + /* unused in list-end */ + /* entry */ +}; + +static void get_default_domain_name(void); +static void get_command_line_args(int argc, char **argv); +static unsigned short send_message(struct server *ps, + unsigned long program, long *err); +static void make_server_list(void); +static void one_host_list(void); +static void add_server(char *sname, int namelen); +static int generate_callback(unsigned long *program); +static void xactid_seed(unsigned long *xactid); +static void main_loop(unsigned long program); +static void listener_exit(unsigned long program, int stat); +static void listener_dispatch(struct svc_req *rqstp, SVCXPRT *transp); +static void print_state_msg(struct server *s, long e); +static void print_callback_msg(struct server *s); +static void rpcerr_msg(enum clnt_stat e); +static void get_xfr_response(SVCXPRT *transp); + +#ifdef SYSVCONFIG +extern void sysvconfig(void); +#endif +extern int yp_getalias(char *key, char *key_alias, int maxlen); +extern int getdomainname(char *, int); + +extern struct rpc_createerr rpc_createerr; +extern char *sys_errlist[]; +extern int sys_nerr; +extern CLIENT *__yp_clnt_create_rsvdport(); + +int +main(int argc, char **argv) +{ + unsigned long program; + struct stat sbuf; + + get_command_line_args(argc, argv); + + if (!domain) { + get_default_domain_name(); + } + +#ifdef SYSVCONFIG + sysvconfig(); +#endif + + if (yp_getalias(domain, domain_alias, NAME_MAX) != 0) + fprintf(stderr, "domain alias for %s not found\n", domain); + if (yp_getalias(map, map_alias, MAXALIASLEN) != 0) + fprintf(stderr, "map alias for %s not found\n", map); + + /* check to see if the map exists in this domain */ + if (is_yptol_mode()) + sprintf(ypmapname, "%s/%s/%s%s.dir", ypdbpath, domain_alias, + NTOL_PREFIX, map_alias); + else + sprintf(ypmapname, "%s/%s/%s.dir", ypdbpath, domain_alias, + map_alias); + if (stat(ypmapname, &sbuf) < 0) { + fprintf(stderr, "yppush: Map does not exist.\n"); + exit(1); + } + + if (onehost) { + one_host_list(); + } else { + make_server_list(); + } + + /* + * All process exits after the call to generate_callback should be + * through listener_exit(program, status), not exit(status), so the + * transient server can get unregistered with the portmapper. + */ + + if (!generate_callback(&program)) { + fprintf(stderr, "Can't set up transient callback server.\n"); + } + + main_loop(program); + + listener_exit(program, 0); + + /* NOTREACHED */ + return (0); +} + +/* + * This does the command line parsing. + */ +static void +get_command_line_args(int argc, char **argv) +{ + pusage = err_usage; + argv++; + + if (argc < 2) { + fprintf(stderr, pusage); + exit(1); + } + + while (--argc) { + if ((*argv)[0] == '-') { + switch ((*argv)[1]) { + case 'v': + verbose = TRUE; + argv++; + break; + case 'd': + if (argc > 1) { + argv++; + argc--; + domain = *argv; + argv++; + if (((int)strlen(domain)) > + YPMAXDOMAIN) { + fprintf(stderr, + err_bad_args, + err_bad_domainname); + exit(1); + } + } else { + fprintf(stderr, pusage); + exit(1); + } + break; + case 'h': + if (argc > 1) { + onehost = TRUE; + argv++; + argc--; + host = *argv; + argv++; + } else { + fprintf(stderr, pusage); + exit(1); + } + break; + + case 'p': + + if (argc > 1) { + argv++; + argc--; + if (sscanf(*argv, "%d", &curpar) != 1) { + (void) fprintf(stderr, pusage); + exit(1); + } + argv++; + if (curpar < 1) { + (void) fprintf(stderr, pusage); + exit(1); + } + } else { + (void) fprintf(stderr, pusage); + exit(1); + } + break; + + default: + fprintf(stderr, pusage); + exit(1); + } + } else { + if (!map) { + map = *argv; + } else { + fprintf(stderr, pusage); + exit(1); + } + argv++; + } + } + + if (!map) { + fprintf(stderr, pusage); + exit(1); + } +} + +/* + * This gets the local kernel domainname, and sets the global domain to it. + */ +static void +get_default_domain_name(void) +{ + if (!getdomainname(default_domain_name, YPMAXDOMAIN)) { + domain = default_domain_name; + } else { + fprintf(stderr, err_cant_get_kname, err_bad_domainname); + exit(1); + } + + if ((int)strlen(domain) == 0) { + fprintf(stderr, err_null_kname, err_bad_domainname); + exit(1); + } +} + +/* + * This verifies that the hostname supplied by the user is in the map + * "ypservers" then calls add_server to make it the only entry on the + * list of servers. + */ +static void +one_host_list(void) +{ + char *key; + int keylen; + char *val; + int vallen; + int err; + char *ypservers = "ypservers"; + + if (verbose) { + printf("Verifying YP server: %s\n", host); + fflush(stdout); + } + + if (err = yp_bind(domain_alias)) { + fprintf(stderr, err_cant_bind, domain, yperr_string(err)); + exit(1); + } + + keylen = strlen(host); + + if (yp_match(domain_alias, ypservers, host, keylen, + &val, &vallen)) { + fprintf(stderr, err_cant_find_host, host); + exit(1); + } + + add_server(host, keylen); +} + +/* + * This uses yp operations to retrieve each server name in the map + * "ypservers". add_server is called for each one to add it to the list of + * servers. + */ +static void +make_server_list(void) +{ + char *key; + int keylen; + char *outkey; + int outkeylen; + char *val; + int vallen; + int err; + char *ypservers = "ypservers"; + int count; + + if (verbose) { + printf("Finding YP servers: "); + fflush(stdout); + count = 4; + } + + if (err = yp_bind(domain_alias)) { + fprintf(stderr, err_cant_bind, domain, yperr_string(err)); + exit(1); + } + + if (err = yp_first(domain_alias, ypservers, &outkey, &outkeylen, + &val, &vallen)) { + fprintf(stderr, err_cant_build_serverlist, yperr_string(err)); + exit(1); + } + + for (;;) { + add_server(outkey, outkeylen); + if (verbose) { + printf(" %s", outkey); + fflush(stdout); + if (count++ == 8) { + printf("\n"); + count = 0; + } + } + free(val); + key = outkey; + keylen = outkeylen; + + if (err = yp_next(domain_alias, ypservers, key, keylen, + &outkey, &outkeylen, &val, &vallen)) { + + if (err == YPERR_NOMORE) { + break; + } else { + fprintf(stderr, err_cant_build_serverlist, + yperr_string(err)); + exit(1); + } + } + + free(key); + } + if (count != 0) { + if (verbose) + printf("\n"); + } +} + +/* + * This adds a single server to the server list. + */ +static void +add_server(char *sname, int namelen) +{ + struct server *ps; + static unsigned long seq; + static unsigned long xactid = 0; + + if (strcmp(sname, my_name) == 0) + return; + + if (xactid == 0) { + xactid_seed(&xactid); + } + + if ((ps = (struct server *)malloc((unsigned)sizeof (struct server))) + == (struct server *)NULL) { + perror("yppush: malloc failure"); + exit(1); + } + + sname[namelen] = '\0'; + strcpy(ps->svc_name, sname); + ps->state = SSTAT_INIT; + ps->status = 0; + ps->oldvers = FALSE; + ps->xactid = xactid + seq++; + ps->pnext = server_list; + server_list = ps; +} + +/* + * This sets the base range for the transaction ids used in speaking the the + * server ypxfr processes. + */ +static void +xactid_seed(unsigned long *xactid) +{ + struct timeval t; + + if (gettimeofday(&t) == -1) { + perror("yppush gettimeofday failure"); + *xactid = 1234567; + } else { + *xactid = t.tv_sec; + } +} + +/* + * This generates the channel which will be used as the listener process' + * service rendezvous point, and comes up with a transient program number + * for the use of the RPC messages from the ypxfr processes. + */ +static int +generate_callback(unsigned long *program) +{ + unsigned long prognum = 0x40000000, maxprognum; + union { + unsigned long p; + unsigned char b[sizeof (unsigned long)]; + } u; + int ret, i; + struct netconfig *nc4, *nc6, *nc; + SVCXPRT *trans; + + nc4 = getnetconfigent("udp"); + nc6 = getnetconfigent("udp6"); + if (nc4 == 0 && nc6 == 0) { + fprintf(stderr, + "yppush: Could not get udp or udp6 netconfig entry\n"); + exit(1); + } + + transport4 = (nc4 == 0) ? 0 : svc_tli_create(RPC_ANYFD, nc4, 0, 0, 0); + transport6 = (nc6 == 0) ? 0 : svc_tli_create(RPC_ANYFD, nc6, 0, 0, 0); + if (transport4 == 0 && transport6 == 0) { + fprintf(stderr, "yppush: Could not create server handle(s)\n"); + exit(1); + } + + /* Find the maximum possible program number using an unsigned long */ + for (i = 0; i < sizeof (u.b); i++) + u.b[i] = 0xff; + maxprognum = u.p; + + if (transport4 != 0) { + trans = transport4; + nc = nc4; + } else { + trans = transport6; + nc = nc6; + } + while (prognum < maxprognum && (ret = + rpcb_set(prognum, YPPUSHVERS, nc, &trans->xp_ltaddr)) == 0) + prognum++; + + if (ret == 0) { + fprintf(stderr, "yppush: Could not create callback service\n"); + exit(1); + } else { + if (trans == transport4 && transport6 != 0) { + ret = rpcb_set(prognum, YPPUSHVERS, nc6, + &transport6->xp_ltaddr); + if (ret == 0) { + fprintf(stderr, + "yppush: Could not create udp6 callback service\n"); + exit(1); + } + } + *program = prognum; + } + + return (ret); +} + +/* + * This is the main loop. Send messages to each server, + * and then wait for a response. + */ + + +add_to_active() +{ + struct server *ps; + ps = server_list; + if (ps == NULL) + return (0); + server_list = server_list->pnext; /* delete from server_list */ + ps->pnext = active_list; + active_list = ps; + return (1); +} + +delete_active(in) + struct server *in; +{ + struct server *p; + struct server *n; + if (in == active_list) { + active_list = active_list->pnext; + return (1); + } + p = active_list; + for (n = active_list; n; n = n->pnext) { + if (in == n) { + p->pnext = n->pnext; + return (0); + + } + p = n; + } + return (-1); +} + +void +main_loop(program) + unsigned long program; +{ + pollfd_t *pollset = NULL; + int npollfds = 0; + int pollret; + struct server *ps; + long error; + int hpar; /* this times par count */ + int i; + int j; + int time_now; + int docb; + int actives = 0; + int dead = 0; + + if (grace_period < MIN_GRACE) + grace_period = MIN_GRACE; + if (transport4 != 0) { + if (!svc_reg(transport4, program, YPPUSHVERS, + listener_dispatch, 0)) { + fprintf(stderr, + "Can't set up transient udp callback server.\n"); + } + } + if (transport6 != 0) { + if (!svc_reg(transport6, program, YPPUSHVERS, + listener_dispatch, 0)) { + fprintf(stderr, + "Can't set up transient udp6 callback server.\n"); + } + } + for (;;) { + time_now = time(0); + if (server_list == NULL) { + actives = 0; + dead = 0; + for (ps = active_list; ps; ps = ps->pnext) + if (ps->state == SSTAT_CALLED) { + if ((time_now - ps->start_time) < + grace_period) + actives++; + else + dead++; + } + if (actives == 0) { + if (verbose) { + printf("terminating %d dead\n", dead); + fflush(stdout); + } + + for (ps = active_list; ps; ps = ps->pnext) + if (ps->state == SSTAT_CALLED) { + if ((time_now - ps->start_time) + >= grace_period) { + if (verbose) { + printf( + "no response from %s -- grace of %d seconds expired.\n", + ps->svc_name, grace_period); + fflush(stdout); + } + fprintf(stderr, + "No response from ypxfr on %s\n", ps->svc_name); + } + } + break; + } + } + actives = 0; + for (ps = active_list; ps; ps = ps->pnext) { + if (ps->state == SSTAT_CALLED) { + if ((time_now - ps->start_time) + < grace_period) { + actives++; + + if (verbose) { + printf( + "No response yet from ypxfr on %s\n", ps->svc_name); + fflush(stdout); + } + } + } else { + if (verbose) { + printf("Deactivating %s\n", + ps->svc_name); + fflush(stdout); + } + delete_active(ps); + } + } + + /* add someone to the active list keep up with curpar */ + for (i = 0; i < (curpar - actives); i++) { + if (add_to_active()) { + ps = active_list; + ps->state = send_message(ps, program, &error); + print_state_msg(ps, error); + if (ps->state != SSTAT_CALLED) + delete_active(ps); /* zorch it */ + else + ps->start_time = time(0); /* set time */ + } + } + docb = 0; + for (ps = active_list; ps; ps = ps->pnext) + if (ps->state == SSTAT_CALLED) { + docb = 1; + break; + } + if (docb == 0) { + if (verbose) { + printf("No one to wait for this pass.\n"); + fflush(stdout); + } + continue; /* try curpar more */ + } + + if (npollfds != svc_max_pollfd) { + pollset = realloc(pollset, + sizeof (pollfd_t) * svc_max_pollfd); + npollfds = svc_max_pollfd; + } + + /* + * Get existing array of pollfd's, should really compress + * this but it shouldn't get very large (or sparse). + */ + (void) memcpy(pollset, svc_pollfd, + sizeof (pollfd_t) * svc_max_pollfd); + + errno = 0; + switch (pollret = poll(pollset, npollfds, MIN_GRACE * 1000)) { + case -1: + if (errno != EINTR) { + (void) perror("main loop select"); + } + break; + + case 0: + if (verbose) { + (void) printf("timeout in main loop select.\n"); + fflush(stdout); + } + break; + + default: + svc_getreq_poll(pollset, pollret); + break; + } /* switch */ + } /* for */ +} + +/* + * This does the listener process cleanup and process exit. + */ +static void +listener_exit(unsigned long program, int stat) +{ + svc_unreg(program, YPPUSHVERS); + exit(stat); +} + +/* + * This is the listener process' RPC service dispatcher. + */ +static void +listener_dispatch(struct svc_req *rqstp, SVCXPRT *transp) +{ + switch (rqstp->rq_proc) { + + case YPPUSHPROC_NULL: + if (!svc_sendreply(transp, xdr_void, 0)) { + fprintf(stderr, "Can't reply to rpc call.\n"); + } + break; + + case YPPUSHPROC_XFRRESP: + get_xfr_response(transp); + break; + + default: + svcerr_noproc(transp); + break; + } +} + + +/* + * This dumps a server state message to stdout. It is called in cases where + * we have no expectation of receiving a callback from the remote ypxfr. + */ +static void +print_state_msg(struct server *s, long e) +{ + struct state_duple *sd; + + if (s->state == SSTAT_SYSTEM) + return; /* already printed */ + + if (!verbose && (s->state == SSTAT_RESPONDED || + s->state == SSTAT_CALLED)) + return; + + for (sd = state_duples; sd->state_msg; sd++) { + if (sd->state == s->state) { + printf(sd->state_msg, s->svc_name); + + if (s->state == SSTAT_RPC) { + rpcerr_msg((enum clnt_stat) e); + } + + printf("\n"); + fflush(stdout); + return; + } + } + + fprintf(stderr, "yppush: Bad server state value %d.\n", s->state); +} + +/* + * This dumps a transfer status message to stdout. It is called in + * response to a received RPC message from the called ypxfr. + */ +static void +print_callback_msg(struct server *s) +{ + register struct status_duple *sd; + + if (!verbose && + (s->status == YPPUSH_AGE) || + (s->status == YPPUSH_SUCC)) + + return; + + for (sd = status_duples; sd->status_msg; sd++) { + + if (sd->status == s->status) { + printf("Status received from ypxfr on %s:\n\t%s\n", + s->svc_name, sd->status_msg); + fflush(stdout); + return; + } + } + + fprintf(stderr, "yppush listener: Garbage transaction " + "status (value %d) from ypxfr on %s.\n", + (int)s->status, s->svc_name); +} + +/* + * This dumps an RPC error message to stdout. This is basically a rewrite + * of clnt_perrno, but writes to stdout instead of stderr. + */ +static void +rpcerr_msg(enum clnt_stat e) +{ + struct rpcerr_duple *rd; + + for (rd = rpcerr_duples; rd->rpc_msg; rd++) { + + if (rd->rpc_stat == e) { + printf(rd->rpc_msg); + return; + } + } + + fprintf(stderr, "Bad error code passed to rpcerr_msg: %d.\n", e); +} + +/* + * This picks up the response from the ypxfr process which has been started + * up on the remote node. The response status must be non-zero, otherwise + * the status will be set to "ypxfr error". + */ +static void +get_xfr_response(SVCXPRT *transp) +{ + struct yppushresp_xfr resp; + register struct server *s; + + if (!svc_getargs(transp, (xdrproc_t)xdr_yppushresp_xfr, + (caddr_t)&resp)) { + svcerr_decode(transp); + return; + } + + if (!svc_sendreply(transp, xdr_void, 0)) { + (void) fprintf(stderr, "Can't reply to rpc call.\n"); + } + + for (s = active_list; s; s = s->pnext) { + + if (s->xactid == resp.transid) { + s->status = resp.status ? resp.status: YPPUSH_XFRERR; + print_callback_msg(s); + s->state = SSTAT_RESPONDED; + return; + } + } +} + +/* + * This sends a message to a single ypserv process. The return value is + * a state value. If the RPC call fails because of a version + * mismatch, we'll assume that we're talking to a version 1 ypserv process, + * and will send him an old "YPPROC_GET" request, as was defined in the + * earlier version of yp_prot.h + */ +static unsigned short +send_message(struct server *ps, unsigned long program, long *err) +{ + struct ypreq_newxfr req; + struct ypreq_xfr oldreq; + enum clnt_stat s; + struct rpc_err rpcerr; + + if ((ps->domb.dom_client = __yp_clnt_create_rsvdport(ps->svc_name, + YPPROG, YPVERS, + (char *)NULL, + 0, 0)) == NULL) { + + if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) { + return (SSTAT_PROGNOTREG); + } else { + printf("Error talking to %s: ", ps->svc_name); + rpcerr_msg(rpc_createerr.cf_stat); + printf("\n"); + fflush(stdout); + return (SSTAT_SYSTEM); + } + } + + if (sysinfo(SI_HOSTNAME, my_name, sizeof (my_name)) == -1) { + return (SSTAT_RSCRC); + } + + if (!oldxfr) { + req.ypxfr_domain = domain; + req.ypxfr_map = map; + req.ypxfr_ordernum = 0; + req.ypxfr_owner = my_name; + req.name = ps->svc_name; + /* + * the creation of field req.name, instead of ypreq_xfr (old) + * req.port, does not make any sense. it doesn't give any + * information to receiving ypserv except its own name !! + * new ypserv duplicates work for YPPROC_XFR and YPPROC_NEWXFR + */ + req.transid = ps->xactid; + req.proto = program; + s = (enum clnt_stat) clnt_call(ps->domb.dom_client, + YPPROC_NEWXFR, + (xdrproc_t)xdr_ypreq_newxfr, + (caddr_t)&req, + xdr_void, 0, timeout); + } + + clnt_geterr(ps->domb.dom_client, &rpcerr); + + if (s == RPC_PROCUNAVAIL) { + oldreq.ypxfr_domain = domain; + oldreq.ypxfr_map = map; + oldreq.ypxfr_ordernum = 0; + oldreq.ypxfr_owner = my_name; + oldreq.transid = ps->xactid; + oldreq.proto = program; + oldreq.port = 0; + s = (enum clnt_stat) clnt_call(ps->domb.dom_client, + YPPROC_XFR, + (xdrproc_t)xdr_ypreq_xfr, + (caddr_t)&oldreq, + xdr_void, 0, timeout); + clnt_geterr(ps->domb.dom_client, &rpcerr); + } + + clnt_destroy(ps->domb.dom_client); + + if (s == RPC_SUCCESS) { + return (SSTAT_CALLED); + } else { + *err = (long)rpcerr.re_status; + return (SSTAT_RPC); + } + /*NOTREACHED*/ +} + +/* + * FUNCTION: is_yptol_mode(); + * + * DESCRIPTION: Determines if we should run in N2L or traditional mode based + * on the presence of the N2L mapping file. + * + * This is a copy of a function from libnisdb. If more than this + * one function become required it may be worth linking the + * entire lib. + * + * INPUTS: Nothing + * + * OUTPUTS: TRUE = Run in N2L mode + * FALSE = Run in traditional mode. + */ +bool_t +is_yptol_mode() +{ + struct stat filestat; + + if (stat(NTOL_MAP_FILE, &filestat) != -1) + return (TRUE); + + return (FALSE); +} |
