dev_dopen() can be called multiple times with only one dev_dclose() when
[dragonfly/vkernel-mp.git] / usr.bin / rpcinfo / rpcinfo.c
blob222be797a6be9f2b2289a2260fc74f66b3a5c42c
1 /*
2 * Copyright (C) 1986, Sun Microsystems, Inc.
4 * @(#)rpcinfo.c 1.22 87/08/12 SMI
5 * @(#)rpcinfo.c 2.2 88/08/11 4.0 RPCSRC
6 * $FreeBSD: src/usr.bin/rpcinfo/rpcinfo.c,v 1.9.2.1 2001/03/04 09:00:23 kris Exp $
7 * $DragonFly: src/usr.bin/rpcinfo/rpcinfo.c,v 1.2 2003/06/17 06:29:31 dillon Exp $
8 */
9 /*
10 * rpcinfo: ping a particular rpc program
11 * or dump the portmapper
15 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
16 * unrestricted use provided that this legend is included on all tape
17 * media and as a part of the software program in whole or part. Users
18 * may copy or modify Sun RPC without charge, but are not authorized
19 * to license or distribute it to anyone else except as part of a product or
20 * program developed by the user.
22 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
23 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
26 * Sun RPC is provided with no support and without any obligation on the
27 * part of Sun Microsystems, Inc. to assist in its use, correction,
28 * modification or enhancement.
30 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
31 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
32 * OR ANY PART THEREOF.
34 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
35 * or profits or other special, indirect and consequential damages, even if
36 * Sun has been advised of the possibility of such damages.
38 * Sun Microsystems, Inc.
39 * 2550 Garcia Avenue
40 * Mountain View, California 94043
43 #include <err.h>
44 #include <ctype.h>
45 #include <rpc/rpc.h>
46 #include <stdio.h>
47 #include <sys/socket.h>
48 #include <netdb.h>
49 #include <rpc/pmap_prot.h>
50 #include <rpc/pmap_clnt.h>
51 #include <signal.h>
52 #include <ctype.h>
53 #include <unistd.h>
54 #include <sys/param.h>
55 #include <arpa/inet.h>
57 #define MAXHOSTLEN 256
59 #define MIN_VERS ((u_long) 0)
60 #define MAX_VERS ((u_long) 4294967295UL)
62 static void udpping(/*u_short portflag, int argc, char **argv*/);
63 static void tcpping(/*u_short portflag, int argc, char **argv*/);
64 static int pstatus(/*CLIENT *client, u_long prognum, u_long vers*/);
65 static void pmapdump(/*int argc, char **argv*/);
66 static bool_t reply_proc(/*void *res, struct sockaddr_in *who*/);
67 static void brdcst(/*int argc, char **argv*/);
68 static void deletereg(/* int argc, char **argv */) ;
69 static void usage(/*void*/);
70 static u_long getprognum(/*char *arg*/);
71 static u_long getvers(/*char *arg*/);
72 static void get_inet_address(/*struct sockaddr_in *addr, char *host*/);
75 * Functions to be performed.
77 #define NONE 0 /* no function */
78 #define PMAPDUMP 1 /* dump portmapper registrations */
79 #define TCPPING 2 /* ping TCP service */
80 #define UDPPING 3 /* ping UDP service */
81 #define BRDCST 4 /* ping broadcast UDP service */
82 #define DELETES 5 /* delete registration for the service */
84 int
85 main(argc, argv)
86 int argc;
87 char **argv;
89 register int c;
90 int errflg;
91 int function;
92 u_short portnum;
94 function = NONE;
95 portnum = 0;
96 errflg = 0;
97 while ((c = getopt(argc, argv, "ptubdn:")) != -1) {
98 switch (c) {
100 case 'p':
101 if (function != NONE)
102 errflg = 1;
103 else
104 function = PMAPDUMP;
105 break;
107 case 't':
108 if (function != NONE)
109 errflg = 1;
110 else
111 function = TCPPING;
112 break;
114 case 'u':
115 if (function != NONE)
116 errflg = 1;
117 else
118 function = UDPPING;
119 break;
121 case 'b':
122 if (function != NONE)
123 errflg = 1;
124 else
125 function = BRDCST;
126 break;
128 case 'n':
129 portnum = (u_short) atoi(optarg); /* hope we don't get bogus # */
130 break;
132 case 'd':
133 if (function != NONE)
134 errflg = 1;
135 else
136 function = DELETES;
137 break;
139 case '?':
140 errflg = 1;
144 if (errflg || function == NONE) {
145 usage();
146 return (1);
149 switch (function) {
151 case PMAPDUMP:
152 if (portnum != 0) {
153 usage();
154 return (1);
156 pmapdump(argc - optind, argv + optind);
157 break;
159 case UDPPING:
160 udpping(portnum, argc - optind, argv + optind);
161 break;
163 case TCPPING:
164 tcpping(portnum, argc - optind, argv + optind);
165 break;
167 case BRDCST:
168 if (portnum != 0) {
169 usage();
170 return (1);
172 brdcst(argc - optind, argv + optind);
173 break;
175 case DELETES:
176 deletereg(argc - optind, argv + optind);
177 break;
180 return (0);
183 static void
184 udpping(portnum, argc, argv)
185 u_short portnum;
186 int argc;
187 char **argv;
189 struct timeval to;
190 struct sockaddr_in addr;
191 enum clnt_stat rpc_stat;
192 CLIENT *client;
193 u_long prognum, vers, minvers, maxvers;
194 int sock = RPC_ANYSOCK;
195 struct rpc_err rpcerr;
196 int failure;
198 if (argc < 2 || argc > 3) {
199 usage();
200 exit(1);
202 prognum = getprognum(argv[1]);
203 get_inet_address(&addr, argv[0]);
204 /* Open the socket here so it will survive calls to clnt_destroy */
205 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP);
206 if (sock < 0) {
207 perror("rpcinfo: socket");
208 exit(1);
210 failure = 0;
211 if (argc == 2) {
213 * A call to version 0 should fail with a program/version
214 * mismatch, and give us the range of versions supported.
216 addr.sin_port = htons(portnum);
217 to.tv_sec = 5;
218 to.tv_usec = 0;
219 if ((client = clntudp_create(&addr, prognum, (u_long)0,
220 to, &sock)) == NULL) {
221 clnt_pcreateerror("rpcinfo");
222 printf("program %lu is not available\n",
223 prognum);
224 exit(1);
226 to.tv_sec = 10;
227 to.tv_usec = 0;
228 rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
229 xdr_void, (char *)NULL, to);
230 if (rpc_stat == RPC_PROGVERSMISMATCH) {
231 clnt_geterr(client, &rpcerr);
232 minvers = rpcerr.re_vers.low;
233 maxvers = rpcerr.re_vers.high;
234 } else if (rpc_stat == RPC_SUCCESS) {
236 * Oh dear, it DOES support version 0.
237 * Let's try version MAX_VERS.
239 addr.sin_port = htons(portnum);
240 to.tv_sec = 5;
241 to.tv_usec = 0;
242 if ((client = clntudp_create(&addr, prognum, MAX_VERS,
243 to, &sock)) == NULL) {
244 clnt_pcreateerror("rpcinfo");
245 printf("program %lu version %lu is not available\n",
246 prognum, MAX_VERS);
247 exit(1);
249 to.tv_sec = 10;
250 to.tv_usec = 0;
251 rpc_stat = clnt_call(client, NULLPROC, xdr_void,
252 (char *)NULL, xdr_void, (char *)NULL, to);
253 if (rpc_stat == RPC_PROGVERSMISMATCH) {
254 clnt_geterr(client, &rpcerr);
255 minvers = rpcerr.re_vers.low;
256 maxvers = rpcerr.re_vers.high;
257 } else if (rpc_stat == RPC_SUCCESS) {
259 * It also supports version MAX_VERS.
260 * Looks like we have a wise guy.
261 * OK, we give them information on all
262 * 4 billion versions they support...
264 minvers = 0;
265 maxvers = MAX_VERS;
266 } else {
267 (void) pstatus(client, prognum, MAX_VERS);
268 exit(1);
270 } else {
271 (void) pstatus(client, prognum, (u_long)0);
272 exit(1);
274 clnt_destroy(client);
275 for (vers = minvers; vers <= maxvers; vers++) {
276 addr.sin_port = htons(portnum);
277 to.tv_sec = 5;
278 to.tv_usec = 0;
279 if ((client = clntudp_create(&addr, prognum, vers,
280 to, &sock)) == NULL) {
281 clnt_pcreateerror("rpcinfo");
282 printf("program %lu version %lu is not available\n",
283 prognum, vers);
284 exit(1);
286 to.tv_sec = 10;
287 to.tv_usec = 0;
288 rpc_stat = clnt_call(client, NULLPROC, xdr_void,
289 (char *)NULL, xdr_void, (char *)NULL, to);
290 if (pstatus(client, prognum, vers) < 0)
291 failure = 1;
292 clnt_destroy(client);
295 else {
296 vers = getvers(argv[2]);
297 addr.sin_port = htons(portnum);
298 to.tv_sec = 5;
299 to.tv_usec = 0;
300 if ((client = clntudp_create(&addr, prognum, vers,
301 to, &sock)) == NULL) {
302 clnt_pcreateerror("rpcinfo");
303 printf("program %lu version %lu is not available\n",
304 prognum, vers);
305 exit(1);
307 to.tv_sec = 10;
308 to.tv_usec = 0;
309 rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
310 xdr_void, (char *)NULL, to);
311 if (pstatus(client, prognum, vers) < 0)
312 failure = 1;
314 (void) close(sock); /* Close it up again */
315 if (failure)
316 exit(1);
319 static void
320 tcpping(portnum, argc, argv)
321 u_short portnum;
322 int argc;
323 char **argv;
325 struct timeval to;
326 struct sockaddr_in addr;
327 enum clnt_stat rpc_stat;
328 CLIENT *client;
329 u_long prognum, vers, minvers, maxvers;
330 int sock = RPC_ANYSOCK;
331 struct rpc_err rpcerr;
332 int failure;
334 if (argc < 2 || argc > 3) {
335 usage();
336 exit(1);
338 prognum = getprognum(argv[1]);
339 get_inet_address(&addr, argv[0]);
340 failure = 0;
341 if (argc == 2) {
343 * A call to version 0 should fail with a program/version
344 * mismatch, and give us the range of versions supported.
346 addr.sin_port = htons(portnum);
347 if ((client = clnttcp_create(&addr, prognum, MIN_VERS,
348 &sock, 0, 0)) == NULL) {
349 clnt_pcreateerror("rpcinfo");
350 printf("program %lu is not available\n",
351 prognum);
352 exit(1);
354 to.tv_sec = 10;
355 to.tv_usec = 0;
356 rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
357 xdr_void, (char *)NULL, to);
358 if (rpc_stat == RPC_PROGVERSMISMATCH) {
359 clnt_geterr(client, &rpcerr);
360 minvers = rpcerr.re_vers.low;
361 maxvers = rpcerr.re_vers.high;
362 } else if (rpc_stat == RPC_SUCCESS) {
364 * Oh dear, it DOES support version 0.
365 * Let's try version MAX_VERS.
367 addr.sin_port = htons(portnum);
368 if ((client = clnttcp_create(&addr, prognum, MAX_VERS,
369 &sock, 0, 0)) == NULL) {
370 clnt_pcreateerror("rpcinfo");
371 printf("program %lu version %lu is not available\n",
372 prognum, MAX_VERS);
373 exit(1);
375 to.tv_sec = 10;
376 to.tv_usec = 0;
377 rpc_stat = clnt_call(client, NULLPROC, xdr_void,
378 (char *)NULL, xdr_void, (char *)NULL, to);
379 if (rpc_stat == RPC_PROGVERSMISMATCH) {
380 clnt_geterr(client, &rpcerr);
381 minvers = rpcerr.re_vers.low;
382 maxvers = rpcerr.re_vers.high;
383 } else if (rpc_stat == RPC_SUCCESS) {
385 * It also supports version MAX_VERS.
386 * Looks like we have a wise guy.
387 * OK, we give them information on all
388 * 4 billion versions they support...
390 minvers = 0;
391 maxvers = MAX_VERS;
392 } else {
393 (void) pstatus(client, prognum, MAX_VERS);
394 exit(1);
396 } else {
397 (void) pstatus(client, prognum, MIN_VERS);
398 exit(1);
400 clnt_destroy(client);
401 (void) close(sock);
402 sock = RPC_ANYSOCK; /* Re-initialize it for later */
403 for (vers = minvers; vers <= maxvers; vers++) {
404 addr.sin_port = htons(portnum);
405 if ((client = clnttcp_create(&addr, prognum, vers,
406 &sock, 0, 0)) == NULL) {
407 clnt_pcreateerror("rpcinfo");
408 printf("program %lu version %lu is not available\n",
409 prognum, vers);
410 exit(1);
412 to.tv_usec = 0;
413 to.tv_sec = 10;
414 rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
415 xdr_void, (char *)NULL, to);
416 if (pstatus(client, prognum, vers) < 0)
417 failure = 1;
418 clnt_destroy(client);
419 (void) close(sock);
420 sock = RPC_ANYSOCK;
423 else {
424 vers = getvers(argv[2]);
425 addr.sin_port = htons(portnum);
426 if ((client = clnttcp_create(&addr, prognum, vers, &sock,
427 0, 0)) == NULL) {
428 clnt_pcreateerror("rpcinfo");
429 printf("program %lu version %lu is not available\n",
430 prognum, vers);
431 exit(1);
433 to.tv_usec = 0;
434 to.tv_sec = 10;
435 rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
436 xdr_void, (char *)NULL, to);
437 if (pstatus(client, prognum, vers) < 0)
438 failure = 1;
440 if (failure)
441 exit(1);
445 * This routine should take a pointer to an "rpc_err" structure, rather than
446 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
447 * a CLIENT structure rather than a pointer to an "rpc_err" structure.
448 * As such, we have to keep the CLIENT structure around in order to print
449 * a good error message.
451 static int
452 pstatus(client, prognum, vers)
453 register CLIENT *client;
454 u_long prognum;
455 u_long vers;
457 struct rpc_err rpcerr;
459 clnt_geterr(client, &rpcerr);
460 if (rpcerr.re_status != RPC_SUCCESS) {
461 clnt_perror(client, "rpcinfo");
462 printf("program %lu version %lu is not available\n",
463 prognum, vers);
464 return (-1);
465 } else {
466 printf("program %lu version %lu ready and waiting\n",
467 prognum, vers);
468 return (0);
472 static void
473 pmapdump(argc, argv)
474 int argc;
475 char **argv;
477 struct sockaddr_in server_addr;
478 register struct hostent *hp;
479 struct pmaplist *head = NULL;
480 int socket = RPC_ANYSOCK;
481 struct timeval minutetimeout;
482 register CLIENT *client;
483 struct rpcent *rpc;
485 if (argc > 1) {
486 usage();
487 exit(1);
489 if (argc == 1)
490 get_inet_address(&server_addr, argv[0]);
491 else {
492 bzero((char *)&server_addr, sizeof server_addr);
493 server_addr.sin_family = AF_INET;
494 if ((hp = gethostbyname("localhost")) != NULL)
495 bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
496 MIN(hp->h_length,sizeof(server_addr.sin_addr)));
497 else
498 server_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
500 minutetimeout.tv_sec = 60;
501 minutetimeout.tv_usec = 0;
502 server_addr.sin_port = htons(PMAPPORT);
503 if ((client = clnttcp_create(&server_addr, PMAPPROG,
504 PMAPVERS, &socket, 50, 500)) == NULL) {
505 clnt_pcreateerror("rpcinfo: can't contact portmapper");
506 exit(1);
508 if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
509 xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) {
510 fprintf(stderr, "rpcinfo: can't contact portmapper: ");
511 clnt_perror(client, "rpcinfo");
512 exit(1);
514 if (head == NULL) {
515 printf("No remote programs registered.\n");
516 } else {
517 printf(" program vers proto port\n");
518 for (; head != NULL; head = head->pml_next) {
519 printf("%10ld%5ld",
520 head->pml_map.pm_prog,
521 head->pml_map.pm_vers);
522 if (head->pml_map.pm_prot == IPPROTO_UDP)
523 printf("%6s", "udp");
524 else if (head->pml_map.pm_prot == IPPROTO_TCP)
525 printf("%6s", "tcp");
526 else
527 printf("%6ld", head->pml_map.pm_prot);
528 printf("%7ld", head->pml_map.pm_port);
529 rpc = getrpcbynumber(head->pml_map.pm_prog);
530 if (rpc)
531 printf(" %s\n", rpc->r_name);
532 else
533 printf("\n");
539 * reply_proc collects replies from the broadcast.
540 * to get a unique list of responses the output of rpcinfo should
541 * be piped through sort(1) and then uniq(1).
544 /*ARGSUSED*/
545 static bool_t
546 reply_proc(res, who)
547 void *res; /* Nothing comes back */
548 struct sockaddr_in *who; /* Who sent us the reply */
550 register struct hostent *hp;
552 hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr,
553 AF_INET);
554 printf("%s %s\n", inet_ntoa(who->sin_addr),
555 (hp == NULL) ? "(unknown)" : hp->h_name);
556 return(FALSE);
559 static void
560 brdcst(argc, argv)
561 int argc;
562 char **argv;
564 enum clnt_stat rpc_stat;
565 u_long prognum, vers;
567 if (argc != 2) {
568 usage();
569 exit(1);
571 prognum = getprognum(argv[0]);
572 vers = getvers(argv[1]);
573 rpc_stat = clnt_broadcast(prognum, vers, NULLPROC, xdr_void,
574 (char *)NULL, xdr_void, (char *)NULL, reply_proc);
575 if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
576 fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
577 clnt_sperrno(rpc_stat));
578 exit(1);
580 exit(0);
583 static void
584 deletereg(argc, argv)
585 int argc;
586 char **argv;
587 { u_long prog_num, version_num ;
589 if (argc != 2) {
590 usage() ;
591 exit(1) ;
593 if (getuid()) /* This command allowed only to root */
594 errx(1, "sorry, you are not root") ;
595 prog_num = getprognum(argv[0]);
596 version_num = getvers(argv[1]);
597 if ((pmap_unset(prog_num, version_num)) == 0)
598 errx(1, "could not delete registration for prog %s version %s",
599 argv[0], argv[1]) ;
602 static void
603 usage()
605 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
606 "usage: rpcinfo [-n portnum] -u host prognum [versnum]",
607 " rpcinfo [-n portnum] -t host prognum [versnum]",
608 " rpcinfo -p [host]",
609 " rpcinfo -b prognum versnum",
610 " rpcinfo -d prognum versnum");
613 static u_long
614 getprognum(arg)
615 char *arg;
617 register struct rpcent *rpc;
618 register u_long prognum;
620 if (isalpha(*arg)) {
621 rpc = getrpcbyname(arg);
622 if (rpc == NULL)
623 errx(1, "%s is unknown service", arg);
624 prognum = rpc->r_number;
625 } else {
626 prognum = (u_long) atoi(arg);
629 return (prognum);
632 static u_long
633 getvers(arg)
634 char *arg;
636 register u_long vers;
638 vers = (int) atoi(arg);
639 return (vers);
642 static void
643 get_inet_address(addr, host)
644 struct sockaddr_in *addr;
645 char *host;
647 register struct hostent *hp;
649 bzero((char *)addr, sizeof *addr);
650 addr->sin_addr.s_addr = (u_long) inet_addr(host);
651 if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
652 if ((hp = gethostbyname(host)) == NULL)
653 errx(1, "%s is unknown host\n", host);
654 bcopy(hp->h_addr, (char *)&addr->sin_addr,
655 MIN(hp->h_length,sizeof(addr->sin_addr)));
657 addr->sin_family = AF_INET;