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