nos_
ENRU
All documentation

Tools

Shell commands

docs/shell-commands.mdView on GitHub

The interactive shell runs on the serial console and the screen, and every command also works over the UDP remote shell. Trace output is suppressed while the shell is active (it still lands in dmesg).

Command Description
cls Clear screen
cpu Dump CPU state
lscpu Identify the CPU and report the features the kernel depends on (1 GiB pages, NX, PAT, invariant TSC, ARAT), the performance counters it has (Intel architectural perfmon, or AMD core counters and PerfMonV2), and which of them profile will actually sample with
dmesg [lines] [filter] Dump kernel log: newest lines messages (all of it if omitted), optional substring filter
loglevel [N] Show or set the trace level (0-5) on a running kernel
uptime Show uptime
date Show wall clock date and time (RTC + boot time)
igbdump The igb chip's own state: MAC command/status registers, ring head and tail, receive statistics; the interrupt layout (INTx, one MSI-X vector, or a queue vector and another) with each vector's count, the throttle and the receive rate it follows, and how often under load the poll looked at an empty ring again rather than arm the interrupt, with the time that cost; and the PHY's view of the link — what it advertised, what the partner offered, both 1000BASE-T registers. What made the I210's 10 Mb/s latch diagnosable
nicdump The r8125's own state: command register (is the receiver still enabled?), interrupt status and mask, and whose the head receive descriptor is. For a machine that has stopped receiving and can still be typed at
stacks Stack high-water marks: every stack is filled with a pattern when it is created, and what is still intact is what it never reached. Catches a spike that lasted microseconds during boot, and costs nothing while the machine runs
ps Show tasks
top [ms] Per-task CPU use over a sampling window, percent per CPU (a busy thread reads 100%, a 20-CPU box tops out at 2000%), plus the number of tasks moved between CPU queues since boot, and of reschedules deferred because the task they landed on had preemption off, in the window and since boot -- how many of those on an idle task
profile [ms] [pid|all] [chains] Sampling profiler: where the kernel spends its time, as whole call chains -- samples are folded by their entire stack, not by the leaf symbol, and the hottest chains are printed in full. chains caps how many, for a console with no scrollback -- profile 2000 all 3 fits a screen where the default does not. Every frame carries its offset: the leaf as the instruction the sample landed on (a span when they spread across the body, so a hot spinlock says whether it sat on the exchange or in the pause loop), each caller as the return address that names which call site led there. Samples on a performance counter overflowing into an NMI (~1 kHz, and catches code running with interrupts off) where the CPU has one -- Intel's architectural fixed counter 1, or AMD's PMCx076 on family 15h and later, both counting unhalted core cycles; falls back to the 100 Hz per-CPU tick where it does not, which includes any machine whose hypervisor answers CPUID for a PMU it declines to virtualise (the counter is asked to prove it counts before the profiler trusts it). The report names which
bt <pid> Dump stack trace of a task (uses IPI for remote CPUs)
watchdog Watchdog stats: locks watched, table walks, and the slice of the bucket table each CPU walks (the table is divided among the CPUs, so a bucket is visited once per tick rather than once per tick per CPU)
memusage Show memory usage
meminfo Show the firmware memory map, and how much of it the kernel actually uses
memcheck Verify no reserved, kernel-image or absent page reached the free list
pci Show PCI devices
disks List block devices
diskread <disk> <sector> Read and hex-dump a sector
diskwrite <disk> <sector> <hex> Write hex data to a sector. Refused on a device a mounted filesystem, the disk log or a blkload write test holds, or on a disk or partition overlapping one (see Filesystems)
partitions <disk> Show the partition table (MBR or GPT)
disklog Kernel-log-to-disk state: off unless the kernel was booted with disklog=on; otherwise the prepared area it found (if any), boot number, sectors written, lines queued and dropped. The area is laid down under the host OS with scripts/disklog.py format and read back with scripts/disklog.py read
irqstat Show per-device interrupt counters
help List commands
net List network devices and per-protocol stats
arp Show ARP table
nat / nat allow <a.b.c.d[/n]> / nat deny <a.b.c.d[/n]> Whether NAT is on, between which devices and from which address; the first mappings, each with its protocol, the guest's side, where it goes, the external port it has and how long it has left; where the guests are kept from -- link-local (a cloud's metadata server), the private networks, the shared space, the uplink's own subnet -- and what nat allow let through of it; and what NAT has done -- packets out and back, mappings made and those made by taking the least lately used flow of the guest holding the most (a full table), and the packets it had no room, next hop or frame for, does not take, or denied. allow lets the guests reach a network the deny list keeps them from, up to 16, and deny takes that back. The hypervisor's switch turns it on for its guests. See The way out
netpool Show the recycled net frame pool: frames in the ring, in per-CPU caches, in flight
netconsole Show netconsole target, buffered bytes, drop/send counters
icmpstat Show ICMP statistics
tcpstat Show TCP connections and statistics
wget [-o <path>] <url> [path] Fetch a URL via HTTP or HTTPS GET (follows redirects, including http→https). With a path — -o and the trailing argument are the same thing — the body is streamed to that file as it arrives, up to 20 MiB, with a progress line every megabyte. Without one it is printed, and kept in memory, so it is capped at 32 KiB. HTTPS verifies the certificate chain against the built-in roots and the wall clock; see HTTPS
udpsend <ip> <port> <msg> Send a UDP packet
ping <ip|hostname> Send 5 ICMP echo requests with RTT (resolves hostnames via DNS)
nslookup <hostname> Resolve hostname to IP via DNS
dnsflush Flush DNS cache
dhcp [dev] Obtain IP address via DHCP
random [len] Get random bytes as hex string, 1..1024, default 16 — from the kernel's ChaCha20 pool, not from a device
entropy [reseed] Show the random pool (seeded, whether hardware entropy reached it, reseeds, bytes generated) and the registered entropy sources; reseed draws from every source again first. See Randomness
format nanofs <disk> Format disk with nanofs. Refused, like diskwrite, on a device in use
mount ramfs <path> Mount a ramfs at path
mount nanofs <disk> <path> Mount nanofs from disk at path
mount ext2 <disk> <path> [ro] Mount ext2 from disk at path, read-write unless ro (or unless the image carries features the driver does not write; see Filesystems)
umount <path> Unmount filesystem
mounts List mount points
ls [path] List directory contents (default /)
cp [-r] <src> <dst> Copy a file, or a whole directory tree with -r; a dst that is an existing directory takes the copy under its own name
cat <path> Show file contents
write <path> <text> Write text to file (creates if needed)
mkdir <path> Create directory
touch <path> Create empty file
rm <path> Remove file or directory (recursively); del is the same command
append <path> <text> Append text to a file (created if missing)
mv <old> <new> Rename or move a file or directory within one filesystem
stat <path> Type, size and inode number
sync Flush every mounted filesystem to disk
fstest [dir] [size] Filesystem self-test in dir (default /) with a big file of size bytes (K/M suffix; default 300 KiB, at least 8 KiB); fstest / 5M reaches the doubly-indirect blocks at 4 KiB blocks
crc32 <path> CRC-32 of a file, to check a copy against the host
sha256 <path> SHA-256 of a file, printed the way sha256sum prints it, to check a downloaded kernel against the SHA256SUMS of its release
grubenv <path> [name=value ...] Show, or set, the variables of a GRUB environment block — the grubenv file grub-editenv makes and GRUB's load_env/save_env read and write; name= with nothing after it removes one. Edited in place at the same size, the way GRUB's own writer edits it, so GRUB can still read and clear what was set; a block with a line it cannot be sure of reading as GRUB does -- no = before the line's end, a name longer than 64 characters or holding a backslash or a NUL -- is listed as far as that line and never written. What arms a one-shot boot of a downloaded kernel from inside nos: see Real hardware
insmod <path> Load a kernel module — a Rust crate built into a .ko by make modules — from a file, and run its init, in a task of its own. Says why when it refuses one: not a module, another machine's, built against another kernel interface, an import the kernel does not export, a name already loaded or still loading or unloading. A load not done in five seconds carries on in the background, the kernel log saying how it ended. See Loadable modules
rmmod <name> Unload a module in a task of its own: run its exit, which releases everything it holds, then free its code. The exit waits for a call of one of the module's commands still running; past five seconds the shell leaves it to finish in the background
blkload <dev> [randread|randwrite|read|write] [bs=4k] [qd=1] [secs=5] [force] From the blkload module, once it is loaded: a short load test on a disk or a partition — IOPS, bandwidth, latency min/avg/p50/p90/p99/p99.9/max. A write test claims the device first: refused while a mounted filesystem, the disk log or another write test holds it — or the disk it is on, or one of its partitions — and without force on a disk with partitions or a device holding a filesystem, a partition table or a disk log area. See Loadable modules
netload start [port] [sink] / netload send <ip> <port> [size=64] [pps=0] [secs=0] [count=0] [tasks=1] [sport=9998] From the netload module, once it is loaded: a UDP load test from either end, so profile has something to look at other than an idle machine. start is the target: it echoes every datagram from the receive softirq (or drops it, in sink mode; port 9999 unless told), and can be driven from a host too, with scripts/netload.py (--pps to hold a rate, --threads to raise the ceiling). send is the source: tasks senders build datagrams of size bytes of payload straight into frames off the pool and hand them to the NIC a batch at a time -- as fast as it takes them, or pps a second -- until count are sent, secs have passed or netload stop; what comes back to sport is counted as echoes and never answered. It leaves room in the transmit queue for everybody else, so the shell goes on answering under it. See Loadable modules
netload / netload stop / netload reset What the target and the source have counted -- packets, bytes, failures, rates, and which CPUs did the work; stop both; clear the counters
netblk start <disk> <port> [ro] [nic=eth0] [mtu=1500] [cpu=N] [poll=us] From the netblk module, once it is loaded: serve an NVMe disk, or a partition of one, over UDP on port (1024 and up, one instance to a port), zero-copy. Read-write claims the device the way a blkload write test does; ro takes no claim. A port someone else has is refused. poll keeps the worker spinning that long for the next request before it sleeps. See netblk
hv [info] / hv on [cpu|all] / hv off [cpu|all] / hv run <guest|all> [cpu] From the hv module, once it is loaded: the CPU's virtualization extension, and guests under it. hv says which extension the machine has and which CPUs it is on for -- asked of the CPUs themselves, by an IPI that reads the register, so a disagreement with what the module turned on is reported rather than hidden -- and how many times guests switched on a CPU, with whether an IBPB went between each two; under AMD-V whether automatic IBRS is on, and under VT-x what the CPU the command runs on does for its speculation around every entry -- enhanced or legacy IBRS, BHI_DIS_S, VERW, the L1D flush -- with a warning for any CPU whose IA32_SPEC_CTRL no longer has what hv on set there, read from each CPU's register. hv info adds everything the CPU said about it, a feature a line: nested paging, next-RIP save, ASIDs, x2APIC, 1 GiB pages, and on arm64 the exception level the kernel is at and what stage-2 would translate into. hv on and hv off turn it on and off for one CPU or every running one; rmmod turns it off for all of them. hv run runs a built-in guest (exits, uart, hypercall, fault, absent, mmio, triple, refused, spin, tpr, asid, smp, ioapic, debug, cr4, msr, dr), or all of them, each in a VM of its own on a task bound to cpu when one is named, and says what it did and whether that was what it was told (x86-64, AMD-V). See The hypervisor
hv boot <bzImage> [mem=MiB] [cpus=N] [secs=N] [cpu=N] [xapic] [ioapic] [initrd=path] [disk=path[:ro]]... [input=...] [cmdline=...] A Linux guest for secs (60 by default): the bzImage and initrd read from files into its memory, run on a vCPU -- or with cpus=N on N of them, up to 16, each on a host CPU of its own, the first on cpu (see More than one CPU); xapic has their local APICs come out of reset in xAPIC mode, reached through the page, for a kernel that reads it before it looks at the mode firmware left (see MMIO); ioapic gives a guest of more than one CPU an IO-APIC, its devices' interrupts routed through it to any CPU and its local APICs in xAPIC mode (see The IO-APIC) -- then its console and how it ended printed, the console also going to the kernel log a line at a time (`hvguest
hv start <bzImage> [mem=MiB] [cpus=N] [cpu=N] [xapic] [ioapic] [initrd=path] [disk=path[:ro]]... [input=...] [log] [restart] [net] [cmdline=...] / hv list / hv console <id> [bytes=N] / hv attach <id> / hv send <id> <text> / hv exec <id> [secs=N] <line> / hv wait <id> [secs=N] [boot=N] <text> / hv restart <id> / hv stop <id|all> [secs=N] A Linux guest that runs until it is stopped, on a vCPU task of its own bound to cpu or to the CPU with the fewest guests -- with cpus=N, a task for each of its N CPUs, each on a host CPU of its own -- and what reaches it while it runs: list says which run, on which host CPUs and on which its disks are served, how the others ended, how often each was restarted and how often a frame kicked it out of its guest, and what of its network it lost -- frames for it its inbox had no room for, frames it sent as another, frames for hv0 past its share of the backlog, broadcasts past their rate; console prints the end of one's console, escape sequences taken out; attach, from an SSH session with a terminal (ssh -t), is the console live and typed at, until ^] detaches; send types at it now, as at a terminal -- at a login prompt too, which a script's line waits for in vain -- and from then on for that boot exec's lines go in as they are typed; exec types a line and prints the answer, up to the prompt printed after the line went in (10 s by default), and waits to type it for a shell's prompt until send has typed; wait returns once the current boot's console shows text -- with boot=N, not before the VM's Nth restart, what a script waits for after typing reboot -- or it stops; a disk= with :ro is read-only to the guest, and an image one guest's disk writes is no other's -- any number of disks read one nobody writes, and a start that would break that is refused; restart boots it again from its files, running or stopped, and restart on start does that each time the guest resets itself (a reboot), at most five times a minute; stop presses its power button, gives it secs (30 by default, 0 not to ask) to turn itself off -- a guest with ACPI shuts down when it is pressed -- then stops it and prints how it ended; one that does not listen to the button is stopped at once. log also sends its console to the kernel log (`hvvm<id>
hv bench [cpu=N] [exits=N] [pages=N] [flush] [profile] [mmio] What a VM exit costs: a guest of nothing but CPUIDs, each after a read of pages pages, on a task bound to cpu (the extension's last CPU by default), timed -- flush flushes the whole TLB on every entry, as before ASIDs, profile splits an entry into its parts, and mmio times MMIO loads instead, each a nested fault whose instruction is fetched, decoded and performed (x86-64), with profile the access's own share of the time as well. See What an exit costs
hv cores [own|shared] Whether a guest's cores are its own -- whole cores no other guest has a CPU on, its vCPUs or the task serving its disks, its vCPUs filling their threads, and a guest that would need another's core refused -- or may be shared, as before (own, the default, at every load); and which guest holds which CPUs. Guests running keep where they are (x86-64). See The hypervisor
hv forward [add <port> <vm> <guest-port> | del <port>] A port of nos's relayed to a port of a net guest's -- how a guest's server is reached from outside. hv forward alone lists them, with the connections each has carried (x86-64, AMD-V). The other way, a net guest reaches what nos reaches through NAT, and the switch answers its DHCP: hv list says which address the guests go out from and counts the DHCP answers. See A network
hv help Every hv subcommand, a line each
netblk list / netblk stop <port>|all The instances served and their counters; stop one, or all -- waiting for what the disk still has in flight
lsmod List the modules: name, size, load address, how many kernel functions each binds to, and which are permanent, still loading or still unloading. Never waits on a load or unload in progress
rc [add <line>|del <n>|clear|run] Show or edit /etc/rc: shell commands, a line each (blank lines and # comments skipped), that the shell's task runs once at boot after DHCP -- how a module such as sshd gets loaded and started on a machine nobody can reach until it is. rc numbers the lines, add appends one, del takes one out, clear removes the file, run runs it now. What it prints at boot goes to the kernel log and the screen; rc=off skips it
usb Show xHCI controllers, connected root ports and keyboard report counters
panic [type] Trigger kernel panic (direct, pagefault, divzero, ud)
version Show kernel version
poweroff / shutdown Power off (ACPI S5)
reboot Reset system (keyboard controller)