git: 03221b189a48 - main - certctl: Create output directories

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Fri, 22 Aug 2025 15:34:53 UTC
The branch main has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=03221b189a48a509c1bc9adb8331638ae3eac065

commit 03221b189a48a509c1bc9adb8331638ae3eac065
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2025-08-22 15:33:45 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2025-08-22 15:33:45 +0000

    certctl: Create output directories
    
    In a pkgbase world, we cannot assume that these directories exist; we
    must create them ourselves.
    
    Fixes:          c340ef28fd38 ("certctl: Reimplement in C")
    Reviewed by:    markj
    Differential Revision:  https://reviews.freebsd.org/D52121
---
 usr.sbin/certctl/certctl.c             | 32 ++++++++++++++++++++++++++++----
 usr.sbin/certctl/tests/certctl_test.sh |  6 +++---
 2 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/usr.sbin/certctl/certctl.c b/usr.sbin/certctl/certctl.c
index ed7f05126ca7..3601f6929fc4 100644
--- a/usr.sbin/certctl/certctl.c
+++ b/usr.sbin/certctl/certctl.c
@@ -100,6 +100,28 @@ static char *bundle_dest;
 
 static FILE *mlf;
 
+/*
+ * Create a directory and its parents as needed.
+ */
+static void
+mkdirp(const char *dir)
+{
+	struct stat sb;
+	const char *sep;
+	char *parent;
+
+	if (stat(dir, &sb) == 0)
+		return;
+	if ((sep = strrchr(dir, '/')) != NULL) {
+		parent = xasprintf("%.*s", (int)(sep - dir), dir);
+		mkdirp(parent);
+		free(parent);
+	}
+	info("creating %s", dir);
+	if (mkdir(dir, 0755) != 0)
+		err(1, "mkdir %s", dir);
+}
+
 /*
  * Remove duplicate and trailing slashes from a path.
  */
@@ -685,7 +707,7 @@ save_trusted(void)
 {
 	int ret;
 
-	/* save untrusted certs */
+	mkdirp(trusted_dest);
 	ret = write_certs(trusted_dest, &trusted);
 	return (ret);
 }
@@ -700,6 +722,7 @@ save_untrusted(void)
 {
 	int ret;
 
+	mkdirp(untrusted_dest);
 	ret = write_certs(untrusted_dest, &untrusted);
 	return (ret);
 }
@@ -721,6 +744,7 @@ save_bundle(void)
 	} else {
 		dir = xasprintf("%.*s", (int)(sep - bundle_dest), bundle_dest);
 		file = sep + 1;
+		mkdirp(dir);
 	}
 	ret = write_bundle(dir, file, &trusted);
 	free(dir);
@@ -995,17 +1019,17 @@ set_defaults(void)
 
 	if ((value = getenv("TRUSTDESTDIR")) != NULL ||
 	    (value = getenv("CERTDESTDIR")) != NULL)
-		trusted_dest = xstrdup(value);
+		trusted_dest = normalize_path(value);
 	else
 		trusted_dest = expand_path(TRUSTED_PATH);
 
 	if ((value = getenv("UNTRUSTDESTDIR")) != NULL)
-		untrusted_dest = xstrdup(value);
+		untrusted_dest = normalize_path(value);
 	else
 		untrusted_dest = expand_path(UNTRUSTED_PATH);
 
 	if ((value = getenv("BUNDLE")) != NULL)
-		bundle_dest = xstrdup(value);
+		bundle_dest = normalize_path(value);
 	else
 		bundle_dest = expand_path(BUNDLE_PATH);
 
diff --git a/usr.sbin/certctl/tests/certctl_test.sh b/usr.sbin/certctl/tests/certctl_test.sh
index f60bac6ffbb3..74749db0b3f5 100644
--- a/usr.sbin/certctl/tests/certctl_test.sh
+++ b/usr.sbin/certctl/tests/certctl_test.sh
@@ -76,9 +76,9 @@ certctl_setup()
 	mkdir -p ${DESTDIR}${DISTBASE}/usr/share/certs/untrusted
 	mkdir -p ${DESTDIR}/usr/local/share/certs
 
-	# Create output directories
-	mkdir -p ${DESTDIR}${DISTBASE}/etc/ssl/certs
-	mkdir -p ${DESTDIR}${DISTBASE}/etc/ssl/untrusted
+	# Do not create output directories; certctl will take care of it
+	#mkdir -p ${DESTDIR}${DISTBASE}/etc/ssl/certs
+	#mkdir -p ${DESTDIR}${DISTBASE}/etc/ssl/untrusted
 
 	# Generate a random key
 	keyname="testkey"