No empty .Rs/.Re
[netbsd-mini2440.git] / usr.bin / ypwhich / ypwhich.c
blobaccf28bc07355442a9f99fa98afcbd23a03d7d98
1 /* $NetBSD: ypwhich.c,v 1.16 2009/06/20 19:27:26 christos Exp $ */
3 /*
5 * Copyright (c) 1997 Charles D. Cranor
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ypwhich
33 * author: Chuck Cranor <chuck@ccrc.wustl.edu>
34 * date: 31-Oct-97
36 * notes: this is a full rewrite of Theo de Raadt's ypwhich.
37 * this version allows you full control of which ypserv you
38 * talk to for the "-m" command.
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <sys/time.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
48 #include <err.h>
49 #include <netdb.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
55 #include <rpc/rpc.h>
56 #include <rpcsvc/yp_prot.h>
57 #include <rpcsvc/ypclnt.h>
59 #include "ypalias_init.h"
62 * ypwhich: query a host about its yp service
64 * usage:
65 * ypwhich [-d domain] [[-h] host]
66 * (who is host's ypserv?)
67 * ypwhich [-h host] [-d domain] [-f] [-t] -m [mapname]
68 * (who is the master of a map?)
69 * ypwhich -x
70 * (what nicknames do you use?)
72 * -d: the domainname to ask about
73 * -f: for -m, force us to talk directly to ypserv on the specified host
74 * without going through ypbind.
75 * -h: specify a host to ask [default = localhost]
76 * -m: find master server for a specific map (no map means 'all maps')
77 * -t: inhibit nickname translation
78 * -T: use TCP instead of UDP
79 * -x: print list of yp map aliases and exit
83 * prototypes
86 static void find_mapmaster(const char *, const char *, const char *,
87 int, int, int, const struct ypalias *);
88 static struct in_addr *find_server(const char *, const char *, int);
89 static CLIENT *mkclient(struct sockaddr_in *, unsigned long, unsigned long,
90 int);
91 static void usage(void) __attribute__((__noreturn__));
94 * main
96 int
97 main(int argc, char *argv[])
100 const char *targhost = "localhost";
101 char *ourdomain;
102 int inhibit = 0, force = 0, tcp = 0;
103 char *targmap = NULL;
104 int ch, saw_m;
105 struct in_addr *inaddr;
106 struct hostent *he;
107 size_t i;
108 const struct ypalias *ypaliases;
111 * get default domainname and parse options
114 ypaliases = ypalias_init();
115 (void)yp_get_default_domain(&ourdomain);
116 saw_m = 0;
117 while ((ch = getopt(argc, argv, "h:d:xtTfm")) != -1) {
118 switch (ch) {
119 case 'h':
120 targhost = optarg;
121 break;
122 case 'd':
123 ourdomain = optarg;
124 break;
125 case 'x':
126 for (i = 0; ypaliases[i].alias; i++)
127 (void)printf("Use \"%s\" for map \"%s\"\n",
128 ypaliases[i].alias, ypaliases[i].name);
129 return 0;
130 case 'f':
131 force = 1;
132 break;
133 case 't':
134 inhibit = 1;
135 break;
136 case 'T':
137 tcp = 1;
138 break;
139 case 'm':
140 if (optind < argc && argv[optind][0] != '-')
141 targmap = argv[optind++];
142 saw_m = 1;
143 break;
144 case '?':
145 default:
146 usage();
149 argc -= optind;
150 argv += optind;
151 if (argc) {
152 if (argc > 1)
153 usage();
154 targhost = argv[0];
156 #ifdef DEBUG
157 (void)printf("target_host=%s, domain=%s, inhibit=%d, saw_m=%d, map=%s, "
158 "force=%d, tcp=%d\n",
159 targhost, ourdomain, inhibit, saw_m, targmap, force, tcp);
160 #endif
163 * need a valid domain
166 if (ourdomain == NULL)
167 errx(1, "the domain hasn't been set on this machine.");
170 * now do it
172 if (saw_m)
173 find_mapmaster(targhost, ourdomain, targmap, inhibit, force,
174 tcp, ypaliases);
175 else {
176 inaddr = find_server(targhost, ourdomain, tcp);
177 he = gethostbyaddr((void *)&inaddr->s_addr,
178 sizeof(inaddr->s_addr), AF_INET);
179 if (he)
180 (void)printf("%s\n", he->h_name);
181 else
182 (void)printf("%s\n", inet_ntoa(*inaddr));
184 return 0;
188 * usage: print usage and exit
190 static void
191 usage(void)
193 const char *pname = getprogname();
194 (void)fprintf(stderr, "Usage:\t%s [-T] [-d domain] [[-h] host]\n"
195 "\t%s [-fTt] [-d domain] [-h host] -m [mapname]\n"
196 "\t%s [-T] -x\n", pname, pname, pname);
197 exit(1);
200 static CLIENT *
201 mkclient(struct sockaddr_in *sin, unsigned long prog, unsigned long vers,
202 int tcp)
204 static struct timeval tv = { 15, 0 };
205 int fd = RPC_ANYSOCK;
207 if (tcp)
208 return clnttcp_create(sin, prog, vers, &fd, 0, 0);
209 else
210 return clntudp_create(sin, prog, vers, tv, &fd);
214 * find_server: ask a host's ypbind who its current ypserver is
216 static struct in_addr *
217 find_server(const char *host, const char *domain, int tcp)
219 static struct in_addr result;
220 struct sockaddr_in sin;
221 CLIENT *ypbind;
222 struct timeval tv;
223 enum clnt_stat retval;
224 struct ypbind_resp ypbind_resp;
227 * get address of host
229 (void)memset(&sin, 0, sizeof(sin));
230 sin.sin_family = AF_INET;
231 if (inet_aton(host, &sin.sin_addr) == 0) {
232 struct hostent *he;
234 he = gethostbyname(host);
235 if (he == NULL)
236 errx(1, "%s: %s", host, hstrerror(h_errno));
237 (void)memmove(&sin.sin_addr, he->h_addr, sizeof(sin.sin_addr));
241 * establish connection to ypbind
243 ypbind = mkclient(&sin, YPBINDPROG, YPBINDVERS, tcp);
244 if (ypbind == NULL)
245 errx(1, "clnt%s_create: %s: %s", tcp ? "tcp" : "udp", host,
246 yperr_string(YPERR_YPBIND));
249 * now call ypbind's "DOMAIN" procedure to get the server name
251 tv.tv_sec = 5;
252 tv.tv_usec = 0;
253 retval = clnt_call(ypbind, (unsigned int)YPBINDPROC_DOMAIN,
254 xdr_ypdomain_wrap_string, &domain, xdr_ypbind_resp, &ypbind_resp,
255 tv);
256 clnt_destroy(ypbind);
257 if (retval != RPC_SUCCESS)
258 errx(1, "clnt_call: %s: %s", host, clnt_sperrno(retval));
259 if (ypbind_resp.ypbind_status != YPBIND_SUCC_VAL)
260 errx(1, "ypbind on %s for domain %s failed: %s", host, domain,
261 yperr_string(ypbind_resp.ypbind_status));
264 * got it!
266 result.s_addr = ypbind_resp.ypbind_respbody.
267 ypbind_bindinfo.ypbind_binding_addr.s_addr; /* love that name! */
268 return (&result);
272 * find_mapmaster: ask a host's ypserver who its map's master is
274 static void
275 find_mapmaster(const char *host, const char *domain, const char *map,
276 int inhibit, int force, int tcp, const struct ypalias *ypaliases)
278 struct in_addr *inaddr, faddr;
279 struct hostent *he;
280 struct sockaddr_in sin;
281 CLIENT *ypserv;
282 int yperr;
283 enum clnt_stat retval;
284 struct timeval tv;
285 struct ypresp_maplist yprespmlist;
286 struct ypmaplist fakelist, *ypml;
287 struct ypresp_master yprespmaster;
288 struct ypreq_nokey ypreqkey;
289 size_t i;
292 * we can either ask the hosts ypbind where it's ypserv is located,
293 * or we can be forced to assume that ypserv is running on the host.
295 if (force) {
296 if (inet_aton(host, &faddr) == 0) {
297 he = gethostbyname(host);
298 if (he == NULL)
299 errx(1, "%s: %s", host, hstrerror(h_errno));
300 (void)memmove(&faddr, he->h_addr, sizeof(faddr));
302 inaddr = &faddr;
303 } else {
304 /* ask host "host" who is currently serving its maps */
305 inaddr = find_server(host, domain, tcp);
309 * now translate nicknames [unless inhibited]
311 if (map && !inhibit) {
312 /*###325 [cc] error: 'i' undeclared (first use in this function)%%%*/
313 /*###325 [cc] error: (Each undeclared identifier is reported only once%%%*/
314 /*###325 [cc] error: for each function it appears in.)%%%*/
315 for (i = 0; ypaliases[i].alias; i++) {
316 if (strcmp(map, ypaliases[i].alias) == 0) {
317 map = ypaliases[i].name;
318 break;
321 #ifdef DEBUG
322 (void)printf("translated map name = %s\n", map);
323 #endif
327 * now we try and connect to host's ypserv
329 (void)memset(&sin, 0, sizeof(sin));
330 sin.sin_family = AF_INET;
331 sin.sin_addr.s_addr = inaddr->s_addr;
332 ypserv = mkclient(&sin, YPPROG, YPVERS, tcp);
333 if (ypserv == NULL) {
334 warnx("clnt%s_create: %s: %s", tcp ? "tcp" : "udp", host,
335 yperr_string(YPERR_YPSERV));
336 goto error;
340 * did the user specify a map?
342 if (map == NULL) {
344 * if no map specified, we ask ypserv for a list of all maps
346 (void)memset(&yprespmlist, 0, sizeof(yprespmlist));
347 tv.tv_sec = 5;
348 tv.tv_usec = 0;
349 retval = clnt_call(ypserv, (unsigned int)YPPROC_MAPLIST,
350 xdr_ypdomain_wrap_string, &domain, xdr_ypresp_maplist,
351 &yprespmlist, tv);
352 if (retval != RPC_SUCCESS) {
353 warnx("clnt_call MAPLIST: %s: %s", host,
354 clnt_sperrno(retval));
355 goto error;
357 yperr = ypprot_err(yprespmlist.status);
358 if (yperr) {
359 warnx("clnt_call: %s: %s", host, yperr_string(yperr));
360 goto error;
362 ypml = yprespmlist.list;
363 } else {
365 * build a fake "list" of maps containing only the list the user
366 * asked about in it.
368 (void)memset(&fakelist, 0, sizeof(fakelist));
369 (void)strlcpy(fakelist.ypml_name, map, sizeof(fakelist.ypml_name));
370 fakelist.ypml_next = NULL;
371 ypml = &fakelist;
375 * we now have a list of maps. ask ypserv who is the master for
376 * each map...
378 for ( /* null */ ; ypml != NULL; ypml = ypml->ypml_next) {
379 ypreqkey.domain = domain;
380 ypreqkey.map = ypml->ypml_name;
381 (void)memset(&yprespmaster, 0, sizeof(yprespmaster));
382 tv.tv_sec = 5;
383 tv.tv_usec = 0;
384 retval = clnt_call(ypserv, (unsigned int)YPPROC_MASTER,
385 xdr_ypreq_nokey, &ypreqkey, xdr_ypresp_master,
386 &yprespmaster, tv);
387 if (retval != RPC_SUCCESS) {
388 warnx("clnt_call MASTER: %s: %s", host,
389 clnt_sperrno(retval));
390 goto error;
392 yperr = ypprot_err(yprespmaster.status);
393 if (yperr) {
394 warnx("clnt_call: %s: %s: %s", host, ypml->ypml_name,
395 yperr_string(yperr));
396 } else {
397 (void)printf("%s %s\n", ypml->ypml_name,
398 yprespmaster.master);
400 xdr_free(xdr_ypresp_master, (void *)&yprespmaster);
402 clnt_destroy(ypserv);
405 * done
407 return;
409 error:
410 /* print host's ypserv's IP address to prevent confusion */
411 if (ypserv)
412 clnt_destroy(ypserv);
413 if (!force)
414 (void)fprintf(stderr,
415 "\t[note %s's ypserv running on host %s]\n",
416 host, inet_ntoa(*inaddr));
417 exit(1);