version 1.7.3.0
[socat.git] / fdname.c
blob8542a2b9b7dfd3acb16671cf84f4e61efd425e0e
1 /* source: fdname.c */
2 /* Copyright Gerhard Rieger 2003-2011 */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* the subroutine sockname prints the basic info about the address of a socket
6 NOTE: it works on UNIX (kernel) file descriptors, not on libc files! */
8 #include "config.h"
9 #include "xioconfig.h" /* what features are enabled */
11 #include "sysincludes.h"
13 #include "mytypes.h"
14 #include "compat.h"
15 #include "error.h"
16 #include "sycls.h"
17 #include "sysutils.h"
19 #include "filan.h"
22 struct sockopt {
23 int so;
24 char *name;
28 int statname(const char *file, int fd, int filetype, FILE *outfile);
29 int cdevname(int fd, FILE *outfile);
30 int sockname(int fd, FILE *outfile);
31 int unixame(int fd, FILE *outfile);
32 int tcpname(int fd, FILE *outfile);
35 int fdname(const char *file, int fd, FILE *outfile, const char *numform) {
36 struct stat buf = {0};
37 int filetype;
38 Debug1("checking file descriptor %u", fd);
39 if (fd >= 0) {
40 if (Fstat(fd, &buf) < 0) {
41 if (errno == EBADF) {
42 Debug2("fstat(%d): %s", fd, strerror(errno));
43 return -1;
44 } else {
45 Error2("fstat(%d): %s", fd, strerror(errno));
48 filetype = (buf.st_mode&S_IFMT)>>12;
49 if (numform != NULL) {
50 fprintf(outfile, numform, fd);
52 return statname(file, fd, filetype, outfile);
53 } else {
54 if (Stat(file, &buf) < 0) {
55 Error2("stat(\"%s\"): %s", file, strerror(errno));
57 filetype = (buf.st_mode&S_IFMT)>>12;
58 return statname(file, -1, filetype, outfile);
62 #if HAVE_PROC_DIR_FD
63 static int procgetfdname(int fd, char *filepath, size_t pathsize) {
64 static pid_t pid = -1;
65 char procpath[PATH_MAX];
66 int len;
68 /* even if configure has shown that we have /proc, we must check if it
69 exists at runtime, because we might be in a chroot environment */
70 #if HAVE_STAT64
72 struct stat64 buf;
73 if (Stat64("/proc", &buf) < 0) {
74 return -1;
76 if (!S_ISDIR(buf.st_mode)) {
77 return -1;
80 #else /* !HAVE_STAT64 */
82 struct stat buf;
83 if (Stat("/proc", &buf) < 0) {
84 return -1;
86 if (!S_ISDIR(buf.st_mode)) {
87 return -1;
90 #endif /* !HAVE_STAT64 */
92 if (pid < 0) pid = Getpid();
93 snprintf(procpath, sizeof(procpath), "/proc/"F_pid"/fd/%d", pid, fd);
94 if ((len = Readlink(procpath, filepath, pathsize-1)) < 0) {
95 Error4("readlink(\"%s\", %p, "F_Zu"): %s",
96 procpath, filepath, pathsize, strerror(errno));
97 return -1;
99 filepath[len] = '\0';
100 return 0;
102 #endif /* HAVE_PROC_DIR_FD */
104 int statname(const char *file, int fd, int filetype, FILE *outfile) {
105 char filepath[PATH_MAX];
107 filepath[0] = '\0';
108 #if HAVE_PROC_DIR_FD
109 if (fd >= 0) {
110 procgetfdname(fd, filepath, sizeof(filepath));
111 if (filepath[0] == '/') {
112 file = filepath;
115 #endif /* HAVE_PROC_DIR_FD */
116 /* now see for type specific infos */
117 switch (filetype) {
118 case (S_IFIFO>>12): /* 1, FIFO */
119 fputs("pipe", outfile);
120 if (file) fprintf(outfile, " %s", file);
121 break;
122 case (S_IFCHR>>12): /* 2, character device */
123 if (cdevname(fd, outfile) == 0) {
124 if (file) fprintf(outfile, " %s", file);
126 break;
127 case (S_IFDIR>>12): /* 4, directory */
128 fputs("dir", outfile);
129 if (file) fprintf(outfile, " %s", file);
130 break;
131 case (S_IFBLK>>12): /* 6, block device */
132 fputs("blkdev", outfile);
133 if (file) fprintf(outfile, " %s", file);
134 break;
135 case (S_IFREG>>12): /* 8, regular file */
136 fputs("file", outfile);
137 if (file) fprintf(outfile, " %s", file);
138 break;
139 case (S_IFLNK>>12): /* 10, symbolic link */
140 fputs("link", outfile);
141 if (file) fprintf(outfile, " %s", file);
142 break;
143 case (S_IFSOCK>>12): /* 12, socket */
144 #if _WITH_SOCKET
145 if (fd >= 0) {
146 sockname(fd, outfile);
147 } else if (file) {
148 fprintf(outfile, "socket %s", file);
149 } else {
150 fputs("socket", outfile);
152 #else
153 Error("SOCKET support not compiled in");
154 return -1;
155 #endif /* !_WITH_SOCKET */
156 break;
158 /* ioctl() */
159 fputc('\n', outfile);
161 return 0;
165 /* character device analysis */
166 /* return -1 on error, 0 if no name was found, or 1 if it printed ttyname */
167 int cdevname(int fd, FILE *outfile) {
168 int ret;
170 if ((ret = Isatty(fd)) < 0) {
171 Error2("isatty(%d): %s", fd, strerror(errno));
172 return -1;
174 if (ret > 0) {
175 char *name;
177 fputs("tty", outfile);
178 if ((name = Ttyname(fd)) != NULL) {
179 fputc(' ', outfile);
180 fputs(name, outfile);
181 return 1;
183 } else {
184 fputs("chrdev", outfile);
186 return 0;
190 #if _WITH_SOCKET
191 int sockname(int fd, FILE *outfile) {
192 #define FDNAME_OPTLEN 256
193 #define FDNAME_NAMELEN 256
194 socklen_t optlen;
195 int opttype;
196 #ifdef SO_ACCEPTCONN
197 int optacceptconn;
198 #endif
199 int result /*0, i*/;
200 char namebuff[FDNAME_NAMELEN];
201 char peerbuff[FDNAME_NAMELEN];
202 /* in Linux these optcodes are 'enum', but on AIX they are bits! */
203 union sockaddr_union sockname, peername; /* the longest I know of */
204 socklen_t namelen;
205 #if 0 && defined(SIOCGIFNAME)
206 /*Linux struct ifreq ifc = {{{ 0 }}};*/
207 struct ifreq ifc = {{ 0 }};
208 #endif
210 optlen = FDNAME_OPTLEN;
212 Getsockopt(fd, SOL_SOCKET, SO_TYPE, &opttype, &optlen);
213 #ifdef SO_ACCEPTCONN
214 Getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &optacceptconn, &optlen);
215 #endif
217 namelen = sizeof(sockname);
218 result = Getsockname(fd, &sockname.soa, &namelen);
219 if (result < 0) {
220 Error2("getsockname(%d): %s", fd, strerror(errno));
221 return -1;
224 namelen = sizeof(peername);
225 result = Getpeername(fd, (struct sockaddr *)&peername, &namelen);
226 if (result < 0) {
227 Error2("getpeername(%d): %s", fd, strerror(errno));
230 switch (sockname.soa.sa_family) {
231 #if WITH_UNIX
232 case AF_UNIX:
233 fprintf(outfile, "unix%s%s %s",
234 opttype==SOCK_DGRAM?"datagram":"",
235 #ifdef SO_ACCEPTCONN
236 optacceptconn?"(listening)":
237 #endif
239 sockaddr_unix_info(&sockname.un, namelen,
240 namebuff, sizeof(namebuff)));
241 break;
242 #endif
243 #if WITH_IP4
244 case AF_INET:
245 switch (opttype) {
246 #if WITH_TCP
247 case SOCK_STREAM:
248 fprintf(outfile, "tcp%s %s %s",
249 #ifdef SO_ACCEPTCONN
250 optacceptconn?"(listening)":
251 #endif
253 sockaddr_inet4_info(&sockname.ip4,
254 namebuff, sizeof(namebuff)),
255 sockaddr_inet4_info(&peername.ip4,
256 peerbuff, sizeof(peerbuff)));
257 break;
258 #endif
259 #if WITH_UDP
260 case SOCK_DGRAM:
261 fprintf(outfile, "udp%s %s %s",
262 #ifdef SO_ACCEPTCONN
263 optacceptconn?"(listening)":
264 #endif
266 sockaddr_inet4_info(&sockname.ip4,
267 namebuff, sizeof(namebuff)),
268 sockaddr_inet4_info(&peername.ip4,
269 peerbuff, sizeof(peerbuff)));
270 break;
271 #endif
272 default:
273 fprintf(outfile, "ip %s",
274 sockaddr_inet4_info(&sockname.ip4,
275 namebuff, sizeof(namebuff)));
276 break;
278 break;
279 #endif /* WITH_IP4 */
281 #if WITH_IP6
282 case AF_INET6:
283 switch (opttype) {
284 #if WITH_TCP
285 case SOCK_STREAM:
286 fprintf(outfile, "tcp6%s %s %s",
287 #ifdef SO_ACCEPTCONN
288 optacceptconn?"(listening)":
289 #endif
291 sockaddr_inet6_info(&sockname.ip6,
292 namebuff, sizeof(namebuff)),
293 sockaddr_inet6_info(&peername.ip6,
294 peerbuff, sizeof(peerbuff)));
295 break;
296 #endif
297 #if WITH_UDP
298 case SOCK_DGRAM:
299 fprintf(outfile, "udp6%s %s %s",
300 #ifdef SO_ACCEPTCONN
301 optacceptconn?"(listening)":
302 #endif
304 sockaddr_inet6_info(&sockname.ip6,
305 namebuff, sizeof(namebuff)),
306 sockaddr_inet6_info(&peername.ip6,
307 peerbuff, sizeof(peerbuff)));
308 break;
309 #endif
310 default:
311 fprintf(outfile, "ip6 %s",
312 sockaddr_inet6_info(&sockname.ip6,
313 namebuff, sizeof(namebuff)));
314 break;
316 #endif /* WITH_IP6 */
317 default:
318 fputs("socket", outfile);
321 return result;
322 #undef FDNAME_OPTLEN
323 #undef FDNAME_NAMELEN
325 #endif /* _WITH_SOCKET */