Restore the partition table if cfdisk Resize shrinks an existing OS - #122
Restore the partition table if cfdisk Resize shrinks an existing OS#122rastermanden wants to merge 3 commits into
Conversation
Free-space install offers cfdisk when the disk has no unallocated gap. The screen already says to leave Free space, but cfdisk's Resize looks like the way to make that gap. It only rewrites the GPT. The filesystem — NTFS, ext4, btrfs, LUKS — still claims the old size, and the next boot into the other OS is a corrupt /home or UNMOUNTABLE_BOOT_VOLUME. That is the conversion-path trap: Quattro advertises single-drive dual-boot, the manual says shrink from Windows Disk Management first, and the installer then hands people a tool that cannot do that job. Reports: omacom/omarchy#7262, omacom/omarchy#7903. The partition tool now says Resize is destructive, snapshots the table before cfdisk, and writes the snapshot back if any existing partition shrank. Deleting an unused partition or creating nothing still stands. Filesystem-aware shrink (ntfsresize and friends) is out of scope; the documented path is still "make the gap from the other OS."
There was a problem hiding this comment.
Pull request overview
Adds a safety guard to prevent cfdisk partition-table-only shrinking from corrupting existing filesystems during free-space installs.
Changes:
- Snapshot, detect, and restore partition tables when existing partitions shrink.
- Add warnings and refusal flows around
cfdisk. - Add image-based regression tests.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Summary |
|---|---|
test/unit/partition-shrink-guard-test.sh |
Tests shrink restoration and delete, create, grow, and no-op behavior. |
configs/airootfs/usr/share/omarchy-iso/disk-partitioning.sh |
Implements partition comparison and restoration; post-cfdisk table-read failures currently fail open. |
configs/airootfs/root/configurator |
Adds warnings and invokes the guard; snapshot or baseline failures currently allow cfdisk to launch. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| dump=$(mktemp) | ||
| before=$(partition_starts_and_sizes "$disk") | ||
| save_partition_table "$disk" "$dump" || { rm -f "$dump"; dump=""; } |
There was a problem hiding this comment.
Fixed in 96927a6. The baseline scan and the snapshot are now prerequisites rather than best-effort: if either fails, open_partition_tool refuses to launch cfdisk and sends the user to Windows Disk Management instead. save_partition_table also checks sfdisk's exit status now, not just that the dump is non-empty, so a partial dump is never accepted as a snapshot.
Covered by test/unit/partition-shrink-guard-test.sh ("save_partition_table rejects a disk it cannot read", "a failed dump is not accepted as a snapshot").
| after=$(partition_starts_and_sizes "$disk") | ||
| shrunk=$(shrunk_partition_lines "$before" "$after") | ||
| [[ -n $shrunk ]] || return 1 |
There was a problem hiding this comment.
Fixed in 96927a6. partition_starts_and_sizes now captures parted's output into a variable first, so the status it returns is parted's rather than awk's, and it returns 1 when parted fails. restore_shrunk_partitions gained status 3 for "cannot tell", which the configurator aborts on — a missing snapshot returns 3 as well, so an unverifiable table can no longer collapse into the status-1 "table is fine" path.
Covered by "partition_starts_and_sizes reports an unreadable disk" and "a table that will not read back is 'cannot tell', not 'fine'".
Greptile SummaryThe PR prevents unsafe
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| configs/airootfs/root/.automated_script.sh | Clears all known staged inputs and enforces successful, current configuration before dashboard handoff, resolving the prior gate and credential-retention findings. |
| configs/airootfs/root/configurator | Adds fail-closed partition-table snapshot, shrink restoration, and abort handling around the interactive partition tool. |
| configs/airootfs/usr/share/omarchy-iso/disk-partitioning.sh | Adds helpers to capture partition geometry, detect meaningful shrink operations, snapshot GPT state, and restore it. |
| test/unit/installer-gate-test.sh | Exercises configurator failure, stale configuration, credential cleanup, missing output, and valid interactive and cidata handoffs. |
| test/unit/partition-shrink-guard-test.sh | Covers shrink restoration, permitted table edits, unreadable snapshots, unverifiable tables, and failed restores. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Start installer session] --> B[Clear prior inputs and credentials]
B --> C{Valid cidata input?}
C -->|Yes| D[Load current configuration]
C -->|No| E[Run configurator]
E --> F{Open cfdisk?}
F -->|No| G[Continue configuration]
F -->|Yes| H[Read and snapshot partition table]
H -->|Failure| I[Refuse partition tool]
H -->|Success| J[Run cfdisk]
J --> K{Existing partition shrank?}
K -->|No| G
K -->|Yes| L[Restore previous table]
L -->|Failure| M[Abort installation]
L -->|Success| I
D --> N{Configuration exists?}
G --> N
N -->|No| M
N -->|Yes| O[Start installer dashboard]
Reviews (3): Last reviewed commit: "Clear the previous attempt's SSH and Tai..." | Re-trigger Greptile
| say --foreground 1 "cfdisk Resize only changes the partition table. It does not shrink the filesystem." | ||
| say "The previous table could not be restored automatically. Do not continue this install." | ||
| abort "Aborted: shrinking an existing partition would corrupt the other OS." | ||
| fi |
There was a problem hiding this comment.
Failed restore does not stop install
When sfdisk fails to restore a shrunk partition table, this branch calls abort, but .automated_script.sh ignores the configurator's nonzero exit and unconditionally launches the installer dashboard. The install therefore continues after the safety guard reports that the existing filesystem remains behind a shortened partition boundary, producing a later failure or allowing retained configuration from an earlier attempt to operate against the damaged table.
Knowledge Base Used:
There was a problem hiding this comment.
Addressed in 96927a6, with one correction: .automated_script.sh sets set -euo pipefail at the top, and the else body inherits it (only the if condition is exempt), so a failing configurator did already terminate the script. The install was not actually reachable that way.
The guard is worth stating explicitly regardless, so the call is now ./configurator || exit 1, and a [[ -f user_configuration.json ]] gate covers both branches before the dashboard handoff. The launcher also clears the previous run's inputs first, since the abort message tells people to re-run it and a leftover configuration describes a partition layout the guard just rejected.
test/unit/installer-gate-test.sh runs the real handoff region against a sandboxed /root and asserts no install starts without a clean configurator exit and a configuration this run produced.
Review found the guard only covered the case where it worked. Every way of not knowing still returned "the table is fine", which is the one answer that lets the install proceed over a filesystem that now sits past its partition end. A missing snapshot no longer opens cfdisk unguarded — without a baseline to compare against and a dump to write back, a Resize is neither visible nor recoverable, so the tool is refused and the user is sent to Windows Disk Management. A table that will not read back after cfdisk, and a shrink whose restore fails, now abort with their own screens instead of falling through. parted is judged by its exit status rather than by whether it printed anything: an unreadable disk arriving as empty output reads exactly like a disk with no partitions. The launcher has to honour that refusal for any of it to mean anything. It now clears the previous run's outputs before starting — the abort tells people to re-run it, and a leftover configuration describes a layout the guard just rejected — and requires both a configurator that exited clean and a configuration file before it hands off to the installer. test/unit/installer-gate-test.sh runs the real handoff region against a sandboxed /root, and the shrink guard tests now cover the failure branches: no snapshot, an empty snapshot, a table that will not read back, and a restore that fails with the shrink still on the table.
Review caught that the retry cleanup was scoped to the wizard's own outputs. omarchy-cidata-load clears the full set before it copies, but that cleanup sits behind the drive-found check and never runs when no cidata drive is present. An autoinstall attempt that aborts and is retried with the drive pulled therefore falls through to the wizard with authorized_keys and tailscale_authkey still in /root, and the orchestrator treats both as present-means-use-it — the new machine would authorize the imaging rig's SSH key and enroll with its Tailscale key. The launcher now clears the same set the loader does. The test compares the two lists rather than trusting two hand-maintained copies, so a new optional input on the loader side fails instead of quietly reopening the leak.
Free-space installer's cfdisk Resize shrinks the GPT only — corrupts NTFS/ext4 (data loss)
Repo: omacom-io/omarchy-iso (installer lives here, not in
basecamp/omarchy)Related
/home)UNMOUNTABLE_BOOT_VOLUME, nontfsresize)What's wrong
Quattro's free-space install is the dual-boot conversion path. When the disk has no unallocated gap, the configurator offers Open partition tool, which launches
cfdisk:https://github.com/omacom-io/omarchy-iso/blob/quattro/configs/airootfs/root/configurator
The copy tells people to "Create unallocated free space" and "leave the target area as Free space." It does not say that Resize is partition-table-only.
cfdiskrewrites the GPT end sector and does not shrink NTFS, ext4, btrfs, or LUKS.If someone resizes an existing Windows
C:or Linux/home:STOP CODE: UNMOUNTABLE_BOOT_VOLUME. Install log showedPartition 3 resizedand never ranntfsresize.This is not a support mix-up. It is a validated data-loss bug on the path Omarchy just advertised.
Expected
Do not implement in-installer filesystem shrink (
ntfsresize/resize2fs/ btrfs shrink). That is the slow path and fights the documented model.Deleting an unused partition to make free space must still work.
Patch
Branch on a local checkout of
omacom-io/omarchy-iso:fix/cfdisk-resize-restores-tableopen_partition_tool()snapshots the table withsfdisk -dbefore cfdisk, restores if any existing partition (matched by start sector) shrank by more than 1MiB.partedis judged by its exit status, not by whether it printed anything — an unreadable disk arriving as empty output otherwise reads exactly like a disk with no partitions..automated_script.shhonours the refusal: it clears the previous run's inputs before starting (the abort tells people to re-run it, and a leftover configuration describes a layout the guard just rejected) and requires both a clean configurator exit and a configuration file before handing off to the installer. The cleanup covers the same setomarchy-cidata-loadclears, because the loader's own cleanup sits behind its drive-found check: an autoinstall attempt that aborts and is retried with the drive pulled would otherwise carryauthorized_keysandtailscale_authkeyinto the interactive install, and the orchestrator uses both whenever the files exist.test/unit/partition-shrink-guard-test.shcovers restore-on-shrink and the edits that must be left alone (delete, create, grow, no-op), plus every failure branch — no snapshot, an empty snapshot, a table that will not read back, and a failed restore with the shrink still on the table.test/unit/installer-gate-test.shruns the launcher's real handoff region against a sandboxed/rootand asserts no install starts without a configurator that exited clean and a configuration this run produced, that a pulled cidata drive leaves no remote-access credentials behind, and that the launcher's cleanup list still matches the loader's../test/allpasses.Why this is an adoption issue
Single-drive dual-boot is how Windows/Mac people try Omarchy without wiping the machine. If first contact eats
/homeor Windows, they do not become users — they become anti-advocates. The rest of the dual-boot cluster (#7263, #7515, #7867, ISO #111) is the same funnel; this one is the footgun that destroys data before the install even finishes.