/* source: filan.c */ /* Copyright Gerhard Rieger and contributors (see file CHANGES) */ /* Published under the GNU General Public License V.2, see file COPYING */ /* the subroutine filan makes a "FILe descriptor ANalysis". It checks the type of file descriptor and tries to retrieve as much info about it as possible without modifying its state. NOTE: it works on UNIX (kernel) file descriptors, not on libc files! */ #include "config.h" #include "xioconfig.h" /* what features are enabled */ #include "sysincludes.h" #include "mytypes.h" #include "compat.h" #include "error.h" #include "sycls.h" #include "sysutils.h" #include "filan.h" struct sockopt { int so; char *name; }; static int filan_streams_analyze(int fd, FILE *outfile); /* global variables for configuring filan */ bool filan_followsymlinks; bool filan_rawoutput; int sockoptan(int fd, const struct sockopt *optname, int socklay, FILE *outfile); int tcpan(int fd, FILE *outfile); const char *getfiletypestring(int st_mode); static int printtime(FILE *outfile, time_t time); static int headprinted; /* analyse a file system entry, referred by file name */ int filan_file(const char *filename, FILE *outfile) { int fd = -1; int result; #if HAVE_STAT64 struct stat64 buf = {0}; #else struct stat buf = {0}; #endif /* !HAVE_STAT64 */ if (filan_followsymlinks) { #if HAVE_STAT64 result = Stat64(filename, &buf); #else result = Stat(filename, &buf); #endif /* !HAVE_STAT64 */ if (result < 0) { Warn3("stat(\"%s\", %p): %s", filename, &buf, strerror(errno)); } } else { #if HAVE_STAT64 result = Lstat64(filename, &buf); #else result = Lstat(filename, &buf); #endif /* !HAVE_STAT64 */ if (result < 0) { Warn3("lstat(\"%s\", %p): %s", filename, &buf, strerror(errno)); } } switch (buf.st_mode&S_IFMT) { #ifdef S_IFSOCK case S_IFSOCK: /* probably, it's useless to make a socket and describe it */ break; #endif /* S_IFSOCK */ default: if ((fd = Open(filename, O_RDONLY|O_NOCTTY|O_NONBLOCK #ifdef O_LARGEFILE |O_LARGEFILE #endif , 0700)) < 0) { Warn2("open(\"%s\", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0700): %s", filename, strerror(errno)); } } result = filan_stat(&buf, fd, -1, outfile); fputc('\n', outfile); return result; } /* analyze a file descriptor */ int filan_fd(int fd, FILE *outfile) { #if HAVE_STAT64 struct stat64 buf = {0}; #else struct stat buf = {0}; #endif /* !HAVE_STAT64 */ int result; Debug1("checking file descriptor %u", fd); #if HAVE_STAT64 result = Fstat64(fd, &buf); #else result = Fstat(fd, &buf); #endif /* !HAVE_STAT64 */ if (result < 0) { if (errno == EBADF) { Debug2("fstat(%d): %s", fd, strerror(errno)); } else { Warn2("fstat(%d): %s", fd, strerror(errno)); } return -1; } Debug2("fd %d is a %s", fd, getfiletypestring(buf.st_mode)); result = filan_stat(&buf, fd, fd, outfile); if (result >= 0) { /* even more dynamic info */ { /* see if data is available */ struct pollfd ufds; ufds.fd = fd; ufds.events = POLLIN|POLLPRI|POLLOUT #ifdef POLLRDNORM |POLLRDNORM #endif #ifdef POLLRDBAND |POLLRDBAND #endif |POLLWRNORM #ifdef POLLWRBAND |POLLWRBAND #endif #ifdef POLLMSG |POLLMSG #endif ; #if HAVE_POLL if (Poll(&ufds, 1, 0) < 0) { Warn4("poll({%d, %hd, %hd}, 1, 0): %s", ufds.fd, ufds.events, ufds.revents, strerror(errno)); } else { fputs("poll: ", outfile); if (ufds.revents & POLLIN) fputs("IN,", outfile); if (ufds.revents & POLLPRI) fputs("PRI,", outfile); if (ufds.revents & POLLOUT) fputs("OUT,", outfile); if (ufds.revents & POLLERR) fputs("ERR,", outfile); if (ufds.revents & POLLNVAL) fputs("NVAL,", outfile); #ifdef FIONREAD if (ufds.revents & POLLIN) { size_t sizet; if ((result = Ioctl(fd, FIONREAD, &sizet) >= 0)) { fprintf (outfile, "; FIONREAD="F_Zu, sizet); } } #endif /* defined(FIONREAD) */ #if _WITH_SOCKET && defined(MSG_DONTWAIT) if ((ufds.revents & POLLIN) && isasocket(fd)) { char _peername[SOCKADDR_MAX]; struct sockaddr *pa = (struct sockaddr *)_peername; struct msghdr msgh = {0}; char peekbuff[1]; /* [0] fails with some compilers */ #if HAVE_STRUCT_IOVEC struct iovec iovec; #endif char ctrlbuff[5120]; ssize_t bytes; fputs("; ", outfile); msgh.msg_name = pa; msgh.msg_namelen = sizeof(*pa); #if HAVE_STRUCT_IOVEC iovec.iov_base = peekbuff; iovec.iov_len = sizeof(peekbuff); msgh.msg_iov = &iovec; msgh.msg_iovlen = 1; #endif #if HAVE_STRUCT_MSGHDR_MSGCONTROL msgh.msg_control = ctrlbuff; #endif #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN msgh.msg_controllen = sizeof(ctrlbuff); #endif #if HAVE_STRUCT_MSGHDR_MSGFLAGS msgh.msg_flags = 0; #endif if ((bytes = Recvmsg(fd, &msgh, MSG_PEEK|MSG_DONTWAIT)) < 0) { Warn1("recvmsg(): %s", strerror(errno)); } else { fprintf(outfile, "recvmsg="F_Zd", ", bytes); } } #endif /* _WITH_SOCKET && defined(MSG_DONTWAIT) */ } #endif /* HAVE_POLL */ } } fputc('\n', outfile); return 0; } int filan_stat( #if HAVE_STAT64 struct stat64 *buf #else struct stat *buf #endif /* !HAVE_STAT64 */ , int statfd, int dynfd, FILE *outfile) { char stdevstr[8]; /* print header */ if (!headprinted) { if (filan_rawoutput) { fputs(" FD type\tdevice\tinode\tmode\tlinks\tuid\tgid" #if HAVE_ST_RDEV "\trdev" #endif "\tsize" #if HAVE_ST_BLKSIZE "\tblksize" #endif #if HAVE_ST_BLOCKS "\tblocks" #endif "\tatime\t\tmtime\t\tctime\t\tcloexec\tflags" #if defined(F_GETOWN) "\tsigown" #endif , outfile); } else /* !rawoutput */ { fputs(" FD type\tdevice\tinode\tmode\tlinks\tuid\tgid" #if HAVE_ST_RDEV "\trdev" #endif "\tsize" #if HAVE_ST_BLKSIZE "\tblksize" #endif #if HAVE_ST_BLOCKS "\tblocks" #endif "\tatime\t\t\t\tmtime\t\t\t\tctime\t\t\t\tcloexec\tflags" #if defined(F_GETOWN) "\tsigown" #endif , outfile); } /* endif !rawoutput */ #if defined(F_GETSIG) fputs("\tsigio", outfile); #endif /* defined(F_GETSIG) */ fputc('\n', outfile); headprinted = 1; } if (filan_rawoutput) { snprintf(stdevstr, 8, F_dev, buf->st_dev); } else { snprintf(stdevstr, 8, "%hu,%hu", (unsigned short)(buf->st_dev>>8), (unsigned short)(buf->st_dev&0xff)); } fprintf(outfile, "%4d: %s\t%s\t" #if HAVE_STAT64 F_st64_ino #else F_st_ino #endif /* HAVE_STAT64 */ "\t"F_mode"\t"F_st_nlink"\t"F_uid"\t"F_gid #if HAVE_ST_RDEV "\t%hu,%hu" #endif "\t" #if HAVE_STAT64 F_st64_size #else F_st_size #endif /* HAVE_STAT64 */ #if HAVE_ST_BLKSIZE "\t"F_st_blksize #endif #if HAVE_ST_BLOCKS #if HAVE_STAT64 "\t"F_st64_blocks #else "\t"F_st_blocks #endif /* HAVE_STAT64 */ #endif , (dynfd>=0?dynfd:statfd), getfiletypestring(buf->st_mode), stdevstr, buf->st_ino, buf->st_mode, buf->st_nlink, buf->st_uid, buf->st_gid, #if HAVE_ST_RDEV (unsigned short)(buf->st_rdev>>8), (unsigned short)(buf->st_rdev&0xff), #endif buf->st_size #if HAVE_ST_BLKSIZE , buf->st_blksize #endif #if HAVE_ST_BLOCKS , buf->st_blocks /* on Linux, this applies to stat and stat64 */ #endif ); printtime(outfile, buf->st_atime); printtime(outfile, buf->st_mtime); printtime(outfile, buf->st_ctime); #if 0 { fputc('\t', outfile); time = asctime(localtime(&buf->st_mtime)); if (strchr(time, '\n')) *strchr(time, '\n') = '\0'; fputs(time, outfile); fputc('\t', outfile); time = asctime(localtime(&buf->st_ctime)); if (strchr(time, '\n')) *strchr(time, '\n') = '\0'; fputs(time, outfile); } #endif /* here comes dynamic info - it is only meaningful with preexisting FDs */ if (dynfd >= 0) { /*!indent */ int cloexec, flags; #if defined(F_GETOWN) int sigown; #endif #if defined(F_GETSIG) int sigio; #endif /* defined(F_GETSIG) */ cloexec = Fcntl(dynfd, F_GETFD); flags = Fcntl(dynfd, F_GETFL); #if defined(F_GETOWN) sigown = Fcntl(dynfd, F_GETOWN); #endif #if defined(F_GETSIG) sigio = Fcntl(dynfd, F_GETSIG); #endif /* defined(F_GETSIG) */ fprintf(outfile, "\t%d\tx%06x", cloexec, flags); #if defined(F_GETOWN) fprintf(outfile, "\t%d", sigown); #endif #if defined(F_GETSIG) fprintf(outfile, "\t%d", sigio); #endif /* defined(F_GETSIG) */ } else { fputs("\t\t" #if defined(F_GETOWN) "\t" #endif #if defined(F_GETSIG) "\t" #endif /* defined(F_GETSIG) */ , outfile); } /* ever heard of POSIX streams? here we handle these */ filan_streams_analyze(statfd, outfile); /* now see for type specific infos */ if (statfd >= 0) { /*!indent */ switch (buf->st_mode&S_IFMT) { case (S_IFIFO): /* 1, FIFO */ break; case (S_IFCHR): /* 2, character device */ cdevan(statfd, outfile); break; case (S_IFDIR): /* 4, directory */ break; case (S_IFBLK): /* 6, block device */ break; case (S_IFREG): /* 8, regular file */ break; case (S_IFLNK): /* 10, symbolic link */ break; #ifdef S_IFSOCK case (S_IFSOCK): /* 12, socket */ #if _WITH_SOCKET sockan(statfd, outfile); #else Warn("SOCKET support not compiled in"); return -1; #endif /* !_WITH_SOCKET */ break; #endif /* S_IFSOCK */ } } /* ioctl() */ return 0; } #if LATER int fdinfo(int fd) { int result; result = Fcntl(fd, F_GETFD); fcntl(fd, F_GETFL, ); fcntl(fd, F_GETLK, ); #ifdef F_GETOWN fcntl(fd, F_GETOWN, ); #endif #ifdef F_GETSIG fcntl(fd, F_GETSIG, ); #endif } int devinfo(int fd) { ioctl(); } #endif /* returns 0 on success (not a stream descriptor, or no module) returns <0 on failure */ static int filan_streams_analyze(int fd, FILE *outfile) { #ifdef I_LIST # define SL_NMODS 8 /* max number of module names we can store */ struct str_list modnames; int i; if (!isastream(fd)) { fprintf(outfile, "\t(no STREAMS modules)"); return 0; } #if 0 /* uncomment for debugging */ fprintf(outfile, "\tfind=%d", ioctl(fd, I_FIND, "ldterm")); #endif modnames.sl_nmods = ioctl(fd, I_LIST, 0); if (modnames.sl_nmods < 0) { fprintf(stderr, "ioctl(%d, I_LIST, 0): %s\n", fd, strerror(errno)); return -1; } modnames.sl_modlist = Malloc(modnames.sl_nmods*(sizeof(struct str_mlist))); if (modnames.sl_modlist == NULL) { fprintf(stderr, "out of memory\n"); return -1; } if (ioctl(fd, I_LIST, &modnames) < 0) { fprintf(stderr, "ioctl(%d, I_LIST, %p): %s\n", fd, &modnames, strerror(errno)); free(modnames.sl_modlist); return -1; } fprintf(outfile, "\tSTREAMS: "); for (i = 0; i < modnames.sl_nmods; ++i) { fprintf(outfile, "\"%s\"", modnames.sl_modlist[i].l_name); if (i+1 < modnames.sl_nmods) fputc(',', outfile); } free(modnames.sl_modlist); #endif /* defined(I_LIST) */ return 0; } /* character device analysis */ int cdevan(int fd, FILE *outfile) { int ret; #if _WITH_TERMIOS if ((ret = Isatty(fd)) < 0) { Warn2("isatty(%d): %s", fd, strerror(errno)); return -1; } if (ret > 0) { struct termios termarg; char *name; int i; if ((name = Ttyname(fd)) == NULL) { /*Warn2("ttyname(%d): %s", fd, strerror(errno));*/ fputs("\tNULL", outfile); } else { fprintf(outfile, "\t%s", name); } if (Tcgetattr(fd, &termarg) < 0) { Warn3("tcgetattr(%d, %p): %s", fd, &termarg, strerror(errno)); return -1; } fprintf(outfile, " \tIFLAGS=%08x OFLAGS=%08x CFLAGS=%08x LFLAGS=%08x", (unsigned int)termarg.c_iflag, (unsigned int)termarg.c_oflag, (unsigned int)termarg.c_cflag, (unsigned int)termarg.c_lflag); /* and the control characters */ if (filan_rawoutput) { for (i=0; i>4)>=10?(ch>>4)-10+'A':(ch>>4)+'0'; s[2] = (ch&0x0f)>=10?(ch&0x0f)-10+'A':(ch&0x0f)+'0'; s[3] = '\0'; } fprintf(outfile, " cc[%d]=%s", i, s); } } } #endif /* _WITH_TERMIOS */ return 0; } #if _WITH_SOCKET int sockan(int fd, FILE *outfile) { #define FILAN_OPTLEN 256 #define FILAN_NAMELEN 256 socklen_t optlen; int result /*0, i*/; char nambuff[FILAN_NAMELEN]; /* in Linux these optcodes are 'enum', but on AIX they are bits! */ static const struct sockopt sockopts[] = { {SO_DEBUG, "DEBUG"}, {SO_REUSEADDR, "REUSEADDR"}, #ifdef SO_PROTOCOL {SO_PROTOCOL, "PROTOCOL"}, #elif defined(SO_PROTOTYPE) {SO_PROTOTYPE, "PROTOTYPE"}, #endif {SO_TYPE, "TYPE"}, {SO_ERROR, "ERROR"}, {SO_DONTROUTE, "DONTROUTE"}, {SO_BROADCAST, "BROADCAST"}, {SO_SNDBUF, "SNDBUF"}, {SO_RCVBUF, "RCVBUF"}, {SO_KEEPALIVE, "KEEPALIVE"}, {SO_OOBINLINE, "OOBINLINE"}, #ifdef SO_NO_CHECK {SO_NO_CHECK, "NO_CHECK"}, #endif #ifdef SO_PRIORITY {SO_PRIORITY, "PRIORITY"}, #endif {SO_LINGER, "LINGER"}, #ifdef SO_BSDCOMPAT {SO_BSDCOMPAT, "BSDCOMPAT"}, #endif #ifdef SO_REUSEPORT {SO_REUSEPORT, "REUSEPORT"}, #endif /* defined(SO_REUSEPORT) */ #ifdef SO_PASSCRED {SO_PASSCRED, "PASSCRED"}, #endif #ifdef SO_PEERCRED {SO_PEERCRED, "PEERCRED"}, #endif #ifdef SO_RCVLOWAT {SO_RCVLOWAT, "RCVLOWAT"}, #endif #ifdef SO_SNDLOWAT {SO_SNDLOWAT, "SNDLOWAT"}, #endif #ifdef SO_RCVTIMEO {SO_RCVTIMEO, "RCVTIMEO"}, #endif #ifdef SO_SNDTIMEO {SO_SNDTIMEO, "SNDTIMEO"}, #endif #ifdef SO_SECURITY_AUTHENTICATION {SO_SECURITY_AUTHENTICATION, "SECURITY_AUTHENTICATION"}, #endif #ifdef SO_SECURITY_ENCRYPTION_TRANSPORT {SO_SECURITY_ENCRYPTION_TRANSPORT, "SECURITY_ENCRYPTION_TRANSPORT"}, #endif #ifdef SO_SECURITY_ENCRYPTION_NETWORK {SO_SECURITY_ENCRYPTION_NETWORK, "SECURITY_ENCRYPTION_NETWORK"}, #endif #ifdef SO_BINDTODEVICE {SO_BINDTODEVICE, "BINDTODEVICE"}, #endif #ifdef SO_ATTACH_FILTER {SO_ATTACH_FILTER, "ATTACH_FILTER"}, #endif #ifdef SO_DETACH_FILTER {SO_DETACH_FILTER, "DETACH_FILTER"}, #endif {0, NULL} } ; union { char c[FILAN_OPTLEN]; int i[FILAN_OPTLEN/sizeof(int)]; } optval; const struct sockopt *optname; union sockaddr_union sockname, peername; /* the longest I know of */ socklen_t namelen; #if 0 && defined(SIOCGIFNAME) /*Linux struct ifreq ifc = {{{ 0 }}};*/ struct ifreq ifc = {{ 0 }}; #endif optlen = FILAN_OPTLEN; result = Getsockopt(fd, SOL_SOCKET, SO_TYPE, optval.c, &optlen); if (result < 0) { Debug4("getsockopt(%d, SOL_SOCKET, SO_TYPE, %p, {"F_socklen"}): %s", fd, optval.c, optlen, strerror(errno)); } else { # define TYPENAMEMAX 16 char typename[TYPENAMEMAX]; sockettype(*optval.i, typename, sizeof(typename)); Debug3("fd %d: socket of type %d (\"%s\")", fd, *optval.i, typename); } optname = sockopts; while (optname->so) { optlen = FILAN_OPTLEN; result = Getsockopt(fd, SOL_SOCKET, optname->so, (void *)optval.c, &optlen); if (result < 0) { Debug5("getsockopt(%d, SOL_SOCKET, %d, %p, {"F_socklen"}): %s", fd, optname->so, optval.c, optlen, strerror(errno)); fputc('\t', outfile); } else if (optlen == sizeof(int)) { Debug2("getsockopt(,,, {%d}, %d)", *optval.i, optlen); /*Info2("%s: %d", optname->name, optval.i);*/ fprintf(outfile, "%s=%d\t", optname->name, *optval.i); } else { Debug3("getsockopt(,,, {%d,%d}, %d)", optval.i[0], optval.i[1], optlen); fprintf(outfile, "%s={%d,%d}\t", optname->name, optval.i[0], optval.i[1]); } ++optname; } namelen = sizeof(sockname); result = Getsockname(fd, (struct sockaddr *)&sockname, &namelen); if (result < 0) { putc('\n', outfile); Warn2("getsockname(%d): %s", fd, strerror(errno)); return -1; } fputc('\t', outfile); fputs(sockaddr_info((struct sockaddr *)&sockname, namelen, nambuff, sizeof(nambuff)), outfile); namelen = sizeof(peername); result = Getpeername(fd, (struct sockaddr *)&peername, &namelen); if (result < 0) { putc('\n', outfile); Warn2("getpeername(%d): %s", fd, strerror(errno)); } else { /* only valid if getpeername() succeeded */ fputs(" <-> ", outfile); fprintf(outfile, "%s\t", sockaddr_info((struct sockaddr *)&peername, namelen, nambuff, sizeof(nambuff))); } #if 0 && defined(SIOCGIFNAME) if ((result = Ioctl(fd, SIOCGIFNAME, &ifc)) < 0) { Warn3("ioctl(%d, SIOCGIFNAME, %p): %s", fd, &ifc, strerror(errno)); } else { fprintf(outfile, "IFNAME=\"%s\"\t", ifc.ifr_name); } #endif /* SIOCGIFNAME */ switch (((struct sockaddr *)&sockname)->sa_family) { #if WITH_UNIX case AF_UNIX: /* no options for unix domain sockets known yet -> no unixan() */ result = 0; break; #endif #if WITH_IP4 case AF_INET: result = ipan(fd, outfile); break; #endif #if WITH_IP6 case AF_INET6: result = ipan(fd, outfile); result |= ip6an(fd, outfile); break; #endif default: fputs("**** NO FURTHER ANALYSIS FOR THIS SOCKET TYPE IMPLEMENTED", outfile); result = 0; } return result; #undef FILAN_OPTLEN #undef FILAN_NAMELEN } #endif /* _WITH_SOCKET */ #if WITH_IP4 || WITH_IP6 /* prints the option values for the IP protocol and the IP based protocols */ /* no distinction between IP4 and IP6 yet */ int ipan(int fd, FILE *outfile) { /* in Linux these optcodes are 'enum', but on AIX they are bits! */ static const struct sockopt ipopts[] = { {IP_TOS, "IP_TOS"}, {IP_TTL, "IP_TTL"}, #ifdef IP_HDRINCL {IP_HDRINCL, "IP_HDRINCL"}, #endif #ifdef IP_OPTIONS {IP_OPTIONS, "IP_OPTIONS"}, #endif #ifdef IP_ROUTER_ALERT {IP_ROUTER_ALERT, "IP_ROUTER_ALERT"}, #endif #ifdef IP_RECVOPTS {IP_RECVOPTS, "IP_RECVOPTS"}, #endif #ifdef IP_RETOPTS {IP_RETOPTS, "IP_RETOPTS"}, #endif #ifdef IP_PKTINFO {IP_PKTINFO, "IP_PKTINFO"}, #endif #ifdef IP_PKTOPTIONS {IP_PKTOPTIONS, "IP_PKTOPTIONS"}, #endif #ifdef IP_MTU_DISCOVER {IP_MTU_DISCOVER, "IP_MTU_DISCOVER"}, #endif #ifdef IP_RECVERR {IP_RECVERR, "IP_RECVERR"}, #endif #ifdef IP_RECVTTL {IP_RECVTTL, "IP_RECVTTL"}, #endif #ifdef IP_RECVTOS {IP_RECVTOS, "IP_RECVTOS"}, #endif #ifdef IP_MTU {IP_MTU, "IP_MTU"}, #endif #ifdef IP_FREEBIND {IP_FREEBIND, "IP_FREEBIND"}, #endif #ifdef IP_MULTICAST_TTL {IP_MULTICAST_TTL, "IP_MULTICAST_TTL"}, #endif #ifdef IP_MULTICAST_LOOP {IP_MULTICAST_LOOP, "IP_MULTICAST_LOOP"}, #endif {0, NULL} } ; const struct sockopt *optname; int optproto; socklen_t optlen = sizeof(optproto); optname = ipopts; while (optname->so) { sockoptan(fd, optname, SOL_IP, outfile); ++optname; } /* want to pass the fd to the next layer protocol. */ #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) if (Getsockopt(fd, SOL_SOCKET, #ifdef SO_PROTOCOL SO_PROTOCOL, #elif defined(SO_PROTOTYPE) SO_PROTOTYPE, #endif &optproto, &optlen) >= 0) { switch (optproto) { #if WITH_TCP case IPPROTO_TCP: tcpan(fd, outfile); break; #endif } } #endif /* defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) */ return 0; } #endif /* WITH_IP */ #if WITH_IP6 /* prints the option values for the IPv6 protocol */ int ip6an(int fd, FILE *outfile) { static const struct sockopt ip6opts[] = { #ifdef IPV6_V6ONLY {IPV6_V6ONLY, "IPV6_V6ONLY"}, #endif {0, NULL} } ; const struct sockopt *optname; optname = ip6opts; while (optname->so) { sockoptan(fd, optname, SOL_IPV6, outfile); ++optname; } return 0; } #endif /* WITH_IP6 */ #if WITH_TCP int tcpan(int fd, FILE *outfile) { static const struct sockopt tcpopts[] = { #ifdef TCP_NODELAY { TCP_NODELAY, "TCP_NODELAY" }, #endif #ifdef TCP_MAXSEG { TCP_MAXSEG, "TCP_MAXSEG" }, #endif #ifdef TCP_STDURG { TCP_STDURG, "TCP_STDURG" }, #endif #ifdef TCP_RFC1323 { TCP_RFC1323, "TCP_RFC1323" }, #endif #ifdef TCP_CORK { TCP_CORK, "TCP_CORK" }, #endif #ifdef TCP_KEEPIDLE { TCP_KEEPIDLE, "TCP_KEEPIDLE" }, #endif #ifdef TCP_KEEPINTVL { TCP_KEEPINTVL, "TCP_KEEPINTVL" }, #endif #ifdef TCP_KEEPCNT { TCP_KEEPCNT, "TCP_KEEPCNT" }, #endif #ifdef TCP_SYNCNT { TCP_SYNCNT, "TCP_SYNCNT" }, #endif #ifdef TCP_LINGER2 { TCP_LINGER2, "TCP_LINGER2" }, #endif #ifdef TCP_DEFER_ACCEPT { TCP_DEFER_ACCEPT, "TCP_ACCEPT" }, #endif #ifdef TCP_WINDOW_CLAMP { TCP_WINDOW_CLAMP, "TCP_WINDOW_CLAMP" }, #endif #ifdef TCP_INFO { TCP_INFO, "TCP_INFO" }, #endif #ifdef TCP_QUICKACK { TCP_QUICKACK, "TCP_QUICKACK" }, #endif #ifdef TCP_MD5SIG { TCP_MD5SIG, "TCP_MD5SIG" }, #endif #ifdef TCP_NOOPT { TCP_NOOPT, "TCP_NOOPT" }, #endif #ifdef TCP_NOPUSH { TCP_NOPUSH, "TCP_NOPUSH" }, #endif #ifdef TCP_SACK_DISABLE { TCP_SACK_DISABLE, "TCP_SACK_DISABLE" }, #endif #ifdef TCP_SIGNATURE_ENABLE { TCP_SIGNATURE_ENABLE, "TCP_SIGNATURE_ENABLE" }, #endif #ifdef TCP_ABORT_THRESHOLD { TCP_ABORT_THRESHOLD, "TCP_ABORT_THRESHOLD" }, #endif #ifdef TCP_CONN_ABORT_THRESHOLD { TCP_CONN_ABORT_THRESHOLD, "TCP_CONN_ABORT_THRESHOLD" }, #endif #ifdef TCP_KEEPINIT { TCP_KEEPINIT, "TCP_KEEPINIT" }, #endif #ifdef TCP_PAWS { TCP_PAWS, "TCP_PAWS" }, #endif #ifdef TCP_SACKENA { TCP_SACKENA, "TCP_SACKENA" }, #endif #ifdef TCP_TSOPTENA { TCP_TSOPTENA, "TCP_TSOPTENA" }, #endif {0, NULL} } ; const struct sockopt *optname; optname = tcpopts; while (optname->so) { sockoptan(fd, optname, SOL_TCP, outfile); ++optname; } return 0; } #endif /* WITH_TCP */ #if _WITH_SOCKET int sockoptan(int fd, const struct sockopt *optname, int socklay, FILE *outfile) { #define FILAN_OPTLEN 256 union { char c[FILAN_OPTLEN]; int i[FILAN_OPTLEN/sizeof(int)]; } optval; socklen_t optlen; int result; optlen = FILAN_OPTLEN; result = Getsockopt(fd, socklay, optname->so, (void *)optval.c, &optlen); if (result < 0) { Debug6("getsockopt(%d, %d, %d, %p, {"F_socklen"}): %s", fd, socklay, optname->so, optval.c, optlen, strerror(errno)); fputc('\t', outfile); return -1; } else if (optlen == 0) { Debug1("getsockopt(,,, {}, %d)", optlen); fprintf(outfile, "%s=\"\"\t", optname->name); } else if (optlen == sizeof(int)) { Debug2("getsockopt(,,, {%d}, %d)", *optval.i, optlen); fprintf(outfile, "%s=%d\t", optname->name, *optval.i); } else { char outbuf[FILAN_OPTLEN*9+128], *cp = outbuf; int i; for (i = 0; i < optlen/sizeof(unsigned int); ++i) { cp += sprintf(cp, "%08x ", (unsigned int)optval.i[i]); } *--cp = '\0'; /* delete trailing space */ Debug2("getsockopt(,,, {%s}, %d)", outbuf, optlen); fflush(outfile); fprintf(outfile, "%s={%s}\t", optname->name, outbuf); } return 0; #undef FILAN_OPTLEN } #endif /* _WITH_SOCKET */ #if _WITH_SOCKET int isasocket(int fd) { int retval; #if HAVE_STAT64 struct stat64 props; #else struct stat props; #endif /* HAVE_STAT64 */ retval = #if HAVE_STAT64 Fstat64(fd, &props); #else Fstat(fd, &props); #endif if (retval < 0) { Info3("fstat(%d, %p): %s", fd, &props, strerror(errno)); return 0; } /* note: when S_ISSOCK was undefined, it always gives 0 */ return S_ISSOCK(props.st_mode); } #endif /* _WITH_SOCKET */ const char *getfiletypestring(int st_mode) { const char *s; switch (st_mode&S_IFMT) { case S_IFIFO: s = "pipe"; break; case S_IFCHR: s = "chrdev"; break; case S_IFDIR: s = "dir"; break; case S_IFBLK: s = "blkdev"; break; case S_IFREG: s = "file"; break; case S_IFLNK: s = "symlink"; break; case S_IFSOCK: s = "socket"; break; /*! AIX: MT? */ default: s = "undef"; break; } return s; } static int printtime(FILE *outfile, time_t time) { const char *s; if (filan_rawoutput) { fprintf(outfile, "\t"F_time, time); } else { fputc('\t', outfile); s = asctime(localtime(&time)); if (strchr(s, '\n')) *strchr(s, '\n') = '\0'; fputs(s, outfile); } return 0; }