#!/bin/sh # # Copyright 2026 Colin Percival # # SPDX-License-Identifier: BSD-2-Clause # # PROVIDE: growfs_postboot # KEYWORD: nostart # Triggered by /etc/devd/growfs_postboot.conf: When a disk grows, enlarge the # final partition to fill the available space (if the disk is partitioned) or # enlarge the UFS filesystem or ZFS zpool (if in use for one of those). Note # that in the common case of "a disk is partitioned and one of the partitions # contains a filesystem" this script is invoked twice -- the repartitioning # done on the first call generates a new devd event which triggers the second # invocation. # # Enable by setting # growfs_postboot_enable=YES # in /etc/rc.conf. Note that on systems with growfs_enable=YES, it will often # be necessary to set growfs_swap_size=0 in order to disable swap creation; # otherwise the "final partition" is the swap space, not the filesystem and # growing the disk will not cause the most likely desired results. . /etc/rc.subr name="growfs_postboot" desc="automatically grow file systems during runtime" rcvar="growfs_postboot_enable" start_cmd="growfs_postboot_start" disktype() { sysctl -n kern.geom.conftxt | awk -v dev="$1" ' BEGIN { partitioned=0 indev=0 } { if (dev == $3) { indev=1 devlevel=$1 } else if (devlevel >= $1) { indev=0 } else if (indev == 1) { if ($2 == "PART") { partitioned=1 } } } END { if (partitioned == 1) { print "partitioned" } else { print "unpartitioned" } }' } growpart() { # Run 'gpart recover' if GPT if gpart list "$1" | grep -qi 'scheme: GPT'; then gpart recover "$1" || true fi # Find the index of the last partition; note that we need to compare # the starting sectors in case partitions are not numbered sensibly. idx=$(gpart backup "$1" | awk ' NR == 1 { next } $3 + 0 > start { start = $3 + 0; idx = $1 } END { print idx }') if [ -z "$idx" ]; then echo "Error finding final partition of $1" return 1 fi # Expand that partition gpart resize -i "$idx" "$1" } growfilesystem() { case $(fstyp -u "/dev/$1" 2>/dev/null) in ufs) growfs -y "/dev/$1" ;; zfs) zpool list -H -o name | while read -r pool; do zpool list -vH -o name "$pool" | grep "^[[:space:]]" | while read -r dev; do if [ "$dev" = "$1" ]; then zpool online -e "$pool" "$1" fi done done ;; "") # Nothing to grow here ;; *) echo "Don't know how to grow filesystem on /dev/$1" ;; esac } growfs_postboot_start() { # Run either growpart or growfilesystem depending on whether this is # something which is partitioned or not. case $(disktype "$1") in partitioned) growpart "$1" ;; unpartitioned) growfilesystem "$1" ;; esac } load_rc_config $name run_rc_command "$@"