Peios Learn
Products
PePeios pkpekit PvProvium UDUniversal Directory TrTrail PrProject WiWispist
Using Peios Security Basics Technical Documentation Source
Using Peios Security Basics Technical Documentation Source
Peios

Registry tools

Single-page view · as markdown

reg

Peios / Using Peios / Peiosutils / Registry tools

reg is the command-line interface to the live registry — the running LCS store, reached through the registry system calls. Where regman reads shipped documentation and tells you what a key means, reg talks to the kernel and reads or writes what a key is. It is the everyday tool for scripting configuration: querying effective values, writing to layers, masking and hiding, managing security descriptors, watching for change, and taking backups.

reg <command> [options] <key> [value] [data]

reg is the read/write half of the registry toolset and regman is the lookup half. The division is exact:

To…Use…
Read or change what a value is set to, on this machine, right nowreg
Look up what a value means — its type, default, valid range, when it appliesregman

Consult regman first to learn the legal range for a knob, then use reg set to write a value inside it. reg never checks a value's meaning and regman never touches the live store; they are complementary.

How reg treats access and privilege #

Every reg operation goes through the kernel's access check against the single key it opens — the same access-control path as any other protected object, with no traversal check on the parent keys. reg performs no identity or membership checks of its own: it does not refuse a privileged operation up front. It attempts the operation and reports faithfully whatever the kernel returns. An operation that needs a privilege you lack (creating a link, a positive-precedence layer, a backup or restore, reading a SACL) simply fails with access denied (exit 3) rather than being blocked by the tool. A single reg command may legitimately span privilege tiers.

Addressing model #

Almost every subcommand shares one addressing scheme: a key path positional, and an optional value name positional. Understanding the split is most of understanding reg.

Key paths #

The key is a positional path argument. Both / and \ are accepted as separators — neither character is legal inside an LCS key component, so there is no ambiguity, and you may use whichever your shell quotes most comfortably:

reg get Machine/System/KMES
reg get 'Machine\System\KMES'      # identical

A leading separator is optional and ignored (/Machine/X is the same as Machine/X). Paths are compared case-insensitively. The first component is the hive:

PathMeaning
Machine\…The machine hive — system-wide configuration.
Users\<SID>\…A specific principal's hive.
CurrentUser\…A kernel alias, rewritten to the caller's own Users\<SID>\ at the syscall boundary.

On output, reg displays paths with a backslash by default. --sep=/ (or REG_SEP=/) switches display to forward slash for that invocation; this affects display only, never how a path is parsed.

The value-name positional #

The value name is a separate positional argument — it is never folded into the key path. This is deliberate: an LCS value name may itself contain / or \ (which a key component may not), so keeping them apart removes all ambiguity.

reg get Machine/System/KMES BufferCapacity
#       └──── key path ─────┘ └── value ──┘

The presence or absence of the value argument selects what the command targets:

  • No value argument ⇒ the command targets the key itself — its metadata, its values as a set, its security descriptor, its children.
  • A value argument ⇒ the command targets that one named value.
  • The default value (the empty-name value) is addressed by the literal token @ in the value-name position, mirroring .reg convention: reg get Machine\App @.

This split applies uniformly to get, set, del, mask, and unmask.

Value literals and types #

On set (and in a batch), the value's data is a single token whose registry type is either forced by a type: prefix or inferred from its shape. The registry value types and their literal syntax:

PrefixRegistry typeData syntax
sz:REG_SZUTF-8 string (rest of token, verbatim).
expand:REG_EXPAND_SZUTF-8 string, %VAR% left unexpanded on disk.
dword:REG_DWORD42 or 0x2A; must fit u32.
dword-be:REG_DWORD_BIG_ENDIAN42 or 0x2A; must fit u32.
qword:REG_QWORD42 or 0x2A; must fit u64.
multi:REG_MULTI_SZComma-separated; \, escapes a literal comma.
hex: / bin:REG_BINARYHex bytes; :, -, and space separators are ignored.
link:REG_LINKAn absolute key path (a symlink target).
none:REG_NONENo data (token must be empty after the prefix).

When the substring before the first : is not a recognised keyword (for example http://host), the token is not treated as typed and inference applies:

Token shapeInferred type
all decimal digits, fits u32REG_DWORD
all decimal digits, fits u64 but not u32REG_QWORD
0x… hex, ≤ 8 significant hex digitsREG_DWORD
0x… hex, ≤ 16 significant hex digitsREG_QWORD
anything else (including empty)REG_SZ

Inference is intentionally broad, so any all-digit token becomes a number — a PIN, a zip code, or 007 becomes a REG_DWORD and loses its textual form. To force a string, prefix it with sz: (sz:007 stores the string 007; sz:dword:42 stores the literal string dword:42). Because the coercion is a known trap, reg set always echoes the resolved type on success, so a surprising conversion is never silent even under --quiet.

Global options #

Every subcommand accepts the following. Each behavioural toggle also has an environment-variable equivalent, so it can be set per-invocation (the flag) or once per shell or script (the variable). The flag wins over the variable, which wins over the built-in default.

OptionEnv varEffect
--jsonREG_JSON=1Emit structured JSON instead of human text. watch emits JSON-lines.
-v, --verboseREG_VERBOSE=1More detailed output.
-q, --quiet—Suppress non-essential output. (A surprising type coercion is still reported.)
--sep=CHARREG_SEPPath display separator: \ (default) or /.
--help—Print help for the command and exit 0.
--version—Print the version and exit 0.

Mutating subcommands additionally accept:

OptionEnv varEffect
--layer NAMEREG_LAYERTarget layer for the write (default: the base layer).
-y, --yesREG_ASSUME_YES=1Skip the confirmation prompt on a destructive command.

Destructive commands (del -r, restore, layer del) prompt for confirmation when standard input is a terminal, and auto-proceed when it is not — so interactive use is guarded while scripts are never blocked. Set -y/--yes or REG_ASSUME_YES=1 to skip the prompt explicitly.


Reading #

reg get <key> [value] #

Read the effective (resolved) value. With a value, prints that value's data; with no value, lists the key's effective values (the default @ value first, then named values sorted case-insensitively) — a shorthand for ls --values-only.

OptionEffect
-L, --layersAnnotate the value with the layer it resolved from and its sequence number.
--rawWrite the value's raw bytes to standard output verbatim — for piping REG_BINARY data.
--no-followOperate on a symlink key itself rather than following it to its target.

The single-value default form prints data bare (no quotes; one element per line for REG_MULTI_SZ) so it pipes cleanly. -L shows the winning layer's provenance:

$ reg get Machine\System\KMES BufferCapacity
4194304

$ reg get Machine\App Theme -L
Theme = REG_SZ "dark"   (layer: policy, seq 7)

Only the winning value is shown; the full shadowed stack beneath it is not yet exposed by any client ABI (the -L flag will render the whole stack unchanged once that primitive lands). See Layers for what "effective" resolves against.

reg ls <key> #

One-level listing of a key's immediate subkeys and values.

OptionEffect
-l, --longLong form: for subkeys, child and value counts; for values, type and byte size.
--keys-onlyList subkeys only.
--values-onlyList values only.
$ reg ls Machine\System\KMES -l
BufferCapacity = REG_QWORD 4194304   (8 bytes)
MaxEventSize   = REG_DWORD 65536   (4 bytes)

reg tree <key> #

Recursively list the subkey tree rooted at key.

OptionEffect
--depth NLimit recursion to N levels.
--valuesInclude each node's values, not just its keys.
$ reg tree Machine\System --depth 2

reg info <key> #

Print a key's metadata: leaf name, subkey and value counts, last-write time, hive generation, security-descriptor size, and the volatile and symlink flags.

OptionEffect
--no-followInspect a symlink key itself rather than its target.
$ reg info Machine\System\KMES
path             Machine\System\KMES
name             KMES
subkeys          0
values           4
last_write_ns    1717243800000000000
hive_generation  42
sd_size          164
volatile         false
symlink          false

Writing #

reg set <key> <value> <data> #

Create or update a value. The value name (or @) and the data token are both required. Writes are tagged with --layer (default: base). See value literals for the data syntax.

OptionEffect
--layer NAMEWrite into layer NAME instead of the base layer.
-p, --parentsCreate any missing ancestor keys.
--expected-seq NCompare-and-swap guard: apply only if the value's current sequence is N; a mismatch exits 6 without writing.
$ reg set Machine\App Build 4096
set Machine\App Build = REG_DWORD 4096   (layer: base)

$ reg set Machine\App Servers multi:alpha,beta --layer policy

--expected-seq supports lock-free read-modify-write: read the value with -L to learn its sequence, then write back with --expected-seq set to that number; if another writer changed it in between, your write fails cleanly instead of clobbering theirs.

reg new <key> #

Create a key with no values. Reports whether the key was created or already existed.

OptionEffect
--layer NAMECreate the key in layer NAME.
-p, --parentsCreate any missing ancestor keys.
--volatileCreate a volatile (RAM-only) key that does not survive a reboot.
$ reg new Machine\App\Cache --volatile
created Machine\App\Cache   (layer: base)

reg del <key> [value] #

Delete a value, or a key. (Alias: delete.)

With a value, deletes this layer's entry for that value only — lower-layer entries resurface, because a per-layer delete is not a tombstone (use mask for that). With no value, deletes the key, which must be empty unless -r is given.

OptionEffect
--layer NAMEDelete from layer NAME.
-r, --recursiveDelete the key and all its descendants (walks and removes children).
-y, --yesSkip the confirmation prompt (recursive deletes prompt on a terminal).
$ reg del Machine\App Legacy
deleted value Legacy from Machine\App

$ reg del Machine\App\Temp -r
Recursively delete key Machine\App\Temp and all its contents? [y/N] y
deleted Machine\App\Temp (3 keys)

See Deleting keys and values for how a per-layer delete differs from a tombstone.


Masking and hiding #

These commands expose LCS's tombstone and hide primitives, which mask lower-precedence state rather than removing a layer's own entry — the distinction that makes layers revertible. The layer is chosen with --layer (default: base).

reg mask <key> [value] / reg unmask <key> [value] #

mask sets a tombstone: a per-value marker in the target layer that hides that value from all layers below it. unmask clears it.

OptionEffect
--layer NAMEThe layer that carries the tombstone.
--allBlanket tombstone: mask all lower-layer values on the key (no value argument).

A value is required unless --all is given.

$ reg mask Machine\App ApiKey --layer policy
set tombstone on Machine\App ApiKey (layer: policy)

$ reg mask Machine\App --all --layer policy
set blanket tombstone on Machine\App (layer: policy)

reg hide <key> / reg unhide <key> #

hide installs a HIDDEN path entry in the target layer, masking the key's existence in that layer and below. unhide removes that layer's path entry, letting the key reappear.

OptionEffect
--layer NAMEThe layer that hides (or unhides) the key.
$ reg hide Machine\App\Debug --layer policy
hid Machine\App\Debug (layer: policy)

Layers #

reg layer ls #

List layers with name, precedence, enabled state, and (informational) owner SID, ordered by descending precedence.

OptionEffect
-l, --longLong form.
$ reg layer ls
policy                   prec=100    enabled   owner=S-1-5-32-544
base                     prec=0      enabled

reg layer new <name> #

Create a layer by writing its metadata key under Machine\System\Registry\Layers\.

OptionEffect
--precedence NPrecedence (higher wins). A precedence above 0 requires SeTcbPrivilege; the tool attempts it and reports any denial.
--owner SIDRecord an informational owner SID.
--disabledCreate the layer disabled.
$ reg layer new policy --precedence 100 --owner S-1-5-32-544
created layer policy (precedence 100, enabled)

reg layer set <name> #

Modify an existing layer's metadata.

OptionEffect
--precedence NChange the precedence.
--enable / --disableEnable or disable the layer.
--owner SIDChange the informational owner SID.

reg layer del <name> #

Delete a layer — removes its metadata key; LCS tears down the layer's entries. Prompts for confirmation on a terminal.

$ reg layer del policy
Delete layer policy and all its entries? [y/N] y
deleted layer policy

Managing per-process private layer views is out of scope for reg; see private hives and layers.


Security descriptors #

reg sd <key> #

Show or set a key's security descriptor as SDDL, using the same codec as the sd tool, so its output is consistent. With no scope flags, the default is owner + group + DACL (a SACL requires the privileged ACCESS_SYSTEM_SECURITY right).

OptionEffect
--set SDDLApply the given SDDL. Without it, sd prints the current descriptor.
--ownerScope to the owner.
--groupScope to the group.
--daclScope to the DACL.
--saclScope to the SACL (needs ACCESS_SYSTEM_SECURITY).
$ reg sd Machine\App
O:BAG:BAD:(A;;KA;;;BA)(A;;KR;;;WD)

$ reg sd Machine\App --set 'O:BAG:BAD:(A;;KA;;;BA)' --owner --dacl
set security descriptor on Machine\App

A security-descriptor change takes effect on future opens only (existing handles keep the access mask they were granted). Security changes are not layered and are not undone by layer removal — they mutate the key object directly. See Access control on keys.


Symlinks #

reg link <key> <target> #

Create a symlink key pointing at the absolute target key path. This creates a key with the immutable symlink flag and a default REG_LINK value holding the target. Requires KEY_CREATE_LINK and SeTcbPrivilege/Administrator; the tool attempts it and reports any denial.

OptionEffect
--layer NAMECreate the link key in layer NAME.
$ reg link Machine\App\CurrentConfig Machine\App\Config\v3
linked Machine\App\CurrentConfig -> Machine\App\Config\v3 (layer: base)

get and info follow symlinks to their target by default; pass --no-follow to inspect the link key itself. See Advanced: registry links.


Watching #

reg watch <key> #

Arm a change watch and stream one event per change until interrupted (or until --count events). Each event faithfully means "something under the filter changed — re-read"; reg does not decode the change records' contents. With --json, emits one JSON object per line.

OptionEffect
--subtreeWatch descendant keys too, not just this key.
--filter LISTComma-separated subset of value, subkey, sd (default: all).
--count NExit after N events.
$ reg watch Machine\System\KMES --subtree --filter value
changed: Machine\System\KMES
changed: Machine\System\KMES

See Watching for changes for why a service watches instead of polling.


Batch, export, backup, and restore #

Two paths move a subtree around: export/apply are the portable, reviewable path (a diffable text or JSON document); backup/restore are the exact, privileged path (an opaque kernel snapshot).

reg apply <file> #

Apply a batch of operations to one hive in a single transaction — all-or-nothing. All operations must target one hive (a cross-hive batch fails with exit 4). - reads standard input.

OptionEffect
--dir DIRApply every batch file in DIR (sorted), each as its own transaction. A missing or empty directory applies nothing and succeeds.
--once-deleteDelete each batch file after it applies successfully (a drain).
-y, --yesSkip confirmation.

The batch format is JSON (canonical and exact) or a line-oriented text format; apply auto-detects (a leading { or [ means JSON). Text-format input is not yet implemented — supply JSON, or generate one with reg export --json. Text export works for review.

$ reg export --json Machine\App - | reg apply -
applied 4 keys

reg export <key> [file] #

Dump a subtree to the batch format. Omit file (or pass -) to write to standard output. Human-readable text by default; --json emits the canonical exact form.

OptionEffect
--layer NAMEExport one layer's view (default: the effective state).
$ reg export Machine\App app-config.reg

reg backup <key> <file> #

Write an opaque, exact, binary kernel snapshot of a key and its subtree to file. Requires SeBackupPrivilege.

$ reg backup Machine\System\KMES kmes.snap
backed up Machine\System\KMES -> kmes.snap

reg restore <key> <file> #

Replace a key and its entire subtree from a snapshot, in one transaction. Requires SeRestorePrivilege. Prompts for confirmation on a terminal.

$ reg restore Machine\System\KMES kmes.snap
Replace key Machine\System\KMES and its entire subtree from kmes.snap? [y/N] y
restored Machine\System\KMES from kmes.snap

See Backup and restore for when to reach for each path.


Output formats #

Default output is terse, human-readable, and grep-friendly. --json switches every command to structured output — a single self-contained JSON document, except watch, which emits JSON-lines (one object per event). In any value listing, the default (@) value is emitted first, then named values sorted case-insensitively.

Type formatting on read:

Registry typeHuman formJSON form
REG_SZ / REG_EXPAND_SZthe string{"type":"sz","data":"…"}
REG_DWORD / REG_QWORDdecimal{"type":"dword","data":42}
REG_MULTI_SZone element per line{"type":"multi","data":["a","b"]}
REG_BINARYhex{"type":"binary","data":"deadbeef"}
REG_LINKthe target path{"type":"link","data":"…"}

Exit status #

CodeMeaningTypical cause
0Success.—
1Usage error.Bad arguments; a required option missing.
2Key or value not found.ENOENT.
3Access denied.EACCES, EPERM — the kernel refused the operation.
4Invalid specification.Bad path, type, or literal; a cross-hive batch; a name too long (EINVAL, EXDEV, ENAMETOOLONG).
5Syscall or source failure.EIO, ETIMEDOUT, ENOSPC, ENOMEM.
6Compare-and-swap conflict.EAGAIN — an --expected-seq guard did not match; the value changed under you.

A denial (3) reports the operation, the target, and, where relevant, the access that was required — in the style of the sd and token tools.

See also #

  • regman — the registry manual: what a key or value means, as opposed to what it is set to. Consult it before you reg set.
  • Keys, values, and types — the data model reg addresses.
  • Layers — what "effective" resolves against, and what --layer, mask, and hide operate on.
  • Access control on keys — the check every reg operation goes through.

regman

Peios / Using Peios / Peiosutils / Registry tools

Configuration, not storage established that the registry holds values but not their meaning: it keeps a type tag and some bytes, and never knows that BufferCapacity must be a power of two or what it is for. That knowledge has to live somewhere a person can look it up. It lives in regman, the registry's manual.

regman is the man of the registry. Give it a path and it tells you what a key or value actually is. It is the everyday tool for configuring a Peios system — before you touch a knob, regman is how you find out what it does and what changing it will cost.

regman, in one sentence #

regman <path> [value] documents what a registry key or value means — its type, default, valid values, when a change takes effect, and a prose description — drawn from shipped documentation, never from the live registry.

That last clause is the one to hold onto; there is a section on it below.

Looking up a value #

Give regman a key path and a value name and it prints a knob-card — an identity line, an aligned block of facts, and a description:

$ regman Machine\System\KMES BufferCapacity

Machine\System\KMES BufferCapacity                    documented by kmes

  Type     REG_QWORD
  Default  4194304  (4 MB)
  Valid    65536–268435456 bytes (64 KB–256 MB), power of two
  Applies  live — ring-buffer swap

Per-CPU ring buffer capacity, in bytes. Must be a power of two; values
that are not are treated as invalid and ignored.

Every registry value is a knob, and every knob has the same few facts worth knowing, so the card is uniform rather than free-form:

FieldTells you
TypeThe value's registry type (REG_QWORD, REG_SZ, …).
DefaultThe value used when nothing is set.
ValidThe range, set, or constraint a sensible value must satisfy.
AppliesWhen a change takes effect — live, on restart, or on reboot.

The Applies field is the one operators reach for most: it is the difference between "edit it and you're done" and "edit it and schedule a reboot". Only the fields that make sense for a given item are shown, and a knob that is being retired carries a prominent deprecation notice at the top of its card.

Looking up a key #

Give regman just a key — no value — and it does double duty as an index: the key's own description, then a list of every value documented under it, one summary line each.

$ regman Machine\System\KMES

Machine\System\KMES                                   documented by kmes

The KMES event subsystem reads its tuning parameters from the values
under this key...

Values
  BufferCapacity         Per-CPU ring buffer capacity in bytes.
  MaxEventSize           Max total size of a userspace-emitted event.
  MaxNestingDepth        Max nesting depth for userspace event payloads.
  MaxEmitRatePerProcess  Max events per second a single process may emit.

So you can start at a subtree, see what is configurable there, and drill into any single value.

Searching, when you do not know the path #

If you don't know where a setting lives, regman -k searches names and summaries — the registry's apropos:

$ regman -k buffer
Machine\System\KMES BufferCapacity   Per-CPU ring buffer capacity in bytes.

regman documents intent, not current state #

This is the boundary that matters most. regman tells you what a setting should be — what it means and which values are legal — not what it is currently set to on this machine. It reads shipped documentation, never the live registry; it does not talk to LCS at all. Ask regman about BufferCapacity and you learn it must be a power of two and defaults to 4 MB; you do not learn that this particular box has it set to 8 MB right now. Reading the current value is a separate, live query against the registry — that is reg's job. regman tells you a knob should be a power of two; reg get tells you what it is set to, and reg set changes it. Reach for regman to decide what to write, and reg to write it.

Put regman next to the other two things from Configuration, not storage and a clean division of labour appears:

To learn…Look at…
What a setting means, and what is validregman — the manual
What the value is set toreg — a live query against the store
What the subsystem is actually running onthe event log

regman is the one you consult first, and the only one that works before you have changed anything — because documentation ships with the software, not with the machine's state. It is the natural complement to reject-or-keep: regman tells you the valid range up front, so you set a good value the first time instead of writing one the owning subsystem will quietly refuse.

Where the documentation comes from #

regman has no built-in database of every setting. Each package ships its own documentation as files dropped into a well-known directory (/usr/share/regman/), one fragment per package documenting that package's whole configuration surface. Install a package and its registry documentation appears; remove the package and it goes away. The package that owns a set of keys is the package that documents them — the only arrangement that stays correct as the system changes.

A consequence worth knowing: regman can only describe settings that some installed package has documented. An undocumented key is invisible to it — regman is exactly as complete as the packages on the machine make it. If two packages happen to document the same item, regman shows both and flags the overlap rather than silently picking a winner.

(For the people who write that documentation, regman fmt and regman lint prepare and check fragments, and regman index keeps lookups fast on large corpora — the lookup is always correct without an index, which is purely an accelerator. These are packaging concerns rather than everyday operator ones.)

Where to go next #

For the idea regman exists to serve — why the registry holds values without holding their meaning, and what reject-or-keep means — read Configuration, not storage.

For the other half of the picture — reading what a value is actually set to, which is a live query against the store rather than a documentation lookup — read LCS and sources.

Peios Learn — documentation for the Peios project.

Built with Trail.