xref: /freebsd/libexec/rc/rc.d/growfs_postboot (revision 5a31987d4c395ec4d3ed303cbc2e1d12ea54a039)
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