xref: /onnv-gate/usr/src/cmd/svc/servinfo/servinfo.c (revision 8823:000507e9108d)
1*8823STruong.Q.Nguyen@Sun.COM /*
2*8823STruong.Q.Nguyen@Sun.COM  * CDDL HEADER START
3*8823STruong.Q.Nguyen@Sun.COM  *
4*8823STruong.Q.Nguyen@Sun.COM  * The contents of this file are subject to the terms of the
5*8823STruong.Q.Nguyen@Sun.COM  * Common Development and Distribution License (the "License").
6*8823STruong.Q.Nguyen@Sun.COM  * You may not use this file except in compliance with the License.
7*8823STruong.Q.Nguyen@Sun.COM  *
8*8823STruong.Q.Nguyen@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*8823STruong.Q.Nguyen@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*8823STruong.Q.Nguyen@Sun.COM  * See the License for the specific language governing permissions
11*8823STruong.Q.Nguyen@Sun.COM  * and limitations under the License.
12*8823STruong.Q.Nguyen@Sun.COM  *
13*8823STruong.Q.Nguyen@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*8823STruong.Q.Nguyen@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*8823STruong.Q.Nguyen@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*8823STruong.Q.Nguyen@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*8823STruong.Q.Nguyen@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*8823STruong.Q.Nguyen@Sun.COM  *
19*8823STruong.Q.Nguyen@Sun.COM  * CDDL HEADER END
20*8823STruong.Q.Nguyen@Sun.COM  */
21*8823STruong.Q.Nguyen@Sun.COM 
22*8823STruong.Q.Nguyen@Sun.COM /*
23*8823STruong.Q.Nguyen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*8823STruong.Q.Nguyen@Sun.COM  * Use is subject to license terms.
25*8823STruong.Q.Nguyen@Sun.COM  */
26*8823STruong.Q.Nguyen@Sun.COM 
27*8823STruong.Q.Nguyen@Sun.COM /*
28*8823STruong.Q.Nguyen@Sun.COM  * This file delivers /usr/lib/servinfo which provides description for
29*8823STruong.Q.Nguyen@Sun.COM  * IANA and running RPC services. Given a IANA name or RPC program name
30*8823STruong.Q.Nguyen@Sun.COM  * or number, the program uses getservbyname(3SOCKET) and rpcbind(3NSL)
31*8823STruong.Q.Nguyen@Sun.COM  * to obtain port and proto information for the specified service.
32*8823STruong.Q.Nguyen@Sun.COM  */
33*8823STruong.Q.Nguyen@Sun.COM 
34*8823STruong.Q.Nguyen@Sun.COM #include <stdio.h>
35*8823STruong.Q.Nguyen@Sun.COM #include <stdlib.h>
36*8823STruong.Q.Nguyen@Sun.COM #include <strings.h>
37*8823STruong.Q.Nguyen@Sun.COM #include <netconfig.h>
38*8823STruong.Q.Nguyen@Sun.COM #include <netdb.h>
39*8823STruong.Q.Nguyen@Sun.COM #include <rpc/rpc.h>
40*8823STruong.Q.Nguyen@Sun.COM #include <rpc/rpcent.h>
41*8823STruong.Q.Nguyen@Sun.COM #include <sys/types.h>
42*8823STruong.Q.Nguyen@Sun.COM #include <netinet/in.h>
43*8823STruong.Q.Nguyen@Sun.COM #include <netdir.h>
44*8823STruong.Q.Nguyen@Sun.COM #include <inttypes.h>
45*8823STruong.Q.Nguyen@Sun.COM #include <limits.h>
46*8823STruong.Q.Nguyen@Sun.COM #include <libintl.h>
47*8823STruong.Q.Nguyen@Sun.COM #include <locale.h>
48*8823STruong.Q.Nguyen@Sun.COM 
49*8823STruong.Q.Nguyen@Sun.COM #ifndef	TEXT_DOMAIN
50*8823STruong.Q.Nguyen@Sun.COM #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
51*8823STruong.Q.Nguyen@Sun.COM #endif /* TEXT_DOMAIN */
52*8823STruong.Q.Nguyen@Sun.COM 
53*8823STruong.Q.Nguyen@Sun.COM #define	TCP	"tcp"
54*8823STruong.Q.Nguyen@Sun.COM #define	TCP6	"tcp6"
55*8823STruong.Q.Nguyen@Sun.COM #define	UDP	"udp"
56*8823STruong.Q.Nguyen@Sun.COM #define	UDP6	"udp6"
57*8823STruong.Q.Nguyen@Sun.COM 
58*8823STruong.Q.Nguyen@Sun.COM #define	DEFAULT 0x1
59*8823STruong.Q.Nguyen@Sun.COM #define	PORT	0x2
60*8823STruong.Q.Nguyen@Sun.COM #define	PROTO	0x4
61*8823STruong.Q.Nguyen@Sun.COM 
62*8823STruong.Q.Nguyen@Sun.COM #define	NETID_LEN	12 /* length for a netid or 2^16 port value */
63*8823STruong.Q.Nguyen@Sun.COM 
64*8823STruong.Q.Nguyen@Sun.COM static void
usage(char * arg0)65*8823STruong.Q.Nguyen@Sun.COM usage(char *arg0)
66*8823STruong.Q.Nguyen@Sun.COM {
67*8823STruong.Q.Nguyen@Sun.COM 	(void) fprintf(stderr, gettext("Usage: %s [-R] [-Pp] [-tu[6]] "
68*8823STruong.Q.Nguyen@Sun.COM 	    "-s service_name\n"), arg0);
69*8823STruong.Q.Nguyen@Sun.COM }
70*8823STruong.Q.Nguyen@Sun.COM 
71*8823STruong.Q.Nguyen@Sun.COM static rpcport_t
uaddr2port(char * addr)72*8823STruong.Q.Nguyen@Sun.COM uaddr2port(char *addr)
73*8823STruong.Q.Nguyen@Sun.COM {
74*8823STruong.Q.Nguyen@Sun.COM 	rpcport_t port = 0;
75*8823STruong.Q.Nguyen@Sun.COM 	char *dot, *p;
76*8823STruong.Q.Nguyen@Sun.COM 
77*8823STruong.Q.Nguyen@Sun.COM 	if ((dot = strrchr(addr, '.')) == 0) {
78*8823STruong.Q.Nguyen@Sun.COM 		return (0);
79*8823STruong.Q.Nguyen@Sun.COM 	} else {
80*8823STruong.Q.Nguyen@Sun.COM 		if (dot == addr)
81*8823STruong.Q.Nguyen@Sun.COM 			return (0);
82*8823STruong.Q.Nguyen@Sun.COM 
83*8823STruong.Q.Nguyen@Sun.COM 		p = dot - 1;
84*8823STruong.Q.Nguyen@Sun.COM 		while (*p != '.') {
85*8823STruong.Q.Nguyen@Sun.COM 			/*
86*8823STruong.Q.Nguyen@Sun.COM 			 * If the first dot hasn't been seen, it's a
87*8823STruong.Q.Nguyen@Sun.COM 			 * malformed universal address.
88*8823STruong.Q.Nguyen@Sun.COM 			 */
89*8823STruong.Q.Nguyen@Sun.COM 			if (p == addr)
90*8823STruong.Q.Nguyen@Sun.COM 				return (0);
91*8823STruong.Q.Nguyen@Sun.COM 			p--;
92*8823STruong.Q.Nguyen@Sun.COM 		}
93*8823STruong.Q.Nguyen@Sun.COM 
94*8823STruong.Q.Nguyen@Sun.COM 		port = strtol(p + 1, &dot, 10) << 8;
95*8823STruong.Q.Nguyen@Sun.COM 		port = port | strtol(dot + 1, (char **)NULL, 10);
96*8823STruong.Q.Nguyen@Sun.COM 	}
97*8823STruong.Q.Nguyen@Sun.COM 
98*8823STruong.Q.Nguyen@Sun.COM 	return (port);
99*8823STruong.Q.Nguyen@Sun.COM }
100*8823STruong.Q.Nguyen@Sun.COM 
101*8823STruong.Q.Nguyen@Sun.COM static int
svc_getrpcinfo(char * sname,char * sproto,int options)102*8823STruong.Q.Nguyen@Sun.COM svc_getrpcinfo(char *sname, char *sproto, int options)
103*8823STruong.Q.Nguyen@Sun.COM {
104*8823STruong.Q.Nguyen@Sun.COM 	struct netconfig *nconf;
105*8823STruong.Q.Nguyen@Sun.COM 	struct rpcblist *blist;
106*8823STruong.Q.Nguyen@Sun.COM 	int	prognum = -1;
107*8823STruong.Q.Nguyen@Sun.COM 	rpcport_t rpc_port;
108*8823STruong.Q.Nguyen@Sun.COM 	struct rpcent  rentry;
109*8823STruong.Q.Nguyen@Sun.COM 	struct rpcent  *rpc;
110*8823STruong.Q.Nguyen@Sun.COM 	char line[LINE_MAX] = "";
111*8823STruong.Q.Nguyen@Sun.COM 	int  line_len = LINE_MAX - 1;
112*8823STruong.Q.Nguyen@Sun.COM 	char buf[NETID_LEN];
113*8823STruong.Q.Nguyen@Sun.COM 
114*8823STruong.Q.Nguyen@Sun.COM 	prognum = atoi(sname);
115*8823STruong.Q.Nguyen@Sun.COM 	if (prognum > 0)
116*8823STruong.Q.Nguyen@Sun.COM 		rpc = (struct rpcent *)getrpcbynumber(prognum);
117*8823STruong.Q.Nguyen@Sun.COM 	else
118*8823STruong.Q.Nguyen@Sun.COM 		rpc = (struct rpcent *)getrpcbyname(sname);
119*8823STruong.Q.Nguyen@Sun.COM 
120*8823STruong.Q.Nguyen@Sun.COM 	/*
121*8823STruong.Q.Nguyen@Sun.COM 	 * If an entry doesn't exist, it could be a running program
122*8823STruong.Q.Nguyen@Sun.COM 	 * without a registered RPC entry.
123*8823STruong.Q.Nguyen@Sun.COM 	 */
124*8823STruong.Q.Nguyen@Sun.COM 	if (rpc == NULL) {
125*8823STruong.Q.Nguyen@Sun.COM 		if (prognum <= 0) {
126*8823STruong.Q.Nguyen@Sun.COM 			(void) fprintf(stderr,
127*8823STruong.Q.Nguyen@Sun.COM 			    gettext("Can't get rpc entry\n"));
128*8823STruong.Q.Nguyen@Sun.COM 			return (1);
129*8823STruong.Q.Nguyen@Sun.COM 		}
130*8823STruong.Q.Nguyen@Sun.COM 
131*8823STruong.Q.Nguyen@Sun.COM 		rpc = &rentry;
132*8823STruong.Q.Nguyen@Sun.COM 		rpc->r_number = prognum;
133*8823STruong.Q.Nguyen@Sun.COM 		rpc->r_name = sname;
134*8823STruong.Q.Nguyen@Sun.COM 	}
135*8823STruong.Q.Nguyen@Sun.COM 
136*8823STruong.Q.Nguyen@Sun.COM 	if (setnetconfig() == NULL) {
137*8823STruong.Q.Nguyen@Sun.COM 		(void) fprintf(stderr, gettext("setnetconfig failed\n"));
138*8823STruong.Q.Nguyen@Sun.COM 		return (1);
139*8823STruong.Q.Nguyen@Sun.COM 	}
140*8823STruong.Q.Nguyen@Sun.COM 
141*8823STruong.Q.Nguyen@Sun.COM 	if ((nconf = getnetconfigent(TCP)) == NULL) {
142*8823STruong.Q.Nguyen@Sun.COM 		(void) fprintf(stderr, gettext("getnetconfig failed\n"));
143*8823STruong.Q.Nguyen@Sun.COM 		return (1);
144*8823STruong.Q.Nguyen@Sun.COM 	}
145*8823STruong.Q.Nguyen@Sun.COM 
146*8823STruong.Q.Nguyen@Sun.COM 	if ((blist = (struct rpcblist *)rpcb_getmaps(nconf, "localhost"))
147*8823STruong.Q.Nguyen@Sun.COM 	    == NULL) {
148*8823STruong.Q.Nguyen@Sun.COM 		(void) fprintf(stderr,
149*8823STruong.Q.Nguyen@Sun.COM 		    gettext("Failed: rpcb_getmaps failed\n"));
150*8823STruong.Q.Nguyen@Sun.COM 		return (1);
151*8823STruong.Q.Nguyen@Sun.COM 	}
152*8823STruong.Q.Nguyen@Sun.COM 
153*8823STruong.Q.Nguyen@Sun.COM 	for (; blist != NULL; blist = blist->rpcb_next) {
154*8823STruong.Q.Nguyen@Sun.COM 		if (blist->rpcb_map.r_prog != rpc->r_number)
155*8823STruong.Q.Nguyen@Sun.COM 			continue;
156*8823STruong.Q.Nguyen@Sun.COM 
157*8823STruong.Q.Nguyen@Sun.COM 		if (sproto) {
158*8823STruong.Q.Nguyen@Sun.COM 			if (strcmp(blist->rpcb_map.r_netid, sproto) != 0)
159*8823STruong.Q.Nguyen@Sun.COM 				continue;
160*8823STruong.Q.Nguyen@Sun.COM 		} else {
161*8823STruong.Q.Nguyen@Sun.COM 			if (strcmp(blist->rpcb_map.r_netid, UDP) &&
162*8823STruong.Q.Nguyen@Sun.COM 			    strcmp(blist->rpcb_map.r_netid, UDP6) &&
163*8823STruong.Q.Nguyen@Sun.COM 			    strcmp(blist->rpcb_map.r_netid, TCP) &&
164*8823STruong.Q.Nguyen@Sun.COM 			    strcmp(blist->rpcb_map.r_netid, TCP6))
165*8823STruong.Q.Nguyen@Sun.COM 				continue;
166*8823STruong.Q.Nguyen@Sun.COM 		}
167*8823STruong.Q.Nguyen@Sun.COM 		rpc_port = uaddr2port(blist->rpcb_map.r_addr);
168*8823STruong.Q.Nguyen@Sun.COM 
169*8823STruong.Q.Nguyen@Sun.COM 		if (options & DEFAULT) {
170*8823STruong.Q.Nguyen@Sun.COM 			(void) printf("Program %ld\n", blist->rpcb_map.r_prog);
171*8823STruong.Q.Nguyen@Sun.COM 			(void) printf("Protocol %s\n", blist->rpcb_map.r_netid);
172*8823STruong.Q.Nguyen@Sun.COM 			(void) printf("Port %ld\n", rpc_port);
173*8823STruong.Q.Nguyen@Sun.COM 			(void) printf("Version %ld\n", blist->rpcb_map.r_vers);
174*8823STruong.Q.Nguyen@Sun.COM 			(void) printf("Name %s\n", rpc->r_name);
175*8823STruong.Q.Nguyen@Sun.COM 
176*8823STruong.Q.Nguyen@Sun.COM 		} else if (options & PROTO) {
177*8823STruong.Q.Nguyen@Sun.COM 			if (strstr(line, blist->rpcb_map.r_netid))
178*8823STruong.Q.Nguyen@Sun.COM 				continue;
179*8823STruong.Q.Nguyen@Sun.COM 
180*8823STruong.Q.Nguyen@Sun.COM 			(void) snprintf(buf, sizeof (buf), "%5s ",
181*8823STruong.Q.Nguyen@Sun.COM 			    blist->rpcb_map.r_netid);
182*8823STruong.Q.Nguyen@Sun.COM 
183*8823STruong.Q.Nguyen@Sun.COM 			if (strlen(buf) > line_len)
184*8823STruong.Q.Nguyen@Sun.COM 				continue;
185*8823STruong.Q.Nguyen@Sun.COM 
186*8823STruong.Q.Nguyen@Sun.COM 			line_len = line_len - strlen(buf);
187*8823STruong.Q.Nguyen@Sun.COM 			(void) strlcat(line, buf, sizeof (line));
188*8823STruong.Q.Nguyen@Sun.COM 		} else {
189*8823STruong.Q.Nguyen@Sun.COM 			(void) snprintf(buf, sizeof (buf), "%-7ld ", rpc_port);
190*8823STruong.Q.Nguyen@Sun.COM 
191*8823STruong.Q.Nguyen@Sun.COM 			if (strstr(line, buf) || strlen(buf) > line_len)
192*8823STruong.Q.Nguyen@Sun.COM 				continue;
193*8823STruong.Q.Nguyen@Sun.COM 
194*8823STruong.Q.Nguyen@Sun.COM 			line_len = line_len - strlen(buf);
195*8823STruong.Q.Nguyen@Sun.COM 			(void) strlcat(line, buf, sizeof (line));
196*8823STruong.Q.Nguyen@Sun.COM 		}
197*8823STruong.Q.Nguyen@Sun.COM 	}
198*8823STruong.Q.Nguyen@Sun.COM 
199*8823STruong.Q.Nguyen@Sun.COM 	/*
200*8823STruong.Q.Nguyen@Sun.COM 	 * Print the concatenated output if options is PROTO or PORT.
201*8823STruong.Q.Nguyen@Sun.COM 	 */
202*8823STruong.Q.Nguyen@Sun.COM 	if (options & (PROTO | PORT))
203*8823STruong.Q.Nguyen@Sun.COM 		(void) puts(line);
204*8823STruong.Q.Nguyen@Sun.COM 
205*8823STruong.Q.Nguyen@Sun.COM 	return (0);
206*8823STruong.Q.Nguyen@Sun.COM }
207*8823STruong.Q.Nguyen@Sun.COM 
208*8823STruong.Q.Nguyen@Sun.COM int
main(int argc,char * argv[])209*8823STruong.Q.Nguyen@Sun.COM main(int argc, char *argv[])
210*8823STruong.Q.Nguyen@Sun.COM {
211*8823STruong.Q.Nguyen@Sun.COM 	struct servent *service;
212*8823STruong.Q.Nguyen@Sun.COM 	char *sname = NULL;
213*8823STruong.Q.Nguyen@Sun.COM 	char *sproto = NULL;
214*8823STruong.Q.Nguyen@Sun.COM 	int options = DEFAULT;
215*8823STruong.Q.Nguyen@Sun.COM 	int c, isrpc = 0, v6_flag = 0;
216*8823STruong.Q.Nguyen@Sun.COM 
217*8823STruong.Q.Nguyen@Sun.COM 	(void) setlocale(LC_ALL, "");
218*8823STruong.Q.Nguyen@Sun.COM 	(void) textdomain(TEXT_DOMAIN);
219*8823STruong.Q.Nguyen@Sun.COM 
220*8823STruong.Q.Nguyen@Sun.COM 	optind = 1;
221*8823STruong.Q.Nguyen@Sun.COM 	opterr = 1;
222*8823STruong.Q.Nguyen@Sun.COM 	while ((c = getopt(argc, argv, "s:PplRtu6?")) != -1) {
223*8823STruong.Q.Nguyen@Sun.COM 		switch (c) {
224*8823STruong.Q.Nguyen@Sun.COM 		case 's':
225*8823STruong.Q.Nguyen@Sun.COM 			sname = optarg;
226*8823STruong.Q.Nguyen@Sun.COM 			break;
227*8823STruong.Q.Nguyen@Sun.COM 		case 't':
228*8823STruong.Q.Nguyen@Sun.COM 			sproto = TCP;
229*8823STruong.Q.Nguyen@Sun.COM 			break;
230*8823STruong.Q.Nguyen@Sun.COM 		case 'u':
231*8823STruong.Q.Nguyen@Sun.COM 			sproto = UDP;
232*8823STruong.Q.Nguyen@Sun.COM 			break;
233*8823STruong.Q.Nguyen@Sun.COM 		case '6':
234*8823STruong.Q.Nguyen@Sun.COM 			v6_flag = 1;
235*8823STruong.Q.Nguyen@Sun.COM 			break;
236*8823STruong.Q.Nguyen@Sun.COM 		case 'P':
237*8823STruong.Q.Nguyen@Sun.COM 			options = PROTO;
238*8823STruong.Q.Nguyen@Sun.COM 			break;
239*8823STruong.Q.Nguyen@Sun.COM 		case 'p':
240*8823STruong.Q.Nguyen@Sun.COM 			options = PORT;
241*8823STruong.Q.Nguyen@Sun.COM 			break;
242*8823STruong.Q.Nguyen@Sun.COM 		case 'R':
243*8823STruong.Q.Nguyen@Sun.COM 			isrpc = 1;
244*8823STruong.Q.Nguyen@Sun.COM 			break;
245*8823STruong.Q.Nguyen@Sun.COM 		default:
246*8823STruong.Q.Nguyen@Sun.COM 			usage(argv[0]);
247*8823STruong.Q.Nguyen@Sun.COM 			return (1);
248*8823STruong.Q.Nguyen@Sun.COM 		}
249*8823STruong.Q.Nguyen@Sun.COM 	}
250*8823STruong.Q.Nguyen@Sun.COM 	if (sname == NULL) {
251*8823STruong.Q.Nguyen@Sun.COM 		usage(argv[0]);
252*8823STruong.Q.Nguyen@Sun.COM 		return (1);
253*8823STruong.Q.Nguyen@Sun.COM 	}
254*8823STruong.Q.Nguyen@Sun.COM 
255*8823STruong.Q.Nguyen@Sun.COM 	/*
256*8823STruong.Q.Nguyen@Sun.COM 	 * Specified service is an RPC service.
257*8823STruong.Q.Nguyen@Sun.COM 	 */
258*8823STruong.Q.Nguyen@Sun.COM 	if (isrpc) {
259*8823STruong.Q.Nguyen@Sun.COM 		if (sproto && v6_flag) {
260*8823STruong.Q.Nguyen@Sun.COM 			if (strcmp(sproto, TCP) == 0)
261*8823STruong.Q.Nguyen@Sun.COM 				sproto = TCP6;
262*8823STruong.Q.Nguyen@Sun.COM 			if (strcmp(sproto, UDP) == 0)
263*8823STruong.Q.Nguyen@Sun.COM 				sproto = UDP6;
264*8823STruong.Q.Nguyen@Sun.COM 		}
265*8823STruong.Q.Nguyen@Sun.COM 
266*8823STruong.Q.Nguyen@Sun.COM 		return (svc_getrpcinfo(sname, sproto, options));
267*8823STruong.Q.Nguyen@Sun.COM 	}
268*8823STruong.Q.Nguyen@Sun.COM 
269*8823STruong.Q.Nguyen@Sun.COM 	if ((service = getservbyname(sname, sproto)) == NULL) {
270*8823STruong.Q.Nguyen@Sun.COM 		(void) fprintf(stderr, gettext(
271*8823STruong.Q.Nguyen@Sun.COM 		    "Failed to get information for %s\n"), sname);
272*8823STruong.Q.Nguyen@Sun.COM 		return (1);
273*8823STruong.Q.Nguyen@Sun.COM 	}
274*8823STruong.Q.Nguyen@Sun.COM 
275*8823STruong.Q.Nguyen@Sun.COM 	if (options & DEFAULT) {
276*8823STruong.Q.Nguyen@Sun.COM 		(void) printf("Name %s\n", service->s_name);
277*8823STruong.Q.Nguyen@Sun.COM 		(void) printf("Protocol %s\n", service->s_proto);
278*8823STruong.Q.Nguyen@Sun.COM 		(void) printf("Port %d\n", htons(service->s_port));
279*8823STruong.Q.Nguyen@Sun.COM 	} else if (options & PROTO)
280*8823STruong.Q.Nguyen@Sun.COM 		(void) printf("%s\n", service->s_proto);
281*8823STruong.Q.Nguyen@Sun.COM 	else
282*8823STruong.Q.Nguyen@Sun.COM 		(void) printf("%d\n", htons(service->s_port));
283*8823STruong.Q.Nguyen@Sun.COM 
284*8823STruong.Q.Nguyen@Sun.COM 	return (0);
285*8823STruong.Q.Nguyen@Sun.COM }
286