1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1992-2010 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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
23static const char usage[] =
24"[-?\n@(#)$Id: fds (AT&T Research) 2009-09-09 $\n]"
25USAGE_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
61typedef struct NV_s
62{
63	const char*	name;
64	int		value;
65} NV_t;
66
67static 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
158int
159b_fds(int argc, char** argv, void* 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			continue;
204		case ':':
205			error(2, "%s", opt_info.arg);
206			continue;
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