Check which getprotobynumber_r() variant to use
[socat.git] / fdname.c
blobee1d5ce7868b897e36117d584c34209ded515b6a
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
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"/fd/%d", pid, fd);
95 if ((len = Readlink(procpath, filepath, pathsize-1)) < 0) {
96 Error4("readlink(\"%s\", %p, "F_Zu"): %s",
97 procpath, filepath, pathsize, strerror(errno));
98 return -1;
100 filepath[len] = '\0';
101 return 0;
103 #endif /* HAVE_PROC_DIR_FD */
105 int statname(const char *file, int fd, int filetype, FILE *outfile,
106 char style) {
107 char filepath[PATH_MAX];
109 filepath[0] = '\0';
110 #if HAVE_PROC_DIR_FD
111 if (fd >= 0) {
112 procgetfdname(fd, filepath, sizeof(filepath));
113 if (filepath[0] == '/') {
114 file = filepath;
117 #endif /* HAVE_PROC_DIR_FD */
118 /* now see for type specific infos */
119 switch (filetype) {
120 case (S_IFIFO>>12): /* 1, FIFO */
121 fputs("pipe", outfile);
122 if (file) fprintf(outfile, " %s", file);
123 break;
124 case (S_IFCHR>>12): /* 2, character device */
125 if (cdevname(fd, outfile) == 0) {
126 if (file) fprintf(outfile, " %s", file);
128 break;
129 case (S_IFDIR>>12): /* 4, directory */
130 fputs("dir", outfile);
131 if (file) fprintf(outfile, " %s", file);
132 break;
133 case (S_IFBLK>>12): /* 6, block device */
134 fputs("blkdev", outfile);
135 if (file) fprintf(outfile, " %s", file);
136 break;
137 case (S_IFREG>>12): /* 8, regular file */
138 fputs("file", outfile);
139 if (file) fprintf(outfile, " %s", file);
140 break;
141 case (S_IFLNK>>12): /* 10, symbolic link */
142 fputs("link", outfile);
143 if (file) fprintf(outfile, " %s", file);
144 break;
145 case (S_IFSOCK>>12): /* 12, socket */
146 #if _WITH_SOCKET
147 if (fd >= 0) {
148 sockname(fd, outfile, style);
149 } else if (file) {
150 fprintf(outfile, "socket %s", file);
151 } else {
152 fputs("socket", outfile);
154 #else
155 Error("SOCKET support not compiled in");
156 return -1;
157 #endif /* !_WITH_SOCKET */
158 break;
160 /* ioctl() */
161 fputc('\n', outfile);
163 return 0;
167 /* character device analysis */
168 /* return -1 on error, 0 if no name was found, or 1 if it printed ttyname */
169 int cdevname(int fd, FILE *outfile) {
170 int ret;
172 if ((ret = Isatty(fd)) < 0) {
173 Error2("isatty(%d): %s", fd, strerror(errno));
174 return -1;
176 if (ret > 0) {
177 char *name;
179 fputs("tty", outfile);
180 if ((name = Ttyname(fd)) != NULL) {
181 fputc(' ', outfile);
182 fputs(name, outfile);
183 return 1;
185 } else {
186 fputs("chrdev", outfile);
188 return 0;
191 int sockettype(int socktype, char *typename, size_t typenamemax) {
192 switch (socktype) {
193 case SOCK_STREAM: strncpy(typename, "stream", typenamemax); break;
194 case SOCK_DGRAM: strncpy(typename, "dgram", typenamemax); break;
195 case SOCK_SEQPACKET: strncpy(typename, "seqpacket", typenamemax); break;
196 case SOCK_RAW: strncpy(typename, "raw", typenamemax); break;
197 case SOCK_RDM: strncpy(typename, "rdm", typenamemax); break;
198 #ifdef SOCK_PACKET
199 case SOCK_PACKET: strncpy(typename, "packet", typenamemax); break;
200 #endif
201 default: snprintf(typename, typenamemax, "socktype%u", socktype); break;
203 return 0;
206 #if _WITH_SOCKET
207 int sockname(int fd, FILE *outfile, char style) {
208 #define FDNAME_OPTLEN 256
209 #define FDNAME_NAMELEN 256
210 socklen_t optlen;
211 #if HAVE_GETPROTOBYNUMBER || HAVE_GETPROTOBYNUMBER_R
212 struct protoent protoent, *protoentp;
213 #endif
214 #define PROTONAMEMAX 1024
215 char protoname[PROTONAMEMAX];
216 #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
217 int proto;
218 #endif
219 int opttype;
220 #ifdef SO_ACCEPTCONN
221 int optacceptconn;
222 #endif
223 int result /*0, i*/;
224 char socknamebuff[FDNAME_NAMELEN];
225 char peernamebuff[FDNAME_NAMELEN];
226 /* in Linux these optcodes are 'enum', but on AIX they are bits! */
227 union sockaddr_union sockname, peername; /* the longest I know of */
228 socklen_t socknamelen, peernamelen;
229 # define TYPENAMEMAX 16
230 char typename[TYPENAMEMAX];
231 #if 0 && defined(SIOCGIFNAME)
232 /*Linux struct ifreq ifc = {{{ 0 }}};*/
233 struct ifreq ifc = {{ 0 }};
234 #endif
235 int rc;
237 #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
238 optlen = sizeof(proto);
239 #ifdef SO_PROTOCOL
240 Getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &optlen);
241 #elif defined(SO_PROTOTYPE)
242 Getsockopt(fd, SOL_SOCKET, SO_PROTOTYPE, &proto, &optlen);
243 #endif
244 #endif /* defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) */
246 optlen = sizeof(opttype);
247 Getsockopt(fd, SOL_SOCKET, SO_TYPE, &opttype, &optlen);
248 sockettype(opttype, typename, sizeof(typename));
250 optlen = sizeof(optacceptconn);
251 #ifdef SO_ACCEPTCONN
252 Getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &optacceptconn, &optlen);
253 #endif
255 #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
256 #if HAVE_GETPROTOBYNUMBER_R==1 /* Linux */
257 rc = getprotobynumber_r(proto, &protoent, protoname, sizeof(protoname), &protoentp);
258 if (protoentp == NULL) {
259 Warn2("sockname(): getprotobynumber_r(proto=%d, ...): %s",
260 proto, strerror(rc));
262 strncpy(protoname, protoentp->p_name, sizeof(protoname));
263 #elif HAVE_GETPROTOBYNUMBER_R==2 /* Solaris */
264 protoentp = getprotobynumber(proto);
265 strncpy(protoname, protoentp->p_name, sizeof(protoname));
266 #else
267 switch (proto) {
268 case IPPROTO_TCP: strcpy(protoname, "tcp"); break;
269 case IPPROTO_UDP: strcpy(protoname, "udp"); break;
270 case IPPROTO_SCTP: strcpy(protoname, "sctp"); break;
271 default: sprintf(protoname, "proto%d", proto); break;
273 #endif
274 #else
275 if (opttype == SOCK_STREAM) {
276 strcpy(protoname, "tcp");
277 } else if (opttype == SOCK_DGRAM) {
278 strcpy(protoname, "udp");
279 } else {
280 strcpy(protoname, "socket");
282 #endif /* defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) */
283 socknamelen = sizeof(sockname);
284 result = Getsockname(fd, &sockname.soa, &socknamelen);
285 if (result < 0) {
286 Error2("getsockname(%d): %s", fd, strerror(errno));
287 return -1;
290 peernamelen = sizeof(peername);
291 result = Getpeername(fd, (struct sockaddr *)&peername, &peernamelen);
292 if (result < 0) {
293 Warn2("getpeername(%d): %s", fd, strerror(errno));
296 switch (sockname.soa.sa_family) {
297 #if WITH_UNIX
298 case AF_UNIX:
299 switch (style) {
300 case 's':
301 fprintf(outfile, "unix%s%s %s",
302 opttype==SOCK_DGRAM?"datagram":"",
303 #ifdef SO_ACCEPTCONN
304 optacceptconn?"(listening)":
305 #endif
307 sockaddr_unix_info(&sockname.un, socknamelen,
308 socknamebuff, sizeof(socknamebuff)));
309 break;
310 case 'S':
311 //sockettype(opttype, typename, TYPENAMEMAX);
312 fprintf(outfile, "unix %s-%s %s %s",
313 sockaddr_unix_info(&sockname.un, socknamelen,
314 socknamebuff, sizeof(socknamebuff)),
315 sockaddr_unix_info(&peername.un, peernamelen,
316 peernamebuff, sizeof(peernamebuff)),
317 typename,
318 #ifdef SO_ACCEPTCONN
319 optacceptconn?"(listening)":
320 #endif
321 "");
322 break;
324 break;
325 #endif /* WITH_UNIX */
326 #if WITH_IP4
327 case AF_INET:
328 switch (style) {
329 case 's':
330 switch (opttype) {
331 #if WITH_TCP
332 case SOCK_STREAM:
333 fprintf(outfile, "%s%s %s %s",
334 protoname,
335 #ifdef SO_ACCEPTCONN
336 optacceptconn?"(listening)":
337 #endif
339 sockaddr_inet4_info(&sockname.ip4,
340 socknamebuff, sizeof(socknamebuff)),
341 sockaddr_inet4_info(&peername.ip4,
342 peernamebuff, sizeof(peernamebuff)));
343 break;
344 #endif
345 #if WITH_UDP
346 case SOCK_DGRAM:
347 fprintf(outfile, "%s%s %s %s",
348 protoname,
349 #ifdef SO_ACCEPTCONN
350 optacceptconn?"(listening)":
351 #endif
353 sockaddr_inet4_info(&sockname.ip4,
354 socknamebuff, sizeof(socknamebuff)),
355 sockaddr_inet4_info(&peername.ip4,
356 peernamebuff, sizeof(peernamebuff)));
357 break;
358 #endif
359 default:
360 fprintf(outfile, "ip %s",
361 sockaddr_inet4_info(&sockname.ip4,
362 socknamebuff, sizeof(socknamebuff)));
363 break;
365 break;
366 case 'S':
367 fprintf(outfile, "%s %s-%s (%s) %s",
368 protoname,
369 sockaddr_inet4_info(&sockname.ip4,
370 socknamebuff, sizeof(socknamebuff)),
371 sockaddr_inet4_info(&peername.ip4,
372 peernamebuff, sizeof(peernamebuff)),
373 typename,
374 #ifdef SO_ACCEPTCONN
375 optacceptconn?"(listening)":
376 #endif
377 "");
378 break;
380 break;
381 #endif /* WITH_IP4 */
383 #if WITH_IP6
384 case AF_INET6:
385 switch (style) {
386 case 's':
387 switch (opttype) {
388 #if WITH_TCP
389 case SOCK_STREAM:
390 fprintf(outfile, "%s6%s %s %s",
391 protoname,
392 #ifdef SO_ACCEPTCONN
393 optacceptconn?"(listening)":
394 #endif
396 sockaddr_inet6_info(&sockname.ip6,
397 socknamebuff, sizeof(socknamebuff)),
398 sockaddr_inet6_info(&peername.ip6,
399 peernamebuff, sizeof(peernamebuff)));
400 break;
401 #endif
402 #if WITH_UDP
403 case SOCK_DGRAM:
404 fprintf(outfile, "%s6%s %s %s",
405 protoname,
406 #ifdef SO_ACCEPTCONN
407 optacceptconn?"(listening)":
408 #endif
410 sockaddr_inet6_info(&sockname.ip6,
411 socknamebuff, sizeof(socknamebuff)),
412 sockaddr_inet6_info(&peername.ip6,
413 peernamebuff, sizeof(peernamebuff)));
414 break;
415 #endif
416 default:
417 fprintf(outfile, "ip6 %s",
418 sockaddr_inet6_info(&sockname.ip6,
419 socknamebuff, sizeof(socknamebuff)));
420 break;
422 break;
423 case 'S':
424 fprintf(outfile, "%s6 %s-%s (%s) %s",
425 protoname,
426 sockaddr_inet6_info(&sockname.ip6,
427 socknamebuff, sizeof(socknamebuff)),
428 sockaddr_inet6_info(&peername.ip6,
429 peernamebuff, sizeof(peernamebuff)),
430 typename,
431 #ifdef SO_ACCEPTCONN
432 optacceptconn?"(listening)":
433 #endif
434 "");
435 break;
437 break;
438 #endif /* WITH_IP6 */
440 default:
441 fprintf(outfile, "socket(family/domain=%d)", sockname.soa.sa_family);
444 #if HAVE_GETPROTOENT
445 if (ipproto >= 0) {
446 endprotoent();
448 #endif
449 return result;
450 #undef FDNAME_OPTLEN
451 #undef FDNAME_NAMELEN
453 #endif /* _WITH_SOCKET */