NFSv2/usr/src/usr.bin/ypwhich.c

Compare this file to the similar file:
Show the results in this format:

#ifndef lint
static  char sccsid[] = "@(#)ypwhich.c 1.1 85/05/31 Copyr 1985 Sun Micro";
#endif

/*
 * This is a user command which tells which yp server is being used by
 * a given machine, or which yp server is the master for a named map, or
 * prints a list of all maps in the domain, and tells which yp server is
 * master of each of them.
 *
 * Usage is:
 *	ypwhich [-d domain] [-t] [-m [name] | host]
 *
 *  where:  the -d switch can be used to specify a domain other than the
 * default domain.  -m with a name tells the master of that map, -m with no
 * name gives a list of all maps in the domain and their associated
 * masters.  If name is specified it may be either a mapname, or a nickname
 * which will be translated into a mapname according to the translation
 * table at transtable.  The  -t switch inhibits this translation.  If the
 * -m option is used, ypwhich will act like a vanilla yp client, and will
 * not attempt to choose a particular yp server.  On the other hand, if no
 * -m switch is used, ypwhich will talk directly to the yp bind process on
 * the named host, or to the local ypbind process if no host name is
 * specified.
 */

#include <dbm.h>
#undef NULL
#include <stdio.h>
#include <rpc/rpc.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>

void get_command_line_args();
void getdomain();
void getlochost();
void getrmthost();
void call_binder();
void get_map_master();
void dump_ypmaps();

#define TIMEOUT 30			/* Total seconds for timeout */
#define INTER_TRY 10			/* Seconds between tries */

int translate = TRUE;
char *domain = NULL;
char default_domain_name[YPMAXDOMAIN];
char *host = NULL;
char default_host_name[256];
struct in_addr host_addr;
bool get_master = FALSE;
bool get_server = FALSE;
char *map = NULL;
struct timeval udp_intertry = {
	INTER_TRY,			/* Seconds */
	0				/* Microseconds */
	};
struct timeval udp_timeout = {
	TIMEOUT,			/* Seconds */
	0				/* Microseconds */
	};
char *transtable[] = {
	"passwd", "passwd.byname",
	"group", "group.byname",
	"networks", "networks.byaddr",
	"hosts", "hosts.byaddr",
	"protocols","protocols.bynumber",
	"services","services.byname",
	NULL
};
char err_usage[] =
"Usage:\n\
	ypwhich [-d domain] [-t] [-m [name] | host]\n";
char err_bad_args[] =
	"ypwhich:  %s argument is bad.\n";
char err_cant_get_kname[] =
	"ypwhich:  can't get %s back from system call.\n";
char err_null_kname[] =
	"ypwhich:  the %s hasn't been set on this machine.\n";
char err_bad_mapname[] = "mapname";
char err_bad_domainname[] = "domainname";
char err_bad_hostname[] = "hostname";
char err_cant_bind[] =
	"ypwhich:  can't bind to yp server for domain %s.  Reason:  %s.\n";
char err_first_failed[] =
	"ypwhich:  can't get first record from yp.  Reason:  %s.\n";
char err_next_failed[] =
	"ypwhich:  can't get next record from yp.  Reason:  %s.\n";
char err_udp_failure[] =
	"ypwhich:  can't set up a udp connection to ypserv on host %s.\n";
char err_rpc_failure[] =
	"ypwhich:  couldn't send rpc message to ypserv on host %s.\n";

/*
 * This is the main line for the ypwhich process.
 */
main(argc, argv)
	char **argv;
{
	int addr;
	int err;
	struct ypbind_resp response;
	int i;

	get_command_line_args(argc, argv);

	if (!domain) {
		getdomain();
	}
	
	if (get_server) {
		
		if (!host) {
			getlochost();
		} else {
			getrmthost();
		}

		call_binder();
	} else {
		
		if (map) {
	
			if (translate) {
						
			    for (i = 0; transtable[i]; i+=2)
					    
				 if (strcmp(map,
				     transtable[i]) == 0) {
					map = transtable[i+1];
				}
			}
			
			get_map_master();
		} else {
			dump_ypmaps();
		}
	}

	exit(0);
}

/*
 * This does the command line argument processing.
 */
void
get_command_line_args(argc, argv)
	int argc;
	char **argv;
	
{
	struct hostent *hp;
	
	argv++;

	if (argc == 1) {
		get_server = TRUE;
		return;
	}
	
	while (--argc) {

		if ( (*argv)[0] == '-') {

			switch ((*argv)[1]) {

			case 't': {
				translate = FALSE;
				argv++;
				break;
			}

			case 'm': {
				get_master = TRUE;
				argv++;
				
				if (argc > 1) {
					
					if ( (*(argv))[0] == '-') {
						break;
					}
					
					argc--;
					map = *argv;
					argv++;

					if (strlen(map) > YPMAXMAP) {
						fprintf(stderr, err_bad_args,
						    err_bad_mapname);
						exit(1);
					}
					
				} 
				
				break;
			}
				
			case 'd': {

				if (argc > 1) {
					argv++;
					argc--;
					domain = *argv;
					argv++;

					if (strlen(domain) > YPMAXDOMAIN) {
						fprintf(stderr, err_bad_args,
						    err_bad_domainname);
						exit(1);
					}
					
				} else {
					fprintf(stderr, err_usage);
					exit(1);
				}
				
				break;
			}
				
			default: {
				fprintf(stderr, err_usage);
				exit(1);
			}
			
			}
			
		} else {
			
			if (get_server) {
				fprintf(stderr, err_usage);
				exit(1);
			}
		
			get_server = TRUE;
			host = *argv;
			argv++;
			
			if (strlen(host) > 256) {
				fprintf(stderr, err_bad_args, err_bad_hostname);
				exit(1);
			}
		}
	}

	if (get_master && get_server) {
		fprintf(stderr, err_usage);
		exit(1);
	}
	
	if (!get_master && !get_server) {
		get_server = TRUE;
	} 
}

/*
 * This gets the local default domainname, and makes sure that it's set
 * to something reasonable.  domain is set here.
 */
void
getdomain()		
{
	if (!getdomainname(default_domain_name, YPMAXDOMAIN) ) {
		domain = default_domain_name;
	} else {
		fprintf(stderr, err_cant_get_kname, err_bad_domainname);
		exit(1);
	}

	if (strlen(domain) == 0) {
		fprintf(stderr, err_null_kname, err_bad_domainname);
		exit(1);
	}
}

/*
 * This gets the local hostname back from the kernel, and comes up with an
 * address for the local node without using the yp.  host_addr is set here.
 */
void
getlochost()
{
	struct sockaddr_in myaddr;

	if (! gethostname(default_host_name, 256)) {
		host = default_host_name;
	} else {
		fprintf(stderr, err_cant_get_kname, err_bad_hostname);
		exit(1);
	}

	get_myaddress(&myaddr);
	host_addr = myaddr.sin_addr;
}

/*
 * This gets an address for some named node by calling the standard library
 * routine gethostbyname.  host_addr is set here.
 */
void
getrmthost()
{		
	struct hostent *hp;
	
	hp = gethostbyname(host);
		
	if (hp == NULL) {
	    	fprintf(stderr, "ypwhich: can't find %s\n", host);
		exit(1);
	}
	
	host_addr.s_addr = *(u_long *)hp->h_addr;
}

/*
 * This sends a message to the ypbind process on the node with address held
 * in host_addr, and then translates the returned server address to a name.
 * If the returned address is the same as the local address as returned by
 * get_myaddress, the name is that retrieved from the kernel.  If it's any
 * other address (including another ip address for the local machine), we'll
 * get a name by using the standard library routine (which calls the yp).
 */
void
call_binder()
{
	struct hostent *hp;
	struct sockaddr_in query;
	CLIENT *client;
	int sock = RPC_ANYSOCK;
	enum clnt_stat rpc_stat;
	struct ypbind_resp response;
	struct in_addr server;
	
	query.sin_family = AF_INET;
	query.sin_port = 0;
	query.sin_addr = host_addr;
	
	if ((client =
	    clntudp_create(&query, YPBINDPROG, YPBINDVERS, udp_intertry,
	    &sock)) == NULL) {
		fprintf(stderr, err_udp_failure, host);
		exit(1);
	}

	rpc_stat =
	    clnt_call(client, YPBINDPROC_DOMAIN, xdr_ypdomain_wrap_string,
	    &domain, xdr_ypbind_resp, &response, udp_timeout);
	    
	if (rpc_stat != RPC_SUCCESS) {
		fprintf(stderr, err_rpc_failure, host);
		exit(1);
	}

	if (response.ypbind_status != YPBIND_SUCC_VAL) {
		fprintf(stderr, "ypbinder of %s didn't return a value\n",host);
		exit(1);
	}

	server = response.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr;
	getlochost();		/* This resets host, host_addr, and my_addr */
	
	if (server.s_addr == host_addr.s_addr) {
		printf(host);
		printf("\n");
	} else {
		hp = gethostbyaddr(&server, sizeof(server), AF_INET);
	
		if (hp == NULL) {
			printf("0x%x\n", server);
		} else {
			printf("%s\n", hp->h_name);
		}
	}
}

/*
 * This does a yp "match" operation within the map "ypmaps" in the domain
 * at global "domain" for the map at global "map".  
 */
void
get_map_master()
{
	int err;
	char *master;
	int len;
     
	err = yp_match(domain, "ypmaps", map, strlen(map), &master, &len);
	
	if (err) {
		
		if (err == YPERR_KEY) {
			fprintf(stderr,
			"ypwhich:  mapname %s is not in ypmaps in domain %s.\n",
			    map, domain);
		} else {
			fprintf(stderr,
			    "ypwhich:  yp_match failed.  Reason: %s.\n",
		    	    yperr_string(err) );
		}
		
	} else {
		printf(master);
	}
}


/*
 * This enumerates the entries within map "ypmaps" in the domain at global 
 * "domain", and prints them out key and value per single line.
 */
void
dump_ypmaps()
{
	char *key;
	int keylen;
	char *outkey;
	int outkeylen;
	char *val;
	int vallen;
	int err;
	char *scan;
	
	if (err = yp_first(domain, "ypmaps", &outkey, &outkeylen, &val,
	    &vallen) ) {

		if (err == YPERR_NOMORE) {
			fprintf(stderr, "ypwhich:  map \"ypmaps\" is empty.\n");
		} else {
			fprintf(stderr, err_first_failed,
			    yperr_string(err) );
		}

		exit(1);
	}

	while (TRUE) {

		for (scan = outkey; *scan != NULL; scan++) {

			if (*scan == '\n') {
				*scan = ' ';  
			}
		}

		printf(outkey);
		printf(val);
		free(val);
		key = outkey;
		keylen = outkeylen;
		
		if (err = yp_next(domain, "ypmaps", key, keylen, &outkey,
		    &outkeylen, &val, &vallen) ) {

			if (err == YPERR_NOMORE) {
				break;
			} else {
				fprintf(stderr, err_next_failed,
				    yperr_string(err) );
				exit(1);
			}
		}

		free(key);
	}
}