max / alloy
| 1 | //! Attached storage and what is mounted: the `alloy disk` verb. |
| 2 | //! |
| 3 | //! Without this verb, plugging in a USB stick does nothing: udisks2 is in the |
| 4 | //! image, nothing else drives it, yazi ships no mount path, and a stick or a |
| 5 | //! Framework expansion card stays invisible until somebody mounts it by hand as |
| 6 | //! root. |
| 7 | //! |
| 8 | //! # What this verb is not |
| 9 | //! |
| 10 | //! **It does not write installer media.** `alloy disk` manages disks and |
| 11 | //! partitions, not ISOs. |
| 12 | //! |
| 13 | //! `alloy image` already does it, and the |
| 14 | //! constraint it works under (docs/CONSOLE.md, "It does not write the disk") |
| 15 | //! applies with more force here: `build/build-image.sh --write` refuses |
| 16 | //! partitions, refuses anything mounted, and verifies with `cmp` against a |
| 17 | //! negative control. Re-deriving that behind a second verb is how a disk-eating |
| 18 | //! bug gets written. A user who wants to make an install drive wants |
| 19 | //! `alloy image`, and the empty state says so rather than leaving them to guess. |
| 20 | //! |
| 21 | //! # What it does do: partitions |
| 22 | //! |
| 23 | //! Create, delete, format and resize, on the volume tab rather than behind a |
| 24 | //! tab of their own. One fewer place to look, and the operations act on the |
| 25 | //! volume already selected there. |
| 26 | //! |
| 27 | //! Three rules hold this surface, and the first is the one the rest rest on: |
| 28 | //! |
| 29 | //! 1. **The disk the running system boots from is refused outright**, and the |
| 30 | //! check is drive-wide. See [`DiskView::drive_is_system`] for why a |
| 31 | //! volume-level check is not enough, which is the least obvious thing in |
| 32 | //! this file. |
| 33 | //! 2. **Every partition write confirms, naming what is on the volume.** Not the |
| 34 | //! command that would run and not "are you sure": the size, the label and |
| 35 | //! the filesystem about to be destroyed. `describe_loss` in [`view`] is that sentence, |
| 36 | //! in one place so four prompts cannot drift. |
| 37 | //! 3. **Still nothing escalates.** The operations are not in `udisksctl`, whose |
| 38 | //! verbs are mount, unmount, unlock, lock, loop-setup, loop-delete, |
| 39 | //! power-off and smart-simulate. They are on the udisks2 D-Bus interfaces, |
| 40 | //! reached with `busctl call` so they stay argv and stay in the command log. |
| 41 | //! See `udisks_call` in [`backend`]. |
| 42 | //! |
| 43 | //! # Two tools, one screen |
| 44 | //! |
| 45 | //! Reading is `lsblk`, acting is `udisksctl`, and they are detected separately |
| 46 | //! because a machine can have the first without the second. lsblk is in |
| 47 | //! util-linux and is on anything; udisks2 is a daemon that has to be running. A |
| 48 | //! machine with lsblk alone still gets the inventory, with the action keys shown |
| 49 | //! as unavailable and a reason, rather than a screen that lists rows and then |
| 50 | //! does nothing when they are pressed. |
| 51 | //! |
| 52 | //! Nothing here escalates. udisks answers a session user through polkit for |
| 53 | //! removable media, which is the whole reason it is the right tool: the |
| 54 | //! alternative is `mount(8)` behind `run0`, which is a privilege prompt for |
| 55 | //! plugging in a USB stick. |
| 56 | //! |
| 57 | //! # Removable is not the `RM` flag |
| 58 | //! |
| 59 | //! Measured on fw13: a Samsung PSSD T9 over USB reports `rm: false` |
| 60 | //! and `tran: "usb"`. It is an external drive a person unplugs, and the kernel's |
| 61 | //! removable bit says otherwise, because that bit means "the medium can leave |
| 62 | //! the drive" (a card reader, an optical drive) rather than "the drive can leave |
| 63 | //! the machine". Going by `RM` alone would put the one disk the user came here |
| 64 | //! for on the wrong tab. So [`Drive::detachable`](model::Drive::detachable) is the flag OR a hot-plug |
| 65 | //! transport, and the T9 is the fixture that pins it. |
| 66 | //! |
| 67 | //! # Nothing is filtered away |
| 68 | //! |
| 69 | //! The default tab is the removable one because that is what the verb is for, |
| 70 | //! but the other tab is every volume on the machine, on the rule install.rs |
| 71 | //! already states: a user whose disk is simply missing has no way to tell a |
| 72 | //! filter from a hardware fault. Rows that cannot be acted on are listed and say |
| 73 | //! why. |
| 74 | //! |
| 75 | //! <!-- wiki: alloy-console --> |
| 76 | |
| 77 | |
| 78 | |
| 79 | |
| 80 | |
| 81 | |
| 82 | // The verb's vocabulary stays inside the verb: `model`, `lsblk` and `backend` |
| 83 | // are `pub(super)` throughout and are named by nothing outside this directory. |
| 84 | // What crosses the boundary is the screen and the tab `main.rs` opens it on, so |
| 85 | // that is what the facade carries, and `crate::disk::DiskView` is the path it |
| 86 | // was before the split. |
| 87 | pub use ; |
| 88 | |
| 89 | |
| 90 | |
| 91 |