[git commit] netstat, pscan: don't use getservbyport(), it links in a static buffer

Denys Vlasenko vda.linux at googlemail.com
Tue Feb 24 21:42:30 UTC 2026


commit: https://git.busybox.net/busybox/commit/?id=c0037a997420886ea9cc295a7cd76d0955064c88
branch: https://git.busybox.net/busybox/log/?h=master

function                                             old     new   delta
bb_get_servname_by_port                                -     182    +182
ip_port_str                                          112     121      +9
pscan_main                                           594     591      -3
getservbyport                                         53       -     -53
getservbyport_r                                      430       -    -430
------------------------------------------------------------------------------
(add/remove: 2/4 grow/shrink: 1/1 up/down: 191/-486)         Total: -295 bytes
   text	   data	    bss	    dec	    hex	filename
1080362	    555	   5056	1085973	 109215	busybox_old
1080067	    555	   5024	1085646	 1090ce	busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 include/libbb.h                 |  3 +++
 libbb/bb_get_servname_by_port.c | 48 +++++++++++++++++++++++++++++++++++++++++
 networking/netstat.c            | 11 +++++-----
 networking/pscan.c              | 12 ++++++-----
 4 files changed, 64 insertions(+), 10 deletions(-)

diff --git a/include/libbb.h b/include/libbb.h
index df974e3fc..f02d2c756 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -911,6 +911,9 @@ char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa) FAST_FUNC RETU
 /* inet_[ap]ton on steroids */
 char* xmalloc_sockaddr2dotted(const struct sockaddr *sa) FAST_FUNC RETURNS_MALLOC;
 char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa) FAST_FUNC RETURNS_MALLOC;
+// NB: unlike getservbyport, port paramenter is NOT in network order
+#define getservbyport dont_use_getservbyport_uses_global_buffer
+char* bb_get_servname_by_port(char **p_etc_services, int port, const char *type) FAST_FUNC RETURNS_MALLOC;
 // "old" (ipv4 only) API
 // users: traceroute.c hostname.c - use _list_ of all IPs
 struct hostent *xgethostbyname(const char *name) FAST_FUNC;
diff --git a/libbb/bb_get_servname_by_port.c b/libbb/bb_get_servname_by_port.c
new file mode 100644
index 000000000..d8ba55226
--- /dev/null
+++ b/libbb/bb_get_servname_by_port.c
@@ -0,0 +1,48 @@
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2026 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+//kbuild:lib-$(CONFIG_NETSTAT) += bb_get_servname_by_port.o
+//kbuild:lib-$(CONFIG_PSCAN) += bb_get_servname_by_port.o
+#include "libbb.h"
+
+char* FAST_FUNC bb_get_servname_by_port(char **p_etc_services, int port, const char *type)
+{
+	char *sp;
+
+	sp = *p_etc_services;
+	if (!sp) {
+//TODO: we need mmap_entire_file() for this use case!
+		sp = xmalloc_open_read_close("/etc/services", NULL);
+		if (!sp)
+			return NULL;
+		*p_etc_services = sp;
+	}
+	while (*sp) {
+		const char *portstr, *sp_end;
+		char *end;
+		unsigned portnum;
+
+		sp = skip_whitespace(sp);
+		if (*sp == '#')
+			goto next;
+		sp_end = skip_non_whitespace(sp);
+		portstr = skip_whitespace(sp_end);
+		portnum = bb_strtou(portstr, &end, 10);
+		if (portnum != port || *end != '/')
+			goto next;
+		if (type) {
+			end++;
+			end = is_prefixed_with(end, type);
+			if (!end || !(isspace(*end) || *end == '\0'))
+				goto next;
+		}
+		return auto_string(xstrndup(sp, sp_end - sp));
+ next:
+		sp = strchrnul(sp, '\n');
+	}
+	return NULL;
+}
diff --git a/networking/netstat.c b/networking/netstat.c
index d7afa8fdd..80d94221b 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -176,6 +176,7 @@ struct globals {
 	smallint prg_cache_loaded;
 	struct prg_node *prg_hash[PRG_HASH_SIZE];
 #endif
+	char **p_etc_services;
 #if ENABLE_FEATURE_NETSTAT_PRG
 	const char *progname_banner;
 #endif
@@ -378,15 +379,15 @@ static void build_ipv4_addr(char* local_addr, struct sockaddr_in* localaddr)
 
 static const char *get_sname(int port, const char *proto, int numeric)
 {
-	if (!port)
+	if (port == 0)
 		return "*";
 	if (!numeric) {
-		struct servent *se = getservbyport(port, proto);
+		const char *se = bb_get_servname_by_port(G.p_etc_services, port, proto);
 		if (se)
-			return se->s_name;
+			return se;
 	}
 	/* hummm, we may return static buffer here!! */
-	return itoa(ntohs(port));
+	return itoa(port);
 }
 
 static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int numeric)
@@ -402,7 +403,7 @@ static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int
 	if (!host)
 		host = xmalloc_sockaddr2dotted_noport(addr);
 
-	xasprintf_inplace(host, "%s:%s", host, get_sname(htons(port), proto, numeric));
+	xasprintf_inplace(host, "%s:%s", host, get_sname(port, proto, numeric));
 	return host;
 }
 
diff --git a/networking/pscan.c b/networking/pscan.c
index 13785deca..454dba3fb 100644
--- a/networking/pscan.c
+++ b/networking/pscan.c
@@ -37,13 +37,13 @@
 #define DERR(...) ((void)0)
 #endif
 
-static const char *port_name(unsigned port)
+static const char *port_name(char **p_etc_services, unsigned port)
 {
-	struct servent *server;
+	char *server;
 
-	server = getservbyport(htons(port), NULL);
+	server = bb_get_servname_by_port(p_etc_services, port, NULL);
 	if (server)
-		return server->s_name;
+		return server;
 	return "unknown";
 }
 
@@ -62,6 +62,7 @@ int pscan_main(int argc UNUSED_PARAM, char **argv)
 	 * Rule of thumb: with min_rtt of N msec, scanning 1000 ports
 	 * will take N seconds at absolute minimum */
 	const char *opt_min_rtt = "5";          /* -T: default min rtt in msec */
+	char *p_etc_services = NULL;
 	const char *result_str;
 	len_and_sockaddr *lsap;
 	int s;
@@ -152,7 +153,8 @@ int pscan_main(int argc UNUSED_PARAM, char **argv)
 		DMSG("out of loop @%u", diff);
 		if (result_str)
 			printf("%5u" "\t" "tcp" "\t" "%s" "\t" "%s" "\n",
-					port, result_str, port_name(port));
+				port, result_str, port_name(&p_etc_services, port)
+			);
 
 		/* Estimate new rtt - we don't want to wait entire timeout
 		 * for each port. *4 allows for rise in net delay.


More information about the busybox-cvs mailing list