xref: /illumos-gate/usr/src/contrib/ast/src/lib/libcmd/fds.c (revision b30d1939)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1992-2012 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                                                                      *
20da2e3ebdSchin ***********************************************************************/
21da2e3ebdSchin #pragma prototyped
22da2e3ebdSchin 
23da2e3ebdSchin static const char usage[] =
2434f9b3eeSRoland Mainz "[-?\n@(#)$Id: fds (AT&T Research) 2009-09-09 $\n]"
25da2e3ebdSchin USAGE_LICENSE
26da2e3ebdSchin "[+NAME?fds - list open file descriptor status]"
27da2e3ebdSchin "[+DESCRIPTION?\bfds\b lists the status for each open file descriptor. "
28da2e3ebdSchin     "When invoked as a shell builtin it accesses the file descriptors of the "
29da2e3ebdSchin     "calling shell, otherwise it lists the file descriptors passed across "
30da2e3ebdSchin     "\bexec\b(2).]"
31da2e3ebdSchin "[l:long?List file descriptor details.]"
3234f9b3eeSRoland Mainz "[u:unit?Write output to \afd\a.]#[fd]"
337c2fbfb3SApril Chin "[+SEE ALSO?\blogname\b(1), \bwho\b(1), \bgetgroups\b(2), \bgetsockname\b(2), \bgetsockopts\b(2)]"
34da2e3ebdSchin ;
35da2e3ebdSchin 
36da2e3ebdSchin #include <cmd.h>
37da2e3ebdSchin #include <ls.h>
38da2e3ebdSchin 
39da2e3ebdSchin #include "FEATURE/sockets"
40da2e3ebdSchin 
41da2e3ebdSchin #if defined(S_IFSOCK) && _sys_socket && _hdr_arpa_inet && _hdr_netinet_in && _lib_getsockname && _lib_getsockopt && _lib_inet_ntoa
42da2e3ebdSchin #include <sys/socket.h>
43da2e3ebdSchin #include <netinet/in.h>
44da2e3ebdSchin #include <arpa/inet.h>
45da2e3ebdSchin #else
46da2e3ebdSchin #undef	S_IFSOCK
47da2e3ebdSchin #endif
48da2e3ebdSchin 
49da2e3ebdSchin #ifndef minor
50da2e3ebdSchin #define minor(x)	(int)((x)&0xff)
51da2e3ebdSchin #endif
52da2e3ebdSchin #ifndef major
53da2e3ebdSchin #define major(x)	(int)(((unsigned int)(x)>>8)&0xff)
54da2e3ebdSchin #endif
55da2e3ebdSchin 
567c2fbfb3SApril Chin #undef	getconf
577c2fbfb3SApril Chin #define getconf(x)	strtol(astconf(x,NiL,NiL),NiL,0)
587c2fbfb3SApril Chin 
597c2fbfb3SApril Chin #ifdef S_IFSOCK
607c2fbfb3SApril Chin 
617c2fbfb3SApril Chin typedef struct NV_s
627c2fbfb3SApril Chin {
637c2fbfb3SApril Chin 	const char*	name;
647c2fbfb3SApril Chin 	int		value;
657c2fbfb3SApril Chin } NV_t;
667c2fbfb3SApril Chin 
677c2fbfb3SApril Chin static const NV_t	family[] =
687c2fbfb3SApril Chin {
697c2fbfb3SApril Chin #ifdef AF_LOCAL
707c2fbfb3SApril Chin 	"pipe",		AF_LOCAL,
717c2fbfb3SApril Chin #endif
727c2fbfb3SApril Chin #ifdef AF_UNIX
737c2fbfb3SApril Chin 	"pipe",		AF_UNIX,
747c2fbfb3SApril Chin #endif
757c2fbfb3SApril Chin #ifdef AF_FILE
767c2fbfb3SApril Chin 	"FILE",		AF_FILE,
777c2fbfb3SApril Chin #endif
787c2fbfb3SApril Chin #ifdef AF_INET
797c2fbfb3SApril Chin 	"INET",		AF_INET,
807c2fbfb3SApril Chin #endif
817c2fbfb3SApril Chin #ifdef AF_AX25
827c2fbfb3SApril Chin 	"AX25",		AF_AX25,
837c2fbfb3SApril Chin #endif
847c2fbfb3SApril Chin #ifdef AF_IPX
857c2fbfb3SApril Chin 	"IPX",		AF_IPX,
867c2fbfb3SApril Chin #endif
877c2fbfb3SApril Chin #ifdef AF_APPLETALK
887c2fbfb3SApril Chin 	"APPLETALK",	AF_APPLETALK,
897c2fbfb3SApril Chin #endif
907c2fbfb3SApril Chin #ifdef AF_NETROM
917c2fbfb3SApril Chin 	"NETROM",	AF_NETROM,
927c2fbfb3SApril Chin #endif
937c2fbfb3SApril Chin #ifdef AF_BRIDGE
947c2fbfb3SApril Chin 	"BRIDGE",	AF_BRIDGE,
957c2fbfb3SApril Chin #endif
967c2fbfb3SApril Chin #ifdef AF_ATMPVC
977c2fbfb3SApril Chin 	"ATMPVC",	AF_ATMPVC,
987c2fbfb3SApril Chin #endif
997c2fbfb3SApril Chin #ifdef AF_X25
1007c2fbfb3SApril Chin 	"X25",		AF_X25,
1017c2fbfb3SApril Chin #endif
1027c2fbfb3SApril Chin #ifdef AF_INET6
1037c2fbfb3SApril Chin 	"INET6",	AF_INET6,
1047c2fbfb3SApril Chin #endif
1057c2fbfb3SApril Chin #ifdef AF_ROSE
1067c2fbfb3SApril Chin 	"ROSE",		AF_ROSE,
1077c2fbfb3SApril Chin #endif
1087c2fbfb3SApril Chin #ifdef AF_DECnet
1097c2fbfb3SApril Chin 	"DECnet",	AF_DECnet,
1107c2fbfb3SApril Chin #endif
1117c2fbfb3SApril Chin #ifdef AF_NETBEUI
1127c2fbfb3SApril Chin 	"NETBEUI",	AF_NETBEUI,
1137c2fbfb3SApril Chin #endif
1147c2fbfb3SApril Chin #ifdef AF_SECURITY
1157c2fbfb3SApril Chin 	"SECURITY",	AF_SECURITY,
1167c2fbfb3SApril Chin #endif
1177c2fbfb3SApril Chin #ifdef AF_KEY
1187c2fbfb3SApril Chin 	"KEY",		AF_KEY,
1197c2fbfb3SApril Chin #endif
1207c2fbfb3SApril Chin #ifdef AF_NETLINK
1217c2fbfb3SApril Chin 	"NETLINK",	AF_NETLINK,
1227c2fbfb3SApril Chin #endif
1237c2fbfb3SApril Chin #ifdef AF_ROUTE
1247c2fbfb3SApril Chin 	"ROUTE",	AF_ROUTE,
1257c2fbfb3SApril Chin #endif
1267c2fbfb3SApril Chin #ifdef AF_PACKET
1277c2fbfb3SApril Chin 	"PACKET",	AF_PACKET,
1287c2fbfb3SApril Chin #endif
1297c2fbfb3SApril Chin #ifdef AF_ASH
1307c2fbfb3SApril Chin 	"ASH",		AF_ASH,
1317c2fbfb3SApril Chin #endif
1327c2fbfb3SApril Chin #ifdef AF_ECONET
1337c2fbfb3SApril Chin 	"ECONET",	AF_ECONET,
1347c2fbfb3SApril Chin #endif
1357c2fbfb3SApril Chin #ifdef AF_ATMSVC
1367c2fbfb3SApril Chin 	"ATMSVC",	AF_ATMSVC,
1377c2fbfb3SApril Chin #endif
1387c2fbfb3SApril Chin #ifdef AF_SNA
1397c2fbfb3SApril Chin 	"SNA",		AF_SNA,
1407c2fbfb3SApril Chin #endif
1417c2fbfb3SApril Chin #ifdef AF_IRDA
1427c2fbfb3SApril Chin 	"IRDA",		AF_IRDA,
1437c2fbfb3SApril Chin #endif
1447c2fbfb3SApril Chin #ifdef AF_PPPOX
1457c2fbfb3SApril Chin 	"PPPOX",	AF_PPPOX,
1467c2fbfb3SApril Chin #endif
1477c2fbfb3SApril Chin #ifdef AF_WANPIPE
1487c2fbfb3SApril Chin 	"WANPIPE",	AF_WANPIPE,
1497c2fbfb3SApril Chin #endif
1507c2fbfb3SApril Chin #ifdef AF_BLUETOOTH
1517c2fbfb3SApril Chin 	"BLUETOOTH",	AF_BLUETOOTH,
1527c2fbfb3SApril Chin #endif
1537c2fbfb3SApril Chin 	0
1547c2fbfb3SApril Chin };
1557c2fbfb3SApril Chin 
1567c2fbfb3SApril Chin #endif
1577c2fbfb3SApril Chin 
158da2e3ebdSchin int
b_fds(int argc,char ** argv,Shbltin_t * context)159*b30d1939SAndy Fiddaman b_fds(int argc, char** argv, Shbltin_t* context)
160da2e3ebdSchin {
161da2e3ebdSchin 	register char*		s;
162da2e3ebdSchin 	register int		i;
163da2e3ebdSchin 	register char*		m;
164da2e3ebdSchin 	register char*		x;
165da2e3ebdSchin 	int			flags;
166da2e3ebdSchin 	int			details;
1677c2fbfb3SApril Chin 	int			open_max;
16834f9b3eeSRoland Mainz 	int			unit;
16934f9b3eeSRoland Mainz 	Sfio_t*			sp;
170da2e3ebdSchin 	struct stat		st;
171da2e3ebdSchin #ifdef S_IFSOCK
172da2e3ebdSchin 	struct sockaddr_in	addr;
1737c2fbfb3SApril Chin 	char*			a;
1747c2fbfb3SApril Chin 	unsigned char*		b;
1757c2fbfb3SApril Chin 	unsigned char*		e;
1767c2fbfb3SApril Chin 	socklen_t		addrlen;
177da2e3ebdSchin 	socklen_t		len;
178da2e3ebdSchin 	int			type;
1797c2fbfb3SApril Chin 	int			port;
180da2e3ebdSchin 	int			prot;
1817c2fbfb3SApril Chin 	char			num[64];
1827c2fbfb3SApril Chin 	char			fam[64];
18334f9b3eeSRoland Mainz #ifdef INET6_ADDRSTRLEN
18434f9b3eeSRoland Mainz 	char			nam[256];
18534f9b3eeSRoland Mainz #endif
186da2e3ebdSchin #endif
187da2e3ebdSchin 
188da2e3ebdSchin 	cmdinit(argc, argv, context, ERROR_CATALOG, 0);
189da2e3ebdSchin 	details = 0;
19034f9b3eeSRoland Mainz 	unit = 1;
191da2e3ebdSchin 	for (;;)
192da2e3ebdSchin 	{
193da2e3ebdSchin 		switch (optget(argv, usage))
194da2e3ebdSchin 		{
195da2e3ebdSchin 		case 'l':
196da2e3ebdSchin 			details = opt_info.num;
197da2e3ebdSchin 			continue;
19834f9b3eeSRoland Mainz 		case 'u':
19934f9b3eeSRoland Mainz 			unit = opt_info.num;
20034f9b3eeSRoland Mainz 			continue;
201da2e3ebdSchin 		case '?':
202da2e3ebdSchin 			error(ERROR_USAGE|4, "%s", opt_info.arg);
203*b30d1939SAndy Fiddaman 			break;
204da2e3ebdSchin 		case ':':
205da2e3ebdSchin 			error(2, "%s", opt_info.arg);
206*b30d1939SAndy Fiddaman 			break;
207da2e3ebdSchin 		}
208da2e3ebdSchin 		break;
209da2e3ebdSchin 	}
210da2e3ebdSchin 	argv += opt_info.index;
211da2e3ebdSchin 	if (error_info.errors || *argv)
212da2e3ebdSchin 		error(ERROR_USAGE|4, "%s", optusage(NiL));
2137c2fbfb3SApril Chin 	if ((open_max = getconf("OPEN_MAX")) <= 0)
2147c2fbfb3SApril Chin 		open_max = OPEN_MAX;
21534f9b3eeSRoland Mainz 	if (unit == 1)
21634f9b3eeSRoland Mainz 		sp = sfstdout;
21734f9b3eeSRoland Mainz 	else if (fstat(unit, &st) || !(sp = sfnew(NiL, NiL, SF_UNBOUND, unit, SF_WRITE)))
21834f9b3eeSRoland Mainz 		error(ERROR_SYSTEM|3, "%d: cannot write to file descriptor");
2197c2fbfb3SApril Chin 	for (i = 0; i <= open_max; i++)
2207c2fbfb3SApril Chin 	{
221da2e3ebdSchin 		if (fstat(i, &st))
222da2e3ebdSchin 		{
2237c2fbfb3SApril Chin 			/* not open */
2247c2fbfb3SApril Chin 			continue;
2257c2fbfb3SApril Chin 		}
2267c2fbfb3SApril Chin 		if (!details)
2277c2fbfb3SApril Chin 		{
22834f9b3eeSRoland Mainz 			sfprintf(sp, "%d\n", i);
2297c2fbfb3SApril Chin 			continue;
2307c2fbfb3SApril Chin 		}
2317c2fbfb3SApril Chin 		if ((flags = fcntl(i, F_GETFL, (char*)0)) == -1)
2327c2fbfb3SApril Chin 			m = "--";
2337c2fbfb3SApril Chin 		else
2347c2fbfb3SApril Chin 			switch (flags & (O_RDONLY|O_WRONLY|O_RDWR))
2357c2fbfb3SApril Chin 			{
2367c2fbfb3SApril Chin 			case O_RDONLY:
2377c2fbfb3SApril Chin 				m = "r-";
2387c2fbfb3SApril Chin 				break;
2397c2fbfb3SApril Chin 			case O_WRONLY:
2407c2fbfb3SApril Chin 				m = "-w";
2417c2fbfb3SApril Chin 				break;
2427c2fbfb3SApril Chin 			case O_RDWR:
2437c2fbfb3SApril Chin 				m = "rw";
2447c2fbfb3SApril Chin 				break;
2457c2fbfb3SApril Chin 			default:
2467c2fbfb3SApril Chin 				m = "??";
2477c2fbfb3SApril Chin 				break;
2487c2fbfb3SApril Chin 			}
2497c2fbfb3SApril Chin 		x = (fcntl(i, F_GETFD, (char*)0) > 0) ? "x" : "-";
2507c2fbfb3SApril Chin 		if (isatty(i) && (s = ttyname(i)))
2517c2fbfb3SApril Chin 		{
25234f9b3eeSRoland Mainz 			sfprintf(sp, "%02d %s%s %s %s\n", i, m, x, fmtmode(st.st_mode, 0), s);
2537c2fbfb3SApril Chin 			continue;
2547c2fbfb3SApril Chin 		}
255da2e3ebdSchin #ifdef S_IFSOCK
2567c2fbfb3SApril Chin 		addrlen = sizeof(addr);
2577c2fbfb3SApril Chin 		memset(&addr, 0, addrlen);
2587c2fbfb3SApril Chin 		if (!getsockname(i, (struct sockaddr*)&addr, (void*)&addrlen))
2597c2fbfb3SApril Chin 		{
2607c2fbfb3SApril Chin 			type = 0;
2617c2fbfb3SApril Chin 			prot = 0;
262da2e3ebdSchin #ifdef SO_TYPE
2637c2fbfb3SApril Chin 			len = sizeof(type);
2647c2fbfb3SApril Chin 			if (getsockopt(i, SOL_SOCKET, SO_TYPE, (void*)&type, (void*)&len))
2657c2fbfb3SApril Chin 				type = -1;
266da2e3ebdSchin #endif
267da2e3ebdSchin #ifdef SO_PROTOTYPE
2687c2fbfb3SApril Chin 			len = sizeof(prot);
2697c2fbfb3SApril Chin 			if (getsockopt(i, SOL_SOCKET, SO_PROTOTYPE, (void*)&prot, (void*)&len))
2707c2fbfb3SApril Chin 				prot = -1;
271da2e3ebdSchin #endif
2727c2fbfb3SApril Chin 			if (!st.st_mode)
2737c2fbfb3SApril Chin 				st.st_mode = S_IFSOCK|S_IRUSR|S_IWUSR;
2747c2fbfb3SApril Chin 			s = 0;
2757c2fbfb3SApril Chin 			switch (type)
276da2e3ebdSchin 			{
2777c2fbfb3SApril Chin 			case SOCK_DGRAM:
2787c2fbfb3SApril Chin 				switch (addr.sin_family)
279da2e3ebdSchin 				{
2807c2fbfb3SApril Chin 				case AF_INET:
2817c2fbfb3SApril Chin #ifdef AF_INET6
2827c2fbfb3SApril Chin 				case AF_INET6:
2837c2fbfb3SApril Chin #endif
284da2e3ebdSchin 					s = "udp";
285da2e3ebdSchin 					break;
2867c2fbfb3SApril Chin 				}
2877c2fbfb3SApril Chin 				break;
2887c2fbfb3SApril Chin 			case SOCK_STREAM:
2897c2fbfb3SApril Chin 				switch (addr.sin_family)
2907c2fbfb3SApril Chin 				{
2917c2fbfb3SApril Chin 				case AF_INET:
2927c2fbfb3SApril Chin #ifdef AF_INET6
2937c2fbfb3SApril Chin 				case AF_INET6:
2947c2fbfb3SApril Chin #endif
295da2e3ebdSchin #ifdef IPPROTO_SCTP
2967c2fbfb3SApril Chin 					if (prot == IPPROTO_SCTP)
297da2e3ebdSchin 						s = "sctp";
2987c2fbfb3SApril Chin 					else
299da2e3ebdSchin #endif
3007c2fbfb3SApril Chin 						s = "tcp";
301da2e3ebdSchin 					break;
302da2e3ebdSchin 				}
3037c2fbfb3SApril Chin 				break;
3047c2fbfb3SApril Chin #ifdef SOCK_RAW
3057c2fbfb3SApril Chin 			case SOCK_RAW:
3067c2fbfb3SApril Chin 				s = "raw";
3077c2fbfb3SApril Chin 				break;
3087c2fbfb3SApril Chin #endif
3097c2fbfb3SApril Chin #ifdef SOCK_RDM
3107c2fbfb3SApril Chin 			case SOCK_RDM:
3117c2fbfb3SApril Chin 				s = "rdm";
3127c2fbfb3SApril Chin 				break;
3137c2fbfb3SApril Chin #endif
3147c2fbfb3SApril Chin #ifdef SOCK_SEQPACKET
3157c2fbfb3SApril Chin 			case SOCK_SEQPACKET:
3167c2fbfb3SApril Chin 				s = "seqpacket";
3177c2fbfb3SApril Chin 				break;
3187c2fbfb3SApril Chin #endif
319da2e3ebdSchin 			}
3207c2fbfb3SApril Chin 			if (!s)
3217c2fbfb3SApril Chin 			{
3227c2fbfb3SApril Chin 				for (type = 0; family[type].name && family[type].value != addr.sin_family; type++);
3237c2fbfb3SApril Chin 				if (!(s = (char*)family[type].name))
3247c2fbfb3SApril Chin 					sfsprintf(s = num, sizeof(num), "family.%d", addr.sin_family);
3257c2fbfb3SApril Chin 			}
3267c2fbfb3SApril Chin 			port = 0;
3277c2fbfb3SApril Chin #ifdef INET6_ADDRSTRLEN
3287c2fbfb3SApril Chin 			if (a = (char*)inet_ntop(addr.sin_family, &addr.sin_addr, nam, sizeof(nam)))
3297c2fbfb3SApril Chin 				port = ntohs(addr.sin_port);
3307c2fbfb3SApril Chin 			else
331da2e3ebdSchin #endif
3327c2fbfb3SApril Chin 			if (addr.sin_family == AF_INET)
3337c2fbfb3SApril Chin 			{
3347c2fbfb3SApril Chin 				a = inet_ntoa(addr.sin_addr);
3357c2fbfb3SApril Chin 				port = ntohs(addr.sin_port);
3367c2fbfb3SApril Chin 			}
3377c2fbfb3SApril Chin 			else
3387c2fbfb3SApril Chin 			{
3397c2fbfb3SApril Chin 				a = fam;
3407c2fbfb3SApril Chin 				e = (b = (unsigned char*)&addr) + addrlen;
3417c2fbfb3SApril Chin 				while (b < e && a < &fam[sizeof(fam)-1])
3427c2fbfb3SApril Chin 					a += sfsprintf(a, &fam[sizeof(fam)] - a - 1, ".%d", *b++);
3437c2fbfb3SApril Chin 				a = a == fam ? "0" : fam + 1;
3447c2fbfb3SApril Chin 			}
3457c2fbfb3SApril Chin 			if (port)
34634f9b3eeSRoland Mainz 				sfprintf(sp, "%02d %s%s %s /dev/%s/%s/%d\n", i, m, x, fmtmode(st.st_mode, 0), s, a, port);
347da2e3ebdSchin 			else
34834f9b3eeSRoland Mainz 				sfprintf(sp, "%02d %s%s %s /dev/%s/%s\n", i, m, x, fmtmode(st.st_mode, 0), s, a);
3497c2fbfb3SApril Chin 			continue;
350da2e3ebdSchin 		}
3517c2fbfb3SApril Chin #endif
35234f9b3eeSRoland Mainz 		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);
35334f9b3eeSRoland Mainz 	}
35434f9b3eeSRoland Mainz 	if (sp != sfstdout)
35534f9b3eeSRoland Mainz 	{
35634f9b3eeSRoland Mainz 		sfsetfd(sp, -1);
35734f9b3eeSRoland Mainz 		sfclose(sp);
3587c2fbfb3SApril Chin 	}
359da2e3ebdSchin 	return 0;
360da2e3ebdSchin }
361