@@ -103,34 +103,63 @@ boot_snapshot() {
103103BOOT_DIR=" /boot/mochiboot"
104104COUNTER_FILE=" $BOOT_DIR /boot_counter"
105105
106+ # EFI variable path (mochiboot GUID: 6d6f6368-6962-6f6f-7400-000000000000)
107+ MOCHIBOOT_GUID=" 6d6f6368-6962-6f6f-7400-000000000000"
108+ EFIVARFS=" /sys/firmware/efi/efivars"
109+ BOOT_COUNT_VAR=" MochiBootBootCount-$MOCHIBOOT_GUID "
110+ FORCE_RECOVERY_VAR=" MochiBootForceRecovery-$MOCHIBOOT_GUID "
111+
112+ # EFI variable attributes (BS|RT = 0x07)
113+ ATTRS=" \x07\x00\x00\x00"
114+
115+ reset_efi_counter () {
116+ local efivar=" $EFIVARFS /$BOOT_COUNT_VAR "
117+ if [ -f " $efivar " ]; then
118+ # attributes (4 bytes LE) + counter value (4 bytes LE) = 8 bytes
119+ printf ' %b\x00\x00\x00\x00' " $ATTRS " > " $efivar "
120+ echo " boot counter reset (efivar)"
121+ fi
122+ }
123+
124+ set_force_recovery () {
125+ local efivar=" $EFIVARFS /$FORCE_RECOVERY_VAR "
126+ printf ' %b\x01\x00\x00\x00' " $ATTRS " > " $efivar "
127+ echo " force recovery on next boot (efivar)"
128+ }
129+
130+ get_efi_counter () {
131+ if [ -f " $EFIVARFS /$BOOT_COUNT_VAR " ]; then
132+ local data
133+ data=$( cat " $EFIVARFS /$BOOT_COUNT_VAR " 2> /dev/null) || return 1
134+ # skip first 4 bytes (attrs), read 4 bytes LE
135+ printf ' %d' " '${data: 4: 1} " 2> /dev/null
136+ fi
137+ }
138+
106139mark_good () {
107140 rm -f " $COUNTER_FILE "
108141 rm -f " $BOOT_DIR /next_snapshot"
142+ if [ -d " $EFIVARFS " ]; then
143+ reset_efi_counter
144+ fi
109145 echo " boot marked successful"
110146}
111147
112148check_counter () {
113149 local max=" ${1:- 3} "
114- if [ -f " $COUNTER_FILE " ]; then
115- local count=$( cat " $COUNTER_FILE " 2> /dev/null || echo 0)
116- if [ " $count " -ge " $max " ]; then
117- echo " recovery"
118- return 0
119- fi
120- fi
121- echo " ok"
122- return 0
123- }
124-
125- increment_counter () {
126150 local count=0
127- if [ -f " $COUNTER_FILE " ]; then
151+ # check efivar first, fall back to file
152+ if [ -f " $EFIVARFS /$BOOT_COUNT_VAR " ]; then
153+ count=$( get_efi_counter) || count=0
154+ elif [ -f " $COUNTER_FILE " ]; then
128155 count=$( cat " $COUNTER_FILE " 2> /dev/null || echo 0)
129156 fi
130- count=$(( count + 1 ))
131- mkdir -p " $BOOT_DIR "
132- echo " $count " > " $COUNTER_FILE "
133- echo " boot count: $count "
157+ if [ " $count " -ge " $max " ]; then
158+ echo " recovery"
159+ return 0
160+ fi
161+ echo " ok"
162+ return 0
134163}
135164
136165cmd=" ${1:- list} "
@@ -153,17 +182,28 @@ case "$cmd" in
153182 check_counter " $@ "
154183 ;;
155184 inc|increment)
156- increment_counter
185+ if [ -d " $EFIVARFS " ]; then
186+ local count=$( get_efi_counter)
187+ count=$(( count + 1 ))
188+ printf ' %b%s' " $ATTRS " " $( printf ' \\x%02x' " $count " ) \x00\x00\x00" > " $EFIVARFS /$BOOT_COUNT_VAR "
189+ echo " boot count: $count (efivar)"
190+ else
191+ increment_counter
192+ fi
193+ ;;
194+ force-recovery|fr)
195+ set_force_recovery
157196 ;;
158197 * )
159- echo " usage: mochi-snapshot {list|select|boot|mark-good|check|inc}"
198+ echo " usage: mochi-snapshot {list|select|boot|mark-good|check|inc|force-recovery }"
160199 echo " "
161- echo " list - list all btrfs snapshots"
162- echo " select - interactively pick a snapshot"
163- echo " boot <path> - set a snapshot to boot next"
164- echo " mark-good - mark current boot as successful"
165- echo " check [max] - check if boot count exceeds max"
166- echo " inc - increment boot counter"
200+ echo " list - list all btrfs snapshots"
201+ echo " select - interactively pick a snapshot"
202+ echo " boot <path> - set a snapshot to boot next"
203+ echo " mark-good - mark current boot as successful"
204+ echo " check [max] - check if boot count exceeds max"
205+ echo " inc - increment boot counter"
206+ echo " force-recovery - force recovery entry on next boot"
167207 exit 1
168208 ;;
169209esac
0 commit comments