Skip to main content

max / alloy

4.3 KB · 91 lines History Blame Raw
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 mod backend;
78 mod lsblk;
79 mod model;
80 mod view;
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(crate) use view::{DiskView, Tab};
88
89 #[cfg(test)]
90 mod fixtures;
91