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

System and processes

Single-page view · as markdown

System and processes

Peios / Using Peios / Peiosutils / System and processes

This topic gathers the commands that deal with the running system rather than with files: reading the time, asking what hardware and system you are on, launching another command under some constraint, signalling a process, working with the terminal.

The commands #

Time

CommandPurpose
datePrint — or set — the system date and time.
sleepPause for a given length of time.
uptimeShow how long the system has been running.

Running a command under a constraint

CommandPurpose
timeoutRun a command, and kill it if it runs too long.
nohupRun a command so it survives the terminal closing.
niceRun a command at an adjusted scheduling priority.
stdbufRun a command with altered stream buffering.
chrootRun a command with a different directory as its root.

Signalling processes

CommandPurpose
killSend a signal to a process.

System identity and capacity

CommandPurpose
unamePrint system information — the OS, the kernel, the machine.
archPrint the machine's hardware architecture.
hostnameDisplay — or set — the system's host name.
hostidPrint the host's numeric identifier.
nprocPrint how many processor cores are available.

Who you are

CommandPurpose
whoamiPrint the name of the user a process is running as.
idPrint the user and group identity of a process, or of a named user.
groupsPrint the groups a user belongs to.
lognamePrint the login name of the user a process is running as.

These report the projection of a token onto POSIX user and group numbers, which is what Linux programs see. The numbers grant nothing on their own — id explains what they can and cannot say, and token shows the identity underneath them.

Tokens and logon sessions

CommandPurpose
tokenInspect and manage a process's token.
logonseInspect and manage logon sessions and their processes.

Storage and terminal

CommandPurpose
syncFlush cached writes out to persistent storage.
ttyPrint the name of the terminal on standard input.
sttyDisplay or change terminal settings.

A note on changing the system #

Most commands here only report. A few can change the running system — date can set the clock, hostname can set the host name. Changing system-wide state is a privileged operation: it succeeds only for a caller whose token holds the right to do it, and is refused otherwise. The pages for those commands say so where it applies, and Privileges is the full picture.

Where to start #

uname answers "what am I running on?". kill is the one to read carefully — sending the wrong signal to the wrong process is a quick way to lose work.

date

Peios / Using Peios / Peiosutils / System and processes

date prints the current date and time. With the right option, it can also set the system clock, display some other moment, or format a date however you need.

date [options] [+format]
$ date
Sun 17 May 2026 14:32:08 BST
$ date +%Y-%m-%d
2026-05-17

Formatting the output #

A +format argument controls the output. The format string is printed literally, except for % sequences, each of which is replaced by a piece of the date. The common ones:

SequenceIs replaced by
%Y %m %dYear, month, day.
%H %M %SHour, minute, second.
%FThe full date — same as %Y-%m-%d.
%TThe time — same as %H:%M:%S.
%A %aWeekday name, full and abbreviated.
%B %bMonth name, full and abbreviated.
%jDay of the year.
%sSeconds since 1970-01-01 UTC.
%z %ZNumeric and named time zone.
%%A literal %.

The full set is long; date --help lists every sequence with an example.

Displaying a different moment #

OptionEffect
-d, --date=STRINGShow the time described by STRING — "yesterday", "next Friday", "@1615432800" — instead of now.
-r, --reference=FILEShow FILE's last modification time.
-f, --file=DATEFILELike -d, but once for each line of DATEFILE.
-u, --universalWork in Coordinated Universal Time (UTC) rather than the local zone.

Standard formats #

OptionOutput
-I, --iso-8601[=FMT]ISO 8601 — FMT is date, hours, minutes, seconds, or ns.
-R, --rfc-emailThe format used in email headers.
--rfc-3339=FMTRFC 3339 — FMT is date, seconds, or ns.

Setting the clock #

OptionEffect
-s, --set=STRINGSet the system clock to the time described by STRING.

Setting the clock changes state for the whole system, so it is a privileged operation — it succeeds only for a caller whose token carries the right to set the time, and is refused otherwise. See Privileges.

Exit status #

CodeMeaning
0The date was printed or set.
1An invalid date or format, or the clock could not be set.

sleep

Peios / Using Peios / Peiosutils / System and processes

sleep does nothing for a given length of time, then exits.

sleep number[suffix]...
$ sleep 5          # pause for five seconds
$ sleep 1.5h       # pause for an hour and a half

It is used to space things out — a pause between the steps of a script, a delay before a retry.

Specifying the duration #

number may be a whole number or a fraction. A suffix gives the unit:

SuffixUnit
sSeconds. This is the default if no suffix is given.
mMinutes.
hHours.
dDays.

Given more than one argument, sleep waits for the sum of them — sleep 1m 30s pauses for ninety seconds.

Exit status #

CodeMeaning
0The full time elapsed.
1A bad argument, or sleep was interrupted before the time was up.

timeout

Peios / Using Peios / Peiosutils / System and processes

timeout runs a command with a time limit. If the command finishes in time, nothing special happens. If it is still running when the limit is reached, timeout kills it.

timeout [options] duration command...
$ timeout 30s slow-fetch https://example.com

It is the guard against a command that might hang — a network fetch, a script that could loop forever.

The duration #

duration is a number with an optional unit suffix: s for seconds (the default), m for minutes, h for hours, d for days. A duration of 0 disables the limit.

How the command is stopped #

When the limit is reached, timeout sends the command a TERM signal — a request to shut down cleanly. A well-behaved command stops there. A command that ignores TERM keeps running, which is what -k is for.

OptionEffect
-s, --signal=SIGNALSend SIGNAL instead of TERM when the limit is reached.
-k, --kill-after=DURATIONIf the command is still running DURATION after the first signal, send it a KILL signal — which cannot be ignored.
--preserve-statusExit with the command's own status even when it timed out.
--foregroundAllow the command to keep reading from the terminal; do not time out the command's own children.
-v, --verboseReport to standard error whenever a signal is sent.

Exit status #

timeout passes through the command's exit status when the command finishes on its own. Otherwise:

CodeMeaning
(command's own)The command finished within the limit.
124The command timed out.
125timeout itself failed.
126The command was found but could not be run.
127The command was not found.
137The command was ended by a KILL signal.

nohup

Peios / Using Peios / Peiosutils / System and processes

nohup runs a command so that it survives the terminal closing. Normally, when a terminal session ends, the system sends a hangup signal to the commands running under it, and they stop. A command started with nohup ignores that signal and keeps running.

nohup [options] command [arg]...
$ nohup long-build &

It is how you start something that needs to outlast your session — a long build, a background job — without it being killed the moment you disconnect.

Where the output goes #

A command run with nohup is meant to outlive the terminal, so nohup cannot leave its streams attached to one. It redirects any stream that is still connected to a terminal:

  • Standard input, if it is a terminal, is replaced with an empty source — the command reads nothing.
  • Standard output, if it is a terminal, is appended to a file named nohup.out in the current directory. If that file cannot be opened there, nohup falls back to nohup.out in your home directory.
  • Standard error, if it is a terminal, is sent to wherever standard output now goes.

Streams that you have already redirected yourself — to a file, or a pipe — are left as they are.

How nohup.out is secured #

When nohup has to create nohup.out, that file is a new file and needs a security descriptor. nohup does not let it inherit one from the directory. It creates nohup.out with a deliberate, locked descriptor: full access for the owner, and no one else.

The reasoning is that nohup.out captures whatever the command writes, which the person running it has not chosen to share. A file that appears as a side effect should not be more open than its creator intended — so nohup gives it the safe default of owner-only, rather than whatever the surrounding directory would have handed down.

The POSIX mode bits agree with the descriptor: the file is created with mode 0600 in the same open call that creates it, so there is no moment at which it exists more openly.

OptionEffect
--sddl=SDDLCreate nohup.out with the security descriptor given as an SDDL string, instead of the owner-only default.

--sddl only matters when nohup actually creates the file. If nohup.out already exists, nohup appends to it and leaves its existing security alone.

Exit status #

When nohup runs a command, it exits with that command's status once it finishes. The exception is a failure in nohup itself:

CodeMeaning
(command's own)The command ran; this is its exit status.
125nohup could not set things up — it could not detach from the terminal, or could not open nohup.out anywhere. The command was not run.

nice

Peios / Using Peios / Peiosutils / System and processes

nice runs a command at an adjusted scheduling priority — making it more, or less, willing to give the processor up to other work.

nice [options] [command [arg]...]
$ nice -n 15 big-batch-job

With no command, nice prints the current niceness.

Niceness #

A process has a niceness — a number from -20 to 19:

  • A high niceness (toward 19) means the process is "nicer" to others — it yields the processor readily. Good for background work that should not get in the way.
  • A low niceness (toward -20) means the process is favoured — it gets the processor more often.

By default nice adds 10 to the niceness, making the command run in the background more gracefully.

OptionEffect
-n, --adjustment=NAdd N to the niceness instead of 10. N may be negative.

Raising a command's niceness — running it lower priority — is always allowed. Lowering the niceness, to claim a higher priority than normal, is a privileged request and may be refused; when it is, nice warns and runs the command at the priority it was permitted.

Exit status #

When nice runs a command, it exits with that command's status. The exception is a failure in nice itself:

CodeMeaning
(command's own)The command ran; this is its exit status.
0No command was given; the niceness was printed.
125nice itself failed — for example, a bad adjustment value.
126The command was found but could not be run.
127The command was not found.

kill

Peios / Using Peios / Peiosutils / System and processes

kill sends a signal to a process. Despite the name, a signal is not always fatal — it is a message, and some signals ask a process to do something other than stop.

kill [options] pid...
$ kill 4821                 # ask process 4821 to terminate
$ kill -KILL 4821           # force it to stop

A pid is a process identifier — the number a running process is known by.

Signals #

With no option, kill sends TERM — a polite request to shut down, which a well-behaved process honours by cleaning up and exiting. The signals you will use most:

SignalMeaning
TERMTerminate. The default — a request to stop cleanly.
KILLStop immediately. Cannot be caught or ignored, so it cannot be refused — but the process gets no chance to clean up. The last resort.
HUPHang up. Conventionally tells a long-running service to reload its configuration.
INTInterrupt — the signal a terminal sends on Ctrl-C.
STOP / CONTSuspend the process / resume a suspended one.
OptionEffect
-s, --signal=SIGNALSend SIGNAL instead of TERM.
-SIGNALA shorthand — -KILL or -9 both send KILL.
-l, --listList the signal names.
-L, --tableList the signals as a table of numbers and names.

Use KILL only when TERM has failed. A process killed outright cannot save its work or release what it holds.

A -N that is not a known signal number is an error ("invalid signal"). It is never reinterpreted as a negative process ID.

Exit status #

CodeMeaning
0Every signal was sent.
1A signal could not be sent — a process that does not exist, or one you are not permitted to signal.

uname

Peios / Using Peios / Peiosutils / System and processes

uname prints information about the system you are running on.

uname [options]
$ uname
Peios
$ uname -a
Peios host-01 1.4.0 #1 SMP 2026-05-10 x86_64 Peios

With no option, uname prints the operating-system name — Peios.

What each option prints #

OptionPrints
-sThe kernel name.
-oThe operating-system name — Peios.
-nThe node name — the name this system is known by on the network.
-rThe kernel release.
-vThe kernel version.
-mThe machine's hardware name (its architecture).
-pThe processor type.
-iThe hardware platform.
-aEverything — equivalent to -mnrsvo.

Give several options and uname prints those fields, in a fixed order, on one line.

The operating system is Peios #

uname -o, and the operating-system field of uname -a, report Peios. This is the field a script should check when it wants to confirm what system it is on.

For the machine architecture alone, arch is the shorter command — it prints exactly what uname -m prints.

Exit status #

CodeMeaning
0The requested information was printed.
1The system information could not be read.

arch

Peios / Using Peios / Peiosutils / System and processes

arch prints the machine's hardware architecture — the kind of processor the system runs on.

arch
$ arch
x86_64

That is the whole command. It takes no options and prints a single name.

arch prints exactly what uname -m prints. It exists as a short, obvious name for the one question "what architecture is this?" — convenient in a script that picks an architecture-specific path.

Exit status #

CodeMeaning
0The architecture was printed.
1The architecture could not be determined.

hostname

Peios / Using Peios / Peiosutils / System and processes

hostname displays the system's host name — the name the system is known by.

hostname [options] [name]
$ hostname
host-01.example.com

What is displayed #

By default hostname prints the fully qualified name. These options narrow or change what is shown:

OptionPrints
-f, --fqdnThe fully qualified domain name — the full host.domain form. This is the default.
-s, --shortThe short host name only — the part before the first dot.
-d, --domainThe DNS domain part only.
-i, --ip-addressThe network address (or addresses) the host name resolves to.

Setting the host name #

Given a name argument, hostname sets the system's host name to it.

$ hostname host-02

Changing the host name changes state for the whole system, so it is a privileged operation — it succeeds only for a caller whose token carries the right to do it, and is refused otherwise. See Privileges.

Exit status #

CodeMeaning
0The host name was displayed or set.
1A failure — the name could not be read, set, or resolved.

hostid

Peios / Using Peios / Peiosutils / System and processes

hostid prints the host's numeric identifier, in hexadecimal.

hostid
$ hostid
007f0100

The host id is a number associated with the system. It takes no options and prints one value.

Where hostname gives the system's name — meant to be read by people — hostid gives a numeric value, used by software that wants a machine identifier in a fixed numeric form.

Exit status #

CodeMeaning
0The host id was printed.

nproc

Peios / Using Peios / Peiosutils / System and processes

nproc prints the number of processor cores available.

nproc [options]
$ nproc
8

By default it prints the number of cores available to the current process — which can be fewer than the machine has, if the process has been restricted to a subset. It is most often used to decide how many parallel jobs to run.

Options #

OptionEffect
--allPrint the number of cores the whole system has, ignoring any restriction on the current process.
--ignore=NSubtract N from the count — for leaving some cores free rather than using every one.

The environment variables OMP_NUM_THREADS and OMP_THREAD_LIMIT, if set, also bound the number nproc reports.

Exit status #

CodeMeaning
0The count was printed.
1An option value was invalid.

uptime

Peios / Using Peios / Peiosutils / System and processes

uptime shows how long the system has been running, along with a few related figures.

uptime [options]
$ uptime
 14:32:08  up 6 days,  3:21,  load average: 0.18, 0.24, 0.21

The default line packs in three things:

  • the current time;
  • how long the system has been up;
  • the load average — a rough measure of how busy the system has been over the last 1, 5, and 15 minutes.

If you know uptime from other systems you may be expecting a count of logged-in users between the uptime and the load average. Peios does not print one. That count comes from a login database (utmp) that Peios does not keep, so the field is left out rather than always reporting 0 users.

To inspect Peios logon sessions and their processes, use logonse. Logon sessions record authentication events, including service and batch logons; their count is not a count of logged-in users.

Options #

OptionEffect
-p, --prettyShow just the uptime, in a readable phrase — up 6 days, 3 hours, 21 minutes.
-s, --sinceShow the date and time the system started, rather than how long ago that was.

Exit status #

CodeMeaning
0The uptime was printed.
1The boot time could not be read.

sync

Peios / Using Peios / Peiosutils / System and processes

sync flushes cached writes to persistent storage.

sync [options] [file...]
$ sync

When a program writes to a file, the data does not always reach the physical device immediately — for speed, the system holds recent writes in memory and writes them out a little later. sync forces that pending data out now, so that what is on the device matches what programs have written.

It is the command to run before doing something that should not lose recent writes — before powering off by hand, or before removing storage.

Options #

With no argument, sync flushes everything. The options narrow it:

OptionEffect
file...Flush only the given files, rather than everything.
-d, --dataFor the given files, flush only the file data, not metadata that does not need it.
-f, --file-systemFlush the entire file system that contains each given file.

Exit status #

CodeMeaning
0The flush completed.
1A named file could not be reached.

tty

Peios / Using Peios / Peiosutils / System and processes

tty prints the name of the terminal connected to standard input.

tty [options]
$ tty
/dev/pts/3

If standard input is not a terminal — because it has been redirected from a file or a pipe — tty prints not a tty instead.

That second behaviour is the useful one: a script can run tty to find out whether it is being run interactively or as part of a pipeline, and behave accordingly.

Options #

OptionEffect
-s, --silentPrint nothing; report the answer only through the exit status.

Exit status #

CodeMeaning
0Standard input is a terminal.
1Standard input is not a terminal.
2A usage error.

stty

Peios / Using Peios / Peiosutils / System and processes

stty displays and changes the settings of a terminal — how it handles input, output, and special keys.

stty [options] [setting...]
$ stty
speed 38400 baud; line = 0;
-brkint -imaxbel iutf8

Run with no arguments, stty prints the settings that differ from the usual defaults. Given setting arguments, it changes them.

Viewing the settings #

OptionEffect
-a, --allPrint every setting, in a readable layout.
-g, --savePrint every setting in a single compact line — a form that can be fed straight back to stty to restore them.

The -g form is how you save and restore a terminal's state:

$ saved=$(stty -g)      # capture the current state
$ stty -echo            # ...change something...
$ stty "$saved"         # restore exactly what was saved

Changing the settings #

A setting argument turns something on or off, or assigns a value. A few common ones:

SettingEffect
echo / -echoShow / hide typed characters — -echo is how a password prompt hides input.
rows N / cols NTell the terminal its size.
A numberSet the connection speed (baud rate).

stty has a large catalog of settings; stty -a shows them all with their current values.

Choosing the terminal #

OptionEffect
-F, --file=DEVICEOperate on DEVICE instead of the terminal on standard input.

Exit status #

CodeMeaning
0The settings were printed or changed.
1A setting was invalid, or the terminal could not be accessed.

stdbuf

Peios / Using Peios / Peiosutils / System and processes

stdbuf runs a command with altered buffering on its standard streams.

stdbuf [options] command...
$ slow-producer | stdbuf -oL grep error

What buffering is, and why change it #

A program usually does not write each piece of output the instant it is produced — it collects output in a buffer and writes it in batches, which is faster. The cost is delay: when a program's output feeds a pipe, that batching can hold lines back for a long time, which is unhelpful when you are watching a pipeline live.

stdbuf lets you override that batching for a command, so its output appears sooner.

Setting the buffering #

OptionStream
-i, --input=MODEStandard input.
-o, --output=MODEStandard output.
-e, --error=MODEStandard error.

MODE is one of:

MODEBuffering
0Unbuffered — every write goes out immediately.
LLine-buffered — output is flushed at the end of each line. Not valid for input.
a sizeFully buffered with a buffer of that many bytes. Accepts suffixes — K, M, and so on.

-oL — line-buffered output — is the common case: it makes a command in a pipeline emit each line as it is finished.

How it works #

stdbuf works by preloading a small helper library, libstdbuf.so, into the command, so the C library's buffering defaults are changed before the command's main runs. The library is installed with the utilities at /usr/libexec/peiosutils/libstdbuf.so; stdbuf looks for it beside its own executable first and in that directory second, and refuses to run the command if it is missing rather than run it unbuffered. stdbuf then waits for the command and exits with its status.

Nothing is written anywhere at run time. Earlier builds embedded the library and extracted it to $TMPDIR on every invocation, which is where two upstream security advisories lived; the shipped build no longer does that.

A limitation #

stdbuf adjusts the default buffering. A command that manages its own stream buffering will override what stdbuf sets, and some commands do not use buffered streams at all — for those, stdbuf has no effect.

Exit status #

When stdbuf runs a command, it exits with that command's status. The exception is a failure in stdbuf itself:

CodeMeaning
(command's own)The command ran; this is its exit status. If the command was killed by a signal, stdbuf exits with 128 plus the signal number, as a shell would.
125stdbuf itself failed, for example an unusable TMPDIR.
126 / 127The command could not be run / could not be found.

chroot

Peios / Using Peios / Peiosutils / System and processes

chroot runs a command with a different directory as its root — its /. Inside that command, the chosen directory is the top of the file system, and nothing above it can be named or reached.

chroot newroot [command [arg]...]
$ chroot /mnt/system /bin/sh

With a command, chroot changes the root to newroot and runs the command there. With no command, it starts an interactive shell.

What it does #

A process normally sees the whole file system, rooted at the real /. After chroot, the named directory becomes that process's /: a path like /etc/config inside the command resolves to newroot/etc/config, and there is no path that reaches outside newroot at all.

It is used to work inside another installed system — repairing or configuring a system image by entering it — and to run a command confined to a known subtree.

For the command to be usable, newroot must already contain what the command needs: the command's own executable, and whatever libraries and files it depends on, all present under newroot.

Options #

OptionEffect
--skip-chdirDo not change the working directory to / after changing the root. Permitted only when newroot is the current /.

A privileged operation #

Changing a process's root directory is a privileged operation. chroot succeeds only for a caller whose token carries the right to do it, and is refused otherwise — the ability to redraw a process's view of the file system is not something every principal holds. See Privileges.

Exit status #

chroot exits with the command's own status once it finishes. Otherwise:

CodeMeaning
125chroot itself failed — for example, newroot is not a directory.
126The command was found but could not be run.
127The command was not found.

whoami

Peios / Using Peios / Peiosutils / System and processes

whoami prints the name of the user the calling process is running as.

whoami
$ whoami
jack

It takes no arguments. It is the same answer as id -un, which is all it has ever been.

Where the name comes from #

The name is resolved from the process's effective user ID, which is a projection of the token's user SID. The lookup goes to the authority — there is no /etc/passwd to read — and comes back as the principal's canonical name. Resolving names is the full picture.

The name is the principal's; the number it was looked up by is not what grants anything. If you want the identity access is actually decided against, id -Z prints the SID.

Exit status #

CodeMeaning
0The name was printed.
1The user ID could not be resolved to a name.

A failure here usually means the authority could not be reached rather than that the account is missing — identity does not resolve before the authority is running, which is the correct answer rather than a gap.

id

Peios / Using Peios / Peiosutils / System and processes

id prints who a process is: its user, its primary group, the groups it belongs to, and its security context.

id [options] [USER]...
$ id
uid=1001000(jack) gid=101(Authenticated Users) groups=101(Authenticated Users),100(Everyone),102(Administrators),107(Local) context=S-1-5-21-1004336348-1177238915-682003330-1000:High

With no argument it reports the calling process. Given one or more users, it reports on those instead.

The numbers are projections #

This is the thing to understand before reading id's output on Peios.

The uid= and gid= numbers are projections of the token's SIDs. They are real, stable, and exactly what Linux programs see and what filesystems store — but nothing is decided by them. Access is decided against the SID the number was projected from, by the access check. A number here grants nothing.

That distinction is not academic, because the projection cannot carry everything a token holds:

  • Groups whose SIDs are deliberately unnumbered — Interactive, Remote Interactive, Network, Batch, Service — cannot appear at all. They are what make a rule like "network logons cap at Low" expressible, and they have no gid by design.
  • A group's attributes have nowhere to go. A deny-only group, which can block access through a deny entry but grant nothing through an allow entry, appears in groups= looking exactly like an ordinary membership.
  • The integrity level and the logon session have no number either.

So two tokens can project to identical numbers and mean different things. The clearest case is a filtered token: it carries the same user SID and the same group numbers as the token it came from, and differs only in attributes the projection cannot express.

That is why the default line ends with a context= field.

The context field #

context= is the authoritative half: the user SID access is actually decided against, and the integrity level.

context=S-1-5-21-1004336348-1177238915-682003330-1000:High

The integrity level is part of it precisely because the SID alone does not separate an elevated token from its filtered counterpart — both carry the same user SID, and the level is what differs.

If you know id from another Unix, this is the field that carries the SELinux context there. Peios has no SELinux; its security context is the token, so that is what the field holds.

context= is omitted when a user is named rather than the calling process — a named user has no token here to read — and when POSIXLY_CORRECT is set, so a caller that asked for the POSIX shape still gets it.

For the whole token rather than this summary, use token.

Options #

OptionEffect
-u, --userPrint only the effective user ID.
-g, --groupPrint only the effective group ID.
-G, --groupsPrint only the group IDs, space-separated.
-n, --nameWith -u, -g or -G, print names instead of numbers.
-r, --realWith -u, -g or -G, print the real ID rather than the effective one.
-z, --zeroSeparate entries with NUL rather than whitespace. Not allowed in the default format.
-Z, --contextPrint only the security context.
-pA readable, multi-line form.
-PPrint as a password-file entry.
-aIgnored; accepted for compatibility.
-ANot applicable on Peios — see below.

-n and -r need one of -u, -g or -G; they do not change the default format.

-r means something different here #

On other Unixes the real/effective split is the setuid boundary. On Peios a setuid bit does not change a token, so that boundary does not exist. What the split tracks instead is impersonation: the real IDs come from the process's own token, the effective ones from whatever token is in force.

id never impersonates, so in practice it reports the same either way and the euid=/egid= fields never appear. That is not a fault — there is genuinely nothing differing to report.

-A is not applicable #

-A reports BSD audit session properties. Peios audits through its own event system and keeps no BSM session, so -A says so rather than silently succeeding at nothing.

id -G and id -G <yourself> differ #

Asking about yourself and asking about your name are two different questions here, and they give different answers:

$ id -G          → 101 100 102 107
$ id -G jack     → 101 102
  • id -G reads your process's credential — the projection of your token's group set, which includes the groups the authority staples on when the token is minted: Everyone and Local, which are on every token.
  • id -G jack looks the name up through the principal store, which returns recorded memberships only. The stapled groups are not recorded anywhere, because membership in them is a rule rather than a stored fact — so they do not come back.

On other systems these two differ only in the order they print. Here the second list is genuinely shorter, and neither is wrong.

The order follows GNU: id -G lists the real group first, then the effective group if it differs, then the rest; the groups= field of the default output leads with the effective group.

Exit status #

CodeMeaning
0The identity was printed.
1A user could not be found, an option combination was rejected, or the context could not be read.

groups

Peios / Using Peios / Peiosutils / System and processes

groups prints the groups a user belongs to.

groups [USERNAME]...
$ groups
Authenticated Users Everyone Administrators Local

$ groups jack
jack : Authenticated Users Administrators

With no argument it reports the calling process. Given names, it reports on those.

Those two answers are both correct #

The example above is not a mistake, and it is the thing worth knowing about this command on Peios.

groups reads the calling process's credential — the projection of its token's group set. That set includes the groups the authority staples on when the token is minted: Everyone and Local are on every token, whoever you are.

groups jack looks the name up through the principal store, which returns recorded memberships — the ones something actually wrote down.

The stapled groups are not recorded anywhere, because membership in them is a rule, not a stored fact. Everyone is in Everyone; nothing needs to record it, and nothing can enumerate it. So they appear in the first answer and not the second.

On other Unixes these two forms differ only in the order they print.

What cannot appear #

Both forms are lossy in the same way, and unavoidably so — a group can only be listed if it has a group ID, and some deliberately do not:

  • Interactive, Remote Interactive, Network, Batch and Service are unnumbered on purpose. They describe how you signed in rather than who you are, which is what lets a rule like "network logons cap at Low" be written at all. You are in Interactive at the console and not over the network, so there is no static answer to record.
  • Your logon session SID is minted fresh for each sign-in and has no number either.
  • A group's attributes are not representable. A deny-only group — one that can block access through a deny entry but grant nothing through an allow entry — is printed exactly like an ordinary membership.

token show --all is the lossless view, with every SID and its attributes.

Exit status #

CodeMeaning
0The groups were printed.
1A named user could not be found, or the group list could not be read.

A group ID with no name is printed as the bare number and sets the exit status, rather than stopping the listing.

logname

Peios / Using Peios / Peiosutils / System and processes

logname prints the login name the calling process runs under.

logname
$ logname
jack

It takes no arguments.

Login name, not current name #

logname and whoami look like the same command and answer slightly different questions.

whoami reports the effective identity — whoever the process is acting as right now. logname reports the login identity: the principal the process's own token is for, regardless of any token it has since taken on. When a process is impersonating a client, whoami follows the impersonation and logname does not.

Most of the time nothing is impersonating and the two agree.

If you know logname from another Unix, note that it answers this from the token rather than from a login-record file. There is no utmp on Peios — nothing writes one — so the traditional source does not exist. The token is the record of who a process is, and it is a better one: it cannot drift from the identity access is actually checked against, because it is that identity.

Exit status #

CodeMeaning
0The login name was printed.
1No login name could be determined.

token

Peios / Using Peios / Peiosutils / System and processes

token is the command-line tool for working with tokens directly. It reads a token's contents, adjusts it, produces derived tokens, and drives impersonation — the low-level operations this topic describes, exposed at a shell.

token subcommand [target] [arguments]
$ token                       # one-line summary of your own token
$ token show --all             # every field of your own token
$ token privs --pid 4821       # the privileges on process 4821's token

token is a direct, debug-level tool. Day to day you do not inspect tokens by hand — the system does. token is for diagnosing an access problem, for understanding what identity a process is really running under, and for building and testing identity setups. Run with no subcommand, it prints a one-line summary of your own token.

Choosing which token #

Almost every subcommand operates on a token, and these flags choose which one. With none, the target is your own.

FlagTarget
--selfYour own token. The default.
--realYour primary token specifically, rather than the effective one — relevant when your thread is impersonating.
--pid PIDThe primary token of process PID.
--tid TIDThe effective token of thread TID: its impersonation token, or the process primary token when not impersonating (used with --pid).
--peer SOCK_FDThe peer's captured token on a connected socket — see Peer tokens.

Reading another process's token is itself access-controlled: it succeeds only with the right authority over that process.

Inspecting a token #

show #

token show prints a token's contents. It is the default — bare token is token show --short.

FlagEffect
--shortA one-line summary.
--allEvery query class — the fullest dump.

Field accessors #

Each of these prints one part of a token, for when you want just that piece:

SubcommandPrints
userThe user SID — who the token is.
ownerThe default owner SID.
groupThe primary group SID.
groupsThe group list.
privsThe privileges, with their enabled state.
capsThe capabilities.
claimsThe user and device claims.
integrityThe integrity level.
logonThe logon type and logon SID.
sourceWhat minted the token.
originThe originating session for a derived token.
statsToken statistics — IDs, timestamps, the modification counter.
default-daclThe token's default DACL.

token show reports the token's LogonSession LUID as session_id and its separate interactive-environment scope as interactivity_scope.

query #

token query CLASS performs a raw read of a single named token-info class and prints the result as JSON — the lowest-level inspection route, for tooling.

compare #

token compare LEFT RIGHT compares two tokens. Each positional target is a positive PID or self. To select a thread, primary self token, or peer token on the right, omit RIGHT and use the usual target flags:

token compare 1482 1500
token compare 1482 --pid 1482 --tid 1509
token compare self --real
token compare self --peer 7 --json

The table shows two value columns with = or != for each user SID, integrity SID, LogonSession ID, group state and privilege state. SIDs include their friendly names where known. Groups are enabled, disabled, or deny-only; privileges are enabled or disabled. A - means the group or privilege is absent from that token. The table includes entries present in either token.

With --json, header contains user, integrity and session_id; groups and privileges are arrays. Every compared field has left, right and a boolean matches. Missing group or privilege values are JSON null. Group entries also carry a group SID/name object, and privilege entries carry bit and name (null when unknown). Equality uses SID identity and the stated values, independent of friendly-name rendering. Both equal and differing comparisons exit successfully when all queries succeed.

threads #

token threads PID lists threads in ascending TID order, with an impersonating yes/no column and the effective user's SID and friendly name:

token threads 1482
token threads 1482 --json

The command enumerates /proc/PID/task and uses the normal access-controlled thread-token query. It reports primary-token threads as no, including when several threads have the same user. An impersonating thread remains yes even if its impersonation token has the same user as the primary token.

JSON output has pid, complete, and a threads array. A successful row contains tid, impersonating and user. A thread that disappears or cannot be queried retains its row with an error, null identity fields, and complete: false; the command exits nonzero. Human output shows ? and the error for that row. Directory-enumeration failures also exit nonzero.

Both commands support the normal --raw, --label and --json output choices. Queries are consecutive observations of a running system, not an atomic snapshot of all token fields or threads.

Changing a token #

adjust #

token adjust mutates a token in place:

FormChanges
adjust privs NAME=STATE …Enable, disable, or remove privileges. STATE is enabled, disabled, or removed.
adjust groups IDX=STATE …Enable or disable groups by their list index.
adjust default --dacl SDDLReplace the token's default DACL. Also --owner-idx / --group-idx.
adjust interactivity-scope SCOPEReplace the token's interactive-environment scope. The legacy name adjust session SCOPE is accepted as an alias; neither form changes the LogonSession auth_id.

restrict #

token restrict produces a restricted token — a more limited variant of a token.

FlagEffect
--drop-privs MASK|NAMESPrivileges to drop.
--deny IDX,…Group indices to mark deny-only.
--restrict SID,…The restricting SIDs to apply.

duplicate #

token duplicate (alias dup) copies a token, optionally changing its --type (primary or impersonation), its impersonation --level, or its --access mask.

link and linked #

token link joins two tokens as an elevation pair — a full token and its filtered counterpart — given their file descriptors and a session id. token linked shows a token's elevation-linked counterpart, if it has one. See Elevation.

Impersonation #

SubcommandEffect
impersonateBegin impersonating the target token on the calling thread. With a trailing -- command …, run that command under the impersonating token.
revertDrop any active impersonation on the calling thread.

See Impersonation for the model these drive.

Creating tokens #

SubcommandEffect
create SPECCreate a token from a binary token-spec (SPEC is a file, or - for standard input).
install SPECCreate a token from a spec and install it as the caller's primary token.

Creating and installing tokens is a privileged operation, reserved for the components that legitimately mint identity.

Output options #

FlagEffect
--rawRender SIDs in raw S-1-… form only.
--labelRender SIDs as their labels where known, falling back to raw.
--jsonEmit JSON instead of human-readable output.

token and the inspection surfaces #

token is the convenient front-end. Underneath, it reads the same kernel surfaces and rules described in Inspecting tokens — that page covers the query mechanism, the access rules for reading another process's token, and what cannot be inspected.

Exit status #

CodeMeaning
0The operation succeeded.
1A usage error.
non-zeroThe operation failed — no such target, an access denial, or a bad spec.

logonse

Peios / Using Peios / Peiosutils / System and processes

logonse is the command-line tool for logon sessions — the kernel's records of authentication events that this topic describes. It lists the active sessions, shows which processes belong to one, creates and destroys sessions, signs them out, and (as a related low-level job) shows a process's Process Security Block (PSB) and sets its mitigation flags.

logonse subcommand [arguments]
$ logonse list
$ logonse show 4711

logonse is a low-level administrative and debugging tool. It requires a subcommand: list, show, create, destroy, end, or psb.

Listing sessions #

logonse list #

Lists every live logon session: who it is for, what kind of sign-in made it, the authentication package, when it was made, and the processes in it.

$ logonse list
session 999  Local System (S-1-5-18)  service
  package: Negotiate
  created: when the machine started
  pids:    [562, 571, 620, 667, 670]
session 1007  jack (S-1-5-21-…-1000)  remote-interactive
  package: lpsd
  created: 2026-10-04 10:02:41
  pids:    [2611, 2633, 2650]

logonse show #

Shows one session, the same way.

$ logonse show 1007

Where the answers come from #

The sessions come from the kernel's own list, /sys/kernel/security/kacs/sessions, which only BUILTIN\Administrators and SYSTEM may read. It lists every session, including one that has no process — held alive only by a token file descriptor somewhere, or made and not yet used — and such a session shows pids: none you can see.

The processes come from walking the running processes and reading each one's token (/proc/<pid>/token) to find which session it belongs to. That shows only the processes you may inspect: an administrator sees every process but the protected ones, such as peinit and authd, which no administrator can inspect. Processes start and exit while the walk runs, so it is a close approximation of the moment, not a locked one.

Without Administrators, the kernel's list is refused, and logonse says so and shows only the sessions of processes you can inspect — your own.

Creating and destroying sessions #

logonse create #

Creates a new logon session for a user, described by a logon type, an authentication-package name, and the user's SID.

$ logonse create --logon-type interactive --auth-package Negotiate --user-sid S-1-5-21-...-1001
FlagMeaning
--logon-type TYPEThe kind of logon: interactive, network, batch, service, network-cleartext, new-credentials, or remote-interactive.
--auth-package STRThe name of the authentication package that vouched for the logon.
--user-sid SIDThe user the session belongs to, as an S-1-… SID or an SDDL alias such as BA.

On success logonse prints the new session's id. Creating a session is a privileged operation — minting authentication records is reserved for the components that legitimately do so.

Note

The tool builds the kernel's binary session spec from these fields for you. The underlying wire format is unchanged; only the command-line surface is typed.

logonse destroy #

Destroys a session — but only an empty one, with no tokens still referencing it.

$ logonse destroy 4711

A session with live tokens cannot be destroyed this way; its tokens must go first. See Session lifecycle.

Signing a session out #

logonse end #

Signs a session out: authd ends every process running in it, asking each to end and, after a few seconds, ending any that haven't. Once the last of them has gone, the kernel ends the session.

$ logonse end 1012
ended session 1012: 2 processes ended

You may end your own sessions, and anyone's that the machine's SessionEndSecurity setting allows, which as shipped is Administrators and SYSTEM. A service's session can't be ended this way: it ends when the service is stopped. Nor can the kernel's own sessions, 999 and 998. A refusal says which of these it is. See Ending a session.

FlagMeaning
--checkOnly ask whether you may end it, and end nothing.

If authd couldn't end every process, logonse end says how many still hold the session and exits with status 1.

A process's PSB #

logonse psb #

With only --pid, logonse psb shows a process's Process Security Block: whether it is protected by PIP (Process Integrity Protection, which shields signed system processes from everyone else), which mitigations are on, and the process's GUID, which events carry.

$ logonse psb --pid 1
psb pid=1
  pip:         protected, Peios TCB
  mitigations: none
  guid:        3f2c9a1e-6b0d-4c8e-9a41-2d7e5f10b6c3

Anyone the process's descriptor lets query it may read this, which by default is everyone — even for a protected process whose everything else is closed to you.

With --mitigations, it requests those mitigation flags instead of showing the PSB. Read the current state with only --pid before considering a change, and use the application and lifecycle guidance to review the required policy and activation limits.

A request is one-way, activation-backed and all-or-nothing. An authorised caller can still be refused because the target's existing state or platform cannot satisfy a protection. The Kernel TRM documents CFIF as unavailable and CFIB activation as self-only, so a mask containing those flags is not a general-purpose way to harden another process. Do not use ALL as a blanket policy. Check the command's result, then inspect the committed state again; a requested mask alone is not proof of protection.

FlagMeaning
--pid PIDThe process to act on.
--mitigations MASKThe mitigation bitmask to request, in hexadecimal or decimal. Without it, the PSB is shown.

This subcommand is about process hardening rather than logon sessions — it lives in logonse because both deal with low-level per-process kernel state. For what the mitigation flags mean and how they behave, see Process mitigations.

Output options #

FlagEffect
--jsonEmit JSON instead of human-readable output. Accepted by every subcommand.

Exit status #

CodeMeaning
0The operation succeeded.
1A usage error, or the operation failed.

Peios Learn — documentation for the Peios project.

Built with Trail.