2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* the subroutine filan makes a "FILe descriptor ANalysis". It checks the
6 type of file descriptor and tries to retrieve as much info about it as
7 possible without modifying its state.
8 NOTE: it works on UNIX (kernel) file descriptors, not on libc files! */
11 #include "xioconfig.h" /* what features are enabled */
13 #include "sysincludes.h"
29 static int filan_streams_analyze(int fd
, FILE *outfile
);
31 /* global variables for configuring filan */
32 bool filan_followsymlinks
;
36 int sockoptan(int fd
, const struct sockopt
*optname
, int socklay
, FILE *outfile
);
37 int tcpan(int fd
, FILE *outfile
);
38 int tcpan2(int fd
, FILE *outfile
);
39 const char *getfiletypestring(int st_mode
);
41 static int printtime(FILE *outfile
, time_t time
);
43 static int headprinted
;
45 /* analyse a file system entry, referred by file name */
46 int filan_file(const char *filename
, FILE *outfile
) {
50 struct stat64 buf
= {0};
52 struct stat buf
= {0};
53 #endif /* !HAVE_STAT64 */
55 if (filan_followsymlinks
) {
57 result
= Stat64(filename
, &buf
);
59 result
= Stat(filename
, &buf
);
60 #endif /* !HAVE_STAT64 */
62 Warn3("stat(\"%s\", %p): %s", filename
, &buf
, strerror(errno
));
66 result
= Lstat64(filename
, &buf
);
68 result
= Lstat(filename
, &buf
);
69 #endif /* !HAVE_STAT64 */
71 Warn3("lstat(\"%s\", %p): %s", filename
, &buf
, strerror(errno
));
74 switch (buf
.st_mode
&S_IFMT
) {
76 case S_IFSOCK
: /* probably, it's useless to make a socket and describe it */
81 Open(filename
, O_RDONLY
|O_NOCTTY
|O_NONBLOCK
83 |(filan_followsymlinks
?0:O_NOFOLLOW
)
90 Warn2("open(\"%s\", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_LARGEFILE, 0700): %s",
91 filename
, strerror(errno
));
95 result
= filan_stat(&buf
, fd
, -1, outfile
, filename
);
100 /* analyze a file descriptor */
101 int filan_fd(int fd
, FILE *outfile
) {
103 struct stat64 buf
= {0};
105 struct stat buf
= {0};
106 #endif /* !HAVE_STAT64 */
109 Debug1("checking file descriptor %u", fd
);
111 result
= Fstat64(fd
, &buf
);
113 result
= Fstat(fd
, &buf
);
114 #endif /* !HAVE_STAT64 */
116 if (errno
== EBADF
) {
117 Debug2("fstat(%d): %s", fd
, strerror(errno
));
119 Warn2("fstat(%d): %s", fd
, strerror(errno
));
123 Debug2("fd %d is a %s", fd
, getfiletypestring(buf
.st_mode
));
125 result
= filan_stat(&buf
, fd
, fd
, outfile
, NULL
);
128 /* even more dynamic info */
129 { /* see if data is available */
132 ufds
.events
= POLLIN
|POLLPRI
|POLLOUT
148 if (Poll(&ufds
, 1, 0) < 0) {
149 Warn4("\tpoll({%d, %hd, %hd}, 1, 0): %s",
150 ufds
.fd
, ufds
.events
, ufds
.revents
, strerror(errno
));
152 fputs("\tpoll: ", outfile
);
153 if (ufds
.revents
& POLLIN
) fputs("IN,", outfile
);
154 if (ufds
.revents
& POLLPRI
) fputs("PRI,", outfile
);
155 if (ufds
.revents
& POLLOUT
) fputs("OUT,", outfile
);
156 if (ufds
.revents
& POLLERR
) fputs("ERR,", outfile
);
157 if (ufds
.revents
& POLLNVAL
) fputs("NVAL,", outfile
);
159 if (ufds
.revents
& POLLIN
) {
161 if ((result
= Ioctl(fd
, FIONREAD
, &sizet
) >= 0)) {
162 fprintf (outfile
, "; FIONREAD="F_Zu
, sizet
);
165 #endif /* defined(FIONREAD) */
166 #if _WITH_SOCKET && defined(MSG_DONTWAIT)
167 if ((ufds
.revents
& POLLIN
) && isasocket(fd
)) {
168 char _peername
[SOCKADDR_MAX
];
169 struct sockaddr
*pa
= (struct sockaddr
*)_peername
;
170 struct msghdr msgh
= {0};
171 char peekbuff
[1]; /* [0] fails with some compilers */
172 #if HAVE_STRUCT_IOVEC
178 fputs("; ", outfile
);
180 msgh
.msg_namelen
= sizeof(*pa
);
181 #if HAVE_STRUCT_IOVEC
182 iovec
.iov_base
= peekbuff
;
183 iovec
.iov_len
= sizeof(peekbuff
);
184 msgh
.msg_iov
= &iovec
;
187 #if HAVE_STRUCT_MSGHDR_MSGCONTROL
188 msgh
.msg_control
= ctrlbuff
;
190 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
191 msgh
.msg_controllen
= sizeof(ctrlbuff
);
193 #if HAVE_STRUCT_MSGHDR_MSGFLAGS
196 if ((bytes
= Recvmsg(fd
, &msgh
, MSG_PEEK
|MSG_DONTWAIT
)) < 0) {
197 Warn1("recvmsg(): %s", strerror(errno
));
199 fprintf(outfile
, "recvmsg="F_Zd
", ", bytes
);
202 #endif /* _WITH_SOCKET && defined(MSG_DONTWAIT) */
204 #endif /* HAVE_POLL */
207 fputc('\n', outfile
);
217 #endif /* !HAVE_STAT64 */
218 , int statfd
, int dynfd
, FILE *outfile
,
219 const char *filename
/* Linux does not (yet) provide an
220 freadlink system call, so we need
221 the original name for readlink in
222 case it is a symlink */
228 if (filan_rawoutput
) {
229 fputs(" FD type\tdevice\tinode\tmode\tlinks\tuid\tgid"
240 "\tatime\t\tmtime\t\tctime\t\tcloexec\tflags"
241 #if defined(F_GETOWN)
245 } else /* !rawoutput */ {
246 fputs(" FD type\tdevice\tinode\tmode\tlinks\tuid\tgid"
257 "\tatime\t\t\t\tmtime\t\t\t\tctime\t\t\t\tcloexec\tflags"
258 #if defined(F_GETOWN)
263 } /* endif !rawoutput */
265 #if defined(F_GETSIG)
266 fputs("\tsigio", outfile
);
267 #endif /* defined(F_GETSIG) */
268 fputc('\n', outfile
);
271 if (filan_rawoutput
) {
272 snprintf(stdevstr
, 8, F_dev
, buf
->st_dev
);
274 snprintf(stdevstr
, 8, "%hu,%hu", (unsigned short)(buf
->st_dev
>>8), (unsigned short)(buf
->st_dev
&0xff));
276 fprintf(outfile
, "%4d: %s\t%s\t"
281 #endif /* HAVE_STAT64 */
282 "\t"F_mode
"\t"F_st_nlink
"\t"F_uid
"\t"F_gid
291 #endif /* HAVE_STAT64 */
300 #endif /* HAVE_STAT64 */
303 (dynfd
>=0?dynfd
:statfd
), getfiletypestring(buf
->st_mode
),
306 buf
->st_mode
, buf
->st_nlink
, buf
->st_uid
,
309 (unsigned short)(buf
->st_rdev
>>8), (unsigned short)(buf
->st_rdev
&0xff),
316 , buf
->st_blocks
/* on Linux, this applies to stat and stat64 */
320 printtime(outfile
, buf
->st_atime
);
321 printtime(outfile
, buf
->st_mtime
);
322 printtime(outfile
, buf
->st_ctime
);
326 fputc('\t', outfile
);
327 time
= asctime(localtime(&buf
->st_mtime
));
328 if (strchr(time
, '\n')) *strchr(time
, '\n') = '\0';
329 fputs(time
, outfile
);
331 fputc('\t', outfile
);
332 time
= asctime(localtime(&buf
->st_ctime
));
333 if (strchr(time
, '\n')) *strchr(time
, '\n') = '\0';
334 fputs(time
, outfile
);
338 /* here comes dynamic info - it is only meaningful with preexisting FDs */
339 if (dynfd
>= 0) { /*!indent */
341 #if defined(F_GETOWN)
344 #if defined(F_GETSIG)
346 #endif /* defined(F_GETSIG) */
348 cloexec
= Fcntl(dynfd
, F_GETFD
);
349 flags
= Fcntl(dynfd
, F_GETFL
);
350 #if defined(F_GETOWN)
351 sigown
= Fcntl(dynfd
, F_GETOWN
);
353 #if defined(F_GETSIG)
354 sigio
= Fcntl(dynfd
, F_GETSIG
);
355 #endif /* defined(F_GETSIG) */
356 fprintf(outfile
, "\t%d\tx%06x", cloexec
, flags
);
357 #if defined(F_GETOWN)
358 fprintf(outfile
, "\t%d", sigown
);
360 #if defined(F_GETSIG)
361 fprintf(outfile
, "\t%d", sigio
);
362 #endif /* defined(F_GETSIG) */
365 #if defined(F_GETOWN)
368 #if defined(F_GETSIG)
370 #endif /* defined(F_GETSIG) */
374 /* ever heard of POSIX streams? here we handle these */
375 filan_streams_analyze(statfd
, outfile
);
377 /* now see for type specific infos */
378 if (statfd
>= 0) { /*!indent */
379 switch (buf
->st_mode
&S_IFMT
) {
380 case (S_IFIFO
): /* 1, FIFO */
381 #if defined(F_GETPIPE_SZ)
382 fprintf(outfile
, "\tF_GETPIPE_SZ=%d", Fcntl(statfd
, F_GETPIPE_SZ
));
385 case (S_IFCHR
): /* 2, character device */
386 cdevan(statfd
, outfile
);
388 case (S_IFDIR
): /* 4, directory */
390 case (S_IFBLK
): /* 6, block device */
392 case (S_IFREG
): /* 8, regular file */
395 case (S_IFLNK
): /* 10, symbolic link */
396 /* we wait for freadlink() sytem call */
401 case (S_IFSOCK
): /* 12, socket */
403 sockan(statfd
, outfile
);
405 Warn("SOCKET support not compiled in");
407 #endif /* !_WITH_SOCKET */
409 #endif /* S_IFSOCK */
412 switch (buf
->st_mode
&S_IFMT
) {
414 case (S_IFLNK
): /* 10, symbolic link */
416 char linktarget
[PATH_MAX
+1];
417 memset(linktarget
, 0, PATH_MAX
+1);
418 if (Readlink(filename
, linktarget
, PATH_MAX
) < 0) {
419 Warn3("readlink(\"%s\", linktarget, %d): %s",
420 filename
, PATH_MAX
, strerror(errno
));
422 fprintf(outfile
, "LINKTARGET=%s", linktarget
);
438 result
= Fcntl(fd
, F_GETFD
);
439 fcntl(fd
, F_GETFL
, );
440 fcntl(fd
, F_GETLK
, );
442 fcntl(fd
, F_GETOWN
, );
445 fcntl(fd
, F_GETSIG
, );
450 int devinfo(int fd
) {
456 /* returns 0 on success (not a stream descriptor, or no module)
457 returns <0 on failure */
458 static int filan_streams_analyze(int fd
, FILE *outfile
) {
460 # define SL_NMODS 8 /* max number of module names we can store */
461 struct str_list modnames
;
464 if (!isastream(fd
)) {
465 fprintf(outfile
, "\t(no STREAMS modules)");
468 #if 0 /* uncomment for debugging */
469 fprintf(outfile
, "\tfind=%d", ioctl(fd
, I_FIND
, "ldterm"));
471 modnames
.sl_nmods
= ioctl(fd
, I_LIST
, 0);
472 if (modnames
.sl_nmods
< 0) {
473 fprintf(stderr
, "ioctl(%d, I_LIST, 0): %s\n", fd
, strerror(errno
));
476 modnames
.sl_modlist
= Malloc(modnames
.sl_nmods
*(sizeof(struct str_mlist
)));
477 if (modnames
.sl_modlist
== NULL
) {
478 fprintf(stderr
, "out of memory\n");
481 if (ioctl(fd
, I_LIST
, &modnames
) < 0) {
482 fprintf(stderr
, "ioctl(%d, I_LIST, %p): %s\n",
483 fd
, &modnames
, strerror(errno
));
484 free(modnames
.sl_modlist
);
487 fprintf(outfile
, "\tSTREAMS: ");
488 for (i
= 0; i
< modnames
.sl_nmods
; ++i
) {
489 fprintf(outfile
, "\"%s\"", modnames
.sl_modlist
[i
].l_name
);
490 if (i
+1 < modnames
.sl_nmods
) fputc(',', outfile
);
492 free(modnames
.sl_modlist
);
493 #endif /* defined(I_LIST) */
498 /* character device analysis */
499 int cdevan(int fd
, FILE *outfile
) {
503 if ((ret
= Isatty(fd
)) < 0) {
504 Warn2("isatty(%d): %s", fd
, strerror(errno
));
508 struct termios termarg
;
512 if ((name
= Ttyname(fd
)) == NULL
) {
513 /*Warn2("ttyname(%d): %s", fd, strerror(errno));*/
514 fputs("\tNULL", outfile
);
516 fprintf(outfile
, "\t%s", name
);
518 if (Tcgetattr(fd
, &termarg
) < 0) {
519 Warn3("tcgetattr(%d, %p): %s", fd
, &termarg
, strerror(errno
));
522 fprintf(outfile
, " \tIFLAGS=%08x OFLAGS=%08x CFLAGS=%08x LFLAGS=%08x",
523 (unsigned int)termarg
.c_iflag
,
524 (unsigned int)termarg
.c_oflag
,
525 (unsigned int)termarg
.c_cflag
,
526 (unsigned int)termarg
.c_lflag
);
528 /* and the control characters */
529 if (filan_rawoutput
) {
530 for (i
=0; i
<NCCS
; ++i
) {
531 fprintf(outfile
, " cc[%d]=%d", i
, termarg
.c_cc
[i
]);
534 for (i
=0; i
<NCCS
; ++i
) {
537 ch
= termarg
.c_cc
[i
];
539 s
[0] = ch
; s
[1]= '\0';
540 } else if (ch
< ' ') {
541 s
[0] = '^'; s
[1] = ch
+'@'; s
[2] = '\0';
544 s
[1] = (ch
>>4)>=10?(ch
>>4)-10+'A':(ch
>>4)+'0';
545 s
[2] = (ch
&0x0f)>=10?(ch
&0x0f)-10+'A':(ch
&0x0f)+'0';
548 fprintf(outfile
, " cc[%d]=%s", i
, s
);
552 #endif /* _WITH_TERMIOS */
558 int sockan(int fd
, FILE *outfile
) {
559 #define FILAN_OPTLEN 256
560 #define FILAN_NAMELEN 256
563 char nambuff
[FILAN_NAMELEN
];
564 /* in Linux these optcodes are 'enum', but on AIX they are bits! */
565 static const struct sockopt sockopts
[] = {
567 {SO_REUSEADDR
, "REUSEADDR"},
569 {SO_PROTOCOL
, "PROTOCOL"},
570 #elif defined(SO_PROTOTYPE)
571 {SO_PROTOTYPE
, "PROTOTYPE"},
575 {SO_DONTROUTE
, "DONTROUTE"},
576 {SO_BROADCAST
, "BROADCAST"},
577 {SO_SNDBUF
, "SNDBUF"},
578 {SO_RCVBUF
, "RCVBUF"},
579 {SO_KEEPALIVE
, "KEEPALIVE"},
580 {SO_OOBINLINE
, "OOBINLINE"},
582 {SO_NO_CHECK
, "NO_CHECK"},
585 {SO_PRIORITY
, "PRIORITY"},
587 {SO_LINGER
, "LINGER"},
589 {SO_BSDCOMPAT
, "BSDCOMPAT"},
592 {SO_REUSEPORT
, "REUSEPORT"},
593 #endif /* defined(SO_REUSEPORT) */
595 {SO_PASSCRED
, "PASSCRED"},
598 {SO_PEERCRED
, "PEERCRED"},
601 {SO_RCVLOWAT
, "RCVLOWAT"},
604 {SO_SNDLOWAT
, "SNDLOWAT"},
607 {SO_RCVTIMEO
, "RCVTIMEO"},
610 {SO_SNDTIMEO
, "SNDTIMEO"},
612 #ifdef SO_SECURITY_AUTHENTICATION
613 {SO_SECURITY_AUTHENTICATION
, "SECURITY_AUTHENTICATION"},
615 #ifdef SO_SECURITY_ENCRYPTION_TRANSPORT
616 {SO_SECURITY_ENCRYPTION_TRANSPORT
, "SECURITY_ENCRYPTION_TRANSPORT"},
618 #ifdef SO_SECURITY_ENCRYPTION_NETWORK
619 {SO_SECURITY_ENCRYPTION_NETWORK
, "SECURITY_ENCRYPTION_NETWORK"},
621 #ifdef SO_BINDTODEVICE
622 {SO_BINDTODEVICE
, "BINDTODEVICE"},
624 #ifdef SO_ATTACH_FILTER
625 {SO_ATTACH_FILTER
, "ATTACH_FILTER"},
627 #ifdef SO_DETACH_FILTER
628 {SO_DETACH_FILTER
, "DETACH_FILTER"},
632 char c
[FILAN_OPTLEN
];
633 int i
[FILAN_OPTLEN
/sizeof(int)];
635 const struct sockopt
*optname
;
636 union sockaddr_union sockname
, peername
; /* the longest I know of */
638 #if 0 && defined(SIOCGIFNAME)
639 /*Linux struct ifreq ifc = {{{ 0 }}};*/
640 struct ifreq ifc
= {{ 0 }};
643 optlen
= FILAN_OPTLEN
;
644 result
= Getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, optval
.c
, &optlen
);
646 Debug4("getsockopt(%d, SOL_SOCKET, SO_TYPE, %p, {"F_socklen
"}): %s",
647 fd
, optval
.c
, optlen
, strerror(errno
));
649 # define TYPENAMEMAX 16
650 char typename
[TYPENAMEMAX
];
651 sockettype(*optval
.i
, typename
, sizeof(typename
));
653 Debug3("fd %d: socket of type %d (\"%s\")", fd
, *optval
.i
,
657 optname
= sockopts
; while (optname
->so
) {
658 optlen
= FILAN_OPTLEN
;
660 Getsockopt(fd
, SOL_SOCKET
, optname
->so
, (void *)optval
.c
, &optlen
);
662 Debug5("getsockopt(%d, SOL_SOCKET, %d, %p, {"F_socklen
"}): %s",
663 fd
, optname
->so
, optval
.c
, optlen
, strerror(errno
));
664 fputc('\t', outfile
);
665 } else if (optlen
== sizeof(int)) {
666 Debug2("getsockopt(,,, {%d}, %d)",
668 /*Info2("%s: %d", optname->name, optval.i);*/
669 fprintf(outfile
, "%s=%d\t", optname
->name
, *optval
.i
);
671 Debug3("getsockopt(,,, {%d,%d}, %d)",
672 optval
.i
[0], optval
.i
[1], optlen
);
673 fprintf(outfile
, "%s={%d,%d}\t", optname
->name
,
674 optval
.i
[0], optval
.i
[1]);
679 namelen
= sizeof(sockname
);
680 result
= Getsockname(fd
, (struct sockaddr
*)&sockname
, &namelen
);
683 Warn2("getsockname(%d): %s", fd
, strerror(errno
));
686 fputc('\t', outfile
);
687 fputs(sockaddr_info((struct sockaddr
*)&sockname
, namelen
, nambuff
, sizeof(nambuff
)),
690 namelen
= sizeof(peername
);
691 result
= Getpeername(fd
, (struct sockaddr
*)&peername
, &namelen
);
694 Warn2("getpeername(%d): %s", fd
, strerror(errno
));
696 /* only valid if getpeername() succeeded */
697 fputs(" <-> ", outfile
);
698 fprintf(outfile
, "%s\t",
699 sockaddr_info((struct sockaddr
*)&peername
, namelen
,
700 nambuff
, sizeof(nambuff
)));
703 #if 0 && defined(SIOCGIFNAME)
704 if ((result
= Ioctl(fd
, SIOCGIFNAME
, &ifc
)) < 0) {
705 Warn3("ioctl(%d, SIOCGIFNAME, %p): %s", fd
, &ifc
, strerror(errno
));
707 fprintf(outfile
, "IFNAME=\"%s\"\t", ifc
.ifr_name
);
709 #endif /* SIOCGIFNAME */
711 switch (((struct sockaddr
*)&sockname
)->sa_family
) {
714 /* no options for unix domain sockets known yet -> no unixan() */
720 result
= ipan(fd
, outfile
);
725 result
= ipan(fd
, outfile
);
726 result
|= ip6an(fd
, outfile
);
730 fputs("**** NO FURTHER ANALYSIS FOR THIS SOCKET TYPE IMPLEMENTED", outfile
);
737 #endif /* _WITH_SOCKET */
740 #if WITH_IP4 || WITH_IP6
741 /* prints the option values for the IP protocol and the IP based protocols */
742 /* no distinction between IP4 and IP6 yet */
743 int ipan(int fd
, FILE *outfile
) {
744 /* in Linux these optcodes are 'enum', but on AIX they are bits! */
745 static const struct sockopt ipopts
[] = {
749 {IP_HDRINCL
, "IP_HDRINCL"},
752 {IP_OPTIONS
, "IP_OPTIONS"},
754 #ifdef IP_ROUTER_ALERT
755 {IP_ROUTER_ALERT
, "IP_ROUTER_ALERT"},
758 {IP_RECVOPTS
, "IP_RECVOPTS"},
761 {IP_RETOPTS
, "IP_RETOPTS"},
764 {IP_PKTINFO
, "IP_PKTINFO"},
767 {IP_PKTOPTIONS
, "IP_PKTOPTIONS"},
769 #ifdef IP_MTU_DISCOVER
770 {IP_MTU_DISCOVER
, "IP_MTU_DISCOVER"},
773 {IP_RECVERR
, "IP_RECVERR"},
776 {IP_RECVTTL
, "IP_RECVTTL"},
779 {IP_RECVTOS
, "IP_RECVTOS"},
781 #ifdef IP_TRANSPARENT
782 {IP_TRANSPARENT
, "IP_TRANSPARENT"},
788 {IP_FREEBIND
, "IP_FREEBIND"},
790 #ifdef IP_MULTICAST_TTL
791 {IP_MULTICAST_TTL
, "IP_MULTICAST_TTL"},
793 #ifdef IP_MULTICAST_LOOP
794 {IP_MULTICAST_LOOP
, "IP_MULTICAST_LOOP"},
797 const struct sockopt
*optname
;
799 socklen_t optlen
= sizeof(optproto
);
801 optname
= ipopts
; while (optname
->so
) {
802 sockoptan(fd
, optname
, SOL_IP
, outfile
);
805 /* want to pass the fd to the next layer protocol. */
806 #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
807 if (Getsockopt(fd
, SOL_SOCKET
,
810 #elif defined(SO_PROTOTYPE)
813 &optproto
, &optlen
) >= 0) {
816 case IPPROTO_TCP
: tcpan(fd
, outfile
); break;
820 #endif /* defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) */
827 /* prints the option values for the IPv6 protocol */
828 int ip6an(int fd
, FILE *outfile
) {
829 static const struct sockopt ip6opts
[] = {
831 {IPV6_V6ONLY
, "IPV6_V6ONLY"},
834 const struct sockopt
*optname
;
836 optname
= ip6opts
; while (optname
->so
) {
837 sockoptan(fd
, optname
, SOL_IPV6
, outfile
);
842 #endif /* WITH_IP6 */
846 int tcpan(int fd
, FILE *outfile
) {
847 static const struct sockopt tcpopts
[] = {
849 { TCP_NODELAY
, "TCP_NODELAY" },
852 { TCP_MAXSEG
, "TCP_MAXSEG" },
855 { TCP_STDURG
, "TCP_STDURG" },
858 { TCP_RFC1323
, "TCP_RFC1323" },
861 { TCP_CORK
, "TCP_CORK" },
864 { TCP_KEEPIDLE
, "TCP_KEEPIDLE" },
867 { TCP_KEEPINTVL
, "TCP_KEEPINTVL" },
870 { TCP_KEEPCNT
, "TCP_KEEPCNT" },
873 { TCP_SYNCNT
, "TCP_SYNCNT" },
876 { TCP_LINGER2
, "TCP_LINGER2" },
878 #ifdef TCP_DEFER_ACCEPT
879 { TCP_DEFER_ACCEPT
, "TCP_ACCEPT" },
881 #ifdef TCP_WINDOW_CLAMP
882 { TCP_WINDOW_CLAMP
, "TCP_WINDOW_CLAMP" },
885 { TCP_INFO
, "TCP_INFO" },
888 { TCP_QUICKACK
, "TCP_QUICKACK" },
891 { TCP_MD5SIG
, "TCP_MD5SIG" },
894 { TCP_NOOPT
, "TCP_NOOPT" },
897 { TCP_NOPUSH
, "TCP_NOPUSH" },
899 #ifdef TCP_SACK_DISABLE
900 { TCP_SACK_DISABLE
, "TCP_SACK_DISABLE" },
902 #ifdef TCP_SIGNATURE_ENABLE
903 { TCP_SIGNATURE_ENABLE
, "TCP_SIGNATURE_ENABLE" },
905 #ifdef TCP_ABORT_THRESHOLD
906 { TCP_ABORT_THRESHOLD
, "TCP_ABORT_THRESHOLD" },
908 #ifdef TCP_CONN_ABORT_THRESHOLD
909 { TCP_CONN_ABORT_THRESHOLD
, "TCP_CONN_ABORT_THRESHOLD" },
912 { TCP_KEEPINIT
, "TCP_KEEPINIT" },
915 { TCP_PAWS
, "TCP_PAWS" },
918 { TCP_SACKENA
, "TCP_SACKENA" },
921 { TCP_TSOPTENA
, "TCP_TSOPTENA" },
925 const struct sockopt
*optname
;
927 optname
= tcpopts
; while (optname
->so
) {
928 sockoptan(fd
, optname
, SOL_TCP
, outfile
);
937 #endif /* WITH_TCP */
939 #if WITH_TCP && defined(TCP_INFO)
941 int tcpan2(int fd
, FILE *outfile
) {
942 struct tcp_info tcpinfo
;
943 socklen_t tcpinfolen
= sizeof(tcpinfo
);
946 result
= Getsockopt(fd
, SOL_TCP
, TCP_INFO
, &tcpinfo
, &tcpinfolen
);
948 Debug4("getsockopt(%d, SOL_TCP, TCP_INFO, %p, {"F_Zu
"}): %s",
949 fd
, &tcpinfo
, sizeof(tcpinfo
), strerror(errno
));
952 fprintf(outfile
, "%s={%u}\t", "TCPI_STATE", tcpinfo
.tcpi_state
);
953 #if 0 /* on BSD these components are prefixed with __ - I get tired... */
954 fprintf(outfile
, "%s={%u}\t", "TCPI_CA_STATE", tcpinfo
.tcpi_ca_state
);
955 fprintf(outfile
, "%s={%u}\t", "TCPI_RETRANSMITS", tcpinfo
.tcpi_retransmits
);
956 fprintf(outfile
, "%s={%u}\t", "TCPI_PROBES", tcpinfo
.tcpi_probes
);
957 fprintf(outfile
, "%s={%u}\t", "TCPI_BACKOFF", tcpinfo
.tcpi_backoff
);
959 fprintf(outfile
, "%s={%u}\t", "TCPI_OPTIONS", tcpinfo
.tcpi_options
);
960 fprintf(outfile
, "%s={%u}\t", "TCPI_SND_WSCALE", tcpinfo
.tcpi_snd_wscale
);
961 fprintf(outfile
, "%s={%u}\t", "TCPI_RCV_WSCALE", tcpinfo
.tcpi_rcv_wscale
);
963 fprintf(outfile
, "%s={%u}\t", "TCPI_DELIVERY_RATE_APP_LIMITED", tcpinfo
.tcpi_delivery_rate_app_limited
);
964 fprintf(outfile
, "%s={%u}\t", "TCPI_FASTOPEN_CLIENT_FAIL", tcpinfo
.tcpi_fastopen_client_fail
);
965 fprintf(outfile
, "%s={%u}\t", "TCPI_", tcpinfo
.tcpi_
);
971 #endif /* WITH_TCP */
975 int sockoptan(int fd
, const struct sockopt
*optname
, int socklay
, FILE *outfile
) {
976 #define FILAN_OPTLEN 256
978 char c
[FILAN_OPTLEN
];
979 int i
[FILAN_OPTLEN
/sizeof(int)];
984 optlen
= FILAN_OPTLEN
;
986 Getsockopt(fd
, socklay
, optname
->so
, (void *)optval
.c
, &optlen
);
988 Debug6("getsockopt(%d, %d, %d, %p, {"F_socklen
"}): %s",
989 fd
, socklay
, optname
->so
, optval
.c
, optlen
, strerror(errno
));
990 fputc('\t', outfile
);
992 } else if (optlen
== 0) {
993 Debug1("getsockopt(,,, {}, %d)", optlen
);
994 fprintf(outfile
, "%s=\"\"\t", optname
->name
);
995 } else if (optlen
== sizeof(int)) {
996 Debug2("getsockopt(,,, {%d}, %d)",
998 fprintf(outfile
, "%s=%d\t", optname
->name
, *optval
.i
);
1000 char outbuf
[FILAN_OPTLEN
*9+128], *cp
= outbuf
;
1002 for (i
= 0; i
< optlen
/sizeof(unsigned int); ++i
) {
1003 cp
+= sprintf(cp
, "%08x ", (unsigned int)optval
.i
[i
]);
1005 *--cp
= '\0'; /* delete trailing space */
1006 Debug2("getsockopt(,,, {%s}, %d)", outbuf
, optlen
);
1008 fprintf(outfile
, "%s={%s}\t", optname
->name
, outbuf
);
1013 #endif /* _WITH_SOCKET */
1017 int isasocket(int fd
) {
1020 struct stat64 props
;
1023 #endif /* HAVE_STAT64 */
1026 Fstat64(fd
, &props
);
1031 Info3("fstat(%d, %p): %s", fd
, &props
, strerror(errno
));
1034 /* note: when S_ISSOCK was undefined, it always gives 0 */
1035 return S_ISSOCK(props
.st_mode
);
1037 #endif /* _WITH_SOCKET */
1040 const char *getfiletypestring(int st_mode
) {
1043 switch (st_mode
&S_IFMT
) {
1044 case S_IFIFO
: s
= "pipe"; break;
1045 case S_IFCHR
: s
= "chrdev"; break;
1046 case S_IFDIR
: s
= "dir"; break;
1047 case S_IFBLK
: s
= "blkdev"; break;
1048 case S_IFREG
: s
= "file"; break;
1049 case S_IFLNK
: s
= "symlink"; break;
1050 case S_IFSOCK
: s
= "socket"; break;
1052 default: s
= "undef"; break;
1057 static int printtime(FILE *outfile
, time_t time
) {
1060 if (filan_rawoutput
) {
1061 fprintf(outfile
, "\t"F_time
, time
);
1063 fputc('\t', outfile
);
1064 s
= asctime(localtime(&time
));
1065 if (strchr(s
, '\n')) *strchr(s
, '\n') = '\0';