Make getfdproto return enum instead of string

Introduce a new enum type sock_proto and use it instead of strings for socket
protocols identification.

* defs.h (sock_proto): New enum.
(get_proto_by_name): New function.
* socketutils.c (protocols): New static table.
(print_sockaddr_by_inode): Use it.  Change type of "proto" argument
to sock_proto.
(get_proto_by_name): New function.
* util.c (getfdproto): Use it.  Change return type to sock_proto.
(printfd): Update.
This commit is contained in:
Fabien Siron 2016-06-17 16:29:53 +00:00 committed by Dmitry V. Levin
parent cb7409c87a
commit 802cc28f39
3 changed files with 62 additions and 34 deletions

13
defs.h
View File

@ -437,6 +437,17 @@ extern const struct xlat whence_codes[];
# define NEED_UID16_PARSERS 0
#endif
enum sock_proto {
SOCK_PROTO_UNKNOWN,
SOCK_PROTO_UNIX,
SOCK_PROTO_TCP,
SOCK_PROTO_UDP,
SOCK_PROTO_TCPv6,
SOCK_PROTO_UDPv6,
SOCK_PROTO_NETLINK
};
extern enum sock_proto get_proto_by_name(const char *);
typedef enum {
CFLAG_NONE = 0,
CFLAG_ONLY_STATS,
@ -636,7 +647,7 @@ extern void printpathn(struct tcb *, long, unsigned int);
#define TIMESPEC_TEXT_BUFSIZE \
(sizeof(intmax_t)*3 * 2 + sizeof("{tv_sec=%jd, tv_nsec=%jd}"))
extern void printfd(struct tcb *, int);
extern bool print_sockaddr_by_inode(const unsigned long, const char *);
extern bool print_sockaddr_by_inode(const unsigned long, const enum sock_proto);
extern bool print_sockaddr_by_inode_cached(const unsigned long);
extern void print_dirfd(struct tcb *, int);
extern void printsock(struct tcb *, long, int);

View File

@ -438,44 +438,59 @@ netlink_print(const int fd, const unsigned long inode)
netlink_parse_response);
}
static const struct {
const char *const name;
bool (*const print)(int, unsigned long);
} protocols[] = {
[SOCK_PROTO_UNIX] = { "UNIX", unix_print },
[SOCK_PROTO_TCP] = { "TCP", tcp_v4_print },
[SOCK_PROTO_UDP] = { "UDP", udp_v4_print },
[SOCK_PROTO_TCPv6] = { "TCPv6", tcp_v6_print },
[SOCK_PROTO_UDPv6] = { "UDPv6", udp_v6_print },
[SOCK_PROTO_NETLINK] = { "NETLINK", netlink_print }
};
enum sock_proto
get_proto_by_name(const char *const name)
{
unsigned int i;
for (i = (unsigned int) SOCK_PROTO_UNKNOWN + 1;
i < ARRAY_SIZE(protocols); ++i) {
if (protocols[i].name && !strcmp(name, protocols[i].name))
return (enum sock_proto) i;
}
return SOCK_PROTO_UNKNOWN;
}
/* Given an inode number of a socket, print out the details
* of the ip address and port. */
bool
print_sockaddr_by_inode(const unsigned long inode, const char *const proto_name)
print_sockaddr_by_inode(const unsigned long inode, const enum sock_proto proto)
{
static const struct {
const char *const name;
bool (*const print)(int, unsigned long);
} protocols[] = {
{ "TCP", tcp_v4_print },
{ "UDP", udp_v4_print },
{ "TCPv6", tcp_v6_print },
{ "UDPv6", udp_v6_print },
{ "UNIX", unix_print },
{ "NETLINK", netlink_print }
};
if ((unsigned int) proto >= ARRAY_SIZE(protocols) ||
(proto != SOCK_PROTO_UNKNOWN && !protocols[proto].print))
return false;
const int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
if (fd < 0)
return false;
bool r = false;
unsigned int i;
if (proto_name) {
for (i = 0; i < ARRAY_SIZE(protocols); ++i) {
if (strcmp(proto_name, protocols[i].name) == 0) {
r = protocols[i].print(fd, inode);
break;
}
}
if (proto != SOCK_PROTO_UNKNOWN) {
r = protocols[proto].print(fd, inode);
if (!r) {
tprintf("%s:[%lu]", proto_name, inode);
tprintf("%s:[%lu]", protocols[proto].name, inode);
r = true;
}
} else {
for (i = 0; i < ARRAY_SIZE(protocols); ++i) {
if ((r = protocols[i].print(fd, inode)))
unsigned int i;
for (i = (unsigned int) SOCK_PROTO_UNKNOWN + 1;
i < ARRAY_SIZE(protocols); ++i) {
if (!protocols[i].print)
continue;
r = protocols[i].print(fd, inode);
if (r)
break;
}
}

20
util.c
View File

@ -472,30 +472,33 @@ sprinttime(time_t t)
return buf;
}
static char *
getfdproto(struct tcb *tcp, int fd, char *buf, unsigned bufsize)
static enum sock_proto
getfdproto(struct tcb *tcp, int fd)
{
#ifdef HAVE_SYS_XATTR_H
size_t bufsize = 256;
char buf[bufsize];
ssize_t r;
char path[sizeof("/proc/%u/fd/%u") + 2 * sizeof(int)*3];
if (fd < 0)
return NULL;
return SOCK_PROTO_UNKNOWN;
sprintf(path, "/proc/%u/fd/%u", tcp->pid, fd);
r = getxattr(path, "system.sockprotoname", buf, bufsize - 1);
if (r <= 0)
return NULL;
return SOCK_PROTO_UNKNOWN;
else {
/*
* This is a protection for the case when the kernel
* side does not append a null byte to the buffer.
*/
buf[r] = '\0';
return buf;
return get_proto_by_name(buf);
}
#else
return NULL;
return SOCK_PROTO_UNKNOWN;
#endif
}
@ -516,9 +519,8 @@ printfd(struct tcb *tcp, int fd)
strtoul(path + socket_prefix_len, NULL, 10);
if (!print_sockaddr_by_inode_cached(inode)) {
char buf[256];
const char *proto =
getfdproto(tcp, fd, buf, sizeof(buf));
const enum sock_proto proto =
getfdproto(tcp, fd);
if (!print_sockaddr_by_inode(inode, proto))
tprints(path);
}