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 + -
显示快捷键?