ypxfr.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,787 行 · 第 1/3 页
C
1,787 行
#ifndef lintstatic char *sccsid = "@(#)ypxfr.c 4.1 ULTRIX 7/2/90";#endif lint/**************************************************************** * * * Licensed to Digital Equipment Corporation, Maynard, MA * * Copyright 1985 Sun Microsystems, Inc. * * All rights reserved. * * * ****************************************************************//* * This is a user command which gets a yp data base from some running * server, and gets it to the local site by using the normal yp client * enumeration functions. The map is copied to a temp name, then the * real map is removed and the temp map is moved to the real name. * ypxfr then sends a "YPPROC_CLEAR" message to the local server to * insure that he will not hold a removed map open, so serving an * obsolete version. * * ypxfr [-h <host>] [-d <domainname>] * [-s <domainname>] [-f] [-c] [-C tid prot ipadd port] map * * where host may be either a name or an internet address of * form ww.xx.yy.zz * * If the host is ommitted, ypxfr will attempt to discover the master * by using normal yp services. If it can't get the record, it will use * the address of the callback, if specified. If the host is specified * as an internet address, no yp services need to be locally available. * * If the domain is not specified, the default domain of the local * machine is used. * * If the -f flag is used, the transfer will be done even if the * master's copy is not newer than the local copy. * * The -c flag suppresses the YPPROC_CLEAR request to the local ypserv. * It may be used if ypserv isn't currently running to suppress the * error message. * * The -C flag is used to pass callback information to ypxfr when it is * activated by ypserv. The callback information is used to send a * yppushresp_xfr message with transaction id "tid" to a yppush process * speaking a transient protocol number "prot". The yppush program is * running on the node with IP address "ipadd", and is listening (UDP) * on "port". * * * The -s option is used to specify a source domain which may be * different from the destination domain, for transfer of maps * that are identical in different domains (e.g. services.byname) */#include <dbm.h>#undef NULL#define DATUM#include <stdio.h>#include <errno.h>#include <sys/time.h>#include <ctype.h>#include <netdb.h>#include <rpc/rpc.h>#include <sys/socket.h>#include <sys/dir.h>#include <sys/file.h>#include <sys/stat.h>#include <rpcsvc/ypclnt.h>#include <rpcsvc/yp_prot.h>#include <rpcsvc/ypv1_prot.h># define PARANOID 1 /* make sure maps have the right # entries */#define UDPINTER_TRY 10 /* Seconds between tries for udp */#define UDPTIMEOUT UDPINTER_TRY*4 /* Total timeout for udp */#define CALLINTER_TRY 10 /* Seconds between callback tries */#define CALLTIMEOUT CALLINTER_TRY*6 /* Total timeout for callback */struct timeval udp_intertry = { UDPINTER_TRY, 0};struct timeval udp_timeout = { UDPTIMEOUT, 0};struct timeval tcp_timeout = { 180, /* timeout for map enumeration (could be long) */ 0};char *domain = NULL;char *source = NULL;char *map = NULL;char *master = NULL; /* The name of the xfer peer as specified as a * -h option, or from querying the yp */struct in_addr master_addr; /* Addr of above */struct dom_binding master_server;/* To talk to above */unsigned int master_prog_vers; /* YPVERS or YPOLDVERS */char *master_name = NULL; /* Map's master as contained in the map */unsigned *master_version = NULL; /* Order number as contained in the map */char *master_ascii_version; /* ASCII order number as contained in the map */bool fake_master_version = FALSE; /* TRUE only if there's no order number in * the map, and the user specified -f */char yp_last_modified[] = "YP_LAST_MODIFIED";char yp_master_name[] = "YP_MASTER_NAME";bool force = FALSE; /* TRUE iff user specified -f flag */bool logging = FALSE; /* TRUE iff no tty, but log file exists */bool send_clear = TRUE; /* FALSE iff user specified -c flag */bool callback = FALSE; /* TRUE iff -C flag set. tid, proto, ipadd, * and port will be set to point to the * command line args. */char *tid;char *proto;char *ipadd;char *port;int entry_count; /* counts entries in the map */char logfile[] = "/etc/yp/ypxfr.log";char err_usage[] ="Usage:\n\ypxfr [-f] [-h <host>] [-d <domainname>]\n\\t[-s <domainname>] [-c] [-C tid prot ipadd port] map\n\n\where\n\ -f forces transfer even if the master's copy is not newer.\n\ host may be either a name or an internet \n\ address of form ww.xx.yy.zz\n\ -c inhibits sending a \"Clear map\" message to the local ypserv.\n\ -C is used by ypserv to pass callback information.\n";char err_bad_args[] = "%s argument is bad.\n";char err_cant_get_kname[] = "Can't get %s back from system call.\n";char err_null_kname[] = "%s hasn't been set on this machine.\n";char err_bad_hostname[] = "hostname";char err_bad_mapname[] = "mapname";char err_bad_domainname[] = "domainname";char err_udp_failure[] = "Can't set up a udp connection to ypserv on host %s.\n";char ypdbpath[] = "/etc/yp";char yptempname_prefix[] = "ypxfr_map.";char ypbkupname_prefix[] = "ypxfr_bkup.";void get_command_line_args();bool get_master_addr();bool bind_to_server();bool ping_server();bool get_private_recs();bool get_order();bool get_v1order();bool get_v2order();bool get_master_name();bool get_v1master_name();bool get_v2master_name();void find_map_master();bool move_map();unsigned get_local_version();void mkfilename();void mk_tmpname();bool rename_map();bool check_map_existence();bool get_map();bool add_private_entries();bool new_mapfiles();void del_mapfiles();void set_output();void logprintf();bool send_ypclear();void xfr_exit();void send_callback();int ypall_callback();int map_yperr_to_pusherr();extern u_long inet_addr();extern struct hostent *gethostbyname();extern int errno;/* * This is the mainline for the ypxfr process. */voidmain(argc, argv) int argc; char **argv; { int i; static char default_domain_name[YPMAXDOMAIN]; static unsigned big = 0xffffffff; int status; set_output(); get_command_line_args(argc, argv); if (!domain) { if (!getdomainname(default_domain_name, YPMAXDOMAIN) ) { domain = default_domain_name; } else { logprintf( err_cant_get_kname, err_bad_domainname); xfr_exit(YPPUSH_RSRC); } if (strlen(domain) == 0) { logprintf( err_null_kname, err_bad_domainname); xfr_exit(YPPUSH_RSRC); } } if (!source) source = domain; if (!master) { find_map_master(); } if (!get_master_addr() ) { xfr_exit(YPPUSH_MADDR); } if (!bind_to_server(master, master_addr, &master_server, &master_prog_vers, &status) ) { xfr_exit(status); } if (!get_private_recs(&status) ) { xfr_exit(status); } if (!master_version) { if (force) { master_version = &big; fake_master_version = TRUE; } else { logprintf( "Can't get order number for map %s from server at %s: use the -f flag.\n", map, master); xfr_exit(YPPUSH_FORCE); } } if (!move_map(&status) ) { xfr_exit(status); } if (send_clear && !send_ypclear(&status) ) { xfr_exit(status); } if (logging) { logprintf("Transferred map %s from %s (%d entries).\n", map, master, entry_count); } xfr_exit(YPPUSH_SUCC);}/* * This decides whether we're being run interactively or not, and, if not, * whether we're supposed to be logging or not. If we are logging, it sets * up stderr to point to the log file, and sets the "logging" * variable. If there's no logging, the output goes in the bit bucket. * Logging output differs from interactive output in the presence of a * timestamp, present only in the log file. stderr is reset, too, because it * it's used by various library functions, including clnt_perror. */voidset_output(){ if (!isatty(1)) { if (access(logfile, W_OK)) { (void) freopen("/dev/null", "w", stderr); } else { (void) freopen(logfile, "a", stderr); logging = TRUE; } }}/* * This constructs a logging record. */voidlogprintf(arg1,arg2,arg3,arg4,arg5,arg6,arg7){ struct timeval t; fseek(stderr,0,2); if (logging) { (void) gettimeofday(&t, NULL); (void) fprintf(stderr, "%19.19s: ", ctime(&t.tv_sec)); } (void) fprintf(stderr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); fflush(stderr);}/* * This does the command line argument processing. */voidget_command_line_args(argc, argv) int argc; char **argv; { argv++; if (argc < 2) { logprintf( err_usage); xfr_exit(YPPUSH_BADARGS); } while (--argc) { if ( (*argv)[0] == '-') { switch ((*argv)[1]) { case 'f': { force = TRUE; argv++; break; } case 'c': { send_clear = FALSE; argv++; break; } case 'h': { if (argc > 1) { argv++; argc--; master = *argv; argv++; if (strlen(master) > 256) { logprintf( err_bad_args, err_bad_hostname); xfr_exit(YPPUSH_BADARGS); } } else { logprintf( err_usage); xfr_exit(YPPUSH_BADARGS); } break; } case 'd': { if (argc > 1) { argv++; argc--; domain = *argv; argv++; if (strlen(domain) > YPMAXDOMAIN) { logprintf( err_bad_args, err_bad_domainname); xfr_exit(YPPUSH_BADARGS); } } else { logprintf( err_usage); xfr_exit(YPPUSH_BADARGS); } break; } case 's': if (argc > 1) { argv++; argc--; source = *argv; argv++; if (strlen(source) > YPMAXDOMAIN) { logprintf( err_bad_args, err_bad_domainname); xfr_exit(YPPUSH_BADARGS); } } else { logprintf( err_usage); xfr_exit(YPPUSH_BADARGS); } break; case 'C': { if (argc > 5) { callback = TRUE; argv++; tid = *argv++; proto = *argv++; ipadd = *argv++; port = *argv++; argc -= 4;#ifdef DEBUGlogprintf("callee ipadd = %s\n",ipadd);logprintf("port = %s --or-- %d\n",port,htons(atoi(port)));logprintf("proto = %s\n",proto);logprintf("tid = %s\n",tid);#endif DEBUG } else { logprintf( err_usage); xfr_exit(YPPUSH_BADARGS); } break; } default: { logprintf( err_usage); xfr_exit(YPPUSH_BADARGS); } } } else { if (!map) { map = *argv; argv++; if (strlen(map) > YPMAXMAP) { logprintf( err_bad_args, err_bad_mapname); xfr_exit(YPPUSH_BADARGS); } } else { logprintf( err_usage); xfr_exit(YPPUSH_BADARGS); } } } if (!map) { logprintf( err_usage); xfr_exit(YPPUSH_BADARGS); }}/* * This checks to see if the master name is an ASCII internet address, in * which case it's translated to an internet address here, or is a host * name. In the second case, the standard library routine gethostbyname(3n) * (which uses the yp services) is called to do the translation. */boolget_master_addr(){ struct in_addr tempaddr; struct hostent *h; bool error = FALSE; if (master==NULL) { /* * if we were unable to get the master name, use the * address of the person who called us. */ if (callback) { master_addr.s_addr = inet_addr(ipadd); master = ipadd; return (TRUE); } return (FALSE); } if (isdigit(*master) ) { tempaddr.s_addr = inet_addr(master); if ((int) tempaddr.s_addr != -1) { master_addr = tempaddr; } else { error = TRUE; } } else { if (h = gethostbyname(master) ) { (void) bcopy(h->h_addr, (char *) &master_addr, h->h_length); } else { error = TRUE; } } if (error) { logprintf( "Can't translate master name %s to an address.\n", master); if (callback) { master_addr.s_addr = inet_addr(ipadd); master = ipadd; return (TRUE); } return (FALSE); } else { return (TRUE); }}/* * This sets up a udp connection to speak the correct program and version * to a yp server. vers is set to one of YPVERS or YPOLDVERS to reflect which * language the server speaks. */boolbind_to_server(host, host_addr, pdomb, vers, status) char *host; struct in_addr host_addr; struct dom_binding *pdomb; unsigned int *vers; int *status; { if (ping_server(host, host_addr, pdomb, YPVERS, status)) { *vers = YPVERS; return (TRUE); } else if (*status == YPPUSH_YPERR) { return (FALSE); } else { if (ping_server(host, host_addr, pdomb, YPOLDVERS, status)) { *vers = YPOLDVERS; return (TRUE); } else { return (FALSE); } }}/* * This sets up a UDP channel to a server which is assumed to speak an input * version of YPPROG. The channel is tested by pinging the server. In all * error cases except "Program Version Number Mismatch", the error is * reported, and in all error cases, the client handle is destroyed and the * socket associated with the channel is closed. */boolping_server(host, host_addr, pdomb, vers, status) char *host; struct in_addr host_addr; struct dom_binding *pdomb; unsigned int vers; int *status;{ enum clnt_stat rpc_stat; pdomb->dom_server_addr.sin_addr = host_addr; pdomb->dom_server_addr.sin_family = AF_INET; pdomb->dom_server_addr.sin_port = htons((u_short) 0); pdomb->dom_server_port = htons((u_short) 0); pdomb->dom_socket = RPC_ANYSOCK; if (pdomb->dom_client = clntudp_create(&(pdomb->dom_server_addr), YPPROG, vers, udp_intertry, &(pdomb->dom_socket )) ) { rpc_stat = clnt_call(pdomb->dom_client, YPBINDPROC_NULL, xdr_void, 0, xdr_void, 0, udp_timeout); if (rpc_stat == RPC_SUCCESS) { return (TRUE); } else { clnt_destroy(pdomb->dom_client); close(pdomb->dom_socket); if (rpc_stat != RPC_PROGVERSMISMATCH) { (void) clnt_perror(pdomb->dom_client, "ypxfr: bind_to_server clnt_call error"); } *status = YPPUSH_RPC; return (FALSE); } } else { logprintf("bind_to_server clntudp_create error"); (void) clnt_pcreateerror(""); fflush(stderr); *status = YPPUSH_RPC; return (FALSE); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?