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