@@ -13,9 +13,13 @@ show_help() {
1313atomic-gc v${VERSION} - Manage generations
1414
1515Usage:
16- atomic-gc [OPTIONS] [COUNT] Garbage collect (keep COUNT, default: $KEEP_GENERATIONS )
17- atomic-gc list List all generations
16+ atomic-gc [OPTIONS] [COUNT] Garbage collect (keep COUNT, default: $KEEP_GENERATIONS )
17+ atomic-gc list List all generations
1818 atomic-gc rm [OPTIONS] GEN_ID [GEN_ID ...] Delete specific generation(s)
19+ atomic-gc activate GEN_ID Mark generation as active (UEFI boots first)
20+ atomic-gc deactivate GEN_ID Remove active mark from generation
21+ atomic-gc protect GEN_ID Protect generation from garbage collection
22+ atomic-gc unprotect GEN_ID Remove protection from generation
1923
2024Options:
2125 -n, --dry-run Show what would be done
3741COMMAND=" gc"
3842
3943case " ${1:- } " in
40- list) COMMAND=" list" ; shift ;;
41- rm) COMMAND=" rm" ; shift ;;
44+ list) COMMAND=" list" ; shift ;;
45+ rm) COMMAND=" rm" ; shift ;;
46+ activate) COMMAND=" activate" ; shift ;;
47+ deactivate) COMMAND=" deactivate" ; shift ;;
48+ protect) COMMAND=" protect" ; shift ;;
49+ unprotect) COMMAND=" unprotect" ; shift ;;
4250esac
4351
4452ARGS=()
@@ -70,10 +78,17 @@ case "$COMMAND" in
7078 generations=$( list_generations)
7179 [[ -z " $generations " ]] && { echo " No generations found" ; exit 0; }
7280 for gen_id in $generations ; do
81+ markers=" "
82+ if [[ -f " ${ESP} /EFI/Linux/0-active-arch-${gen_id} .efi" ]]; then
83+ markers+=" (active)"
84+ fi
85+ if [[ -f " ${ESP} /EFI/Linux/arch-${gen_id} .efi.protected" ]]; then
86+ markers+=" (protected)"
87+ fi
7388 if [[ " root-${gen_id} " == " $current_subvol " ]]; then
74- echo " * ${gen_id} (current)"
89+ echo " * ${gen_id}${markers} (current)"
7590 else
76- echo " ${gen_id} "
91+ echo " ${gen_id}${markers} "
7792 fi
7893 done
7994 ;;
@@ -82,13 +97,18 @@ case "$COMMAND" in
8297 [[ ${# ARGS[@]} -eq 0 ]] && { echo " ERROR: Specify generation(s) to delete" >&2 ; exit 1; }
8398 ensure_btrfs_mounted || exit 1
8499 current_subvol=$( get_current_subvol)
85- # Validate all targets exist before deleting any
100+ # Validate all targets exist and are not protected before deleting any
86101 for gen_id in " ${ARGS[@]} " ; do
87102 if [[ ! -f " ${ESP} /EFI/Linux/arch-${gen_id} .efi" ]] && \
103+ [[ ! -f " ${ESP} /EFI/Linux/0-active-arch-${gen_id} .efi" ]] && \
88104 [[ ! -d " ${BTRFS_MOUNT} /root-${gen_id} " ]]; then
89105 echo " ERROR: Generation not found: ${gen_id} " >&2
90106 exit 1
91107 fi
108+ if [[ -f " ${ESP} /EFI/Linux/arch-${gen_id} .efi.protected" ]]; then
109+ echo " ERROR: Refuse: ${gen_id} is protected (remove protection first)" >&2
110+ exit 1
111+ fi
92112 done
93113 if [[ " $YES " -eq 0 && " $DRY_RUN " -eq 0 ]]; then
94114 echo " Will delete: ${ARGS[*]} "
@@ -111,4 +131,91 @@ case "$COMMAND" in
111131 fi
112132 garbage_collect " $KEEP_COUNT " " $DRY_RUN "
113133 ;;
134+ activate)
135+ [[ ${# ARGS[@]} -eq 0 ]] && { echo " ERROR: Specify generation to activate" >&2 ; exit 1; }
136+ gen_id=" ${ARGS[0]} "
137+ acquire_lock
138+ # Validate gen_id format
139+ if [[ ! " $gen_id " =~ ^[0-9]{8}-[0-9]{6}(-.+)? $ ]]; then
140+ echo " ERROR: Invalid generation ID format: ${gen_id} " >&2
141+ exit 1
142+ fi
143+ # Check if already active
144+ if [[ -f " ${ESP} /EFI/Linux/0-active-arch-${gen_id} .efi" ]]; then
145+ echo " Generation ${gen_id} is already active"
146+ exit 0
147+ fi
148+ # Check if UKI exists (regular or active)
149+ if [[ ! -f " ${ESP} /EFI/Linux/arch-${gen_id} .efi" ]] && \
150+ [[ ! -f " ${ESP} /EFI/Linux/0-active-arch-${gen_id} .efi" ]] && \
151+ [[ ! -d " ${BTRFS_MOUNT} /root-${gen_id} " ]]; then
152+ echo " ERROR: Generation not found: ${gen_id} " >&2
153+ exit 1
154+ fi
155+ # Rename to add active prefix
156+ if [[ -f " ${ESP} /EFI/Linux/arch-${gen_id} .efi" ]]; then
157+ mv " ${ESP} /EFI/Linux/arch-${gen_id} .efi" " ${ESP} /EFI/Linux/0-active-arch-${gen_id} .efi"
158+ fi
159+ echo " Activated: ${gen_id} (will boot first)"
160+ ;;
161+ deactivate)
162+ [[ ${# ARGS[@]} -eq 0 ]] && { echo " ERROR: Specify generation to deactivate" >&2 ; exit 1; }
163+ gen_id=" ${ARGS[0]} "
164+ acquire_lock
165+ # Validate gen_id format
166+ if [[ ! " $gen_id " =~ ^[0-9]{8}-[0-9]{6}(-.+)? $ ]]; then
167+ echo " ERROR: Invalid generation ID format: ${gen_id} " >&2
168+ exit 1
169+ fi
170+ # Check if active
171+ if [[ ! -f " ${ESP} /EFI/Linux/0-active-arch-${gen_id} .efi" ]]; then
172+ echo " Generation ${gen_id} is not active"
173+ exit 0
174+ fi
175+ # Rename to remove active prefix
176+ mv " ${ESP} /EFI/Linux/0-active-arch-${gen_id} .efi" " ${ESP} /EFI/Linux/arch-${gen_id} .efi"
177+ echo " Deactivated: ${gen_id} "
178+ ;;
179+ protect)
180+ [[ ${# ARGS[@]} -eq 0 ]] && { echo " ERROR: Specify generation to protect" >&2 ; exit 1; }
181+ gen_id=" ${ARGS[0]} "
182+ acquire_lock
183+ # Validate gen_id format
184+ if [[ ! " $gen_id " =~ ^[0-9]{8}-[0-9]{6}(-.+)? $ ]]; then
185+ echo " ERROR: Invalid generation ID format: ${gen_id} " >&2
186+ exit 1
187+ fi
188+ # Check if already protected
189+ if [[ -f " ${ESP} /EFI/Linux/arch-${gen_id} .efi.protected" ]]; then
190+ echo " Generation ${gen_id} is already protected"
191+ exit 0
192+ fi
193+ # Check if UKI exists (could be active or regular)
194+ if [[ -f " ${ESP} /EFI/Linux/arch-${gen_id} .efi" ]] || \
195+ [[ -f " ${ESP} /EFI/Linux/0-active-arch-${gen_id} .efi" ]] || \
196+ [[ -d " ${BTRFS_MOUNT} /root-${gen_id} " ]]; then
197+ touch " ${ESP} /EFI/Linux/arch-${gen_id} .efi.protected"
198+ echo " Protected: ${gen_id} (won't be garbage collected)"
199+ else
200+ echo " ERROR: Generation not found: ${gen_id} " >&2
201+ exit 1
202+ fi
203+ ;;
204+ unprotect)
205+ [[ ${# ARGS[@]} -eq 0 ]] && { echo " ERROR: Specify generation to unprotect" >&2 ; exit 1; }
206+ gen_id=" ${ARGS[0]} "
207+ acquire_lock
208+ # Validate gen_id format
209+ if [[ ! " $gen_id " =~ ^[0-9]{8}-[0-9]{6}(-.+)? $ ]]; then
210+ echo " ERROR: Invalid generation ID format: ${gen_id} " >&2
211+ exit 1
212+ fi
213+ # Check if protected
214+ if [[ ! -f " ${ESP} /EFI/Linux/arch-${gen_id} .efi.protected" ]]; then
215+ echo " Generation ${gen_id} is not protected"
216+ exit 0
217+ fi
218+ rm -f " ${ESP} /EFI/Linux/arch-${gen_id} .efi.protected"
219+ echo " Unprotected: ${gen_id} "
220+ ;;
114221esac
0 commit comments