1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1992-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A
1N/Astatic const char usage[] =
1N/A"[-?\n@(#)$Id: fds (AT&T Research) 2009-09-09 $\n]"
1N/AUSAGE_LICENSE
1N/A"[+NAME?fds - list open file descriptor status]"
1N/A"[+DESCRIPTION?\bfds\b lists the status for each open file descriptor. "
1N/A "When invoked as a shell builtin it accesses the file descriptors of the "
1N/A "calling shell, otherwise it lists the file descriptors passed across "
1N/A "\bexec\b(2).]"
1N/A"[l:long?List file descriptor details.]"
1N/A"[u:unit?Write output to \afd\a.]#[fd]"
1N/A"[+SEE ALSO?\blogname\b(1), \bwho\b(1), \bgetgroups\b(2), \bgetsockname\b(2), \bgetsockopts\b(2)]"
1N/A;
1N/A
1N/A#include <cmd.h>
1N/A#include <ls.h>
1N/A
1N/A#include "FEATURE/sockets"
1N/A
1N/A#if defined(S_IFSOCK) && _sys_socket && _hdr_arpa_inet && _hdr_netinet_in && _lib_getsockname && _lib_getsockopt && _lib_inet_ntoa
1N/A#include <sys/socket.h>
1N/A#include <netinet/in.h>
1N/A#include <arpa/inet.h>
1N/A#else
1N/A#undef S_IFSOCK
1N/A#endif
1N/A
1N/A#ifndef minor
1N/A#define minor(x) (int)((x)&0xff)
1N/A#endif
1N/A#ifndef major
1N/A#define major(x) (int)(((unsigned int)(x)>>8)&0xff)
1N/A#endif
1N/A
1N/A#undef getconf
1N/A#define getconf(x) strtol(astconf(x,NiL,NiL),NiL,0)
1N/A
1N/A#ifdef S_IFSOCK
1N/A
1N/Atypedef struct NV_s
1N/A{
1N/A const char* name;
1N/A int value;
1N/A} NV_t;
1N/A
1N/Astatic const NV_t family[] =
1N/A{
1N/A#ifdef AF_LOCAL
1N/A "pipe", AF_LOCAL,
1N/A#endif
1N/A#ifdef AF_UNIX
1N/A "pipe", AF_UNIX,
1N/A#endif
1N/A#ifdef AF_FILE
1N/A "FILE", AF_FILE,
1N/A#endif
1N/A#ifdef AF_INET
1N/A "INET", AF_INET,
1N/A#endif
1N/A#ifdef AF_AX25
1N/A "AX25", AF_AX25,
1N/A#endif
1N/A#ifdef AF_IPX
1N/A "IPX", AF_IPX,
1N/A#endif
1N/A#ifdef AF_APPLETALK
1N/A "APPLETALK", AF_APPLETALK,
1N/A#endif
1N/A#ifdef AF_NETROM
1N/A "NETROM", AF_NETROM,
1N/A#endif
1N/A#ifdef AF_BRIDGE
1N/A "BRIDGE", AF_BRIDGE,
1N/A#endif
1N/A#ifdef AF_ATMPVC
1N/A "ATMPVC", AF_ATMPVC,
1N/A#endif
1N/A#ifdef AF_X25
1N/A "X25", AF_X25,
1N/A#endif
1N/A#ifdef AF_INET6
1N/A "INET6", AF_INET6,
1N/A#endif
1N/A#ifdef AF_ROSE
1N/A "ROSE", AF_ROSE,
1N/A#endif
1N/A#ifdef AF_DECnet
1N/A "DECnet", AF_DECnet,
1N/A#endif
1N/A#ifdef AF_NETBEUI
1N/A "NETBEUI", AF_NETBEUI,
1N/A#endif
1N/A#ifdef AF_SECURITY
1N/A "SECURITY", AF_SECURITY,
1N/A#endif
1N/A#ifdef AF_KEY
1N/A "KEY", AF_KEY,
1N/A#endif
1N/A#ifdef AF_NETLINK
1N/A "NETLINK", AF_NETLINK,
1N/A#endif
1N/A#ifdef AF_ROUTE
1N/A "ROUTE", AF_ROUTE,
1N/A#endif
1N/A#ifdef AF_PACKET
1N/A "PACKET", AF_PACKET,
1N/A#endif
1N/A#ifdef AF_ASH
"ASH", AF_ASH,
#endif
#ifdef AF_ECONET
"ECONET", AF_ECONET,
#endif
#ifdef AF_ATMSVC
"ATMSVC", AF_ATMSVC,
#endif
#ifdef AF_SNA
"SNA", AF_SNA,
#endif
#ifdef AF_IRDA
"IRDA", AF_IRDA,
#endif
#ifdef AF_PPPOX
"PPPOX", AF_PPPOX,
#endif
#ifdef AF_WANPIPE
"WANPIPE", AF_WANPIPE,
#endif
#ifdef AF_BLUETOOTH
"BLUETOOTH", AF_BLUETOOTH,
#endif
0
};
#endif
int
b_fds(int argc, char** argv, void* context)
{
register char* s;
register int i;
register char* m;
register char* x;
int flags;
int details;
int open_max;
int unit;
Sfio_t* sp;
struct stat st;
#ifdef S_IFSOCK
struct sockaddr_in addr;
char* a;
unsigned char* b;
unsigned char* e;
socklen_t addrlen;
socklen_t len;
int type;
int port;
int prot;
char num[64];
char fam[64];
#ifdef INET6_ADDRSTRLEN
char nam[256];
#endif
#endif
cmdinit(argc, argv, context, ERROR_CATALOG, 0);
details = 0;
unit = 1;
for (;;)
{
switch (optget(argv, usage))
{
case 'l':
details = opt_info.num;
continue;
case 'u':
unit = opt_info.num;
continue;
case '?':
error(ERROR_USAGE|4, "%s", opt_info.arg);
break;
case ':':
error(2, "%s", opt_info.arg);
break;
}
break;
}
argv += opt_info.index;
if (error_info.errors || *argv)
error(ERROR_USAGE|4, "%s", optusage(NiL));
if ((open_max = getconf("OPEN_MAX")) <= 0)
open_max = OPEN_MAX;
if (unit == 1)
sp = sfstdout;
else if (fstat(unit, &st) || !(sp = sfnew(NiL, NiL, SF_UNBOUND, unit, SF_WRITE)))
error(ERROR_SYSTEM|3, "%d: cannot write to file descriptor");
for (i = 0; i <= open_max; i++)
{
if (fstat(i, &st))
{
/* not open */
continue;
}
if (!details)
{
sfprintf(sp, "%d\n", i);
continue;
}
if ((flags = fcntl(i, F_GETFL, (char*)0)) == -1)
m = "--";
else
switch (flags & (O_RDONLY|O_WRONLY|O_RDWR))
{
case O_RDONLY:
m = "r-";
break;
case O_WRONLY:
m = "-w";
break;
case O_RDWR:
m = "rw";
break;
default:
m = "??";
break;
}
x = (fcntl(i, F_GETFD, (char*)0) > 0) ? "x" : "-";
if (isatty(i) && (s = ttyname(i)))
{
sfprintf(sp, "%02d %s%s %s %s\n", i, m, x, fmtmode(st.st_mode, 0), s);
continue;
}
#ifdef S_IFSOCK
addrlen = sizeof(addr);
memset(&addr, 0, addrlen);
if (!getsockname(i, (struct sockaddr*)&addr, (void*)&addrlen))
{
type = 0;
prot = 0;
#ifdef SO_TYPE
len = sizeof(type);
if (getsockopt(i, SOL_SOCKET, SO_TYPE, (void*)&type, (void*)&len))
type = -1;
#endif
#ifdef SO_PROTOTYPE
len = sizeof(prot);
if (getsockopt(i, SOL_SOCKET, SO_PROTOTYPE, (void*)&prot, (void*)&len))
prot = -1;
#endif
if (!st.st_mode)
st.st_mode = S_IFSOCK|S_IRUSR|S_IWUSR;
s = 0;
switch (type)
{
case SOCK_DGRAM:
switch (addr.sin_family)
{
case AF_INET:
#ifdef AF_INET6
case AF_INET6:
#endif
s = "udp";
break;
}
break;
case SOCK_STREAM:
switch (addr.sin_family)
{
case AF_INET:
#ifdef AF_INET6
case AF_INET6:
#endif
#ifdef IPPROTO_SCTP
if (prot == IPPROTO_SCTP)
s = "sctp";
else
#endif
s = "tcp";
break;
}
break;
#ifdef SOCK_RAW
case SOCK_RAW:
s = "raw";
break;
#endif
#ifdef SOCK_RDM
case SOCK_RDM:
s = "rdm";
break;
#endif
#ifdef SOCK_SEQPACKET
case SOCK_SEQPACKET:
s = "seqpacket";
break;
#endif
}
if (!s)
{
for (type = 0; family[type].name && family[type].value != addr.sin_family; type++);
if (!(s = (char*)family[type].name))
sfsprintf(s = num, sizeof(num), "family.%d", addr.sin_family);
}
port = 0;
#ifdef INET6_ADDRSTRLEN
if (a = (char*)inet_ntop(addr.sin_family, &addr.sin_addr, nam, sizeof(nam)))
port = ntohs(addr.sin_port);
else
#endif
if (addr.sin_family == AF_INET)
{
a = inet_ntoa(addr.sin_addr);
port = ntohs(addr.sin_port);
}
else
{
a = fam;
e = (b = (unsigned char*)&addr) + addrlen;
while (b < e && a < &fam[sizeof(fam)-1])
a += sfsprintf(a, &fam[sizeof(fam)] - a - 1, ".%d", *b++);
a = a == fam ? "0" : fam + 1;
}
if (port)
sfprintf(sp, "%02d %s%s %s /dev/%s/%s/%d\n", i, m, x, fmtmode(st.st_mode, 0), s, a, port);
else
sfprintf(sp, "%02d %s%s %s /dev/%s/%s\n", i, m, x, fmtmode(st.st_mode, 0), s, a);
continue;
}
#endif
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);
}
if (sp != sfstdout)
{
sfsetfd(sp, -1);
sfclose(sp);
}
return 0;
}