tech-userlevel archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Import truncate(1) from FreeBSD
Hi,
I have attached a patch for importing truncate(1) from FreeBSD.
Please let me know if you come across any issues while testing it.
Regards,
zerous
# HG changeset patch
# User Naveen Narayanan <nnaveen%posteo.net@localhost>
# Date 1761077270 -7200
# Tue Oct 21 22:07:50 2025 +0200
# Branch trunk
# Node ID 18356b65cc89a38396f66914a1f4fcfa3b2681ba
# Parent 03d10f218fce5630dbd63fdd135fec096db9f6ca
Import truncate(1) from FreeBSD
diff -r 03d10f218fce -r 18356b65cc89 distrib/sets/lists/base/mi
--- a/distrib/sets/lists/base/mi Sun Oct 19 18:56:19 2025 +0000
+++ b/distrib/sets/lists/base/mi Tue Oct 21 22:07:50 2025 +0200
@@ -886,6 +886,7 @@
./usr/bin/tpm_version base-tpm-bin tpm
./usr/bin/tput base-util-bin
./usr/bin/tr base-util-bin
+./usr/bin/truncate base-util-bin
./usr/bin/tradcpp base-util-bin
./usr/bin/true base-util-bin
./usr/bin/tset base-util-bin
diff -r 03d10f218fce -r 18356b65cc89 distrib/sets/lists/man/mi
--- a/distrib/sets/lists/man/mi Sun Oct 19 18:56:19 2025 +0000
+++ b/distrib/sets/lists/man/mi Tue Oct 21 22:07:50 2025 +0200
@@ -4263,6 +4263,7 @@
./usr/share/man/man1/tpm_version.1 man-tpm-man tpm,.man
./usr/share/man/man1/tput.1 man-util-man .man
./usr/share/man/man1/tr.1 man-util-man .man
+./usr/share/man/man1/truncate.1 man-util-man .man
./usr/share/man/man1/tradcpp.1 man-util-man .man
./usr/share/man/man1/true.1 man-util-man .man
./usr/share/man/man1/tset.1 man-util-man .man
diff -r 03d10f218fce -r 18356b65cc89 distrib/sets/lists/manhtml/mi
--- a/distrib/sets/lists/manhtml/mi Sun Oct 19 18:56:19 2025 +0000
+++ b/distrib/sets/lists/manhtml/mi Tue Oct 21 22:07:50 2025 +0200
@@ -617,6 +617,7 @@
./usr/share/man/html1/tpm_version.html man-tpm-htmlman tpm,html
./usr/share/man/html1/tput.html man-util-htmlman html
./usr/share/man/html1/tr.html man-util-htmlman html
+./usr/share/man/html1/truncate.html man-util-htmlman html
./usr/share/man/html1/tradcpp.html man-util-htmlman html
./usr/share/man/html1/true.html man-util-htmlman html
./usr/share/man/html1/tset.html man-util-htmlman html
diff -r 03d10f218fce -r 18356b65cc89 distrib/sets/lists/tests/mi
--- a/distrib/sets/lists/tests/mi Sun Oct 19 18:56:19 2025 +0000
+++ b/distrib/sets/lists/tests/mi Tue Oct 21 22:07:50 2025 +0200
@@ -6745,6 +6745,11 @@
./usr/tests/usr.bin/tr/Atffile tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/tr/Kyuafile tests-usr.bin-tests compattestfile,atf,kyua
./usr/tests/usr.bin/tr/t_basic tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/truncate tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/truncate/Atffile tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/truncate/t_grow tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/truncate/t_misc tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/truncate/t_shrink tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/unifdef tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/unifdef/Atffile tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/unifdef/Kyuafile tests-usr.bin-tests compattestfile,atf,kyua
diff -r 03d10f218fce -r 18356b65cc89 etc/mtree/NetBSD.dist.tests
--- a/etc/mtree/NetBSD.dist.tests Sun Oct 19 18:56:19 2025 +0000
+++ b/etc/mtree/NetBSD.dist.tests Tue Oct 21 22:07:50 2025 +0200
@@ -479,6 +479,7 @@
./usr/tests/usr.bin/printf
./usr/tests/usr.bin/pwhash
./usr/tests/usr.bin/realpath
+./usr/tests/usr.bin/truncate
./usr/tests/usr.bin/rump_server
./usr/tests/usr.bin/sdiff
./usr/tests/usr.bin/sed
diff -r 03d10f218fce -r 18356b65cc89 tests/usr.bin/Makefile
--- a/tests/usr.bin/Makefile Sun Oct 19 18:56:19 2025 +0000
+++ b/tests/usr.bin/Makefile Tue Oct 21 22:07:50 2025 +0200
@@ -9,7 +9,7 @@
diff dirname error find fstat ftp gcov gdb grep gzip id indent \
infocmp jot ld locale m4 make mixerctl mkdep mtree nbperf \
netpgpverify patch pkill pr printf pwhash realpath rump_server \
- shmif_dumpbus shmif_pcapin sdiff sed sort stat tar tmux tr \
+ shmif_dumpbus shmif_pcapin sdiff sed sort stat tar tmux tr truncate \
unifdef uniq vmstat xlint ztest
.if ${MKCXX} != "no"
diff -r 03d10f218fce -r 18356b65cc89 tests/usr.bin/truncate/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/usr.bin/truncate/Makefile Tue Oct 21 22:07:50 2025 +0200
@@ -0,0 +1,11 @@
+# $NetBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/usr.bin/truncate
+
+TESTS_SH+= t_grow
+TESTS_SH+= t_shrink
+TESTS_SH+= t_misc
+
+.include <bsd.test.mk>
diff -r 03d10f218fce -r 18356b65cc89 tests/usr.bin/truncate/t_grow.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/usr.bin/truncate/t_grow.sh Tue Oct 21 22:07:50 2025 +0200
@@ -0,0 +1,117 @@
+# $NetBSD$
+# Copyright (c) 2021 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+server="rump_server -lrumpvfs -lrumpdev_disk -lrumpfs_ffs -d key=/dev/dk,hostpath=ffs.img,size=host"
+
+export RUMP_SERVER=unix://ffs
+
+exmount='rumpfs on / type rumpfs (local)
+/dev/dk on /mnt type ffs (local)
+'
+
+t_init()
+{
+ atf_check -s exit:0 -o ignore -e ignore newfs -b 32k -f 4k -F -s 10M ffs.img
+
+ atf_check -s exit:0 -o ignore -e ignore ${server} ${RUMP_SERVER}
+
+ export LD_PRELOAD=/usr/lib/librumphijack.so
+ atf_check -s exit:0 -o ignore -e ignore mkdir /rump/mnt
+ export RUMPHIJACK=vfs=all,blanket=/dev/dk:/mnt
+ atf_check -s exit:0 -o ignore -e ignore mount /dev/dk /mnt
+ atf_check -s exit:0 -o inline:"${exmount}" mount
+}
+
+atf_test_case t_cleanup cleanup
+t_cleanup()
+{
+ rump.halt
+}
+
+atf_test_case abs_grow
+abs_grow_head()
+{
+ atf_set "descr" "Tests that truncate can grow a file to absolute length"
+ atf_set "use.fs" "true"
+ atf_set "require.progs" "ls awk du"
+}
+abs_grow_body()
+{
+ t_init
+
+ # truncate should allocate the first and the last block only
+ atf_check -s exit:0 -o ignore -e ignore truncate -s 10M /mnt/test_file
+ atf_check_equal $(du -s /mnt/test_file | awk '{print $1}') 128
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') $((10 * 1024 * 1024))
+
+ # truncate should allocate 3 blocks in this case since it extends the file
+ atf_check -s exit:0 -o ignore -e ignore truncate -s 20M /mnt/test_file
+ atf_check_equal $(du /mnt/test_file | awk '{print $1}') 192
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') $((20 * 1024 * 1024))
+}
+
+atf_test_case rela_grow
+rela_grow_head()
+{
+ atf_set "descr" "Check truncate can grow file to relative length"
+ atf_set "use.fs" "true"
+ atf_set "require.progs" "ls awk du"
+}
+rela_grow_body()
+{
+ t_init
+
+ # truncate should allocate the first and the last block only
+ atf_check -s exit:0 -o ignore -e ignore truncate -s 10M /mnt/test_file
+ atf_check_equal $(du -s /mnt/test_file | awk '{print $1}') 128
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') $((10 * 1024 * 1024))
+
+ # truncate should allocate 3 blocks in this case since it extends the file
+ atf_check -s exit:0 -o ignore -e ignore truncate -s +10M /mnt/test_file
+ atf_check_equal $(du /mnt/test_file | awk '{print $1}') 192
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') $((20 * 1024 * 1024))
+}
+
+atf_test_case nocreate
+nocreate_head()
+{
+ atf_set "descr" "Check file is not created with -c"
+ atf_set "use.fs" "true"
+}
+nocreate_body()
+{
+ t_init
+
+ # test_file should not exist
+ atf_check -s exit:0 -o ignore -e ignore truncate -c -s 10M /mnt/test_file
+ atf_check -s not-exit:0 -e ignore 'ls /mnt/test_file'
+}
+
+atf_init_test_cases() {
+ atf_add_test_case abs_grow
+ atf_add_test_case rela_grow
+ atf_add_test_case nocreate
+}
diff -r 03d10f218fce -r 18356b65cc89 tests/usr.bin/truncate/t_misc.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/usr.bin/truncate/t_misc.sh Tue Oct 21 22:07:50 2025 +0200
@@ -0,0 +1,146 @@
+# $NetBSD$
+# Copyright (c) 2021 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+server="rump_server -lrumpvfs -lrumpdev_disk -lrumpfs_ffs -d key=/dev/dk,hostpath=ffs.img,size=host"
+
+export RUMP_SERVER=unix://ffs
+
+exmount='rumpfs on / type rumpfs (local)
+/dev/dk on /mnt type ffs (local)
+'
+
+t_init()
+{
+ atf_check -s exit:0 -o ignore -e ignore newfs -b 32k -f 4k -F -s 10M ffs.img
+ atf_check -s exit:0 -o ignore -e ignore ${server} ${RUMP_SERVER}
+
+ export LD_PRELOAD=/usr/lib/librumphijack.so
+ atf_check -s exit:0 -o ignore -e ignore mkdir /rump/mnt
+ export RUMPHIJACK=vfs=all,blanket=/dev/dk:/mnt
+ atf_check -s exit:0 -o ignore -e ignore mount /dev/dk /mnt
+ atf_check -s exit:0 -o inline:"${exmount}" mount
+}
+
+atf_test_case t_cleanup cleanup
+t_cleanup()
+{
+ rump.halt
+}
+
+atf_test_case reference
+reference_head()
+{
+ atf_set "descr" "Tests that truncate can use a reference file"
+ atf_set "use.fs" "true"
+ atf_set "require.progs" "ls awk du"
+}
+reference_body()
+{
+ t_init
+
+ # create a reference file
+ atf_check -s exit:0 -o ignore -e ignore truncate -s 10M /mnt/test_file1
+ atf_check_equal $(du -s /mnt/test_file1 | awk '{print $1}') 128
+ atf_check_equal $(ls -l /mnt/test_file1 | awk '{print $5}') $((10 * 1024 * 1024))
+
+ # truncate should extend the file to the length of the reference file
+ atf_check -s exit:0 -o ignore -e ignore truncate -r /mnt/test_file1 /mnt/test_file2
+ atf_check_equal $(du -s /mnt/test_file2 | awk '{print $1}') 128
+ atf_check_equal $(ls -l /mnt/test_file2 | awk '{print $5}') $((10 * 1024 * 1024))
+}
+
+atf_test_case negative
+negative_head()
+{
+ atf_set "descr" "Tests that truncate treats negative size as zero"
+ atf_set "use.fs" "true"
+ atf_set "require.progs" "ls awk du"
+}
+negative_body()
+{
+ t_init
+
+ # create/extend a file
+ atf_check -s exit:0 -o ignore -e ignore truncate -s 10M /mnt/test_file
+ atf_check_equal $(du -s /mnt/test_file | awk '{print $1}') 128
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') $((10 * 1024 * 1024))
+
+ # truncate should shrink the file to zero size
+ atf_check -s exit:0 -o ignore -e ignore truncate -s -100M /mnt/test_file
+ atf_check_equal $(du -s /mnt/test_file | awk '{print $1}') 0
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') 0
+}
+
+atf_test_case roundup
+roundup_head()
+{
+ atf_set "descr" "Tests that truncate rounds up the size of the file"
+ atf_set "use.fs" "true"
+ atf_set "require.progs" "ls awk du"
+}
+roundup_body()
+{
+ t_init
+
+ # create/extend a file
+ atf_check -s exit:0 -o ignore -e ignore truncate -s 6M /mnt/test_file
+ atf_check_equal $(du -s /mnt/test_file | awk '{print $1}') 128
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') $((6 * 1024 * 1024))
+
+ # truncate should round up the size of the file
+ atf_check -s exit:0 -o ignore -e ignore truncate -s %5M /mnt/test_file
+ atf_check_equal $(du -s /mnt/test_file | awk '{print $1}') 192
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') $((10 * 1024 * 1024))
+}
+
+atf_test_case rounddown
+rounddown_head()
+{
+ atf_set "descr" "Tests that truncate rounds down the size of the file"
+ atf_set "use.fs" "true"
+ atf_set "require.progs" "ls awk du"
+}
+rounddown_body()
+{
+ t_init
+
+ # create/extend a file
+ atf_check -s exit:0 -o ignore -e ignore truncate -s 9M /mnt/test_file
+ atf_check_equal $(du -s /mnt/test_file | awk '{print $1}') 128
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') $((9 * 1024 * 1024))
+
+ # truncate should round down the size of the file
+ atf_check -s exit:0 -o ignore -e ignore truncate -s /2M /mnt/test_file
+ atf_check_equal $(du -s /mnt/test_file | awk '{print $1}') 64
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') $((8 * 1024 * 1024))
+}
+
+atf_init_test_cases() {
+ atf_add_test_case reference
+ atf_add_test_case rounddown
+ atf_add_test_case roundup
+ atf_add_test_case negative
+}
diff -r 03d10f218fce -r 18356b65cc89 tests/usr.bin/truncate/t_shrink.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/usr.bin/truncate/t_shrink.sh Tue Oct 21 22:07:50 2025 +0200
@@ -0,0 +1,100 @@
+# $NetBSD$
+# Copyright (c) 2021 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+server="rump_server -lrumpvfs -lrumpdev_disk -lrumpfs_ffs -d key=/dev/dk,hostpath=ffs.img,size=host"
+
+export RUMP_SERVER=unix://ffs
+
+exmount='rumpfs on / type rumpfs (local)
+/dev/dk on /mnt type ffs (local)
+'
+
+t_init()
+{
+ atf_check -s exit:0 -o ignore -e ignore newfs -b 32k -f 4k -F -s 10M ffs.img
+ atf_check -s exit:0 -o ignore -e ignore ${server} ${RUMP_SERVER}
+
+ export LD_PRELOAD=/usr/lib/librumphijack.so
+ atf_check -s exit:0 -o ignore -e ignore mkdir /rump/mnt
+ export RUMPHIJACK=vfs=all,blanket=/dev/dk:/mnt
+ atf_check -s exit:0 -o ignore -e ignore mount /dev/dk /mnt
+ atf_check -s exit:0 -o inline:"${exmount}" mount
+}
+
+atf_test_case t_cleanup cleanup
+t_cleanup()
+{
+ rump.halt
+}
+
+atf_test_case abs_shrink
+abs_shrink_head()
+{
+ atf_set "descr" "Tests that truncate can shrink a file to absolute length"
+ atf_set "use.fs" "true"
+ atf_set "require.progs" "ls awk du"
+}
+abs_shrink_body()
+{
+ t_init
+
+ # truncate should allocate the first and the last block only
+ atf_check -s exit:0 -o ignore -e ignore truncate -s 10M /mnt/test_file
+ atf_check_equal $(du -s /mnt/test_file | awk '{print $1}') 128
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') $((10 * 1024 * 1024))
+
+ # truncate should allocate only one block post shrink
+ atf_check -s exit:0 -o ignore -e ignore truncate -s 5M /mnt/test_file
+ atf_check_equal $(du -s /mnt/test_file | awk '{print $1}') 64
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') $((5 * 1024 * 1024))
+}
+
+atf_test_case rela_shrink
+rela_shrink_head()
+{
+ atf_set "descr" "Tests that truncate can shrink a file to relative length"
+ atf_set "use.fs" "true"
+ atf_set "require.progs" "ls awk du"
+}
+rela_shrink_body()
+{
+ t_init
+
+ # truncate should allocate the first and the last block only
+ atf_check -s exit:0 -o ignore -e ignore truncate -s 10M /mnt/test_file
+ atf_check_equal $(du -s /mnt/test_file | awk '{print $1}') 128
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') $((10 * 1024 * 1024))
+
+ # truncate should allocate only one block post shrink
+ atf_check -s exit:0 -o ignore -e ignore truncate -s -5M /mnt/test_file
+ atf_check_equal $(du -s /mnt/test_file | awk '{print $1}') 64
+ atf_check_equal $(ls -l /mnt/test_file | awk '{print $5}') $((5 * 1024 * 1024))
+}
+
+atf_init_test_cases() {
+ atf_add_test_case abs_shrink
+ atf_add_test_case rela_shrink
+}
diff -r 03d10f218fce -r 18356b65cc89 usr.bin/Makefile
--- a/usr.bin/Makefile Sun Oct 19 18:56:19 2025 +0000
+++ b/usr.bin/Makefile Tue Oct 21 22:07:50 2025 +0200
@@ -29,7 +29,7 @@
spell split stat su sys_info systat \
tabs tail talk tcopy tee telnet tftp tic time timeout tip touch \
tput \
- tr true tset tsort tty ul uname unexpand unifdef \
+ tr truncate true tset tsort tty ul uname unexpand unifdef \
uniq units unvis unzip usbhidaction usbhidctl users utoppya \
uudecode uuencode uuidgen vacation vgrind videoctl vis \
vmstat vndcompress w \
diff -r 03d10f218fce -r 18356b65cc89 usr.bin/truncate/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr.bin/truncate/Makefile Tue Oct 21 22:07:50 2025 +0200
@@ -0,0 +1,8 @@
+# $NetBSD$
+
+PROG= truncate
+
+DPADD+= ${LIBUTIL}
+LDADD+= -lutil
+
+.include <bsd.prog.mk>
diff -r 03d10f218fce -r 18356b65cc89 usr.bin/truncate/truncate
Binary file usr.bin/truncate/truncate has changed
diff -r 03d10f218fce -r 18356b65cc89 usr.bin/truncate/truncate.1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr.bin/truncate/truncate.1 Tue Oct 21 22:07:50 2025 +0200
@@ -0,0 +1,249 @@
+.\" $NetBSD$
+.\"
+.\" Copyright (c) 2000 Sheldon Hearn <sheldonh%FreeBSD.org@localhost>.
+.\" All rights reserved.
+.\" Copyright (c) 2021 The FreeBSD Foundation
+.\"
+.\" Portions of this manual page were written by Ka Ho Ng <khng%FreeBSD.org@localhost>
+.\" 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 met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 19, 2021
+.Dt TRUNCATE 1
+.Os
+.Sh NAME
+.Nm truncate
+.Nd truncate, extend the length of files, or perform space management in files
+.Sh SYNOPSIS
+.Nm
+.Op Fl c
+.Bk -words
+.Fl s Xo
+.Sm off
+.Op Cm + | - | % | /
+.Ar size
+.Op Cm SUFFIX
+.Sm on
+.Xc
+.Ek
+.Ar
+.Nm
+.Op Fl c
+.Bk -words
+.Fl r Ar rfile
+.Ek
+.Ar
+.Nm
+.Op Fl c
+.Bk -words
+.Fl d
+.Oo
+.Fl o Xo
+.Sm off
+.Ar offset
+.Op Cm SUFFIX
+.Sm on
+.Xc
+.Oc
+.Fl l Xo
+.Sm off
+.Ar length
+.Op Cm SUFFIX
+.Sm on
+.Xc
+.Ek
+.Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility adjusts the length of each regular file given on the command-line, or
+performs space management with the given offset and the length over a regular
+file given on the command-line.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl c
+Do not create files if they do not exist.
+The
+.Nm
+utility does not treat this as an error.
+No error messages are displayed
+and the exit value is not affected.
+.It Fl r Ar rfile
+Truncate or extend files to the length of the file
+.Ar rfile .
+.It Fl s Xo
+.Sm off
+.Op Cm + | - | % | /
+.Ar size
+.Op Cm SUFFIX
+.Sm on
+.Xc
+If the
+.Ar size
+argument is preceded by a plus sign
+.Pq Cm + ,
+files will be extended by this number of bytes.
+If the
+.Ar size
+argument is preceded by a dash
+.Pq Cm - ,
+file lengths will be reduced by no more than this number of bytes,
+to a minimum length of zero bytes.
+If the
+.Ar size
+argument is preceded by a percent sign
+.Pq Cm % ,
+files will be round up to a multiple of this number of bytes.
+If the
+.Ar size
+argument is preceded by a slash sign
+.Pq Cm / ,
+files will be round down to a multiple of this number of bytes,
+to a minimum length of zero bytes.
+Otherwise, the
+.Ar size
+argument specifies an absolute length to which all files
+should be extended or reduced as appropriate.
+.It Fl d
+Zero a region in the specified file.
+If the underlying file system of the given file supports hole-punching,
+file system space deallocation may be performed in the operation region.
+.It Fl o Ar offset
+The space management operation is performed at the given
+.Ar offset
+bytes in the file.
+If this option is not specified, the operation is performed at the beginning of the file.
+.It Fl l Ar length
+The length of the operation range in bytes.
+This option must always be specified if option
+.Fl d
+is specified, and must be greater than 0.
+.El
+.Pp
+The
+.Ar size ,
+.Ar offset
+and
+.Ar length
+arguments may be suffixed with one of
+.Cm K ,
+.Cm M ,
+.Cm G
+or
+.Cm T
+(either upper or lower case) to indicate a multiple of
+Kilobytes, Megabytes, Gigabytes or Terabytes
+respectively.
+.Pp
+Exactly one of the
+.Fl r ,
+.Fl s
+and
+.Fl d
+options must be specified.
+.Pp
+If a file is made smaller, its extra data is lost.
+If a file is made larger,
+it will be extended as if by writing bytes with the value zero.
+If the file does not exist,
+it is created unless the
+.Fl c
+option is specified.
+.Pp
+Note that,
+while truncating a file causes space on disk to be freed,
+extending a file does not cause space to be allocated.
+To extend a file and actually allocate the space,
+it is necessary to explicitly write data to it,
+using (for example) the shell's
+.Ql >>
+redirection syntax, or
+.Xr dd 1 .
+.Sh EXIT STATUS
+.Ex -std
+If the operation fails for an argument,
+.Nm
+will issue a diagnostic
+and continue processing the remaining arguments.
+.Sh EXAMPLES
+Adjust the size of the file
+.Pa test_file
+to 10 Megabytes but do not create it if it does not exist:
+.Bd -literal -offset indent
+truncate -c -s +10M test_file
+.Ed
+.Pp
+Same as above but create the file if it does not exist:
+.Bd -literal -offset indent
+truncate -s +10M test_file
+ls -l test_file
+-rw-r--r-- 1 root wheel 10485760 Jul 22 18:48 test_file
+.Ed
+.Pp
+Adjust the size of
+.Pa test_file
+to the size of the kernel and create another file
+.Pa test_file2
+with the same size:
+.Bd -literal -offset indent
+truncate -r /boot/kernel/kernel test_file test_file2
+ls -l /boot/kernel/kernel test_file*
+-r-xr-xr-x 1 root wheel 31352552 May 15 14:18 /boot/kernel/kernel*
+-rw-r--r-- 1 root wheel 31352552 Jul 22 19:15 test_file
+-rw-r--r-- 1 root wheel 31352552 Jul 22 19:15 test_file2
+.Ed
+.Pp
+Downsize
+.Pa test_file
+in 5 Megabytes:
+.Bd -literal -offset indent
+# truncate -s -5M test_file
+ls -l test_file*
+-rw-r--r-- 1 root wheel 26109672 Jul 22 19:17 test_file
+-rw-r--r-- 1 root wheel 31352552 Jul 22 19:15 test_file2
+.Ed
+.Sh SEE ALSO
+.Xr dd 1 ,
+.Xr touch 1 ,
+.Xr fspacectl 2 ,
+.Xr truncate 2
+.Sh STANDARDS
+The
+.Nm
+utility conforms to no known standards.
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 4.2 .
+.Sh AUTHORS
+The
+.Nm
+utility was written by
+.An Sheldon Hearn Aq Mt sheldonh%starjuice.net@localhost .
+Hole-punching support of this
+utility was developed by
+.An Ka Ho Ng Aq Mt khng%FreeBSD.org@localhost .
diff -r 03d10f218fce -r 18356b65cc89 usr.bin/truncate/truncate.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr.bin/truncate/truncate.c Tue Oct 21 22:07:50 2025 +0200
@@ -0,0 +1,222 @@
+/* $NetBSD$ */
+/*
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2000 Sheldon Hearn <sheldonh%FreeBSD.org@localhost>.
+ * All rights reserved.
+ *
+ * Copyright (c) 2021 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Ka Ho Ng <khng%FreeBSD.org@localhost>
+ * 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 met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <util.h>
+
+__dead static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ struct stat sb;
+ mode_t omode;
+ off_t oflow, rsize, sz, tsize, round, off, len;
+ int64_t usz;
+ int ch, error, fd, oflags, r;
+ int do_dealloc;
+ int do_truncate;
+ int no_create;
+ int do_relative;
+ int do_round;
+ int do_refer;
+ int got_size;
+ char *fname, *rname;
+
+ fd = -1;
+ rsize = tsize = sz = off = 0;
+ len = -1;
+ do_dealloc = no_create = do_relative = do_round = do_refer =
+ got_size = 0;
+ do_truncate = 1;
+ error = r = 0;
+ rname = NULL;
+ while ((ch = getopt(argc, argv, "cdr:s:o:l:")) != -1)
+ switch (ch) {
+ case 'c':
+ no_create = 1;
+ break;
+ case 'd':
+ do_dealloc = 1;
+ do_truncate = 0;
+ break;
+ case 'r':
+ do_refer = 1;
+ rname = optarg;
+ break;
+ case 's':
+ if (*optarg == '+' || *optarg == '-') {
+ do_relative = 1;
+ } else if (*optarg == '%' || *optarg == '/') {
+ do_round = 1;
+ }
+ if (dehumanize_number(do_relative ||
+ do_round ? optarg + 1 : optarg, &usz) == -1 ||
+ usz <= 0)
+ errx(EXIT_FAILURE,
+ "invalid size argument `%s'", optarg);
+
+ sz = (*optarg == '-' || *optarg == '/') ?
+ -usz : usz;
+ got_size = 1;
+ break;
+ case 'o':
+ if (dehumanize_number(optarg, &usz) == -1 ||
+ usz < 0)
+ errx(EXIT_FAILURE,
+ "invalid offset argument `%s'", optarg);
+
+ off = usz;
+ break;
+ case 'l':
+ if (dehumanize_number(optarg, &usz) == -1 ||
+ usz <= 0)
+ errx(EXIT_FAILURE,
+ "invalid length argument `%s'", optarg);
+
+ len = usz;
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ /*
+ * Exactly one of do_refer, got_size or do_dealloc must be specified.
+ * Since do_relative implies got_size, do_relative, do_refer and
+ * do_dealloc are also mutually exclusive. If do_dealloc is specified,
+ * the length argument must be set. See usage() for allowed
+ * invocations.
+ */
+ if (argc < 1 || do_refer + got_size + do_dealloc != 1 ||
+ (do_dealloc == 1 && len == -1))
+ usage();
+ if (do_refer == 1) {
+ if (stat(rname, &sb) == -1)
+ err(EXIT_FAILURE, "%s", rname);
+ tsize = sb.st_size;
+ } else if (do_relative == 1 || do_round == 1)
+ rsize = sz;
+ else if (do_dealloc == 0)
+ tsize = sz;
+
+ if (no_create)
+ oflags = O_WRONLY;
+ else
+ oflags = O_WRONLY | O_CREAT;
+ omode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+
+ while ((fname = *argv++) != NULL) {
+ if (fd != -1)
+ close(fd);
+ if ((fd = open(fname, oflags, omode)) == -1) {
+ if (errno != ENOENT) {
+ warn("%s", fname);
+ error++;
+ }
+ continue;
+ }
+ if (do_relative == 1) {
+ if (fstat(fd, &sb) == -1) {
+ warn("%s", fname);
+ error++;
+ continue;
+ }
+ oflow = sb.st_size + rsize;
+ if (oflow < (sb.st_size + rsize)) {
+ errno = EFBIG;
+ warn("%s", fname);
+ error++;
+ continue;
+ }
+ tsize = oflow;
+ }
+ if (do_round == 1) {
+ if (fstat(fd, &sb) == -1) {
+ warn("%s", fname);
+ error++;
+ continue;
+ }
+ sz = rsize;
+ if (sz < 0)
+ sz = -sz;
+ if (sb.st_size % sz) {
+ round = sb.st_size / sz;
+ if (rsize > 0)
+ round++;
+ tsize = round * sz;
+ } else
+ tsize = sb.st_size;
+ }
+ if (tsize < 0)
+ tsize = 0;
+
+ if (do_dealloc == 1) {
+ r = fdiscard(fd, off, len);
+ }
+ if (do_truncate == 1)
+ r = ftruncate(fd, tsize);
+ if (r == -1) {
+ warn("%s", fname);
+ error++;
+ }
+ }
+ if (fd != -1)
+ close(fd);
+
+ return (error ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+static void
+usage(void)
+{
+ const char *pnam = getprogname();
+ fprintf(stderr, "usage:\t%s %s\n\t%s %s\n\t%s %s\n",
+ pnam, "[-c] -s [+|-|%|/]size[K|k|M|m|G|g|T|t] file ...",
+ pnam, "[-c] -r rfile file ...",
+ pnam, "[-c] -d [-o offset[K|k|M|m|G|g|T|t]] -l length[K|k|M|m|G|g|T|t] file ...");
+ exit(EXIT_FAILURE);
+}
Home |
Main Index |
Thread Index |
Old Index