git: 4907d1c5c7f9 - main - ctld: Normalize physical port names

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Sat, 27 Jun 2026 16:07:08 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=4907d1c5c7f97ca985611441df5871705b90030c

commit 4907d1c5c7f97ca985611441df5871705b90030c
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2026-06-25 16:21:25 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2026-06-27 16:01:55 +0000

    ctld: Normalize physical port names
    
    Don't require ioctl port names to be fully expanded as this
    contradicts the syntax documented in the ctl.conf(5).  However, don't
    require users to exactly guess when pp or vp can be omitted.  Instead,
    normalize all physical port names by parsing any port name with a pp
    or vp value and reformatting them to a standardized format.  This
    format is also used when generating names for kernel-enumerated ports.
    
    Reported by:    Seth Hoffert <seth.hoffert@gmail.com>
    Fixes:          caef3c50ac06 ("ctld: Refactor ioctl port handling")
    Sponsored by:   Chelsio Communications
---
 usr.sbin/ctld/ctld.cc   | 61 +++++++++++++++++++++++++++++++++++++++++--------
 usr.sbin/ctld/kernel.cc |  5 +---
 2 files changed, 52 insertions(+), 14 deletions(-)

diff --git a/usr.sbin/ctld/ctld.cc b/usr.sbin/ctld/ctld.cc
index 834bef4ef363..19baa0486e44 100644
--- a/usr.sbin/ctld/ctld.cc
+++ b/usr.sbin/ctld/ctld.cc
@@ -53,6 +53,7 @@
 #include <cam/scsi/scsi_all.h>
 
 #include <algorithm>
+#include <charconv>
 #include <libutil++.hh>
 
 #include "conf.h"
@@ -1378,17 +1379,55 @@ target::set_auth_type(const char *type)
 bool
 target::add_physical_port(std::string_view pport)
 {
-	/* Normalize ioctl port names. */
+	/* Normalize port names. */
 	std::string pname;
-	if (pport.compare(0, strlen("ioctl/"), "ioctl/") == 0) {
-		int ret, pp, vp;
-
-		pname = std::string(pport);
-		ret = sscanf(pname.c_str(), "ioctl/%d/%d", &pp, &vp);
-		if (ret == 2) {
-			pname = freebsd::stringf("ioctl/%d/%d", pp, vp);
-			pport = pname;
+	size_t pos = pport.find('/');
+	if (pos == 0) {
+		log_warnx("invalid physical port \"%s\" for target "
+		    "\"%s\"", std::string(pport).c_str(), name());
+		return (false);
+	}
+
+	if (pos != pport.npos) {
+		const char *pport_end = pport.data() + pport.size();
+		int pp, vp;
+
+		auto parse_int = [](const char *start, const char *end) -> int {
+			int value;
+
+			if (start == end)
+				return -1;
+
+			auto [ptr, ec] = std::from_chars(start, end, value);
+			if (ec != std::errc() || ptr != end)
+				return -1;
+			return value;
+		};
+
+		const char *ppstart = pport.data() + pos + 1;
+		size_t ppend = pport.find('/', pos + 1);
+		if (ppend == pport.npos) {
+			pp = parse_int(ppstart, pport_end);
+			vp = 0;
+		} else {
+			const char *vpstart = pport.data() + ppend + 1;
+			pp = parse_int(ppstart, pport.data() + ppend);
+			vp = parse_int(vpstart, pport_end);
+		}
+
+		if (pp == -1 || vp == -1) {
+			log_warnx("invalid physical port \"%s\" for target "
+			    "\"%s\"", std::string(pport).c_str(), name());
+			return (false);
+		}
+
+		pname = pport.substr(0, pos);
+		if (pp != 0 || vp != 0) {
+			pname += "/" + std::to_string(pp);
+			if (vp != 0)
+				pname += "/" + std::to_string(vp);
 		}
+		pport = pname;
 	}
 
 	for (const auto &s : t_pports) {
@@ -2679,7 +2718,9 @@ conf::add_pports(struct kports &kports)
 			 */
 			ret = sscanf(pport.c_str(), "ioctl/%d/%d", &i_pp,
 			    &i_vp);
-			if (ret == 2) {
+			if (ret > 0) {
+				if (ret == 1)
+					i_vp = 0;
 				if (!add_port(targ, pport, i_pp, i_vp)) {
 					log_warnx("can't create new port %s "
 					    "for %s", pport.c_str(),
diff --git a/usr.sbin/ctld/kernel.cc b/usr.sbin/ctld/kernel.cc
index f84440d64c23..188d01052a1c 100644
--- a/usr.sbin/ctld/kernel.cc
+++ b/usr.sbin/ctld/kernel.cc
@@ -559,10 +559,7 @@ conf_new_from_kernel(struct kports &kports)
 			continue;
 
 		std::string name = port.port_name;
-		if (port.port_frontend == "ioctl")
-			name += "/" + std::to_string(port.pp) + "/" +
-			    std::to_string(port.vp);
-		else if (port.pp != 0 || port.vp != 0) {
+		if (port.pp != 0 || port.vp != 0) {
 			name += "/" + std::to_string(port.pp);
 			if (port.vp != 0)
 				name += "/" + std::to_string(port.vp);