1*5a31987dSColin Percival#!/bin/sh 2*5a31987dSColin Percival# 3*5a31987dSColin Percival# Copyright 2026 Colin Percival 4*5a31987dSColin Percival# 5*5a31987dSColin Percival# SPDX-License-Identifier: BSD-2-Clause 6*5a31987dSColin Percival# 7*5a31987dSColin Percival# PROVIDE: growfs_postboot 8*5a31987dSColin Percival# KEYWORD: nostart 9*5a31987dSColin Percival 10*5a31987dSColin Percival# Triggered by /etc/devd/growfs_postboot.conf: When a disk grows, enlarge the 11*5a31987dSColin Percival# final partition to fill the available space (if the disk is partitioned) or 12*5a31987dSColin Percival# enlarge the UFS filesystem or ZFS zpool (if in use for one of those). Note 13*5a31987dSColin Percival# that in the common case of "a disk is partitioned and one of the partitions 14*5a31987dSColin Percival# contains a filesystem" this script is invoked twice -- the repartitioning 15*5a31987dSColin Percival# done on the first call generates a new devd event which triggers the second 16*5a31987dSColin Percival# invocation. 17*5a31987dSColin Percival# 18*5a31987dSColin Percival# Enable by setting 19*5a31987dSColin Percival# growfs_postboot_enable=YES 20*5a31987dSColin Percival# in /etc/rc.conf. Note that on systems with growfs_enable=YES, it will often 21*5a31987dSColin Percival# be necessary to set growfs_swap_size=0 in order to disable swap creation; 22*5a31987dSColin Percival# otherwise the "final partition" is the swap space, not the filesystem and 23*5a31987dSColin Percival# growing the disk will not cause the most likely desired results. 24*5a31987dSColin Percival 25*5a31987dSColin Percival. /etc/rc.subr 26*5a31987dSColin Percival 27*5a31987dSColin Percivalname="growfs_postboot" 28*5a31987dSColin Percivaldesc="automatically grow file systems during runtime" 29*5a31987dSColin Percivalrcvar="growfs_postboot_enable" 30*5a31987dSColin Percivalstart_cmd="growfs_postboot_start" 31*5a31987dSColin Percival 32*5a31987dSColin Percivaldisktype() { 33*5a31987dSColin Percival sysctl -n kern.geom.conftxt | awk -v dev="$1" ' 34*5a31987dSColin Percival BEGIN { 35*5a31987dSColin Percival partitioned=0 36*5a31987dSColin Percival indev=0 37*5a31987dSColin Percival } 38*5a31987dSColin Percival { 39*5a31987dSColin Percival if (dev == $3) { 40*5a31987dSColin Percival indev=1 41*5a31987dSColin Percival devlevel=$1 42*5a31987dSColin Percival } else if (devlevel >= $1) { 43*5a31987dSColin Percival indev=0 44*5a31987dSColin Percival } else if (indev == 1) { 45*5a31987dSColin Percival if ($2 == "PART") { 46*5a31987dSColin Percival partitioned=1 47*5a31987dSColin Percival } 48*5a31987dSColin Percival } 49*5a31987dSColin Percival } 50*5a31987dSColin Percival END { 51*5a31987dSColin Percival if (partitioned == 1) { 52*5a31987dSColin Percival print "partitioned" 53*5a31987dSColin Percival } else { 54*5a31987dSColin Percival print "unpartitioned" 55*5a31987dSColin Percival } 56*5a31987dSColin Percival }' 57*5a31987dSColin Percival} 58*5a31987dSColin Percival 59*5a31987dSColin Percivalgrowpart() { 60*5a31987dSColin Percival # Run 'gpart recover' if GPT 61*5a31987dSColin Percival if gpart list "$1" | grep -qi 'scheme: GPT'; then 62*5a31987dSColin Percival gpart recover "$1" || true 63*5a31987dSColin Percival fi 64*5a31987dSColin Percival 65*5a31987dSColin Percival # Find the index of the last partition; note that we need to compare 66*5a31987dSColin Percival # the starting sectors in case partitions are not numbered sensibly. 67*5a31987dSColin Percival idx=$(gpart backup "$1" | awk ' 68*5a31987dSColin Percival NR == 1 { next } 69*5a31987dSColin Percival $3 + 0 > start { start = $3 + 0; idx = $1 } 70*5a31987dSColin Percival END { print idx }') 71*5a31987dSColin Percival if [ -z "$idx" ]; then 72*5a31987dSColin Percival echo "Error finding final partition of $1" 73*5a31987dSColin Percival return 1 74*5a31987dSColin Percival fi 75*5a31987dSColin Percival 76*5a31987dSColin Percival # Expand that partition 77*5a31987dSColin Percival gpart resize -i "$idx" "$1" 78*5a31987dSColin Percival} 79*5a31987dSColin Percival 80*5a31987dSColin Percivalgrowfilesystem() { 81*5a31987dSColin Percival case $(fstyp -u "/dev/$1" 2>/dev/null) in 82*5a31987dSColin Percival ufs) growfs -y "/dev/$1" 83*5a31987dSColin Percival ;; 84*5a31987dSColin Percival zfs) zpool list -H -o name | 85*5a31987dSColin Percival while read -r pool; do 86*5a31987dSColin Percival zpool list -vH -o name "$pool" | 87*5a31987dSColin Percival grep "^[[:space:]]" | 88*5a31987dSColin Percival while read -r dev; do 89*5a31987dSColin Percival if [ "$dev" = "$1" ]; then 90*5a31987dSColin Percival zpool online -e "$pool" "$1" 91*5a31987dSColin Percival fi 92*5a31987dSColin Percival done 93*5a31987dSColin Percival done 94*5a31987dSColin Percival ;; 95*5a31987dSColin Percival "") # Nothing to grow here 96*5a31987dSColin Percival ;; 97*5a31987dSColin Percival *) echo "Don't know how to grow filesystem on /dev/$1" 98*5a31987dSColin Percival ;; 99*5a31987dSColin Percival esac 100*5a31987dSColin Percival} 101*5a31987dSColin Percival 102*5a31987dSColin Percivalgrowfs_postboot_start() { 103*5a31987dSColin Percival # Run either growpart or growfilesystem depending on whether this is 104*5a31987dSColin Percival # something which is partitioned or not. 105*5a31987dSColin Percival case $(disktype "$1") in 106*5a31987dSColin Percival partitioned) 107*5a31987dSColin Percival growpart "$1" 108*5a31987dSColin Percival ;; 109*5a31987dSColin Percival unpartitioned) 110*5a31987dSColin Percival growfilesystem "$1" 111*5a31987dSColin Percival ;; 112*5a31987dSColin Percival esac 113*5a31987dSColin Percival} 114*5a31987dSColin Percival 115*5a31987dSColin Percivalload_rc_config $name 116*5a31987dSColin Percivalrun_rc_command "$@" 117