xref: /illumos-gate/usr/src/contrib/ast/src/lib/libcmd/fds.c (revision b30d1939)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1992-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                                                                      *
20 ***********************************************************************/
21 #pragma prototyped
22 
23 static const char usage[] =
24 "[-?\n@(#)$Id: fds (AT&T Research) 2009-09-09 $\n]"
25 USAGE_LICENSE
26 "[+NAME?fds - list open file descriptor status]"
27 "[+DESCRIPTION?\bfds\b lists the status for each open file descriptor. "
28     "When invoked as a shell builtin it accesses the file descriptors of the "
29     "calling shell, otherwise it lists the file descriptors passed across "
30     "\bexec\b(2).]"
31 "[l:long?List file descriptor details.]"
32 "[u:unit?Write output to \afd\a.]#[fd]"
33 "[+SEE ALSO?\blogname\b(1), \bwho\b(1), \bgetgroups\b(2), \bgetsockname\b(2), \bgetsockopts\b(2)]"
34 ;
35 
36 #include <cmd.h>
37 #include <ls.h>
38 
39 #include "FEATURE/sockets"
40 
41 #if defined(S_IFSOCK) && _sys_socket && _hdr_arpa_inet && _hdr_netinet_in && _lib_getsockname && _lib_getsockopt && _lib_inet_ntoa
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #else
46 #undef	S_IFSOCK
47 #endif
48 
49 #ifndef minor
50 #define minor(x)	(int)((x)&0xff)
51 #endif
52 #ifndef major
53 #define major(x)	(int)(((unsigned int)(x)>>8)&0xff)
54 #endif
55 
56 #undef	getconf
57 #define getconf(x)	strtol(astconf(x,NiL,NiL),NiL,0)
58 
59 #ifdef S_IFSOCK
60 
61 typedef struct NV_s
62 {
63 	const char*	name;
64 	int		value;
65 } NV_t;
66 
67 static const NV_t	family[] =
68 {
69 #ifdef AF_LOCAL
70 	"pipe",		AF_LOCAL,
71 #endif
72 #ifdef AF_UNIX
73 	"pipe",		AF_UNIX,
74 #endif
75 #ifdef AF_FILE
76 	"FILE",		AF_FILE,
77 #endif
78 #ifdef AF_INET
79 	"INET",		AF_INET,
80 #endif
81 #ifdef AF_AX25
82 	"AX25",		AF_AX25,
83 #endif
84 #ifdef AF_IPX
85 	"IPX",		AF_IPX,
86 #endif
87 #ifdef AF_APPLETALK
88 	"APPLETALK",	AF_APPLETALK,
89 #endif
90 #ifdef AF_NETROM
91 	"NETROM",	AF_NETROM,
92 #endif
93 #ifdef AF_BRIDGE
94 	"BRIDGE",	AF_BRIDGE,
95 #endif
96 #ifdef AF_ATMPVC
97 	"ATMPVC",	AF_ATMPVC,
98 #endif
99 #ifdef AF_X25
100 	"X25",		AF_X25,
101 #endif
102 #ifdef AF_INET6
103 	"INET6",	AF_INET6,
104 #endif
105 #ifdef AF_ROSE
106 	"ROSE",		AF_ROSE,
107 #endif
108 #ifdef AF_DECnet
109 	"DECnet",	AF_DECnet,
110 #endif
111 #ifdef AF_NETBEUI
112 	"NETBEUI",	AF_NETBEUI,
113 #endif
114 #ifdef AF_SECURITY
115 	"SECURITY",	AF_SECURITY,
116 #endif
117 #ifdef AF_KEY
118 	"KEY",		AF_KEY,
119 #endif
120 #ifdef AF_NETLINK
121 	"NETLINK",	AF_NETLINK,
122 #endif
123 #ifdef AF_ROUTE
124 	"ROUTE",	AF_ROUTE,
125 #endif
126 #ifdef AF_PACKET
127 	"PACKET",	AF_PACKET,
128 #endif
129 #ifdef AF_ASH
130 	"ASH",		AF_ASH,
131 #endif
132 #ifdef AF_ECONET
133 	"ECONET",	AF_ECONET,
134 #endif
135 #ifdef AF_ATMSVC
136 	"ATMSVC",	AF_ATMSVC,
137 #endif
138 #ifdef AF_SNA
139 	"SNA",		AF_SNA,
140 #endif
141 #ifdef AF_IRDA
142 	"IRDA",		AF_IRDA,
143 #endif
144 #ifdef AF_PPPOX
145 	"PPPOX",	AF_PPPOX,
146 #endif
147 #ifdef AF_WANPIPE
148 	"WANPIPE",	AF_WANPIPE,
149 #endif
150 #ifdef AF_BLUETOOTH
151 	"BLUETOOTH",	AF_BLUETOOTH,
152 #endif
153 	0
154 };
155 
156 #endif
157 
158 int
b_fds(int argc,char ** argv,Shbltin_t * context)159 b_fds(int argc, char** argv, Shbltin_t* context)
160 {
161 	register char*		s;
162 	register int		i;
163 	register char*		m;
164 	register char*		x;
165 	int			flags;
166 	int			details;
167 	int			open_max;
168 	int			unit;
169 	Sfio_t*			sp;
170 	struct stat		st;
171 #ifdef S_IFSOCK
172 	struct sockaddr_in	addr;
173 	char*			a;
174 	unsigned char*		b;
175 	unsigned char*		e;
176 	socklen_t		addrlen;
177 	socklen_t		len;
178 	int			type;
179 	int			port;
180 	int			prot;
181 	char			num[64];
182 	char			fam[64];
183 #ifdef INET6_ADDRSTRLEN
184 	char			nam[256];
185 #endif
186 #endif
187 
188 	cmdinit(argc, argv, context, ERROR_CATALOG, 0);
189 	details = 0;
190 	unit = 1;
191 	for (;;)
192 	{
193 		switch (optget(argv, usage))
194 		{
195 		case 'l':
196 			details = opt_info.num;
197 			continue;
198 		case 'u':
199 			unit = opt_info.num;
200 			continue;
201 		case '?':
202 			error(ERROR_USAGE|4, "%s", opt_info.arg);
203 			break;
204 		case ':':
205 			error(2, "%s", opt_info.arg);
206 			break;
207 		}
208 		break;
209 	}
210 	argv += opt_info.index;
211 	if (error_info.errors || *argv)
212 		error(ERROR_USAGE|4, "%s", optusage(NiL));
213 	if ((open_max = getconf("OPEN_MAX")) <= 0)
214 		open_max = OPEN_MAX;
215 	if (unit == 1)
216 		sp = sfstdout;
217 	else if (fstat(unit, &st) || !(sp = sfnew(NiL, NiL, SF_UNBOUND, unit, SF_WRITE)))
218 		error(ERROR_SYSTEM|3, "%d: cannot write to file descriptor");
219 	for (i = 0; i <= open_max; i++)
220 	{
221 		if (fstat(i, &st))
222 		{
223 			/* not open */
224 			continue;
225 		}
226 		if (!details)
227 		{
228 			sfprintf(sp, "%d\n", i);
229 			continue;
230 		}
231 		if ((flags = fcntl(i, F_GETFL, (char*)0)) == -1)
232 			m = "--";
233 		else
234 			switch (flags & (O_RDONLY|O_WRONLY|O_RDWR))
235 			{
236 			case O_RDONLY:
237 				m = "r-";
238 				break;
239 			case O_WRONLY:
240 				m = "-w";
241 				break;
242 			case O_RDWR:
243 				m = "rw";
244 				break;
245 			default:
246 				m = "??";
247 				break;
248 			}
249 		x = (fcntl(i, F_GETFD, (char*)0) > 0) ? "x" : "-";
250 		if (isatty(i) && (s = ttyname(i)))
251 		{
252 			sfprintf(sp, "%02d %s%s %s %s\n", i, m, x, fmtmode(st.st_mode, 0), s);
253 			continue;
254 		}
255 #ifdef S_IFSOCK
256 		addrlen = sizeof(addr);
257 		memset(&addr, 0, addrlen);
258 		if (!getsockname(i, (struct sockaddr*)&addr, (void*)&addrlen))
259 		{
260 			type = 0;
261 			prot = 0;
262 #ifdef SO_TYPE
263 			len = sizeof(type);
264 			if (getsockopt(i, SOL_SOCKET, SO_TYPE, (void*)&type, (void*)&len))
265 				type = -1;
266 #endif
267 #ifdef SO_PROTOTYPE
268 			len = sizeof(prot);
269 			if (getsockopt(i, SOL_SOCKET, SO_PROTOTYPE, (void*)&prot, (void*)&len))
270 				prot = -1;
271 #endif
272 			if (!st.st_mode)
273 				st.st_mode = S_IFSOCK|S_IRUSR|S_IWUSR;
274 			s = 0;
275 			switch (type)
276 			{
277 			case SOCK_DGRAM:
278 				switch (addr.sin_family)
279 				{
280 				case AF_INET:
281 #ifdef AF_INET6
282 				case AF_INET6:
283 #endif
284 					s = "udp";
285 					break;
286 				}
287 				break;
288 			case SOCK_STREAM:
289 				switch (addr.sin_family)
290 				{
291 				case AF_INET:
292 #ifdef AF_INET6
293 				case AF_INET6:
294 #endif
295 #ifdef IPPROTO_SCTP
296 					if (prot == IPPROTO_SCTP)
297 						s = "sctp";
298 					else
299 #endif
300 						s = "tcp";
301 					break;
302 				}
303 				break;
304 #ifdef SOCK_RAW
305 			case SOCK_RAW:
306 				s = "raw";
307 				break;
308 #endif
309 #ifdef SOCK_RDM
310 			case SOCK_RDM:
311 				s = "rdm";
312 				break;
313 #endif
314 #ifdef SOCK_SEQPACKET
315 			case SOCK_SEQPACKET:
316 				s = "seqpacket";
317 				break;
318 #endif
319 			}
320 			if (!s)
321 			{
322 				for (type = 0; family[type].name && family[type].value != addr.sin_family; type++);
323 				if (!(s = (char*)family[type].name))
324 					sfsprintf(s = num, sizeof(num), "family.%d", addr.sin_family);
325 			}
326 			port = 0;
327 #ifdef INET6_ADDRSTRLEN
328 			if (a = (char*)inet_ntop(addr.sin_family, &addr.sin_addr, nam, sizeof(nam)))
329 				port = ntohs(addr.sin_port);
330 			else
331 #endif
332 			if (addr.sin_family == AF_INET)
333 			{
334 				a = inet_ntoa(addr.sin_addr);
335 				port = ntohs(addr.sin_port);
336 			}
337 			else
338 			{
339 				a = fam;
340 				e = (b = (unsigned char*)&addr) + addrlen;
341 				while (b < e && a < &fam[sizeof(fam)-1])
342 					a += sfsprintf(a, &fam[sizeof(fam)] - a - 1, ".%d", *b++);
343 				a = a == fam ? "0" : fam + 1;
344 			}
345 			if (port)
346 				sfprintf(sp, "%02d %s%s %s /dev/%s/%s/%d\n", i, m, x, fmtmode(st.st_mode, 0), s, a, port);
347 			else
348 				sfprintf(sp, "%02d %s%s %s /dev/%s/%s\n", i, m, x, fmtmode(st.st_mode, 0), s, a);
349 			continue;
350 		}
351 #endif
352 		sfprintf(sp, "%02d %s%s %s /dev/inode/%u/%u\n", i, m, x, fmtmode(st.st_mode, 0), st.st_dev, st.st_ino);
353 	}
354 	if (sp != sfstdout)
355 	{
356 		sfsetfd(sp, -1);
357 		sfclose(sp);
358 	}
359 	return 0;
360 }
361