aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/makefs
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/makefs')
-rw-r--r--usr.sbin/makefs/ffs.c2
-rw-r--r--usr.sbin/makefs/makefs.816
-rw-r--r--usr.sbin/makefs/tests/Makefile4
-rw-r--r--usr.sbin/makefs/tests/makefs_msdos_tests.sh2
-rw-r--r--usr.sbin/makefs/tests/makefs_zfs_tests.sh92
-rw-r--r--usr.sbin/makefs/zfs.c6
-rw-r--r--usr.sbin/makefs/zfs/dsl.c65
-rw-r--r--usr.sbin/makefs/zfs/fs.c45
-rw-r--r--usr.sbin/makefs/zfs/objset.c1
-rw-r--r--usr.sbin/makefs/zfs/vdev.c1
-rw-r--r--usr.sbin/makefs/zfs/zap.c13
11 files changed, 201 insertions, 46 deletions
diff --git a/usr.sbin/makefs/ffs.c b/usr.sbin/makefs/ffs.c
index 4efcd20ad91a..c0fcadf11fba 100644
--- a/usr.sbin/makefs/ffs.c
+++ b/usr.sbin/makefs/ffs.c
@@ -1056,7 +1056,7 @@ ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap)
reclen = DIRSIZ_SWAP(0, &de, needswap);
de.d_reclen = ufs_rw16(reclen, needswap);
- dp = (struct direct *)(dbuf->buf + dbuf->cur);
+ dp = dbuf->buf == NULL ? NULL : (struct direct *)(dbuf->buf + dbuf->cur);
llen = 0;
if (dp != NULL)
llen = DIRSIZ_SWAP(0, dp, needswap);
diff --git a/usr.sbin/makefs/makefs.8 b/usr.sbin/makefs/makefs.8
index a11eaf8206e9..d20f69d87559 100644
--- a/usr.sbin/makefs/makefs.8
+++ b/usr.sbin/makefs/makefs.8
@@ -33,8 +33,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd January 19, 2024
-
+.Dd July 19, 2025
.Dt MAKEFS 8
.Os
.Sh NAME
@@ -551,6 +550,12 @@ This option allows the default heuristic to be overridden.
.It verify-txgs
Prompt OpenZFS to verify pool metadata during import.
This is disabled by default as it may significantly increase import times.
+.It poolguid
+Use the specified 64-bit integer as the pool GUID.
+If this option is not specified, the pool GUID will be random but fixed
+across multiple identical invocations of
+.Nm .
+This option is useful for testing but not required for reproducibility.
.It poolname
The name of the ZFS pool.
This option must be specified.
@@ -596,10 +601,17 @@ The following properties may be set for a dataset:
.Bl -tag -compact -offset indent
.It atime
.It canmount
+.It compression
.It exec
.It mountpoint
.It setuid
.El
+Note that
+.Nm
+does not implement compression of files included in the image,
+regardless of the value of the
+.Dv compression
+property.
.El
.Sh SEE ALSO
.Xr mtree 5 ,
diff --git a/usr.sbin/makefs/tests/Makefile b/usr.sbin/makefs/tests/Makefile
index 345b728651d6..748bafa06211 100644
--- a/usr.sbin/makefs/tests/Makefile
+++ b/usr.sbin/makefs/tests/Makefile
@@ -7,10 +7,6 @@ ATF_TESTS_SH+= makefs_msdos_tests
TEST_METADATA.makefs_msdos_tests+= required_files="/sbin/mount_msdosfs"
.if ${MK_ZFS} != "no"
ATF_TESTS_SH+= makefs_zfs_tests
-# ZFS pools created by makefs always have the same GUID, so OpenZFS
-# refuses to import more than one at a time. Thus the ZFS tests cannot
-# be run in parallel for now.
-TEST_METADATA.makefs_zfs_tests+= is_exclusive="true"
.endif
BINDIR= ${TESTSDIR}
diff --git a/usr.sbin/makefs/tests/makefs_msdos_tests.sh b/usr.sbin/makefs/tests/makefs_msdos_tests.sh
index b36b43b3abf6..fb94429b477b 100644
--- a/usr.sbin/makefs/tests/makefs_msdos_tests.sh
+++ b/usr.sbin/makefs/tests/makefs_msdos_tests.sh
@@ -4,7 +4,7 @@
# Copyright (c) 2025 The FreeBSD Foundation
#
# This software was developed by Klara, Inc.
-# under sponsorship from the FreeBSD Foundation and the Sovereign Tech Agency.
+# under sponsorship from the FreeBSD Foundation.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
diff --git a/usr.sbin/makefs/tests/makefs_zfs_tests.sh b/usr.sbin/makefs/tests/makefs_zfs_tests.sh
index 520d1f211ac3..2fafce85b347 100644
--- a/usr.sbin/makefs/tests/makefs_zfs_tests.sh
+++ b/usr.sbin/makefs/tests/makefs_zfs_tests.sh
@@ -28,7 +28,7 @@
# SUCH DAMAGE.
#
-MAKEFS="makefs -t zfs -o verify-txgs=true"
+MAKEFS="makefs -t zfs -o verify-txgs=true -o poolguid=$$"
ZFS_POOL_NAME="makefstest$$"
TEST_ZFS_POOL_NAME="$TMPDIR/poolname"
@@ -124,6 +124,95 @@ basic_cleanup()
common_cleanup
}
+#
+# Try configuring various compression algorithms.
+#
+atf_test_case compression cleanup
+compression_body()
+{
+ create_test_inputs
+
+ cd $TEST_INPUTS_DIR
+ mkdir dir
+ mkdir dir2
+ cd -
+
+ for alg in off on lzjb gzip gzip-1 gzip-2 gzip-3 gzip-4 \
+ gzip-5 gzip-6 gzip-7 gzip-8 gzip-9 zle lz4 zstd; do
+ atf_check $MAKEFS -s 1g -o rootpath=/ \
+ -o poolname=$ZFS_POOL_NAME \
+ -o fs=${ZFS_POOL_NAME}\;compression=$alg \
+ -o fs=${ZFS_POOL_NAME}/dir \
+ -o fs=${ZFS_POOL_NAME}/dir2\;compression=off \
+ $TEST_IMAGE $TEST_INPUTS_DIR
+
+ import_image
+
+ check_image_contents
+
+ if [ $alg = gzip-6 ]; then
+ # ZFS reports gzip-6 as just gzip since it uses
+ # a default compression level of 6.
+ alg=gzip
+ fi
+ # The "dir" dataset's compression algorithm should be
+ # inherited from the root dataset.
+ atf_check -o inline:$alg\\n -e empty -s exit:0 \
+ zfs get -H -o value compression ${ZFS_POOL_NAME}
+ atf_check -o inline:$alg\\n -e empty -s exit:0 \
+ zfs get -H -o value compression ${ZFS_POOL_NAME}/dir
+ atf_check -o inline:off\\n -e empty -s exit:0 \
+ zfs get -H -o value compression ${ZFS_POOL_NAME}/dir2
+
+ atf_check -e ignore dd if=/dev/random \
+ of=${TEST_MOUNT_DIR}/dir/random bs=1M count=10
+ atf_check -e ignore dd if=/dev/zero \
+ of=${TEST_MOUNT_DIR}/dir/zero bs=1M count=10
+ atf_check -e ignore dd if=/dev/zero \
+ of=${TEST_MOUNT_DIR}/dir2/zero bs=1M count=10
+
+ # Export and reimport to ensure that everything is
+ # flushed to disk.
+ atf_check zpool export ${ZFS_POOL_NAME}
+ atf_check -o ignore -e empty -s exit:0 \
+ zdb -e -p /dev/$(cat $TEST_MD_DEVICE_FILE) -mmm -ddddd \
+ $ZFS_POOL_NAME
+ atf_check zpool import -R $TEST_MOUNT_DIR $ZFS_POOL_NAME
+
+ if [ $alg = off ]; then
+ # If compression is off, the files should be the
+ # same size as the input.
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir/random" \
+ du -m ${TEST_MOUNT_DIR}/dir/random
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir/zero" \
+ du -m ${TEST_MOUNT_DIR}/dir/zero
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir2/zero" \
+ du -m ${TEST_MOUNT_DIR}/dir2/zero
+ else
+ # If compression is on, the dir/zero file ought
+ # to be smaller.
+ atf_check -o match:"^1[[:space:]]+${TEST_MOUNT_DIR}/dir/zero" \
+ du -m ${TEST_MOUNT_DIR}/dir/zero
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir/random" \
+ du -m ${TEST_MOUNT_DIR}/dir/random
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir2/zero" \
+ du -m ${TEST_MOUNT_DIR}/dir2/zero
+ fi
+
+ atf_check zpool destroy ${ZFS_POOL_NAME}
+ atf_check rm -f ${TEST_ZFS_POOL_NAME}
+ atf_check mdconfig -d -u $(cat ${TEST_MD_DEVICE_FILE})
+ atf_check rm -f ${TEST_MD_DEVICE_FILE}
+ done
+}
+compression_cleanup()
+{
+ common_cleanup
+}
+
+#
+# Try destroying a dataset that was created by makefs.
+#
atf_test_case dataset_removal cleanup
dataset_removal_body()
{
@@ -939,6 +1028,7 @@ atf_init_test_cases()
{
atf_add_test_case autoexpand
atf_add_test_case basic
+ atf_add_test_case compression
atf_add_test_case dataset_removal
atf_add_test_case devfs
atf_add_test_case empty_dir
diff --git a/usr.sbin/makefs/zfs.c b/usr.sbin/makefs/zfs.c
index 66e7f8dafc9c..8d50c450541b 100644
--- a/usr.sbin/makefs/zfs.c
+++ b/usr.sbin/makefs/zfs.c
@@ -38,6 +38,7 @@
#include <stdalign.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -85,6 +86,8 @@ zfs_prep_opts(fsinfo_t *fsopts)
0, 0, "Bootable dataset" },
{ '\0', "mssize", &zfs->mssize, OPT_INT64,
MINMSSIZE, MAXMSSIZE, "Metaslab size" },
+ { '\0', "poolguid", &zfs->poolguid, OPT_INT64,
+ 0, INT64_MAX, "ZFS pool GUID" },
{ '\0', "poolname", &zfs->poolname, OPT_STRPTR,
0, 0, "ZFS pool name" },
{ '\0', "rootpath", &zfs->rootpath, OPT_STRPTR,
@@ -547,7 +550,8 @@ pool_init(zfs_opt_t *zfs)
{
uint64_t dnid;
- zfs->poolguid = randomguid();
+ if (zfs->poolguid == 0)
+ zfs->poolguid = randomguid();
zfs->vdevguid = randomguid();
zfs->mos = objset_alloc(zfs, DMU_OST_META);
diff --git a/usr.sbin/makefs/zfs/dsl.c b/usr.sbin/makefs/zfs/dsl.c
index f7264b9d2ca7..1977521d7f92 100644
--- a/usr.sbin/makefs/zfs/dsl.c
+++ b/usr.sbin/makefs/zfs/dsl.c
@@ -119,7 +119,7 @@ dsl_dir_get_mountpoint(zfs_opt_t *zfs, zfs_dsl_dir_t *dir)
if (nvlist_find_string(pdir->propsnv, "mountpoint",
&tmp) == 0) {
- easprintf(&mountpoint, "%s%s%s", tmp,
+ (void)easprintf(&mountpoint, "%s%s%s", tmp,
tmp[strlen(tmp) - 1] == '/' ? "" : "/",
origmountpoint);
free(tmp);
@@ -127,7 +127,7 @@ dsl_dir_get_mountpoint(zfs_opt_t *zfs, zfs_dsl_dir_t *dir)
break;
}
- easprintf(&mountpoint, "%s/%s", pdir->name,
+ (void)easprintf(&mountpoint, "%s/%s", pdir->name,
origmountpoint);
free(origmountpoint);
}
@@ -175,24 +175,57 @@ dsl_dir_set_prop(zfs_opt_t *zfs, zfs_dsl_dir_t *dir, const char *key,
"the root path `%s'", val, zfs->rootpath);
}
}
- nvlist_add_string(nvl, key, val);
+ (void)nvlist_add_string(nvl, key, val);
} else if (strcmp(key, "atime") == 0 || strcmp(key, "exec") == 0 ||
strcmp(key, "setuid") == 0) {
if (strcmp(val, "on") == 0)
- nvlist_add_uint64(nvl, key, 1);
+ (void)nvlist_add_uint64(nvl, key, 1);
else if (strcmp(val, "off") == 0)
- nvlist_add_uint64(nvl, key, 0);
+ (void)nvlist_add_uint64(nvl, key, 0);
else
errx(1, "invalid value `%s' for %s", val, key);
} else if (strcmp(key, "canmount") == 0) {
if (strcmp(val, "noauto") == 0)
- nvlist_add_uint64(nvl, key, 2);
+ (void)nvlist_add_uint64(nvl, key, 2);
else if (strcmp(val, "on") == 0)
- nvlist_add_uint64(nvl, key, 1);
+ (void)nvlist_add_uint64(nvl, key, 1);
else if (strcmp(val, "off") == 0)
- nvlist_add_uint64(nvl, key, 0);
+ (void)nvlist_add_uint64(nvl, key, 0);
else
errx(1, "invalid value `%s' for %s", val, key);
+ } else if (strcmp(key, "compression") == 0) {
+ size_t i;
+
+ const struct zfs_compression_algorithm {
+ const char *name;
+ enum zio_compress alg;
+ } compression_algorithms[] = {
+ { "off", ZIO_COMPRESS_OFF },
+ { "on", ZIO_COMPRESS_ON },
+ { "lzjb", ZIO_COMPRESS_LZJB },
+ { "gzip", ZIO_COMPRESS_GZIP_6 },
+ { "gzip-1", ZIO_COMPRESS_GZIP_1 },
+ { "gzip-2", ZIO_COMPRESS_GZIP_2 },
+ { "gzip-3", ZIO_COMPRESS_GZIP_3 },
+ { "gzip-4", ZIO_COMPRESS_GZIP_4 },
+ { "gzip-5", ZIO_COMPRESS_GZIP_5 },
+ { "gzip-6", ZIO_COMPRESS_GZIP_6 },
+ { "gzip-7", ZIO_COMPRESS_GZIP_7 },
+ { "gzip-8", ZIO_COMPRESS_GZIP_8 },
+ { "gzip-9", ZIO_COMPRESS_GZIP_9 },
+ { "zle", ZIO_COMPRESS_ZLE },
+ { "lz4", ZIO_COMPRESS_LZ4 },
+ { "zstd", ZIO_COMPRESS_ZSTD },
+ };
+ for (i = 0; i < nitems(compression_algorithms); i++) {
+ if (strcmp(val, compression_algorithms[i].name) == 0) {
+ nvlist_add_uint64(nvl, key,
+ compression_algorithms[i].alg);
+ break;
+ }
+ }
+ if (i == nitems(compression_algorithms))
+ errx(1, "invalid compression algorithm `%s'", val);
} else {
errx(1, "unknown property `%s'", key);
}
@@ -204,7 +237,7 @@ dsl_metadir_alloc(zfs_opt_t *zfs, const char *name)
zfs_dsl_dir_t *dir;
char *path;
- easprintf(&path, "%s/%s", zfs->poolname, name);
+ (void)easprintf(&path, "%s/%s", zfs->poolname, name);
dir = dsl_dir_alloc(zfs, path);
free(path);
return (dir);
@@ -236,9 +269,6 @@ dsl_init(zfs_opt_t *zfs)
zfs->rootdsldir = dsl_dir_alloc(zfs, NULL);
- nvlist_add_uint64(zfs->rootdsldir->propsnv, "compression",
- ZIO_COMPRESS_OFF);
-
zfs->rootds = dsl_dataset_alloc(zfs, zfs->rootdsldir);
zfs->rootdsldir->headds = zfs->rootds;
@@ -288,11 +318,15 @@ dsl_init(zfs_opt_t *zfs)
}
/*
- * Set the root dataset's mount point if the user didn't override the
- * default.
+ * Set the root dataset's mount point and compression strategy if the
+ * user didn't override the defaults.
*/
+ if (nvpair_find(zfs->rootdsldir->propsnv, "compression") == NULL) {
+ (void)nvlist_add_uint64(zfs->rootdsldir->propsnv,
+ "compression", ZIO_COMPRESS_OFF);
+ }
if (nvpair_find(zfs->rootdsldir->propsnv, "mountpoint") == NULL) {
- nvlist_add_string(zfs->rootdsldir->propsnv, "mountpoint",
+ (void)nvlist_add_string(zfs->rootdsldir->propsnv, "mountpoint",
zfs->rootpath);
}
}
@@ -397,6 +431,7 @@ dsl_dir_alloc(zfs_opt_t *zfs, const char *name)
STAILQ_INIT(&l);
STAILQ_INSERT_HEAD(&l, zfs->rootdsldir, next);
origname = dirname = nextdir = estrdup(name);
+ parent = NULL;
for (lp = &l;; lp = &parent->children) {
dirname = strsep(&nextdir, "/");
if (nextdir == NULL)
diff --git a/usr.sbin/makefs/zfs/fs.c b/usr.sbin/makefs/zfs/fs.c
index 073dce3ce697..75f6e30e1500 100644
--- a/usr.sbin/makefs/zfs/fs.c
+++ b/usr.sbin/makefs/zfs/fs.c
@@ -28,6 +28,7 @@
* SUCH DAMAGE.
*/
+#include <sys/param.h>
#include <sys/stat.h>
#include <assert.h>
@@ -383,22 +384,34 @@ fs_populate_sattrs(struct fs_populate_arg *arg, const fsnode *cur,
links = 1; /* .. */
objsize = 1; /* .. */
- /*
- * The size of a ZPL directory is the number of entries
- * (including "." and ".."), and the link count is the number of
- * entries which are directories (including "." and "..").
- */
- for (fsnode *c = fsnode_isroot(cur) ? cur->next : cur->child;
- c != NULL; c = c->next) {
- switch (c->type) {
- case S_IFDIR:
- links++;
- /* FALLTHROUGH */
- case S_IFREG:
- case S_IFLNK:
- objsize++;
- break;
+ if ((cur->inode->flags & FI_ROOT) == 0 ) {
+ /*
+ * The size of a ZPL directory is the number of entries
+ * (including "." and ".."), and the link count is the
+ * number of entries which are directories
+ * (including "." and "..").
+ */
+ for (fsnode *c =
+ fsnode_isroot(cur) ? cur->next : cur->child;
+ c != NULL; c = c->next) {
+ switch (c->type) {
+ case S_IFDIR:
+ links++;
+ /* FALLTHROUGH */
+ case S_IFREG:
+ case S_IFLNK:
+ objsize++;
+ break;
+ }
}
+ } else {
+ /*
+ * Root directory children do belong to
+ * different dataset and this directory is
+ * empty in the current objset.
+ */
+ links++; /* . */
+ objsize++; /* . */
}
/* The root directory is its own parent. */
@@ -734,7 +747,7 @@ fs_add_zpl_attr_layout(zfs_zap_t *zap, unsigned int index,
assert(sizeof(layout[0]) == 2);
- snprintf(ti, sizeof(ti), "%u", index);
+ (void)snprintf(ti, sizeof(ti), "%u", index);
zap_add(zap, ti, sizeof(sa_attr_type_t), sacnt,
(const uint8_t *)layout);
}
diff --git a/usr.sbin/makefs/zfs/objset.c b/usr.sbin/makefs/zfs/objset.c
index 6be732db477a..f47953ac4339 100644
--- a/usr.sbin/makefs/zfs/objset.c
+++ b/usr.sbin/makefs/zfs/objset.c
@@ -28,6 +28,7 @@
* SUCH DAMAGE.
*/
+#include <sys/param.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
diff --git a/usr.sbin/makefs/zfs/vdev.c b/usr.sbin/makefs/zfs/vdev.c
index ef9e681af2da..afcce402cb13 100644
--- a/usr.sbin/makefs/zfs/vdev.c
+++ b/usr.sbin/makefs/zfs/vdev.c
@@ -28,6 +28,7 @@
* SUCH DAMAGE.
*/
+#include <sys/param.h>
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
diff --git a/usr.sbin/makefs/zfs/zap.c b/usr.sbin/makefs/zfs/zap.c
index decf5fc6a473..316d1446cecf 100644
--- a/usr.sbin/makefs/zfs/zap.c
+++ b/usr.sbin/makefs/zfs/zap.c
@@ -28,7 +28,7 @@
* SUCH DAMAGE.
*/
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/endian.h>
#include <assert.h>
@@ -172,14 +172,14 @@ zap_add_uint64_self(zfs_zap_t *zap, uint64_t val)
{
char name[32];
- snprintf(name, sizeof(name), "%jx", (uintmax_t)val);
+ (void)snprintf(name, sizeof(name), "%jx", (uintmax_t)val);
zap_add(zap, name, sizeof(uint64_t), 1, (uint8_t *)&val);
}
void
zap_add_string(zfs_zap_t *zap, const char *name, const char *val)
{
- zap_add(zap, name, 1, strlen(val) + 1, val);
+ zap_add(zap, name, 1, strlen(val) + 1, (const uint8_t *)val);
}
bool
@@ -221,7 +221,8 @@ zap_micro_write(zfs_opt_t *zfs, zfs_zap_t *zap)
STAILQ_FOREACH(ent, &zap->kvps, next) {
memcpy(&ment->mze_value, ent->valp, ent->intsz * ent->intcnt);
ment->mze_cd = cd++;
- strlcpy(ment->mze_name, ent->name, sizeof(ment->mze_name));
+ (void)strlcpy(ment->mze_name, ent->name,
+ sizeof(ment->mze_name));
ment++;
}
@@ -247,6 +248,7 @@ zap_fat_write_array_chunk(zap_leaf_t *l, uint16_t li, size_t sz,
struct zap_leaf_array *la;
assert(sz <= ZAP_MAXVALUELEN);
+ assert(sz > 0);
for (uint16_t n, resid = sz; resid > 0; resid -= n, val += n, li++) {
n = MIN(resid, ZAP_LEAF_ARRAY_BYTES);
@@ -503,7 +505,8 @@ zap_fat_write(zfs_opt_t *zfs, zfs_zap_t *zap)
le->le_value_intlen = ent->intsz;
le->le_value_numints = ent->intcnt;
le->le_hash = ent->hash;
- zap_fat_write_array_chunk(&l, *lptr + 1, namelen, ent->name);
+ zap_fat_write_array_chunk(&l, *lptr + 1, namelen,
+ (uint8_t *)ent->name);
zap_fat_write_array_chunk(&l, *lptr + 1 + nnamechunks,
ent->intcnt * ent->intsz, ent->valp);
}