Version 1.8.0.0
[socat.git] / fdname.c
blobe226bdac6b62ab55afaf2b933eb4db1482e7bb53
1 /* source: fdname.c */
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 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, char style);
29 int cdevname(int fd, FILE *outfile);
30 int sockname(int fd, FILE *outfile, char style);
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 char style) {
37 struct stat buf = {0};
38 int filetype;
39 Debug1("checking file descriptor %u", fd);
40 if (fd >= 0) {
41 if (Fstat(fd, &buf) < 0) {
42 if (errno == EBADF) {
43 Debug2("fstat(%d): %s", fd, strerror(errno));
44 return -1;
45 } else {
46 Error2("fstat(%d): %s", fd, strerror(errno));
49 filetype = (buf.st_mode&S_IFMT)>>12;
50 if (numform != NULL) {
51 fprintf(outfile, numform, fd);
53 return statname(file, fd, filetype, outfile, style);
54 } else {
55 if (Stat(file, &buf) < 0) {
56 Error2("stat(\"%s\"): %s", file, strerror(errno));
58 filetype = (buf.st_mode&S_IFMT)>>12;
59 return statname(file, -1, filetype, outfile, style);
63 #if HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH
64 static int procgetfdname(int fd, char *filepath, size_t pathsize) {
65 static pid_t pid = -1;
66 char procpath[PATH_MAX];
67 int len;
69 /* even if configure has shown that we have /proc, we must check if it
70 exists at runtime, because we might be in a chroot environment */
71 #if HAVE_STAT64
73 struct stat64 buf;
74 if (Stat64("/proc", &buf) < 0) {
75 return -1;
77 if (!S_ISDIR(buf.st_mode)) {
78 return -1;
81 #else /* !HAVE_STAT64 */
83 struct stat buf;
84 if (Stat("/proc", &buf) < 0) {
85 return -1;
87 if (!S_ISDIR(buf.st_mode)) {
88 return -1;
91 #endif /* !HAVE_STAT64 */
93 if (pid < 0) pid = Getpid();
94 snprintf(procpath, sizeof(procpath), "/proc/"F_pid"/"
95 #if HAVE_PROC_DIR_PATH
96 "path"
97 #else
98 "fd"
99 #endif
100 "/%d", pid, fd);
101 if ((len = Readlink(procpath, filepath, pathsize-1)) < 0) {
102 Notice4("readlink(\"%s\", %p, "F_Zu"): %s",
103 procpath, filepath, pathsize, strerror(errno));
104 len = 0;
106 filepath[len] = '\0';
107 return 0;
109 #endif /* HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH */
111 int statname(const char *file, int fd, int filetype, FILE *outfile,
112 char style) {
113 char filepath[PATH_MAX];
115 filepath[0] = '\0';
116 #if HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH
117 if (fd >= 0) {
118 procgetfdname(fd, filepath, sizeof(filepath));
119 if (filepath[0] == '/') {
120 file = filepath;
123 #endif /* HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH */
124 /* now see for type specific infos */
125 switch (filetype) {
126 case (S_IFIFO>>12): /* 1, FIFO */
127 fputs("pipe", outfile);
128 if (file) fprintf(outfile, " %s", file);
129 break;
130 case (S_IFCHR>>12): /* 2, character device */
131 if (cdevname(fd, outfile) == 0) {
132 if (file) fprintf(outfile, " %s", file);
134 break;
135 case (S_IFDIR>>12): /* 4, directory */
136 fputs("dir", outfile);
137 if (file) fprintf(outfile, " %s", file);
138 break;
139 case (S_IFBLK>>12): /* 6, block device */
140 fputs("blkdev", outfile);
141 if (file) fprintf(outfile, " %s", file);
142 break;
143 case (S_IFREG>>12): /* 8, regular file */
144 fputs("file", outfile);
145 if (file) fprintf(outfile, " %s", file);
146 break;
147 case (S_IFLNK>>12): /* 10, symbolic link */
148 fputs("link", outfile);
149 if (file) fprintf(outfile, " %s", file);
150 break;
151 case (S_IFSOCK>>12): /* 12, socket */
152 #if _WITH_SOCKET
153 if (fd >= 0) {
154 sockname(fd, outfile, style);
155 } else if (file) {
156 fprintf(outfile, "socket %s", file);
157 } else {
158 fputs("socket", outfile);
160 #else
161 Error("SOCKET support not compiled in");
162 return -1;
163 #endif /* !_WITH_SOCKET */
164 break;
165 #ifdef S_IFDOOR
166 case (S_IFDOOR>>12): /* 13, door (Solaris) */
167 fputs("door", outfile);
168 if (file) fprintf(outfile, " %s", file);
169 break;
170 #endif /* HAVE_MACRO_S_IFDOOR */
171 #ifdef S_IFPORT
172 case (S_IFPORT>>12): /* 14, event port (Solaris) */
173 fputs("event_port", outfile);
174 if (file) fprintf(outfile, " %s", file);
175 break;
176 #endif /* HAVE_MACRO_S_IFPORT */
178 /* ioctl() */
179 fputc('\n', outfile);
181 return 0;
185 /* character device analysis */
186 /* return -1 on error, 0 if no name was found, or 1 if it printed ttyname */
187 int cdevname(int fd, FILE *outfile) {
188 int ret;
190 if ((ret = Isatty(fd)) < 0) {
191 Error2("isatty(%d): %s", fd, strerror(errno));
192 return -1;
194 if (ret > 0) {
195 char *name;
197 fputs("tty", outfile);
198 if ((name = Ttyname(fd)) != NULL) {
199 fputc(' ', outfile);
200 fputs(name, outfile);
201 return 1;
203 } else {
204 fputs("chrdev", outfile);
206 return 0;
209 int sockettype(int socktype, char *typename, size_t typenamemax) {
210 switch (socktype) {
211 case SOCK_STREAM: strncpy(typename, "stream", typenamemax); break;
212 case SOCK_DGRAM: strncpy(typename, "dgram", typenamemax); break;
213 case SOCK_SEQPACKET: strncpy(typename, "seqpacket", typenamemax); break;
214 case SOCK_RAW: strncpy(typename, "raw", typenamemax); break;
215 case SOCK_RDM: strncpy(typename, "rdm", typenamemax); break;
216 #ifdef SOCK_PACKET
217 case SOCK_PACKET: strncpy(typename, "packet", typenamemax); break;
218 #endif
219 default: snprintf(typename, typenamemax, "socktype%u", socktype); break;
221 return 0;
224 #if _WITH_SOCKET
225 int sockname(int fd, FILE *outfile, char style) {
226 #define FDNAME_OPTLEN 256
227 #define FDNAME_NAMELEN 256
228 socklen_t optlen;
229 #if HAVE_GETPROTOBYNUMBER || HAVE_GETPROTOBYNUMBER_R
230 struct protoent protoent, *protoentp;
231 #endif
232 #define PROTONAMEMAX 1024
233 char protoname[PROTONAMEMAX] = "";
234 #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
235 int proto = 0;
236 #endif
237 int opttype;
238 #ifdef SO_ACCEPTCONN
239 int optacceptconn = 0; /* OpenBSD does not give value on unix dgram */
240 #endif
241 int result /*0, i*/;
242 char socknamebuff[FDNAME_NAMELEN];
243 char peernamebuff[FDNAME_NAMELEN];
244 /* in Linux these optcodes are 'enum', but on AIX they are bits! */
245 union sockaddr_union sockname, peername; /* the longest I know of */
246 socklen_t socknamelen, peernamelen;
247 # define TYPENAMEMAX 16
248 char typename[TYPENAMEMAX];
249 #if 0 && defined(SIOCGIFNAME)
250 /*Linux struct ifreq ifc = {{{ 0 }}};*/
251 struct ifreq ifc = {{ 0 }};
252 #endif
253 int rc;
255 #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
256 optlen = sizeof(proto);
257 #ifdef SO_PROTOCOL
258 rc = Getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &optlen);
259 #elif defined(SO_PROTOTYPE)
260 rc = Getsockopt(fd, SOL_SOCKET, SO_PROTOTYPE, &proto, &optlen);
261 #endif
262 if (rc < 0) {
263 Notice5("getsocktop(%d, SOL_SOCKET, "
264 #ifdef SO_PROTOCOL
265 "SO_PROTOCOL"
266 #else
267 "SO_PROTOTYPE"
268 #endif
269 ", &%p, {"F_socklen"}): errno=%d (%s)", fd, &proto, optlen, errno, strerror(errno));
271 #endif /* defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) */
272 optlen = sizeof(opttype);
273 Getsockopt(fd, SOL_SOCKET, SO_TYPE, &opttype, &optlen);
274 sockettype(opttype, typename, sizeof(typename));
276 optlen = sizeof(optacceptconn);
277 #ifdef SO_ACCEPTCONN
278 Getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &optacceptconn, &optlen);
279 #endif
281 #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
282 #if HAVE_GETPROTOBYNUMBER_R==1 /* Linux */
283 rc = getprotobynumber_r(proto, &protoent, protoname, sizeof(protoname), &protoentp);
284 if (protoentp == NULL) {
285 Warn2("sockname(): getprotobynumber_r(proto=%d, ...): %s",
286 proto, strerror(rc));
288 strncpy(protoname, protoentp->p_name, sizeof(protoname));
289 #elif HAVE_GETPROTOBYNUMBER_R==2 /* Solaris */
291 # define FILAN_GETPROTOBYNUMBER_R_BUFLEN 1024
292 char buffer[FILAN_GETPROTOBYNUMBER_R_BUFLEN];
293 protoentp = getprotobynumber_r(proto, &protoent, buffer, FILAN_GETPROTOBYNUMBER_R_BUFLEN);
294 strncpy(protoname, protoentp->p_name, sizeof(protoname));
296 #elif HAVE_GETPROTOBYNUMBER_R==3 /* AIX, OpenBSD */
298 struct protoent_data proto_data = { 0 }; /* OpenBSD might SIGSEGV */
299 rc = getprotobynumber_r(proto, &protoent, &proto_data);
300 if (rc == 0) {
301 strncpy(protoname, protoent.p_name, sizeof(protoname));
302 endprotoent_r(&proto_data);
305 #else
306 switch (proto) {
307 case IPPROTO_TCP: strcpy(protoname, "tcp"); break;
308 case IPPROTO_UDP: strcpy(protoname, "udp"); break;
309 case IPPROTO_SCTP: strcpy(protoname, "sctp"); break;
310 default: sprintf(protoname, "proto%d", proto); break;
312 #endif
313 #else /* ! (defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)) */
314 if (opttype == SOCK_STREAM) {
315 strcpy(protoname, "(stream)");
316 } else if (opttype == SOCK_DGRAM) {
317 strcpy(protoname, "(dgram)");
318 #ifdef SOCK_RAW
319 } else if (opttype == SOCK_RAW) {
320 strcpy(protoname, "(raw)");
321 #endif
322 #ifdef SOCK_RDM
323 } else if (opttype == SOCK_RDM) {
324 strcpy(protoname, "(rdm)");
325 #endif
326 #ifdef SOCK_SEQPACKET
327 } else if (opttype == SOCK_SEQPACKET) {
328 strcpy(protoname, "(seqpacket)");
329 #endif
330 #ifdef SOCK_DCCP
331 } else if (opttype == SOCK_DCCP) {
332 strcpy(protoname, "(dccp)");
333 #endif
334 #ifdef SOCK_PACKET
335 } else if (opttype == SOCK_PACKET) {
336 strcpy(protoname, "(packet)");
337 #endif
338 } else {
339 strcpy(protoname, "socket");
341 #endif /* ! (defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)) */
342 socknamelen = sizeof(sockname);
343 result = Getsockname(fd, &sockname.soa, &socknamelen);
344 if (result < 0) {
345 Error2("getsockname(%d): %s", fd, strerror(errno));
346 return -1;
349 peernamelen = sizeof(peername);
350 result = Getpeername(fd, (struct sockaddr *)&peername, &peernamelen);
351 if (result < 0) {
352 Warn2("getpeername(%d): %s", fd, strerror(errno));
355 switch (sockname.soa.sa_family) {
356 #if WITH_UNIX
357 case AF_UNIX:
358 switch (style) {
359 case 's':
360 fprintf(outfile, "unix%s%s %s",
361 opttype==SOCK_DGRAM?"datagram":"",
362 #ifdef SO_ACCEPTCONN
363 optacceptconn?"(listening)":
364 #endif
366 sockaddr_unix_info(&sockname.un, socknamelen,
367 socknamebuff, sizeof(socknamebuff)));
368 break;
369 case 'S':
370 /* sockettype(opttype, typename, TYPENAMEMAX); */
371 fprintf(outfile, "unix %s-%s %s %s",
372 sockaddr_unix_info(&sockname.un, socknamelen,
373 socknamebuff, sizeof(socknamebuff)),
374 sockaddr_unix_info(&peername.un, peernamelen,
375 peernamebuff, sizeof(peernamebuff)),
376 typename,
377 #ifdef SO_ACCEPTCONN
378 optacceptconn?"(listening)":
379 #endif
380 "");
381 break;
383 break;
384 #endif /* WITH_UNIX */
385 #if WITH_IP4
386 case AF_INET:
387 switch (style) {
388 case 's':
389 switch (opttype) {
390 #if WITH_TCP
391 case SOCK_STREAM:
392 fprintf(outfile, "%s%s %s %s",
393 protoname,
394 #ifdef SO_ACCEPTCONN
395 optacceptconn?"(listening)":
396 #endif
398 sockaddr_inet4_info(&sockname.ip4,
399 socknamebuff, sizeof(socknamebuff)),
400 sockaddr_inet4_info(&peername.ip4,
401 peernamebuff, sizeof(peernamebuff)));
402 break;
403 #endif
404 #if WITH_UDP
405 case SOCK_DGRAM:
406 fprintf(outfile, "%s%s %s %s",
407 protoname,
408 #ifdef SO_ACCEPTCONN
409 optacceptconn?"(listening)":
410 #endif
412 sockaddr_inet4_info(&sockname.ip4,
413 socknamebuff, sizeof(socknamebuff)),
414 sockaddr_inet4_info(&peername.ip4,
415 peernamebuff, sizeof(peernamebuff)));
416 break;
417 #endif
418 default:
419 fprintf(outfile, "ip %s",
420 sockaddr_inet4_info(&sockname.ip4,
421 socknamebuff, sizeof(socknamebuff)));
422 break;
424 break;
425 case 'S':
426 fprintf(outfile, "%s %s-%s (%s) %s",
427 protoname,
428 sockaddr_inet4_info(&sockname.ip4,
429 socknamebuff, sizeof(socknamebuff)),
430 sockaddr_inet4_info(&peername.ip4,
431 peernamebuff, sizeof(peernamebuff)),
432 typename,
433 #ifdef SO_ACCEPTCONN
434 optacceptconn?"(listening)":
435 #endif
436 "");
437 break;
439 break;
440 #endif /* WITH_IP4 */
442 #if WITH_IP6
443 case AF_INET6:
444 switch (style) {
445 case 's':
446 switch (opttype) {
447 #if WITH_TCP
448 case SOCK_STREAM:
449 fprintf(outfile, "%s6%s %s %s",
450 protoname,
451 #ifdef SO_ACCEPTCONN
452 optacceptconn?"(listening)":
453 #endif
455 sockaddr_inet6_info(&sockname.ip6,
456 socknamebuff, sizeof(socknamebuff)),
457 sockaddr_inet6_info(&peername.ip6,
458 peernamebuff, sizeof(peernamebuff)));
459 break;
460 #endif
461 #if WITH_UDP
462 case SOCK_DGRAM:
463 fprintf(outfile, "%s6%s %s %s",
464 protoname,
465 #ifdef SO_ACCEPTCONN
466 optacceptconn?"(listening)":
467 #endif
469 sockaddr_inet6_info(&sockname.ip6,
470 socknamebuff, sizeof(socknamebuff)),
471 sockaddr_inet6_info(&peername.ip6,
472 peernamebuff, sizeof(peernamebuff)));
473 break;
474 #endif
475 default:
476 fprintf(outfile, "ip6 %s",
477 sockaddr_inet6_info(&sockname.ip6,
478 socknamebuff, sizeof(socknamebuff)));
479 break;
481 break;
482 case 'S':
483 fprintf(outfile, "%s6 %s-%s (%s) %s",
484 protoname,
485 sockaddr_inet6_info(&sockname.ip6,
486 socknamebuff, sizeof(socknamebuff)),
487 sockaddr_inet6_info(&peername.ip6,
488 peernamebuff, sizeof(peernamebuff)),
489 typename,
490 #ifdef SO_ACCEPTCONN
491 optacceptconn?"(listening)":
492 #endif
493 "");
494 break;
496 break;
497 #endif /* WITH_IP6 */
499 default:
500 fprintf(outfile, "socket(family/domain=%d)", sockname.soa.sa_family);
503 #if HAVE_GETPROTOENT
504 if (ipproto >= 0) {
505 endprotoent();
507 #endif
508 return result;
509 #undef FDNAME_OPTLEN
510 #undef FDNAME_NAMELEN
512 #endif /* _WITH_SOCKET */