Disks and filesystems
Single-page view · as markdown
Disks and filesystems
Peios / Using Peios / Disks and filesystems
Start with the disk's identity and current use. Partitioning and formatting can destroy data; a familiar device name is not enough to identify the target.
Compare size, model/serial where available, partition layout and mount points. Use Disk Manager for a desktop inspection, and Stable device names for references that must survive a reboot. Unreadable contents are unknown, not evidence that a disk is blank.
Where to start #
| What you need to do | Guide |
|---|---|
| Find software, configuration, service state or user data | Where files live |
| Inspect disks, partitions and mounts on the desktop | Disk Manager, currently inspection-only |
| Diagnose block or inode pressure without changing data | Find why a filesystem is full |
| Write or inspect a GPT | Partitioning |
| Create an ext filesystem with its root permissions already present | Formatting with security descriptors and mke2fs |
| Copy the live system onto bootable storage | Installing to disk |
| Record a filesystem, partition or hardware identity | Stable device names |
| Attach existing storage and choose missing-SD behaviour | Mount policies |
| Explain a file in a merged system directory | StrataFS |
Where this sits in a running system #
debugfs is the tool to reach for when you want to inspect an image offline — without mounting it, and therefore without KACS being involved at all. It reads and writes extended attributes directly, which makes it the way to confirm that a security descriptor really landed on disk:
debugfs -R "ea_list <2>" /dev/vda2
Inode 2 is always the root directory of an ext filesystem, so this asks what extended attributes the filesystem's root carries.
e2fsck has a specific place in boot. Checking and repairing the root filesystem is the initramfs's job, not peinit's — by the time peinit runs, the root is already mounted, and a filesystem checker cannot repair a filesystem that is in use. See The initramfs stage.
FAT and the EFI system partition #
The reason Peios ships FAT tooling at all is the EFI system partition. UEFI requires the ESP to be FAT, so a system that cannot format FAT cannot create its own boot partition.
An ESP is also the clearest case of a filesystem that holds no access control of its own. There is no extended-attribute channel, so no security descriptor is ever written to it, and none can be. Its entire access policy comes from the mount — necessarily one of the synthesising classes, since facs_deny_missing on a filesystem where every file is permanently missing an SD would make the whole partition unreachable. See SD storage by filesystem.
The practical consequence: the protection on your boot partition is the mount policy and the physical security of the disk, not a descriptor on the files. Treat the contents accordingly.
What is not here yet #
Partition tables other than GPT. part writes GPT and only GPT. Peios boots through UEFI with no bootloader, so MBR has nothing to do on a Peios system — but a disk that already carries one is recognised and named rather than silently overwritten. Resizing, moving and MBR↔GPT conversion do not exist either. See Partitioning.
Filesystems other than ext2/3/4 and FAT. The mount side understands XFS, Btrfs and NTFS as well — see SD storage by filesystem — but Peios ships creation tools only for the ext and FAT families.
What ships #
| Package | Contents |
|---|---|
net.sourceforge.e2fsprogs | The tools below. |
net.sourceforge.e2fsprogs-devel | Headers, linker symlinks and pkg-config files for building against the libraries. |
net.sourceforge.e2fsprogs-static | Static archives. |
net.sourceforge.e2fsprogs-libext2fs, net.sourceforge.e2fsprogs-libe2p, net.sourceforge.e2fsprogs-libcom-err, net.sourceforge.e2fsprogs-libss, net.sourceforge.e2fsprogs-libuuid | The runtime shared libraries, packaged separately so a consumer can depend on one without pulling the tools. |
The tools themselves:
| Tool | Purpose |
|---|---|
mke2fs, mkfs.ext2, mkfs.ext3, mkfs.ext4 | Create a filesystem. This is where Peios security descriptors enter. |
e2fsck, fsck.ext2, fsck.ext3, fsck.ext4, fsck | Check and repair a filesystem. |
tune2fs | Change parameters on an existing filesystem, including enabling features after the fact. |
resize2fs | Grow or shrink a filesystem. |
dumpe2fs | Print superblock and block-group information. |
debugfs | Interactive low-level access to a filesystem image, including reading and writing extended attributes directly. |
blkid, findfs | Identify filesystems by label, UUID or type. |
e2label, e2image, e2undo, e2freefrag, filefrag, badblocks, logsave | Labelling, imaging, undo, fragmentation and block-scanning utilities. |
chattr, lsattr | Read and set ext2/3/4 inode attributes. |
uuidgen | Generate a UUID. |
net.sourceforge.e2fsprogs-libuuid comes from e2fsprogs;
org.kernel.libblkid comes from util-linux. The split is arbitrary but fixed:
each library has exactly one owning package, so the two sources never both ship
the same file.
From dosfstools:
| Tool | Purpose |
|---|---|
mkfs.fat, mkfs.vfat, mkfs.msdos | Create a FAT12/16/32 filesystem. |
fsck.fat, fsck.vfat, fsck.msdos | Check and repair a FAT filesystem. |
fatlabel | Read or set a FAT volume label. |
The pre-4.0 aliases (mkdosfs, dosfsck, dosfslabel) are deliberately not shipped — they exist for compatibility with a command-line history Peios does not have.
Where these tools live #
The user-facing filesystem tools above are installed in /usr/bin, reached as /bin through the runtime view. See Install destinations for the broader package-layout policy.
The fsck dispatcher also uses type-specific checker names in /usr/libexec/fsck/, exposed through /libexec/fsck:
/libexec/fsck/fsck.ext2 fsck.ext3 fsck.ext4
fsck.fat fsck.vfat fsck.msdos
These backend paths are the dispatch interface: fsck picks fsck.<type> for the filesystem type it detects or is given. The checker can also have a direct operator interface: e2fsck remains in /usr/bin, and fsck.fat remains there with the fat, vfat and msdos backend names linking to it. This layout is explicit in the pinned e2fsprogs recipe and dosfstools recipe. fsck searches /libexec/fsck first, then the directories on your PATH, so a third-party checker installed elsewhere on PATH is still found.
The mkfs.<type> names stay directly available in /usr/bin: Peios ships no mkfs front-end.
Why these tools are packaged, not rewritten #
Peios ships upstream e2fsprogs for ext2/3/4 and dosfstools for FAT. The on-disk formats remain Linux-compatible. e2fsprogs has Peios additions for security descriptors; dosfstools has no functional patch because FAT has no xattr channel in which to store one.
Filesystem creation and offline repair operate below the mounted access-control
layer. mount is where a filesystem enters KACS and receives its policy.
Peios-specific tools such as mount, lsblk and ls use that security model;
rewriting the formatters and checkers would instead duplicate upstream format
and repair logic without changing this boundary.
Where files live
Peios / Using Peios / Disks and filesystems
Use this map to find files and trace merged paths such as /bin and /etc
to the directories that actually store their contents.
The map describes the base filesystem in
dev.peios.fsbase at 92b0caf.
Images and local configuration can differ. Inspect the running machine before
assuming its layout or storage lifetime matches.
Choose where to look #
| What you are looking for | Location and purpose |
|---|---|
| Vendor-supplied software and defaults | /usr: executables in bin/sbin, helpers in libexec, libraries/modules/firmware in lib, shared files in share, defaults in etc/conf. |
| Local software and file-based overrides | /lcl: operator-managed trees such as bin, sbin, etc and conf. Local entries can hide vendor entries. |
| Files generated from registry configuration | /system/retc: reconciler output projected into /etc. Find the owning setting or component before editing its generated output. |
| Service data and identity stores | /var/state: persistent mutable state, including reserved services and protected secrets namespaces. See registry source paths for the machine's hives. |
| Caches, logs and crash data | /var/cache, /var/log and /var/crash. Check service configuration: recorded events and service output need not be text files here. Start with Event Viewer. |
| A person's files | /home: human home directories; services use configured state/runtime directories. Access depends on security descriptors. |
| Operator-managed bulk data | /data. Its name does not imply a separate disk or a backup policy. |
| Content served by this host | /srv: the host's served-content namespace. Check the service configuration for the actual path. |
| Software with its own directory layout | /opt. |
| Runtime sockets and service directories | /run, including /run/services and the /run/lock directory recreated by peinit at boot. Sockets and PID files are runtime resources, not saved service data. |
| Temporary working files | /tmp and /var/tmp; read the lifetime caveat below. |
| Boot inputs and generated artifacts | /boot holds the initramfs source tree and EFI-partition mount location; /system/boot holds generated initramfs output. Check that the intended EFI partition is mounted. |
| Additional mounted storage | /mnt and /media are available mount locations. Their existence does not attach a device. |
| Kernel and device interfaces | /proc, /sys and /dev. These expose runtime interfaces, not ordinary saved application data. |
A path does not grant access or prove that its data is safe to delete, backed up, or kept during installation. For space problems, use Find why a filesystem is full before deleting anything.
Trace a runtime path to its real file #
The base system uses StrataFS views for /bin, /sbin, /lib, /libexec,
/share, /include, /etc and /conf. Ordinary views put the corresponding
/lcl directory above /usr; the vendor stratum is read-only through that
view. This does not make the underlying /usr tree universally read-only.
Use the read-only inspector:
list shows the current mount namespace; resolve explains providers and write
routing without writing or granting permission. See Inspecting a stack
for interpretation and access limits.
/lib64 is different: the reviewed x86-64 base supplies a relative symlink to
usr/lib/x86_64-linux-peios, not a StrataFS view. The ordinary /lib view maps
the whole lib trees, including modules and firmware. These distinctions are
implemented by the
base recipe
and root-filesystem hook.
Find the owner of configuration #
Start with Find where a setting lives
and the component's regman documentation. A visible /etc file may be generated
from a registry setting; find that setting rather than changing generated output.
In the reviewed real-root hook, /etc has this precedence:
/system/retc: generated registry output./lcl/etc: local configuration, also the create stratum./usr/etc: vendor defaults.
An existing generated name wins over the same name in /lcl/etc. /conf has
only local and vendor tiers. The
initramfs hook
also uses only local and vendor tiers for /etc; do not assume the installed
root and the startup environment have identical views.
/lcl/policy is separate from ordinary file-based configuration. Its autorun
and registry-apply directories carry boot policy, not general-purpose storage;
see peinit’s Phase 1 reference
for their authority and execution rules.
Check temporary-file and boot-storage assumptions #
In the reviewed base setup, /tmp is a plain directory. The fsbase package's
temporary-directory policy
explains that it is disk-backed on an installed system and is not cleared at
boot or size-limited by that setup. A live image's volatile upper layer has a
different lifetime. Do not rely on a reboot to erase temporary files, or assume
that /tmp has a separate space budget. /var/tmp is intended for temporary
files that survive reboot; check the actual mount and local cleanup policy.
For boot files, the activation checklist distinguishes generated output, the intended EFI partition and the running kernel.
Stable device names
Peios / Using Peios / Disks and filesystems
Use a stable identity for a boot command line, saved mount reference or script.
Use the current kernel device name only after checking which device it names
in this boot: /dev/vda, /dev/sda and /dev/nvme0n1 depend on discovery order
and can change when hardware, controllers or probe timing changes.
- Inspect disks and partitions with
part listandlsblk. - Choose the identity that matches the object you mean: filesystem UUID, partition UUID or hardware identity.
- Match that identity back to the size, layout and current mounts before any destructive operation. A readable link identifies a device; it does not establish that its contents can be erased.
The links live under /dev/disk/ and point to the current kernel name:
| Directory | Keyed by | Example |
|---|---|---|
by-uuid | the filesystem's UUID, written when it was formatted | 4ED7-A6AC -> ../../vda2 |
by-label | the filesystem's label | PEIOS -> ../../vda |
by-partuuid | the GPT partition entry's UUID | 2036ae68-…-f118299d5446 -> ../../vda2 |
by-partlabel | the GPT partition entry's name | |
by-id | the hardware's own identity: model and serial, or WWN | nvme-QEMU_NVMe_Ctrl_peiosnvme1 -> ../../nvme0n1 |
by-path | the bus position the device sits at | |
by-diskseq | the kernel's monotonic disk sequence number, for this boot only |
Which one to use depends on what you mean. A filesystem is by-uuid — it follows the data if the disk is cloned, and it is what root=UUID= on the kernel command line names. A partition independent of what is on it is by-partuuid. A physical disk whatever is written to it is by-id. by-label is the human-friendly choice, but labels need not be unique. A filesystem clone also carries its UUID; verify which device a UUID resolves to when copies may be attached.
Partitions appear under the same keys with the parent's identity plus -partN, so by-id/nvme-…-part2 is the second partition of that NVMe disk.
Where they are not available #
The initramfs has none of them. No device manager runs there — only a single pass that loads drivers, described in The initramfs stage. The initramfs still honours root=UUID=, but it resolves the UUID by probing each block device directly rather than by looking in /dev/disk/by-uuid, and lsblk does the same. That is why the installer's cmdline works on a machine the initramfs has never seen: it never depended on the links.
by-diskseq does not survive a reboot. The sequence number is assigned in the order devices appear during this boot, which is precisely the property the other directories exist to avoid depending on. It is there for tools that need to tell a re-plugged device from the one it replaced.
Who creates them #
The names are made by the device manager, eudev, which peinit starts first in phase 2 of boot. As each block device appears — at boot, when it replays the kernel's enumeration, and afterwards whenever a device is plugged in — the device manager probes it (its partition table, and the filesystem signature on each partition) and creates the matching links. Unplug the device and the links go away.
That is the same daemon that loads a driver for each device the kernel reports, so a disk behind a modular controller gets its driver, its kernel name and its stable names from one pass. See Boot and boot modes for where the service sits in the boot order; a service that opens a device by stable name should Requires it, because peinit does not release eudev's dependents until the boot-time replay has finished.
The same idea applies to network interfaces. The kernel names them eth0, eth1 in probe order; the device manager renames each one by where it sits — enp0s3 for the card in PCI slot 3 on bus 0, eno1 for an onboard port the firmware numbers — so a configuration written against the name survives a second card or a driver that probes faster next time. net.ifnames=0 on the kernel command line turns the renaming off.
The device manager does not decide who may open a device. That is the security descriptor on the node, seeded on /dev before any of this runs — see SD storage by filesystem.
Where to go next #
For writing a partition table that gives every partition a by-partuuid name, read Partitioning.
For how the installer records the root filesystem's UUID into the kernel command line, read Installing to disk.
Find why a filesystem is full
Peios / Using Peios / Disks and filesystems
Start with the operation that failed, not with a directory to delete. Keep its exact error, path and time. A permission denial, read-only filesystem or I/O failure is not established as a space problem merely because a write failed.
This procedure inspects capacity and a selected directory tree. It does not delete data, repair or resize a filesystem, change mounts, or stop services. Use your current authorized access; incomplete visibility is a finding, not a reason to broaden privileges automatically.
1. Identify the affected filesystem #
Replace the example path below with a verified existing path involved in the failure. If the attempted new file does not exist, use its existing parent. Quote paths containing spaces.
After each command, retain its exit status and any diagnostics as well as the
report. df reports the filesystem containing
the named path; do not substitute the root filesystem's figures without
checking that it is the one involved.
- Record Filesystem, Type and Mounted on so later measurements refer to the same filesystem.
- Inspect Avail and Use% in the block-space report.
- Inspect the inode counts and free-inode figure in the second report. Inode exhaustion can prevent creating files even when block space remains.
- If the path or filesystem lookup fails, resolve that diagnostic before treating any other printed row as the answer.
These commands use the default no-sync behavior; they do not request a flush. If the reported capacity does not explain the failure, keep the original error and investigate that separately rather than starting cleanup by guesswork.
2. Look within a narrow, permitted tree #
Choose a known directory on that filesystem, such as the affected application's
identified data tree. Substitute that directory for /known/tree:
For suspected inode pressure, count entries instead of allocated space:
Pass the directory itself, not a shell * expansion that omits dotfiles. Start
narrowly and drill into one observed large directory at a time.
Keep stderr and the exit status for every run. A permission or traversal error can occur alongside printed totals; those totals are incomplete. Record files that disappeared or changed during the walk too. Missing observations are not proof that an unreadable directory is empty.
See du for the full options and status codes.
3. Interpret the measurements together #
df describes filesystem capacity. du measures what its walk can reach and
read in the selected tree. Their figures need not match:
- The tree may cover only part of the filesystem, and
-xskips other devices. - Access failures can hide contents from the walk.
- By default,
ducounts allocated blocks, not apparent file length; sparse files and block rounding affect that distinction. - Hard-linked files are counted once by default, and symlinks are not followed.
Do not treat a difference as proof of deleted-open files, quotas, or any other specific cause without a supported observation. Nor does a large total establish how many bytes a particular cleanup would make available.
4. Choose the component's supported remedy #
Identify the owner of the measured data before changing it. Use that component's documented retention, cleanup or recovery procedure, and check what it destroys. This guide supplies no generic deletion, database-file removal, WAL removal, forced-stop or resize recipe.
For event storage, retention settings control which records remain queryable. Deleting records logically does not prove that the physical database files immediately shrink. Preserve incident evidence before a separately authorized destructive retention change.
Evidence capture can itself fail under pressure: evctl needs writable space
and anonymous-temporary-file support in its temporary filesystem as well as
space at the final destination. A destination with free space is not sufficient.
Keep query diagnostics; see failed-query diagnosis
and the temporary-spool implementation.
After applying a separately chosen, supported remedy, rerun the same df
measurements and any relevant narrow du walk. Then check the original failed
operation separately: more free space alone does not prove the application can
write successfully.
Source and scope #
The command behavior was checked in peiosutils 3344d46: named-path filesystem
selection,
du traversal boundaries,
and counting versus printed depth.
This is a source-backed diagnostic workflow, not a runtime-tested cleanup or
capacity-expansion procedure.
Partitioning
Peios / Using Peios / Disks and filesystems
Use part list to inspect storage before making changes. Use part to create,
add or remove GPT partitions only after confirming the target whole disk
and the data you intend to discard. Peios boots through UEFI; part does not
manage MBR, resize or move partitions, or convert between MBR and GPT.
Listing disks #
Run part list with no arguments to see every disk on the machine:
# part list
DEVICE SIZE CONTENTS
/dev/vda 8.0G gpt, 2 partitions
vda1 512M esp EFI system partition
vda2 7.5G linux Peios root
/dev/vdb 8.0G no partition table
This is the view to start from, because it answers the question that precedes every other one: which disk did you mean? The partition names are the ones the kernel actually created — vda1 on a virtio or SATA disk, nvme0n1p1 on an NVMe one — so they are what you can pass straight to mkfs or to the installer.
The structure here comes from the kernel, not from reading a partition table, so a disk carrying a format part cannot manage still shows its partitions. A disk it cannot read at all is still listed, with ? for its contents — the disk you cannot read is exactly the one worth knowing about.
Name a disk to see it in full:
# part list /dev/vda
/dev/vda: 16777216 sectors of 512 bytes (8.0G)
Label: gpt
Disk GUID: DE942295-427C-411D-8023-B689D8BEE907
Usable: 34 .. 16777182
# START END SIZE TYPE NAME
1 2048 1050623 512M esp EFI system partition
2 1050624 16777182 7.5G linux Peios root
Free (aligned): 0B in 0 extent(s), largest 0B
Free (aligned) counts space a new partition could actually occupy, which is not the same as unallocated sectors — the run below the first alignment boundary can never hold one. Reporting raw free space would promise room that add would then refuse to use.
part verify checks the same table's structure: both checksums, the two headers agreeing with each other, no overlaps, everything aligned and inside the usable range.
What it will not do #
part is the one tool on the system whose mistakes cannot be undone, so it is deliberately hard to point at the wrong thing.
It requires --yes. There is no interactive "are you sure": the usual caller is a script, and a prompt nobody can answer is worse than no prompt at all.
It refuses a partition. Naming /dev/vda1 where you meant /dev/vda would write a GPT inside a partition — a table that looks valid to anything reading that partition directly, and is invisible to everything else.
# part create /dev/vda1 --yes
part: /dev/vda1 is a partition, not a whole disk; did you mean /dev/vda?
It refuses a disk with anything mounted on it. Not just the disk itself — any partition of it.
It refuses a table it did not create. This is the important one:
# part create /dev/vdb --yes
part: this disk carries an MBR (dos) partition table, which part cannot manage;
pass --force to replace it — every partition on it will be lost
part list says what it found, not merely that it found no GPT — because "no GPT" is ambiguous between a blank disk and a disk holding somebody's data, and those deserve opposite treatment:
| What is there | What part says |
|---|---|
| an MBR | "an MBR (dos) partition table, which part cannot manage" |
| an Apple, BSD, Sun or SGI label | names it |
| a GPT whose header is corrupt | "the table may be damaged" |
| a filesystem written straight to the disk | "a <type> filesystem … with no partition table" |
| genuinely nothing | "no partition table" |
--force is the way through, and it is a second confirmation, separate from --yes. --yes means "I mean this destructive operation"; --force means "and I know it destroys a table that was already there". Requiring both is proportionate for an operation with no undo.
Creating a table #
# part create /dev/vda --yes
/dev/vda: wrote a new GPT (DE942295-427C-411D-8023-B689D8BEE907)
# part add /dev/vda --size 512M --type esp --name "EFI system partition" --yes
/dev/vda: partition 1 at 2048..1050623 (512M)
# part add /dev/vda --size max --type linux --name "Peios root" --yes
/dev/vda: partition 2 at 1050624..16777182 (7.5G)
add puts each partition in the first free run that fits, aligned to 1 MiB. --size max takes the largest free run rather than merely the last one, so it still does the obvious thing on a disk with a gap in the middle.
part del /dev/vda 2 --yes removes a partition by number. It frees the space and the slot; it does not touch the data that was in it.
After the table is written #
Writing a table changes the disk; it does not by itself change what the kernel believes is on the disk. So part asks the kernel to re-read the table, which is what makes /dev/vda1 appear — without it the partition exists on disk and nowhere else, and the mkfs you run next has no path to format.
The kernel refuses to re-read while any partition of the disk is open. Immediately after a write that is usually nothing lasting: publishing the new nodes is what prompts whatever probes new block devices to open one, so the refusal and its cause arrive together. part therefore keeps asking for up to three seconds, which outlasts a probe comfortably.
If the disk is still held when that time is up, part stops and says what is holding it:
# part add /dev/vdb --size max --type linux --name "Peios root" --yes
part: /dev/vdb: the table was written, but the kernel would not re-read it
within 3000ms: /dev/vdb1 is mounted on /mnt/rootfs. Release it or reboot
before formatting
When nothing of the disk is mounted, it reports that instead. The original
procedure says to run the command again in that case; the table on disk is
already correct and only the kernel's view is behind. Re-inspect the disk before
repeating a mutating command. This guide does not document a separate reread-only
command or establish that repeating add is idempotent. Do not format until the
kernel's partition view matches the written table.
Sizes are sectors unless you say otherwise #
--size takes K, M, G, T — powers of 1024 — or max. A bare number is a sector count, not bytes. --size 2048 is 1 MiB on a 512-byte-sector disk, and you can write 2048s to say so explicitly. Reading it as bytes would silently produce a partition a thousand times smaller than intended.
Types #
--type takes a short alias or a raw GUID:
| Alias | Meaning |
|---|---|
esp | EFI system partition |
linux | Linux filesystem data |
swap | Linux swap |
msdata | Microsoft basic data |
The list is short on purpose. Every type GUID in circulation would be a catalogue to keep current, and since a raw GUID is always accepted, nothing is unreachable for want of an alias.
Names #
Up to 36 UTF-16 code units — fewer if you use characters outside the Basic Multilingual Plane, which cost two units each. A longer name is refused rather than shortened. A partition name is how you identify the thing you are about to format, and a tool that quietly truncates it makes the label on your screen disagree with the label on the disk.
Exit status #
| Code | Meaning |
|---|---|
| 0 | success |
| 1 | usage error, or the operation failed |
| 2 | could not read or write the device |
| 3 | refused by a safety check |
3 is separated from 1 on purpose. A refusal is part working correctly, not malfunctioning, and a script should treat "this disk is not what you said it was" differently from "partitioning broke". peios-install relies on exactly this distinction.
Alignment, and why 1 MiB #
Every partition starts on a 1 MiB boundary — 2048 sectors on a 512-byte-sector disk, 256 on a 4096-byte one. The number is not arbitrary: 1 MiB divides every erase block and RAID stripe width in practical use, so an aligned partition never straddles one. A misaligned filesystem pays a read-modify-write cycle on every boundary-crossing write, for the life of the filesystem.
part reads the logical sector size from the kernel rather than assuming it, so a 4Kn disk gets a correct table rather than one whose every structure is in the wrong place.
The shape of the tool #
If you have used Windows, part occupies the slot diskpart occupies — but it is not the same shape, and the difference is deliberate.
diskpart | part | |
|---|---|---|
| how you use it | an interactive shell: select disk 0, then act on it | one command, one device, one job |
| what it covers | partitions, formatting, drive letters, dynamic disks | the partition table |
Everything else diskpart bundles already has a home here: mke2fs and mkfs.vfat make filesystems, mount mounts them, and Peios has no drive letters. And a select-then-act model is a hazard in a script, which is what usually calls part — a command that acts on "whatever was selected earlier" is one stray line away from acting on the wrong disk.
Where to go next #
To put a filesystem on what you just created, read Formatting with security descriptors and mke2fs.
To have the installer do all of this for you, read Installing to disk — peios-install --whole-disk runs exactly the three commands above before it formats anything.
Formatting with security descriptors
Peios / Using Peios / Disks and filesystems
For a new Peios system filesystem, give mke2fs a root security descriptor at
format time. Without one, the freshly-created root has no SD and normal access
under facs_deny_missing fails. A synthesis policy can make missing descriptors
usable, but is a separate choice about how the mount supplies permissions.
Before formatting:
- Identify the partition using Partitioning and Stable device names.
- Back up needed data and ensure the target is not in use. Formatting is destructive; it is not a repair for one missing descriptor.
- Choose the root ACL and its inheritance deliberately. A private home tree needs per-directory rules; a single root ACL cannot express every policy.
- If populating from a source tree, check its
user.peios.sdcarriers before invokingmke2fs -d.
The root SD, and what it reaches #
You give the descriptor as SDDL, and mke2fs writes it to the security.peios.sd extended attribute on the root directory and on lost+found:
mke2fs -t ext4 -E root_sddl="O:SYG:SYD:(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)" /dev/vda2
That descriptor makes SYSTEM the owner and grants both SYSTEM and BUILTIN\Administrators full control. The OICI flags on each ACE — object-inherit and container-inherit — are what make it reach further than the root directory. Every file and directory subsequently created anywhere on the filesystem derives its own SD from that one through ordinary inheritance.
That is worth stating plainly, because it cuts both ways. A single inheritable ACE on the root is, in practice, the access policy of the entire filesystem. It is a complete answer for a system tree where everything should be administrator-owned. It is not a way to express "readable system tree, private home directories" — one inherited ACL cannot say two different things, and the ACEs that would make /home/alice private have to come from somewhere else.
ID is INHERITED_ACE, so inspect the ancestor when tracing inherited rules.
The original guide also says it means the descriptor is derived rather than
stored. That conflicts with the population path below, which merges inherited
ACEs and writes the result to disk. Do not use ID alone as proof that an SD is
absent from storage; validate the stored descriptor separately.
Verify before mounting #
Inspect the unmounted ext filesystem's root xattrs:
debugfs -R "ea_list <2>" /dev/vda2
The mke2fs example shows the
expected security.peios.sd (96) entry for the exact descriptor above. Presence
on inode 2 confirms only that root xattr. Inspect child descriptors and intended
access after population as well; do not infer that every source node was stamped.
Populating a tree with per-node descriptors #
Inheritance from the root covers files created on the filesystem. It does not cover a tree copied onto it, where the nodes already have descriptors of their own that need preserving.
mke2fs -d populates a new filesystem from a directory on the build host, and on Peios it is security-descriptor aware. For each node it copies, it computes the SD the node should have in its new home, by combining two inputs:
- The explicit descriptor the source node carries — what the creator of that node wanted for it.
- The parent's descriptor in the new filesystem, which supplies the inheritable ACEs.
The two are merged by the same rules that govern inheritance on a live system: explicit ACEs first, inherited ACEs appended after them. A node whose source carries no explicit descriptor is left alone, and inherits normally on first access instead. A node whose parent has no descriptor keeps its explicit one verbatim.
The walk is top-down, and directories are stamped before their contents are visited, so every child reinherits against a parent whose descriptor has already been written.
Why the source uses a different xattr #
The explicit descriptor on the source tree is read from user.peios.sd, not security.peios.sd. This looks like an inconsistency and is not.
security.peios.sd is the canonical, on-disk home for a descriptor — and precisely because it is canonical, it is protected. On a live Peios filesystem the kernel seals it: direct extended-attribute operations on it are refused unconditionally, and access goes through kacs_get_sd and kacs_set_sd instead. On a Linux build host, writing anything in the security.* namespace needs CAP_SYS_ADMIN.
Neither is available to a tool staging a tree. user.peios.sd is subject to neither restriction, which makes it the portable carrier: any user can attach it, on any host, and it travels with the tree through ordinary archive and copy operations. mke2fs -d reads it, computes the result, and writes the answer to the canonical security.peios.sd on the new filesystem. It also skips both names when copying the node's other extended attributes across, so neither the carrier nor a stale canonical value is propagated verbatim.
Synthesised versus stamped #
Use ephemeral synthesis for genuinely missing descriptors when the media should not acquire security metadata, for example files on removable media or a read-only image. An NTFS volume from Windows may already carry valid stored SDs; those remain the input to access checks. A corrupt stored descriptor is denied, not replaced by synthesis.
For a missing SD, synthesis tries parent inheritance, then the mount template,
then the fallback. The result remains in memory under
facs_synthesize_ephemeral. Changing a template can change future synthesis
where that template supplies the inputs; it does not replace valid stored SDs
or automatically change the entire tree.
For a filesystem intended to be a Peios system, stamp its policy at creation
rather than relying on missing-descriptor synthesis. mke2fs accepts a root SD
and writes it onto the filesystem, so that root has a real descriptor when
mounted under facs_deny_missing with no synthesis template required. Verify
populated children separately under the rules above.
This all works offline #
None of the above needs a running Peios kernel. The reinheritance computation is pure userspace, and mke2fs writes the extended attributes through the ext2 library, addressing the image directly rather than going through the host's filesystem layer. That bypasses the host's own security module and the Peios seal alike, for the simple reason that neither is in the path.
The practical consequence is that a Peios filesystem, with its full security policy in place, can be built on a machine that is not running Peios.
Where to go next #
For the exact syntax of the extended options and the defaults mke2fs applies on Peios, read mke2fs.
For how a descriptor is physically stored once written, including when an oversized one needs its own inode, read SD storage by filesystem.
For what the mount policy does with the descriptor you stamped — and what happens on a filesystem that has none — read Policy classes.
mke2fs
Peios / Using Peios / Disks and filesystems
mke2fs creates an ext2, ext3 or ext4 filesystem. Peios packages it from upstream e2fsprogs, so the generic surface — -t, -b, -L, -O, -i, -m, the full extended-option list — is exactly the upstream one and its canonical documentation is the mke2fs(8) man page shipped with the package.
This page documents the Peios security-descriptor options and defaults. For a new system volume, choose the root ACL before formatting and verify it offline before mounting.
mke2fs [-t ext4] [-E root_sddl=SDDL | root_sd_file=PATH] [-d DIRECTORY] DEVICE
Extended options #
Peios adds two options to -E. Both set the security descriptor written to the new filesystem's root directory and to lost+found, in the security.peios.sd extended attribute.
| Option | Meaning |
|---|---|
root_sddl=SDDL | The descriptor as an inline SDDL string. |
root_sd_file=PATH | The descriptor as SDDL read from PATH. |
-E takes a comma-separated option list. Use root_sd_file when the SDDL
contains embedded commas, such as in a conditional expression, or when shell
quoting would be difficult. Multiple ACEs do not by themselves require commas;
the inline example below contains two ACEs.
The file holds SDDL text, not binary — it is the same string root_sddl would take, in a file. Trailing newlines are stripped, so an ordinary one-line text file works. Anything else in the file is part of the descriptor: there is no comment syntax and no blank-line handling.
Both options are parsed in the order they appear. If you give both, or the same one twice, the last one wins.
If the SDDL does not parse, mke2fs prints Invalid root SDDL: followed by the string it was given, and exits without creating a filesystem.
Neither option has a default. Omit both and the filesystem is created with no security descriptor on its root, which is upstream behaviour — mount it under a synthesising policy or it will be unreachable.
Example #
This example grants SYSTEM and Administrators full control through inheritable ACEs. It is not the installer's broader readable-system-tree policy.
mke2fs -q -t ext4 -E root_sddl="O:SYG:SYD:(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)" /dev/vda2
Confirm the result without mounting the filesystem:
debugfs -R "ea_list <2>" /dev/vda2
Extended attributes:
security.peios.sd (96)
Inode 2 is the root directory. To read the descriptor back as bytes rather than just confirm its presence, use debugfs -R "ea_get -V <2> security.peios.sd".
Security-descriptor-aware population #
-d DIRECTORY populates the new filesystem from an existing directory. On Peios this pass also computes a security descriptor for each node it creates.
The source node's explicit descriptor is read from its user.peios.sd extended attribute — not security.peios.sd, which is sealed on a live Peios filesystem and requires CAP_SYS_ADMIN on a Linux build host. Both names are excluded from the generic extended-attribute copy, so neither is propagated verbatim.
For each node:
| Source node | Parent in the new filesystem | Result |
|---|---|---|
Has user.peios.sd | Has a descriptor | Explicit and inherited ACEs merged, written to security.peios.sd. |
Has user.peios.sd | Has none | The explicit descriptor written verbatim. |
Has no user.peios.sd | Either | Nothing written. The node inherits on first access instead. |
Directories are stamped before their contents are visited, so a child always reinherits against a parent whose descriptor is already on disk.
The merge follows the same rules as inheritance on a live system, and runs entirely in userspace — no kernel and no KACS are involved, so a populated Peios filesystem can be built on a host that is not running Peios.
Peios defaults #
mke2fs reads its defaults from a profile. Peios changes three of them, and the changed profile is compiled into the binary, so it applies whether or not a configuration file exists.
| Setting | Upstream | Peios | Reason |
|---|---|---|---|
inode_size | 256 | 512 | Keeps a typical security descriptor in the inode's inline extended-attribute space, where reading it costs no extra I/O. |
default_mntopts | acl,user_xattr | user_xattr | Peios uses security descriptors, not POSIX ACLs. |
| ext4 features | — | + ea_inode | Lets an oversized descriptor spill into its own inode rather than failing to fit. |
base_features, blocksize, inode_ratio and enable_periodic_fsck are unchanged from upstream.
The ext4 quota feature is deliberately not enabled. The Peios kernel is built with CONFIG_QUOTA and CONFIG_QUOTACTL but without CONFIG_QFMT_V2, and ext4 refuses to mount a filesystem carrying the quota feature unless the vfsv1 on-disk format is compiled in. Enabling it in the profile therefore produced filesystems the kernel would not mount. Turning it on again is a pair of changes that have to land together — the kernel option, then the feature.
Resolution order for the profile, highest first:
- The file named by the
MKE2FS_CONFIGenvironment variable, if set. /etc/mke2fs.conf, if present.- The compiled-in Peios profile.
Peios ships no /etc/mke2fs.conf, so the compiled-in profile is what you get unless you deliberately supply a file. Supplying one replaces the profile wholesale — the compiled-in values are a fallback, not a layer underneath — so a partial configuration file silently reverts every setting it does not mention to the upstream default.
Exit status #
| Code | Meaning |
|---|---|
0 | Success. |
1 | Failure. Includes an unparseable root_sddl/root_sd_file value, an unreadable root_sd_file, and a failure to write the descriptor to the new filesystem. |
mke2fs distinguishes no further; unlike e2fsck, it has no bitwise-summed status. When the security-descriptor options fail they report the offending value on standard error before exiting, and no filesystem is created.
Troubleshoot before retrying #
Invalid root SDDL:: inspect the exact descriptor or file content. Aroot_sd_fileis SDDL text with trailing newlines stripped; comments and extra content are not ignored.- A filesystem that will not mount: check whether a custom profile removed
Peios defaults or enabled the unsupported
quotafeature described above. - Root access denied: confirm that a descriptor was stamped and that the selected mount policy matches the filesystem's state.
- An SD-writing failure: do not assume the target's previous contents survived. The source groups this with failures where no filesystem is created, but the partial-write/rollback boundary is not documented. Inspect the target before deciding whether a destructive retry is appropriate.
See also #
For the model behind the two options — why stamping beats mount-time synthesis, and what one inheritable ACE on the root does and does not express — read Formatting with security descriptors.
For reading and rewriting descriptors on a mounted filesystem, read The sd command.
For how the descriptor is stored, and when ea_inode becomes load-bearing, read SD storage by filesystem.
Disk Manager
Peios / Using Peios / Disks and filesystems
Open the launcher and type disk to inspect this machine's storage. Select a
disk to check its identity and partitions, Mounts to inspect current mounts,
or At Startup to review startup entries.
Before moving to a destructive command, compare the disk's device, model, serial, exact size, partition layout and mount points. Not Readable and Contents unknown are visibility limits; neither means the disk is empty.
A disk #
The disk page shows its model or virtual connection, size and device, with a GPT, MBR or System indicator. System identifies storage Peios is running from.
Use the bar or the list below it to inspect each partition. The bar is proportional to size: Linux/ext4 is blue, FAT orange, swap violet, and unformatted partitions grey. Striped areas are free space. Selecting a partition opens its page; selecting free space opens the add-partition form. The list also shows where filesystems are mounted.
This Disk gives the device, model, serial, connection, exact size, sector size and partition table. Removable disks have an Eject control. Erase Disk describes creating a new empty GPT and asks for confirmation, but this and all other change controls still end without changing storage.
A partition #
Check the three groups before choosing a command-line operation:
- Filesystem: type, label, UUID, space usage and the Format form.
- Mounts: mount points, missing-descriptor policy, and Mount or Mount Elsewhere.
- Partition: number, type, name, unique ID, start, exact size and Delete.
A mounted partition cannot be formatted or deleted until unmounted. Storage Peios is running from cannot be changed while it runs. Unavailable actions show why; those checks do not make currently unimplemented changes available.
The Format form describes ext4 or FAT32 with a label. For ext4, its initial
root permissions give SYSTEM and Administrators full control, everyone read
access, and creators ownership of objects they create, matching the installer.
Review that policy rather than assuming it matches the administrator-only
mke2fs example.
The Mount form describes a folder, read-only choice, missing-permissions policy and whether to mount again at startup. Submitting it currently changes none of these.
Files without permissions #
The UI labels map to mount policy classes:
| In Disk Manager | Policy | Meaning for a missing SD |
|---|---|---|
| Deny Access | deny-missing | SD-based access is denied until a valid descriptor is supplied. |
| Give Permissions, Not Saved | synth-ephemeral | Derive from parent/template and keep it in memory. No SD is written to the disk. |
| Give Permissions and Save Them | synth-persist | Derive an SD and schedule it to be saved. |
| Not Managed | unmanaged | FACS does not check this filesystem; the kernel's own per-operation checks still apply. |
A file brought from another system may lack a descriptor, and FAT has nowhere to store one. Filesystems without SD storage are not offered the persistent choice. A mount's Permissions… view shows the synthesis template used when its parent supplies none. StrataFS's policy and kernel-reserved unmanaged policies are fixed.
An ephemeral descriptor can remain cached while the inode is in memory; the UI's “each time it is opened” description should not be read as a promise of re-synthesis on every warm open. Corrupt stored descriptors are denied even with a synthesis policy.
Mounts #
Mounts groups filesystems on disks, shared folders, the system's root and StrataFS views, and the kernel's own filesystems. Select a mount for options and policy. StrataFS pages also list strata in highest-precedence-first order.
If a later mount covers this mount at the same point or above it, the page says so. Check this when a mounted filesystem seems to have disappeared from a path.
At Startup #
Added Here lists filesystems configured for startup, located by UUID so they can be found after moving to another port. Mounted by Peios shows system-managed startup mounts and cannot be changed here. The UI does not yet save changes to either list.
What you may see and change #
Disk changes are described as requiring the Manage Volumes privilege, held by Administrators. Other users get an inspection view with the limitation explained once and no change controls. No user can currently commit changes through Disk Manager because its service is missing.
As shipped, opening a disk to read its table and filesystems is limited to SYSTEM and Administrators. Other users still see kernel-listed partitions and mounted types from the mount table. Unavailable details are Not Readable or Contents unknown, never “not formatted”.
The Disk Manager guide describes policy reads as requiring Manage Volumes. Some command/SDK pages instead say TCB only; see the unresolved privilege discrepancy before diagnosing a policy-read failure.
Disk insertion/removal and mounts changed elsewhere should appear within a couple of seconds. After a command-line change, inspect the refreshed device, partition and mount state rather than treating a completed form as success.
Install, upgrade, or repair a disk
Peios / Using Peios / Disks and filesystems
Boot the Peios install medium to install a fresh system, upgrade a disk to the medium's release, or repair an existing installation. For writing a USB stick and configuring PC firmware, start with Install Peios on a PC.
A live system discards its writes at reboot. An installed system uses a writable filesystem on disk, so its changes persist.
Before you start #
- Back up the target disk before changing it, and identify it by model, size, and device name.
- Keep the machine powered and the medium connected while a job runs.
- Use a trusted network if you use the browser installer. On media that enable it, anyone who can reach the address can open the installer without signing in.
- Choose the operation that matches your goal:
| Goal | Operation | Effect |
|---|---|---|
| Replace everything on a disk with a new Peios system | Install | Erases the disk; first-boot setup creates the administrator account. |
| Keep an installed system and move to the medium's newer release | Upgrade an installation | Updates eligible packages and boot files; does not run first-boot setup again. |
| Restore boot files, check the root filesystem, or reseed its root descriptor | Repair an existing system | Runs the repair you select; it is not a reinstall. |
The current installer is installerd, with console and browser surfaces. The older peios-install script is a separate path: it copies the running system and its accounts. Do not assume the two paths have the same account or certificate behavior.
The installer #
Select and verify the disk #
- Choose the operation on the first page.
- Select a disk using the device, model, size, and bus columns. The boot medium is listed and marked but cannot be selected; other removable disks are marked too. Floppy drives are not listed.
- Use Rescan if the hardware has changed. If disks are missing, read any unclaimed-controller warning beside the table. It identifies the controller kind, PCI vendor/device, and bus location. RAID or VMD mode is a common cause; check firmware settings rather than selecting another disk by guesswork.
- Read the confirmation page. For installation, it names the disk, warns that all of it will be erased, and lists recognised systems and other filesystems containing files, with labels and used space. Back returns to disk selection with your choice retained.
- Start only when the disk and operation are correct. In the browser, hold down the installation button rather than clicking it once.
The confirmation uses a fresh read of the disk. EFI system and Windows recovery partitions are not separately called out, and uninspectable filesystems are not claimed to be empty. A disk that has been removed, or a script request naming the boot medium, is rejected with a reason.
Selecting and inspecting disks does not write to them. See how the scan stays read-only for the supported filesystems and safeguards.
Follow progress and check the result #
The progress page identifies the target, lists phases, and shows every command and its output. It asks for no input. Leave the machine and medium alone until it finishes.
Copy progress measures data written, rather than directory count. The installer estimates the image's size first, for example 1.2 GiB to copy, then checks filesystem usage several times a second. /usr is most of the copy. The estimate runs slightly low, so progress waits just short of complete until copying actually finishes.
Closing the form does not cancel the job. installerd owns the work. Another console or browser surface can attach to the same conversation and watch it. Both surfaces share choices, including the selected disk; coordinate with anyone else using them.
A successful install job reaches Installation complete. Reboot to start Peios. The conversation stays open on this finish page, which offers Reboot now and Back to the start. After the job completes, remove the USB medium before restarting so firmware boots the installed disk. If you land in the installer again, remove the medium and restart; do not reinstall.
In the reviewed installer source, choosing Reboot now ends the conversation only after the restart request is accepted. That is not confirmation that the machine restarted or booted successfully; check the installed system separately.
Check that the installed disk reaches first-boot setup, then complete it and sign in. The current installer copies the shipped image, so live-session accounts are not carried over. Editions without first-boot setup use their own account-provisioning seeds instead.
If a job fails #
- Read the failed phase and its command output. A failed job ends the conversation; it does not resume from that point. The next conversation begins at the first page.
- Do not treat failure as a rollback. Partitioning and formatting may already have changed the disk.
- If copying finished but boot setup failed, Repair boot files can complete that part of a half-finished install.
- If Reboot now fails, the finish page stays open and reports why. The daemon asks peinit to restart the machine, as
rebootdoes; the surface itself has no restart privilege.
Console controls #
| Key | Action |
|---|---|
| Tab / Shift+Tab | Move between fields, including disabled fields. The footer explains why a field is disabled. |
| Up / Down | Move through a list; at either end, move to the next field. |
| Enter | Press the highlighted action or advance from a field. |
| Space | Toggle a checkbox. |
| Esc | Ask before leaving. |
| F1 | Show key help. |
| Ctrl+L | Repaint the whole screen. |
A page focuses its first answerable field. The console form reads terminal size once at startup; first-boot setup uses the same renderer. See console sizing and output if the form is small or its display is damaged.
On Linux virtual terminals the renderer uses the kernel font's supported characters and sets the sixteen-colour palette. On a serial connection it assumes a modern emulator with rounded corners, ticks, and a spinner. --plain forces conservative characters for terminals that need them.
In a browser #
Open https://<machine-address>:7780 from another device, unless the image uses a different GXWI port. Browser installation requires installer-gxwi from dev.peios.installer-gxwi and a medium that enables it as GXWI's overlay. Such a medium opens the installer instead of a sign-in page.
The medium generates its own HTTPS certificate. Before trusting a browser warning, compare the browser's SHA-256 fingerprint with the one read at the machine's own console. The live medium's peios account needs no password:
Do not sign in or enter a password if the fingerprints differ. A page delivered through the connection you are checking is not an independent source for the fingerprint. See the machine's certificate.
installerd attempts to carry the medium's GXWI key and certificate into the
installed system from either surface. This is best-effort: a skipped or failed
transfer does not fail the installation. Existing browser trust can continue
only if the installed system presents the verified certificate and its other
certificate checks pass. If the fingerprint changes, verify it through the
installed machine's trusted console before entering credentials; see
certificate carry-over.
The older peios-install script, or a medium without GXWI, leaves the installed
system to generate its own key when GXWI starts.
After restarting, the browser page waits and follows the machine to setup, the desktop, or the installer if it booted from the medium again. Browser trust affects that waiting page: if the certificate was only bypassed at a warning rather than imported as trusted, the browser may show its own connection error instead. Reopen the address manually in that case.
Upgrading from the medium #
Use Upgrade an installation to move an existing disk to the release on the medium without a network or a fresh installation.
- Select the disk and compare the installed and medium releases on the confirmation page. Both show the edition and full package version.
- Check that Upgrade is enabled. It is enabled only for a newer version of the same edition, using peipkg's ordering including revision.
- Confirm, follow the phase output, and restart from the installed disk when the job completes.
A disabled button explains the mismatch: already current, a newer installed release, another edition, or no recognised Peios installation. Backing out leaves the disk unchanged. To inspect the release without writing to the target, the installer copies its package database to tmpfs and asks peipkg there.
The upgrade follows upgrade-peios on the mounted target:
- Upgrade the edition and its dependency closure, using the alternate-upgrade bypass for the medium's fixed, intentionally stale repository index.
- Stage the release's shared
autoapplyseeds withupgrade-peios --seeds-only. Install-only setup seeds are not repeated. - Upgrade other packages for which the medium carries a newer revision, in every root including the initramfs. Edition dependencies are floors rather than pins.
- Regenerate the boot files from the upgraded disk, as boot repair does.
The medium's repository is removed from the target whether the upgrade succeeds or fails. Operator customisations under /lcl are retained, with the generated boot command line under /lcl/etc/boot/ rebuilt as part of boot setup.
Repairing an installed system #
Choose Repair an existing system, select the installed disk, and choose one operation. Repairs target that disk, never the boot medium.
| Operation | What it does | Limit or next step |
|---|---|---|
| Repair boot files | Regenerates the command line under lcl/etc/boot/, initramfs image, and UKI on the ESP from the disk's kernel and initramfs tree. | It cannot repair a damaged kernel or initramfs tree; that requires reinstalling. |
| Check the filesystem | Runs e2fsck -pf on the root: forced checking with automatic preen repairs. | Refuses if anything on the disk is mounted. Unfixed problems require a shell and manual e2fsck. |
| Reseed security descriptors | Re-stamps the root directory's inheritable descriptor with the value used by the installer. | This is the root policy; it does not define a different policy for every subtree. |
Boot repair uses the installed disk-boot, not a possibly older copy from the medium, and leaves the installed repository list alone. For a half-finished installation whose copy completed but boot setup failed, it detects the medium-only package checkpoint or the remaining live-boot package and finishes the installation's package swap. The checkpoint also covers a failure after live-boot was removed. Packages declared temporary by the medium, including the DWE package on newly built DWE media, are removed; the checkpoint disappears only after that swap succeeds.
Filesystem checking reports whether the filesystem was clean, problems were fixed, or a reboot is required before reuse. Only problems it cannot fix automatically count as failure.
Each repair ends at the finish page. Use Back to the start to perform another repair in the same boot, or Reboot now when finished.
Two ways to invoke it #
This section describes the older peios-install script, not a command-line interface to the current installer conversation. Run this legacy script from a SYSTEM session; direct use from an administrator session is unsupported because its ordinary copy must read SYSTEM-only files and preserve their security metadata. For ordinary console or browser installation, use the current installer described above, whose privileged operations run in installerd.
The whole-disk form runs part to create a fresh GPT, a 512 MiB EFI system partition (ESP), and a root partition using the remainder. It then follows the two-partition form. The whole disk is erased.
A partition table not created by part is refused before formatting; --force explicitly overrides that protection. Do not use it merely to make an unexplained refusal disappear.
For another partition layout, create it with part, then supply the ESP and root partitions to the second form. Both named partitions will be formatted. The installer does not offer separate /home, swap, or encryption setup.
What it refuses before it starts #
Before formatting the named partitions, the script rejects a target that is not a block device, the same partition supplied twice, or either partition currently mounted:
# peios-install --yes /dev/vda1 /dev/vda2
peios-install: /dev/vda2 is mounted; refusing to format it
These checks prevent formatting a mounted running system. A refusal before the first mkfs has not formatted either partition; do not confuse that with a later failure after a whole-disk partitioning step has already changed the disk.
The first-account service is retired, the account is not #
The script copies the running system, including lpsd's account store at /var/state/lpsd/principals. It removes the lpsd-first-account service so that the live-image provisioner does not run against the populated store every boot:
This deletion is made in the live source registry, through the running registryd, before the copy and before either partition is formatted. The script verifies it; a deletion failure stops the install. If the key is already absent, it reports that and continues. Editing the source through its registry service avoids modifying an open database behind registryd's back.
Retiring the service does not remove or secure the copied accounts. Otherwise its non-idempotent lps add would fail on the existing name, and a provisioner that reasserted an image credential could overwrite an operator's later choice.
The current installerd path avoids this transfer: it copies the shipped image, omits the live development-account seed, and uses the edition's first-boot setup to create an administrator.
What the installer does #
This section explains the disk and boot artifacts so you can interpret failures. It is not a sequence to run on top of an installation already in progress.
1. Format the EFI system partition #
mkfs.vfat -F 32 creates the FAT ESP required by UEFI. FAT cannot store Peios security descriptors, so its access policy comes from a synthesising mount policy.
2. Format the root with a security descriptor #
The root is ext4, stamped at format time with the system's inheritable descriptor. The example target is /dev/vdb2; formatting it is destructive:
The root's security.peios.sd makes SYSTEM the owner, grants SYSTEM and Administrators full control, and grants Everyone read and execute. Execute also means directory traversal, so non-SYSTEM services can reach their working directories. The final CREATOR OWNER ACE is inherit-only and grants a newly created object's creator full control.
The live system uses the same root policy. Without the creator-owner ACE, a non-administrator could create a file it could not read back: an inherited non-empty DACL takes precedence over the token's default DACL. See Formatting with security descriptors.
3. Copy the system and preserve its security #
The older script uses cp -ax to copy the running root; the current installer takes the shipped image. cp -a requests owner, DACL, SACL, timestamps, links and extended attributes, but its recursive source-symlink path can suppress a returned copy error. Do not treat a successful status from that older copy step as proof that every link and required attribute was preserved. This limitation does not establish how the current installer reports a failed image copy.
The copy stays within filesystem boundaries. Mountpoints are recreated as empty directories: prelude mount-moves /proc, /sys, and /dev at boot, and StrataFS mounts views over /bin, /etc, /lib, and the other view directories. Their backing content in /usr and /lcl is ordinary root-filesystem content and is copied.
4. Write the kernel command line #
dev.peios.disk-boot supplies the stable template at /usr/share/disk-boot/cmdline. The installer appends root=UUID=<the new root> and writes the per-install command line to /lcl/etc/boot/cmdline on the target.
5. Build the boot artifact #
mkuki bundles the kernel, initramfs, and command line into EFI/BOOT/BOOTX64.EFI on the ESP. UEFI can boot this fallback path without an NVRAM entry. There is no separate bootloader or boot manager between firmware and kernel.
Use UUIDs, not device names #
The installed command line identifies the root by UUID because device names can change. A disk seen as /dev/vdb behind the install medium may become /dev/vda when the medium is removed.
The initramfs probes block devices directly to resolve the UUID. It cannot rely on /dev/disk/by-uuid, because no device manager has created those paths there. See Stable device names.
How the installed system boots #
The reviewed installer replaces the live boot components with the disk-boot
components before rebuilding the installed initramfs. It then verifies that
mount-root-disk.sh is present and that the live mount-root.sh is absent.
An installed image therefore does not select between both hooks at boot.
For disk boot, root= identifies the partition to mount; it is not a live/disk
mode switch. A missing or empty root= makes the disk hook fail rather than
silently leave the work to another hook. The disk hook mounts that partition
directly, without the live medium's writable overlay.
This follows the pinned installer checks and disk-root hook. Check the image you operate; these are source-level descriptions, not a boot repair procedure. For authoring and ordering, see Writing a boot hook.
The disk hook uses policy=deny-missing and does not run seed-sd. The installed filesystem already carries descriptors, so a missing one is an error to investigate. The live squashfs has none: it uses synth-ephemeral and seeds an inheritable descriptor on the tmpfs above it.
To inspect the installed root descriptor:
Check the owner and actual ACEs against the root policy above. ID means INHERITED_ACE; the root's explicit format-time ACEs should not carry it. The installed filesystem carries this access policy itself rather than relying on a mount-time template.
How the disk scan stays read-only #
installerd discovers partitions, used space, and recognised Peios, Linux, or Windows systems without writing to the disks. A read-only filesystem mount alone is not sufficient for ext4, which may replay its journal.
Instead, each inspected partition is bound to a read-only loop device, and that device is mounted. Ext3 and ext4 also use noload. The mount uses synth-ephemeral, allowing filesystems from other systems to be read without writing security descriptors to them.
FAT, exFAT, NTFS, ext2, ext3, and ext4 are inspected this way. Swap, encrypted volumes, and other filesystems are listed by size and partition-table type without opening them. Symbolic links on the inspected disk are never followed, because they could resolve against the install medium. The daemon supplies this detail to surfaces; the console disk page itself shows the table.
Installer services and image configuration #
installerd runs as SYSTEM and performs privileged disk operations. install-tui only draws the console form and has no privileges of its own. They speak MSIP, which also allows scripted interaction through msip-drive and surfaces attaching to an existing job. To study the driver, use Rehearse the headless installer in a lab, a source-derived synthetic dry-run exercise with a private socket. It is not a validated recipe for unattended installation on real disks.
For a browser-enabled medium, the installer-gxwi-overlay seed sets these values under Machine\Software\GXWI:
| Value | Setting |
|---|---|
OverlayUsername | peios, the medium's passwordless account |
OverlaySession | /usr/bin/installer-gxwi |
The edition must list this seed under live_autoapply, not autoapply. installerd deletes the live queue from the installed disk. That leaves the graphical installer program installed without making it the permanent browser entry point. If the seed is shared through autoapply, the installed machine keeps opening the installer; GXWI does not fall back from a requested overlay to sign-in.
What the installer does not do #
- Offer multiple automatic layouts. The whole-disk layout is one 512 MiB ESP and one root using the remainder. Separate
/home, swap, and encryption are not installer options. Use the older script's two-partition form only when you have deliberately prepared another supported layout. - Make every directory's policy the same as its intended use. The root descriptor supplies a baseline; a private subtree needs its own protected descriptor. Account home directories have that separate policy, created at first sign-in.
- Recover every failed system. Boot repair needs an intact kernel and initramfs tree; automatic filesystem checking cannot fix every error. Read the reported failure before choosing a destructive reinstall.
Where to go next #
Complete first-boot setup
Peios / Using Peios / Disks and filesystems
Complete first-boot setup after installing Peios to disk. It creates the first administrator account, sets the machine's name, and optionally applies a manual wired-network address. When it succeeds, you can sign in with your new account and setup does not run again.
The installer copies the system first; these questions are asked on the installed system's first boot. Setup is available on the console and, on images that include oobe-gxwi, in a browser.
Before you start #
- Boot from the installed disk, with the install medium removed after installation has completed.
- Choose an account name, a non-empty password, and a machine name. Their rules are listed below.
- Keep the install medium for recovery until you have successfully signed in.
- You do not need a network for console setup. For browser setup, use a wired connection on a trusted network and verify the machine's certificate.
- Expect an English setup interface and US console keyboard layout. Language and keyboard choices are made after setup, so take care when entering a password with a different physical keyboard layout.
What it asks #
1. Language and keyboard #
The page shows the current language and keyboard information but does not change them. Setup is in English and the console uses the US layout until setup finishes. Afterwards, open System Settings → Language & Keyboard. See the settings overview for the distinction between System Settings, Desktop Settings, and personal settings.
In the terminal, the Language and Keyboard choices are disabled, but each shows its explanation beneath it without needing focus, so this guidance is visible there too.
2. Network #
The network page is informational; lack of connectivity does not block setup. It shows what net status reports for each interface: connected, not connected, or not used. Choose Check again after connecting a cable. In the browser, the interface carrying your current connection is marked.
Wi-Fi joining is shown but disabled. Continue without network configuration, or choose Configure manually for a wired interface.
For a manual address:
- Enter an address with its network prefix, such as
192.168.1.20/24. - Add a gateway and name servers if needed. A gateway must be on the address's network.
- Save and check the network page's confirmation that the setting is kept for later.
Saving validates the values but does not change the active address yet. Setup applies the address after creating the account and setting the machine name, so the browser can keep reaching the current address while you answer the remaining questions. Note the new address before finishing.
3. Account and password #
This account is the machine's first administrator. Choose a password you intend to use for sign-in; the setup page refuses an empty password or mismatched confirmation.
Account names must:
- Be non-empty, plain ASCII, and no longer than 256 characters.
- Contain none of these characters:
@,\,/,:, or,. - Not be
Administrators,Users,Guests,Everyone, orAuthenticated Users. - Not be
peios-oobe-setup, the temporary account reserved for browser setup.
Spaces inside a name are allowed; spaces around it are trimmed. Validation happens when you choose Next, before the account is created. A rejected field explains what to change.
In a browser, typed account details remain in your browser until Next and are not shown to other people viewing the setup conversation. The page previews the account name, checks matching passwords, and rates apparent password strength from Easily guessed to Very strong. The strength meter is advice, not an acceptance rule: any non-empty matching password is accepted.
4. Machine name #
Accept the suggestion or enter one label with:
- Letters, digits, and hyphens only, up to 63 characters.
- No leading or trailing hyphen, dots, or spaces.
- A name other than
localhost.
Spaces around the name are trimmed. This is the name the machine uses for itself and supplies to DHCP. Domain joining is shown but disabled.
The browser validates as you type, previews a prompt such as jack@workshop:~$, and offers suggested names. Shuffle generates more suggestions. The daemon validates the name when you choose Finish.
Finish and verify sign-in #
Choose Finish once the account, name, and any manual network setting are correct. Setup shows each change as it applies:
- Create the account.
- Set the machine name.
- Apply a manually configured network address, if supplied.
On the console, setup releases the terminal and the login prompt appears. In a browser, Setup is complete is shown briefly before the page transitions to sign-in, retaining the same backdrop. Sign in with the account and password you just created.
Check that:
- The new account can sign in.
- The machine name is the one you chose.
- If you configured a manual address, the machine is reachable there from a device on the appropriate network.
- A later boot goes directly to sign-in rather than repeating setup.
For additional accounts and account administration, continue to Creating accounts.
In a browser #
Open https://<machine-address>:7780, unless the image uses a different GXWI port. The graphical surface must be installed at /bin/oobe-gxwi; without it, use the console.
While setup is pending, GXWI shows setup instead of its sign-in page. The console and browser share one conversation, so you can start on one and finish on the other. Coordinate with anyone else who has it open.
Verify the certificate before entering a password #
GXWI uses HTTPS with a certificate the machine makes for itself. Check its SHA-256 fingerprint against a trusted reading from the machine's own console:
Do not use a page delivered over the unverified connection as the source of that fingerprint. If the fingerprints differ, do not enter a password.
installerd attempts to carry the medium's GXWI certificate into the installed
system from either surface, but installation can succeed even if the transfer
is skipped or fails. Compare the certificate actually presented with the
fingerprint you verified on the medium; do not treat installation success as
proof that it is unchanged. A changed fingerprint needs a fresh check through
the installed machine's trusted console before you enter credentials. See
certificate carry-over.
The older peios-install path, or a medium without GXWI, does not carry that key across. If you have not already verified the installed machine and cannot obtain its fingerprint through trusted console access before creating an account, complete setup on the console first. Then sign in locally to verify the certificate before using browser sign-in. See the machine's certificate for the full trust procedure.
If the network address changes #
Setup keeps the current address until its final apply step. If you change the interface your browser uses, the page then checks both the old and new addresses and follows the machine when it answers. At the new address, the sign-in page starts a new backdrop rather than retaining the old page's animation.
If the browser cannot reach the new network, the page reports it; use the machine's screen to check its address. Open the new address from a device that can reach it.
The browser's waiting page also depends on certificate trust. If the certificate was only bypassed at a warning rather than imported, a restart can produce a browser error instead of an automatic reconnect. Reopen the address manually and follow the certificate guide.
The temporary setup account #
Before setup, the machine has no normal account for a graphical session. oobed creates peios-oobe-setup with no password and no groups, and its socket admits that account. The browser overlay uses it to draw the setup conversation.
On successful setup, oobed removes the overlay, restores GXWI sign-in, and removes the temporary account and its home directory. Failed setup leaves them in place for the next attempt.
The account-name page reserves peios-oobe-setup because setup preserves an account that already exists; choosing that name would otherwise leave no usable account after cleanup.
If setup does not finish #
| Symptom | Next step |
|---|---|
| Account, password, or machine name is rejected | Read the field error and compare it with the rules above. Validation happens before final application. |
| No network or Wi-Fi joining is disabled | Continue on the console; a network is not required. Use wired networking for browser access. |
| Browser stays on the old address or a starfield after a manual network change | Check the address on the machine's screen and open the new HTTPS address yourself. See the 2026.8 caveat above. |
| Browser setup is absent | The image may not include oobe-gxwi; use the console. If setup itself is absent, check the edition's provisioning choice below. |
| Setup was closed with Esc or failed | It is not retired. Restart to be offered setup again. A returned login prompt does not prove account creation succeeded. |
| Setup repeatedly fails and no usable account exists | Boot the install medium for recovery. Do not assume you can sign in to repair setup locally. |
| Console text is damaged | Press Ctrl+L to repaint. |
| Form no longer fits after resizing a serial-terminal window | The size was read once at startup. Restart with the desired terminal size, or use the current form size. |
It runs once #
Only a successful setup removes the oobed and oobe-tui service definitions. A failed or abandoned run leaves them so the next boot can retry. It does not retire the only setup path before an account has been successfully provisioned.
A machine whose setup keeps failing may have no account you can use. The install medium is the recovery route, as for a system that will not boot. Installer repair operations describe what the medium can repair and their limits; they are not a guarantee that every setup failure is automatically repairable.
How it gets the console #
This section explains service behavior useful when diagnosing startup or display problems.
| Service | Responsibility |
|---|---|
oobed | Runs as SYSTEM to create the first account and set the machine name. Serves the MSIP conversation on /run/oobed.sock. |
oobe-tui | Draws the console form without privileged rights of its own. |
Setup and the login prompt both use /dev/console. Setup has higher TTYPrecedence, so peinit gives it the console and does not start the login prompt at that point.
When the surface exits, whether successfully, through Esc, or after a crash, it releases the console. The login prompt's tty:released trigger then starts it. The terminal is not left without an owner, even though an unsuccessful setup may still leave no usable account.
How big the form is #
A serial byte stream carries no terminal geometry. The surface moves the cursor beyond the bottom-right corner and reads back its clamped position to discover the size. The installer uses the same renderer.
- The size is read once when the form starts. Later window resizing is not reported to the guest and does not resize the form.
- A terminal that does not answer falls back to 80×24, including captured output or a serial port with no responding terminal.
The console goes quiet while a form is open #
The daemon lowers kernel console output while the conversation is open and restores it when the conversation ends, including if the daemon dies. It does this in the privileged engine rather than in the unprivileged surface. installerd uses the same approach.
Only KERN_EMERG kernel messages continue to print, so a panic is not hidden. Peinit and other services can still write directly to the console. Those writes can disrupt the form, so page changes repaint it in full and Ctrl+L requests a full repaint.
Where it comes from #
dev.peios.oobe ships the inert oobe-service registry seed. An edition opts into it through install_autoapply, so it runs on the installed system rather than taking the console away from the live installer.
An image without dev.peios.oobe, or an edition that omits that seed, boots directly to a login prompt using whatever accounts its own seeds provisioned. Do not assume every custom image provides this setup flow.
A manual network choice is saved as an ordinary profile and rule: Profiles\default\manual-<interface> plus an exception under Rules\Interface\wired, naming the interface by stable ID. After setup, you can change or delete those settings like any other network profile and rule.
StrataFS
Peios / Using Peios / Disks and filesystems / StrataFS
Use stratafs to find which real file supplies a merged path, where a write
would go, and whether local changes hide a packaged default. Start with the
read-only inspector before removing an override or changing a stack.
StrataFS presents ordinary directories as one view while leaving their real paths independently manageable. Highest precedence wins for each name. Directories merge; a non-directory provider masks lower objects of that name, including a lower directory's subtree.
Inspecting a stack #
The stratafs command is a read-only inspector. It does not mount, modify, or
clean anything, and it never gains extra authority. Every direct stratum read
runs with your normal access rights. If it cannot see all the information
needed for a complete answer—especially every participant of a protected
merged directory—it fails instead of showing a misleading partial result.
List every StrataFS mount in the current mount namespace, or one exact mount:
Typical output is:
/bin
[0] /lcl/bin+create (present)
[1] /usr/bin+ro (present)
The order is the precedence order. A stratum is present, absent, or
not_directory; the mount itself is also labelled when generically mounted
read-only.
Explaining one path #
Use resolve when you want to know why a name looks the way it does and where
a mutation would go:
The per-stratum states are:
| State | Meaning |
|---|---|
provider | This object currently provides the name. |
participant | This lower directory contributes to the merged directory. |
shadowed | A higher object of the same type wins. |
masked | A provider of another type hides this object. |
absent | This stratum does not hold the path. |
The report also explains write and delete. A write can route in_place,
copy_up, or create; it can instead report erofs, a missing parent, an
unknown immutable-attribute state, or that content I/O follows a symlink.
Deletion identifies the real provider entry to remove and names a lower object
that will resurface. Removing a directory is still conditional on the complete
merged directory being empty.
These are routing answers, not authorisation promises. KACS checks the actual operation against the caller when it is attempted.
For the kernel's answer without the explanation, print the synthetic origin attribute:
A non-directory prints its one real provider path. A merged directory prints every participating real directory in precedence order, one escaped path per line.
Inspecting local state #
The create stratum is deliberately easy to audit. sweep recursively reports
every object in it:
Each result is classified as:
gap: only the create stratum has this path;override: a lower stratum also has it; orshadowed: a higher stratum, or a higher non-directory ancestor, makes it unreachable.
Directories are included. For a directory, override describes structural
presence; corresponding directories still merge. When sweep says
create stratum is empty, the local stratum has no entries to reconcile. The
command never deletes anything—remove a reviewed entry through the merged view
or at its real create-stratum path, according to the result you intend.
To inspect the content of an override:
diff compares the create-stratum object with the first lower default. It
supports regular files and symbolic links, reports type changes, refuses other
object types, and bounds each regular-file read to 16 MiB. Binary files are
reported only as different.
Structured output and status #
list, resolve, and sweep accept --json. JSON is the stable scripting
interface; it includes the same paths, flags, states, object types, and routing
actions. A non-UTF-8 path is represented losslessly in human output but causes
JSON mode to fail rather than substitute a lossy name.
Exit status has probe-friendly meaning:
| Status | Meaning |
|---|---|
0 | Success; for sweep, no entries; for diff, no difference. |
1 | sweep found entries or diff found a difference. |
2 | Usage, visibility, malformed-state, or operational error. |
Check permissions and unexpected results #
- If an inspection fails, check access to every participating real directory. The inspector runs with your rights and fails rather than presenting an incomplete protected view. It does not elevate your token.
- If deleting a local entry exposes a packaged file, that is the documented
no-whiteout behaviour. Use
resolveanddiffbefore removing the override. - A routing answer is not permission to mutate.
write: copy_upstill needs the actual KACS checks and a usable create stratum. - If a direct stratum path works but its merged path is denied, check stored SDs. StrataFS's fixed deny-missing contract does not use a lower mount's synthesis policy to repair a missing descriptor. This conflicts with the general stacking description in SD storage by filesystem.
- For a copied-up file, check preservation rather than assuming ordinary creation inheritance. The StrataFS copy-up contract preserves the source's full descriptor; ordinary new creations inherit. A descriptor-preservation failure fails the copy-up.
For kernel errors and recovery conditions, use StrataFS failure modes. For example, a copy-up made stale by a changed provider requires reopening; an open that succeeds does not guarantee the first write will succeed.
A /bin example #
Suppose /usr/bin contains packaged programs and /lcl/bin is for local
changes. The command below mounts a new stack at /bin; it is a configuration
example, not an inspection command. Check the current stack first and do not
replace a running system view merely to try it out:
/lcl/bin has higher precedence and receives newly-created objects. The +ro
on /usr/bin means “do not modify this stratum through /bin”. It does not
make the real /usr/bin mount read-only: an authorised writer can still modify
/usr/bin/tool directly at /usr/bin/tool.
Reading /bin/tool uses /lcl/bin/tool when it exists, otherwise
/usr/bin/tool. Writing an existing packaged tool through /bin copies it to
/lcl/bin first and changes the copy. Removing that copy through /bin
restores the unchanged /usr/bin version to view, because StrataFS does not use
whiteouts.
The base Peios topology #
The dev.peios.fsbase-stratafs-mount-hooks package installs the mount-rootfs-stratafs-base.sh boot hook
in the initramfs. It runs after the deployment-specific hook has mounted the
real root and before prelude hands off to it, mounting the conventional
root-level views as one boot step:
| View | Strata, highest precedence first |
|---|---|
/bin | /lcl/bin+create, /usr/bin+ro+am |
/sbin | /lcl/sbin+create, /usr/sbin+ro+am |
/lib | /lcl/lib+create, /usr/lib+ro |
/libexec | /lcl/libexec+create, /usr/libexec+ro+am |
/share | /lcl/share+create, /usr/share+ro+am |
/include | /lcl/include+create, /usr/include+ro+am |
/etc | /system/retc, /lcl/etc+create, /usr/etc+ro+am |
/conf | /lcl/conf+create, /usr/conf+ro+am |
am permits an optional vendor directory to be absent when the system boots
and makes it participate automatically if a later package creates it. The
operator create directories are provisioned by fsbase; their absence is a
boot error rather than something StrataFS silently creates, because their own
security descriptors govern creation through each view.
/lib views /usr/lib rather than the architecture triplet directory beneath
it, so /lib/modules and /lib/firmware resolve. Both matter: kmod has
/lib/modules compiled in, and the kernel's firmware loader searches
/lib/firmware, and neither can be told to look elsewhere. Shared libraries are
unaffected — the loader finds them through its own absolute system search path
rather than through this view — and /lib/x86_64-linux-peios/ still resolves,
one level down, which is the shape a foreign binary expects.
/lib64 is not a StrataFS view. On x86-64 it remains the package-owned relative
symlink lib64 -> usr/lib/x86_64-linux-peios, because the psABI dynamic-loader
path must work before any hook can mount the base topology. It is a distinct
object from the /lib view above and is unaffected by what that view maps.
The mount option grammar is:
strata=<stratum>[:<stratum>]...
<stratum> := <path>[+<flag>]...
<flag> := create | ro | am
Paths are absolute. create selects the one stratum that receives creations
and copy-up, ro prevents modification through the merged view, and am
allows the stratum directory itself to be temporarily absent. Literal :,
+, ,, and \ in a path are escaped with \.
Where to go next #
For the generic command that creates this and other mounts, read
mount. For how access to every real object is
decided, start with File access.