Usage Guide

PySnap exposes a single command line entry point named pysnap.

Help

Running the command without arguments, or with --help, lists the commands in groups with a one-line summary each. Every command has its own help with a description, its arguments and options, and examples:

pysnap --help
pysnap clone --help
pysnap report --help
pysnap report check --help

Open Bundled Documentation

The docs command opens the compiled HTML documentation that is bundled inside the installed PySnap package.

By default, PySnap tries to launch firefox. When it is not available, pass an explicit browser executable through --browser.

pysnap docs
pysnap docs --browser /usr/bin/chromium

List Virtual Machines

The list command prints all detected VirtualBox groups and the names of the virtual machines inside each group.

When the VirtualBox data directories are missing or the VBoxManage service does not respond, for example right after pysnap full-clean, the list command prints No virtual machines found. and exits cleanly. PySnap runs the underlying VBoxManage list calls with a bounded timeout, so a stale VBoxSVC process cannot block the listing forever.

pysnap list

Run an Integration Test

PySnap can run a real end-to-end VirtualBox integration scenario directly from the command line:

pysnap --integration-test image.ova

The integration scenario:

  • imports the appliance as a temporary base VM

  • creates three linked clones

  • connects clone A and B with intnet

  • connects clone B and C with deepnet

  • connects clone C and A with virtnet

  • attaches a serial terminal probe to clone A

  • starts clone B in headless mode without attaching to it

  • captures monitor output and verifies that clone A is Working while clone B is Active

  • prints details for the base VM and all three clones

  • removes the four VMs one by one

Register Proto Settings for a Base VM

The protosettings command registers one base VM in the persistent proto-settings list stored at Path.home() / ".ptotosettings". The file contains one VM name per line and is used as a set without duplicates.

This option exists for the image conventions used in the educational program of CMC MSU. When a base VM is present in the proto-settings list, every linked clone created from it receives additional DMI values:

  • DmiSystemVendor = <CloneVM>

  • DmiSystemSKU = port<Port>[.<net1-name>[.<net2-name>[.<net3-name>]]]

This behavior is relevant for the following CMC MSU courses:

pysnap protosettings BaseVM

Registered base VMs and their clones are also known to have their console on COM1, so PySnap reaches them through the serial console; every other VM is reached through ssh (see Access to the Guest).

Access to the Guest

PySnap reaches the guest of a VM in one of two ways:

  • COM1 serial console for base VMs registered with pysnap protosettings and their clones: UART1 is a TCP server on the host

  • ssh for every other VM: a rule named pysnap-ssh on the NAT adapter forwards a host port on 127.0.0.1 to port 22 of the guest

The choice can be overridden per VM with pysnap set VM access=com|ssh and returned to the automatic choice with access=auto. Clones inherit an explicit choice of their base VM. ssh connections use the guest user root unless pysnap set VM ssh-user=NAME names another one; clones inherit it. pysnap show prints the access of a VM and pysnap monitor shows ssh:PORT instead of the serial port for ssh VMs.

pysnap show first
...
Access: ssh root@127.0.0.1:2400 (default)

pysnap set first access=com
pysnap set first access=auto ssh-user=student

Install the ssh Key

ssh connections of PySnap use only key login. PySnap keeps its own key pair in ~/.pysnap/ssh (pysnap_vm_access_ed25519, created once without a passphrase) and one known_hosts file per VM in ~/.pysnap/ssh/known_hosts.d/<VM UUID>: the first host key of a VM is accepted, a different key later is refused. ~/.ssh is never read or changed, and existing files are never overwritten. PySnap runs the system OpenSSH client ssh, which is part of Linux distributions, macOS and Windows 10 and newer.

pysnap ssh-key installs the key in a running guest:

pysnap ssh-key first --user student
student@127.0.0.1's password:
PySnap: the key is installed for student.
PySnap: enter the root password to install the key for root too (press Enter to skip).
Password:
PySnap: the key is installed for root.
PySnap key works for: student, root
  • ssh logs in with the password of the given user (by default the ssh user of the VM) in the current terminal and adds the key for that user

  • then the guest asks for the root password through su; with it the key is added for root as well, an empty or wrong password skips root

  • many systems refuse a root password over ssh, so the login usually uses an ordinary user with --user

  • when the ssh user of the VM cannot use the key afterwards but the login user can, the ssh user of the VM is switched to the login user

  • with --console the command that adds the key is typed on the VM screen through VirtualBox keyboard input instead, for a shell that is already logged in there; the guest needs a Latin keyboard layout

Import an Appliance

Import either an .ova or .ovf appliance.

If the appliance already defines a group, PySnap keeps it. Otherwise, the virtual machine is placed into the /Others group.

When the appliance contains exactly one VM, an optional VMName argument can override the imported VM name.

Before running VBoxManage import, PySnap checks the final VM name. If the name already exists, the import is aborted before creating anything. For the default one-VM case, PySnap recommends using the optional VMName argument to choose a different target name.

During the import, PySnap renders a live progress bar based on the percentage output reported by VBoxManage import.

pysnap import image.ova
pysnap import image.ovf
pysnap import image.ova RenamedVM

Show Virtual Machine Details

The show command prints the VM name, the assigned group, and the serial TCP port configured through UART1.

pysnap show MyVM

Plug a Virtual Machine for PySnap Connections

The plug command prepares an existing VM for pysnap connect. For a VM reached through ssh it adds the pysnap-ssh forwarding rule on the first NAT adapter with a free host port; this works on stopped, running and paused VMs, and a VM without a NAT adapter is refused with a hint to run pysnap set VM nic1=nat. For a VM reached through the COM1 console it configures UART1 as a tcpserver endpoint when this can be done safely.

For the COM1 console PySnap checks these conditions:

  • the VM exists

  • if UART1 is already configured as tcpserver,<port>, the VM is left unchanged

  • if UART1 is already bound to another backend, PySnap refuses to overwrite it

  • if a reconfiguration is needed, the VM must be in a stopped state

  • the selected TCP port must be free in both VirtualBox and the host OS

When all checks pass, PySnap assigns the same kind of serial TCP port used by the imported protocols-* images, so the VM becomes connectable through the built-in terminal interface.

pysnap plug MyVM
pysnap connect MyVM

Graphviz example diagrams are rendered automatically when the dot executable is available on the documentation build host.

Set Serial Ports and Network Adapters

The set command shows or changes the serial (COM) ports and the network adapters of a VM. Each option is KEY=VALUE; N is any number the VM offers: VirtualBox has COM1-COM4 and, depending on the chipset of the VM, NIC1-NIC8 (PIIX3) or NIC1-NIC36 (ICH9). The output lists NIC1-NIC4 and further adapters up to the last one in use.

  • comN=auto: a TCP server on a free port (an existing TCP server keeps its port); comN=PORT uses the given port

  • comN=server:NAME and comN=client:NAME: a host pipe between two VMs, created by the VM with server and joined by the VM with client

  • comN=off: no serial port

  • nicN=NETWORK: the internal network NETWORK

  • nicN=nat: NAT; nicN=off: no network adapter

  • access=com|ssh|auto and ssh-user=NAME: how PySnap reaches the guest (see Access to the Guest); these two work on a VM in any state

pysnap set first  nic2=left nic3=right com2=server:link
pysnap set second nic2=left com2=client:link
pysnap set first
first (poweroff)
  COM1  TCP server, port 2326
  COM2  pipe server, creates "link" (/tmp/pysnap-link)
  COM3  off
  COM4  off
  NIC1  NAT
  NIC2  internal network "left"
  NIC3  internal network "right"
  NIC4  off

Without options the current settings are printed. Changes require a stopped VM; all options are checked first and then applied together, so an invalid option changes nothing. PySnap checks that a TCP port is not used by another VM, by another COM port of the same VM or on the host. Removing a TCP server prints a warning; pysnap connect uses COM1 and cannot reach a VM without it.

A pipe name is short; PySnap turns it into the path format of the host (\\.\pipe\pysnap-NAME on Windows, a pysnap-NAME socket in the temporary directory elsewhere), so the same name connects two VMs on any platform.

For clones of proto-settings base VMs, the DMI system SKU is rebuilt from the new COM1 port and the internal networks of NIC2-NIC4, for example port2326.left.right. An adapter without an internal network leaves an empty place (port2326..right). When COM1 is no TCP server, the highest TCP port of the other COM ports is used; without any TCP port the port part of the previous SKU is kept.

Connect to a Headless Virtual Machine

The connect command ensures that the selected VM is running in headless mode and then attaches a built-in PySnap terminal interface to the guest: to its UART1 TCP console, or to an ssh login shell for VMs reached through ssh (see Access to the Guest).

For VMs that do not already expose a suitable UART1 tcpserver endpoint or a forwarded ssh port, run pysnap plug <VM> first.

Over ssh, connect logs in with the PySnap key as the ssh user of the VM:

  • while the guest is still booting and no ssh server answers yet, PySnap waits up to three minutes and says so once; Ctrl-C stops waiting

  • when the guest refuses the key, PySnap installs it right away in the same way as pysnap ssh-key (password of the user, then optionally of root) and then logs in with the key

  • the status line shows ssh:PORT instead of UART1:PORT, no waking newline is sent because the login shell prints its own prompt, and the session ends when the login shell exits (exit or Ctrl-D)

  • a paused VM is refused with a hint to run pysnap resume, because a paused guest cannot answer the login

  • one connect session per VM is allowed, as on the serial console

All keys go to the guest, so editors and shells get Esc, Ctrl-L, Ctrl-Q, Alt combinations and function keys as in a regular terminal. PySnap commands start with Ctrl-], which guest programs hardly use, as in telnet; the status line then lists the command keys:

  • q detaches the session; detaching does not stop the virtual machine

  • Up and Down scroll the local scrollback buffer by one line, PgUp and PgDn by one screen, Home jumps to the oldest retained output and End back to the live output; the command keys stay active for further scrolling

  • v pastes the text of the host clipboard (see below)

  • Ctrl-] sends Ctrl-] itself to the guest

  • Esc or any other key leaves the command keys without sending anything

  • on Linux, the mouse wheel or touchpad scroll gesture moves the local scrollback buffer by three lines while the command keys are active

Outside the command keys the mouse belongs to your terminal: select, copy and paste text the way your terminal does it for every program, for example by dragging and Ctrl-Shift-C/Ctrl-Shift-V or the middle button on Linux, Ctrl-C/Ctrl-V or the right button in Windows Terminal, the right button in the Windows console and Cmd-C/Cmd-V on macOS. Text in the local scrollback can be selected after scrolling to it with the command keys. Ctrl-C always goes to the guest as an interrupt.

A pasted text reaches the guest the way a terminal sends it: line breaks of any system become the Enter key (CR), so a text copied on Windows gives no empty lines, and when the guest asked for bracketed paste, as bash and vim do, the text is marked as a paste; bash then waits for Enter instead of running each pasted line, and vim does not indent it again. Ctrl-] v pastes the host clipboard in the same way for terminals without a paste key, for example the Windows console without its Ctrl key shortcuts, where Ctrl-V reaches the guest as ^V. The clipboard is read only then: on Windows through the system API, on macOS with pbpaste, elsewhere with wl-paste (Wayland), xclip or xsel; the status line tells when none is installed. Over the serial console a long paste can lose characters, because the console has no flow control.

Full-screen programs such as vim, nano and less use the alternate screen: while they run, the local scrollback is off, and they scroll with their own keys; when they exit, the shell screen comes back as it was, and their screens never enter the scrollback.

While the session is attached, PySnap continuously tracks the outer terminal size and resizes the visible guest text area to match it. This also works after reconnecting to an already running VM.

For xterm-compatible guest-side tools, PySnap replies to standard size queries such as CSI 18 t and cursor-position reports such as CSI 6 n. On Linux guests this makes terminal-size refresh workflows such as resize much more practical over the raw serial console.

On macOS, PySnap also checks the standard VirtualBox application-bundle path for VBoxManage when the command is not exported in PATH.

pysnap connect MyVM

A paused VM can be attached through UART1 too: the status line shows Paused, keys are held back and nothing is sent to the guest until pysnap resume; the Ctrl-] commands keep working. Then the keys work again, and when the guest has not printed anything yet PySnap sends the usual waking newline. When a VM is paused during a session, the session stays open in the same way, so Ctrl-] q on a paused VM and a new connect lead to the same state. If the paused VM does not accept the serial connection within three seconds, connect fails with a hint to run pysnap resume.

Monitor Active Virtual Machines

The monitor command prints compact runtime records in the form <VM> (state: <State> ; <serial port> ; <group>).

PySnap currently uses these runtime labels:

  • Working when the VM is running and PySnap has an active attached session

  • Active when the VM is running in headless mode without an attached session

  • Stopping when the VM is shutting down gracefully

  • Changing when the VM is starting or otherwise transitioning

  • Paused when VirtualBox reports a paused machine

  • Error when VirtualBox reports an error-like runtime state

pysnap monitor
srv (state: Working ; 2345 ; /Lab)
db (state: Active ; 2346 ; /Lab)
router (state: Stopping ; 2347 ; /Net)

Stop Running Virtual Machines

PySnap stops headless virtual machines through VBoxManage controlvm <VM> acpipowerbutton only. No automatic fallback to savestate or other shutdown modes is used.

When a VM stops, any active pysnap connect session attached to it finishes automatically because the VM state changes and the serial connection is closed.

A paused guest cannot handle the ACPI power button, so stop resumes a paused VM first; stop --all also stops paused VMs.

pysnap stop MyVM
pysnap stop --all

Pause and Resume Virtual Machines

pause freezes a running VM through VBoxManage controlvm <VM> pause; it stays in memory and shows up as Paused in pysnap monitor. resume continues it. With --all the commands act on every running or every paused VM. This is not savestate: nothing is written to disk and the VM does not stop.

pysnap pause MyVM
pysnap resume MyVM
pysnap pause --all
pysnap resume --all

Create a Linked Clone

The clone command creates a linked clone from a base VM. The clone inherits the base VM group.

When -p is provided, its value is used as the host TCP port for modifyvm <VM> --uart1 0x3F8 4 --uartmode1 tcpserver <port>.

When -p is omitted, PySnap scans existing VMs, finds the maximum already used serial TCP port, and assigns the next value. If no serial TCP ports are configured yet, the automatic sequence starts at 1024.

Up to three extra positional arguments configure internal networks:

  • nic1 stays in nat mode, the requested networks are mapped onto nic2 through nic4, and omitted adapters are left enabled. This layout is used for clones of proto-settings base VMs and for every clone reached through ssh, whose ssh port is forwarded on nic1

  • only a clone of a base VM set to access=com without protosettings keeps the legacy layout: networks are mapped sequentially onto nic1 through nic3, and omitted adapters are set to none

A clone copies the settings of its base VM, including its pysnap-ssh rule; PySnap removes that copy, because its host port belongs to the base VM, and a clone reached through ssh gets its own free port.

If the base VM was previously registered through pysnap protosettings, PySnap also applies educational DMI settings to the clone.

pysnap clone BaseVM CloneVM -p 2345 intnet1 intnet2 intnet3
pysnap clone BaseVM CloneVM intnet1

Erase Virtual Machines

PySnap supports three erase modes:

  • pysnap erase VM removes a single VM when no dependent linked clones exist.

  • pysnap erase --group GROUP removes all VMs inside one group.

  • pysnap erase --all removes all registered VirtualBox VMs.

The single-VM erase mode refuses deletion when dependent clones still exist. The group erase mode refuses deletion when descendants outside the target group still depend on the selected VMs.

Every erase mode accepts the --clones-only flag, which restricts the operation to VMs created as PySnap linked clones:

  • pysnap erase --all --clones-only removes every linked clone and keeps the imported base VMs registered.

  • pysnap erase --group GROUP --clones-only removes only the linked clones inside one group. The operation is refused when clones outside the group still depend on the selected clones.

  • pysnap erase VM --clones-only behaves like the normal single-VM erase for a clone. For a base VM, PySnap prints a warning and refuses the deletion, so the flag stays safe in scripted cleanups.

PySnap recognizes clones through the pysnap/kind and pysnap/parent metadata written into VirtualBox extra data during cloning, so the clone list stays correct without a separate registry file.

When a VM is removed successfully, PySnap also removes its name from the proto-settings file if it was registered there.

pysnap erase BaseVM
pysnap erase --group /Lab
pysnap erase --all
pysnap erase --all --clones-only
pysnap erase --group /Lab --clones-only
pysnap erase CloneVM --clones-only

Remove All VirtualBox Data

The full-clean command permanently deletes the VirtualBox machine folder and the VirtualBox configuration directory from the host file system. Stop VirtualBox and all virtual machines before running it.

Without --path, PySnap removes ~/VirtualBox VMs together with the OS-specific configuration directory:

  • ~/.config/VirtualBox on Linux and other Unix systems

  • ~/Library/VirtualBox on macOS

  • ~/.VirtualBox on Windows

  • the directory from VBOX_USER_HOME when the variable is set

The repeated --path option replaces the default selection with explicit directories. This covers custom machine-folder locations configured through VBoxManage setproperty machinefolder.

The command prints the target directories, marks missing ones, and asks for two different explicit confirmations: yes on the first prompt and delete on the second one. Any other answer cancels the cleanup without touching the file system. Directories are removed recursively through shutil.rmtree, so the same behavior applies on every supported operating system.

pysnap full-clean
pysnap full-clean --path /data/vms --path /data/vbox-config

Read Session Reports

Students record their work inside the educational VMs with the report utility, which produces a report.<NN>.<host> archive. The pysnap report command reads such archives safely: nothing is extracted to disk and nothing from the report is sent to the terminal as a raw control sequence.

The text subcommand prints the text of the session without timing, as the student saw it. The prompt installed by report is highlighted and the entered commands are shown in bold; colors produced inside the VM are kept. Colors are used only when the output is a terminal; --color always or --color never overrides the detection, and the NO_COLOR environment variable disables colors.

The --commands option prints only the numbered list of entered commands with the time since the start of the recording. Commands typed at the prompt of another program, for example inside vtysh, are marked with that prompt. Line editing, history recall and interrupted commands are resolved, so the list shows what was actually executed.

Problems found in the report, such as a truncated recording, are printed as warnings to the error stream; the available text is still shown.

When the output is a terminal and the text is longer than the screen, text opens a pager. Like less -S, the pager keeps the recorded line layout: lines longer than the window are cut at its edge, and > or < in the edge column marks text hidden to the right or left.

  • Up/Down or k/j scroll by a line

  • PageUp/PageDown, b and Space scroll by a page

  • g/Home and G/End jump to the start or end

  • Left/Right shift the view by half the window width

  • the mouse wheel scrolls on Linux

  • q or Ctrl-Q quits

--no-pager prints the text directly.

pysnap report text report.01.first
pysnap report text report.01.first --commands
1  00:17.05  ip a show eth1
2  00:29.86  ping -c5 10.9.0.2
pysnap report text report.01.first --color never > report.01.first.txt
pysnap report text report.01.first --no-pager

The show subcommand replays the session with its timing in a safe terminal view of the recorded size. Pauses longer than --max-delay seconds (1 by default, 0 keeps the real pauses) are shortened, like scriptreplay -m, and --speed selects the initial speed. When the window is smaller than the recorded screen, the view is clipped around the cursor and the status line reports the recorded size.

  • Space pauses and resumes playback; resuming at the end starts over

  • + and - change the speed between x0.25 and x16

  • n and p jump to the start of the next or previous command

  • Home and End jump to the start or the end of the recording

  • while paused, Alt-Up/Alt-Down and the mouse wheel on Linux scroll the screen history

  • q or Ctrl-Q quits

Characters that would be invisible, such as zero-width spaces or bidirectional overrides, are shown as ? in text and show.

pysnap report show report.01.first
pysnap report show report.01.first --speed 4 --max-delay 0.5

The check subcommand prints a report information block. Without a check file it shows only this block:

  • Identity: task and host from the report.<NN>.<host> file name and from the prompts recorded by report; a warning is printed when they differ or when the prompts show several hosts

  • Timing: start, end, duration and the exit code of the recorded shell

  • Environment: terminal device, type and size, CPU model and hypervisor from CPU.txt

  • Commands: the number of commands and unique commands, commands interrupted with Ctrl-C, recalled from history (Up, Down, Ctrl-R) or typed at the prompt of another program, and the pause before each command, measured from the last output to the first key

  • Typing: keys per second from the first key of a command to Enter, the share of Backspace keys and input chunks that look pasted (five or more printable characters at once, or a bracketed-paste marker)

  • Addresses in output: IPv4 and MAC addresses shown by the commands, without the broadcast and all-zero MAC addresses

  • Integrity: problems found while reading the report and a comparison of the archive member times with the recording start (CPU.txt) and end (the other members) within two seconds

pysnap report check report.01.first
pysnap report check report.01.first lab02-first.check.toml

Check Files

With a check file, check also checks the expected commands and output blocks and grades the report. A check file is written in TOML, usually with the .check.toml extension, one file per host of a lab:

[report]              # optional expectations, reported as warnings
task = 1
host = "first"

[[command]]
id = "addr"           # optional name used by "of" and "after"
cmd = "ip a show <ETH-A>"

[[command]]
id = "ping"
cmd = "ping -c5 <IP-B>"

[[output]]
of = "addr"           # search only in the output of that command
text = '''
<*>: <ETH-A>: <*>UP<*>
...
    inet <IP-A>/<MASK> scope global <ETH-A>
'''

[[output]]
of = "ping"
min_count = 5         # the block must occur at least five times
text = "64 bytes from <IP-B>: icmp_seq=<*> ttl=64 time=<*>"

[grading]
total = 10
scale = [[90, "5"], [75, "4"], [50, "3"], [0, "2"]]

[[command]] items are compared with the entered commands as a whole. Keys:

  • cmd (required): the command pattern

  • id: a name for of and after references

  • after: the id of an earlier command; the item passes only when its command was entered after that command. If that command did not pass, this item fails too.

  • points: the weight of the item, 1 by default

[[output]] items are blocks of output lines. Keys:

  • text (required): the block; a line holding only ... matches any number of lines, otherwise the lines must follow each other

  • of: the id of a command; the block is searched only in the output of the runs of that command, otherwise in the whole report

  • order = "any": the lines may appear in any order, which suits tables such as ip route; ... is not allowed then

  • min_count: how many times the block must occur, 1 by default, for example for ping replies

  • points: the weight of the item, 1 by default

Patterns may contain placeholders:

  • <IP>, <ETH> and <MASK> match any IPv4 address, ethN interface or prefix length from 0 to 32

  • a label such as <IP-A>, <ETH-A> or <MASK-A> remembers the first matched value; every later use of the same label, in commands and in output blocks, must show the same value

  • any other name, such as <X>, matches one word and also remembers it

  • <*> matches any text inside a line and remembers nothing; use it for values that change, such as ping times or sequence numbers

  • \< writes a literal <; text like < /dev/ttyS1 needs no escaping

Spaces never matter: both the report lines and the patterns are trimmed and every run of spaces or tabs counts as one space, so aligned table columns match patterns written with single spaces.

Commands are checked in file order, then output blocks. PySnap chooses among several possible matches, for example several ping runs, so that as many items as possible pass; with equal results it prefers the earliest match. An item that fails does not make later items fail through wrong label values.

[grading] is required. Every item contributes its weight; the percentage of the passed weight is scaled to total points, and the mark is the first scale step whose threshold in percent is reached. Thresholds are listed from the highest to the lowest.

The output lists every item as PASS or FAIL. A passed command shows the entered command it matched; a passed block shows where it was found; a failed item shows the reason and, for commands, the closest entered command. The values of all labels, the number of passed items, the points, the percentage and the mark follow. When the [report] task or host differs from the report file name or prompts, a warning is printed and the grade is not changed.

Extract a Report from a Running VM

The extract subcommand copies a report from a running VM to the host. A VM reached through ssh (see Access to the Guest) is read through a separate ssh session; every other VM through the same UART1 serial console that pysnap connect uses, so no second COM port and no VM restart are needed.

pysnap report extract first report.01.first
Extracted "$HOME"/report.01.first from first to /home/user/report.01.first (2621 bytes, sha256 ...).
pysnap report extract first /tmp/report.03.pc1 --output reports/pc1 --force

Over ssh:

  • the VM is running, has a forwarded ssh port (see pysnap plug) and the PySnap key is installed for its ssh user (see pysnap ssh-key); unlike connect, extract never asks for a password

  • one command prints the sha256sum of the file and the file itself; PySnap verifies the checksum and writes the file as described below

  • the student’s terminal is not touched: nothing is typed into it, so the command works the same with or without an attached pysnap connect and needs no shell prompt there. A report that is still being recorded is copied as it is at that moment

  • a name without / becomes "$HOME"/NAME and the guest shell of the ssh user expands $HOME: the name is looked up in the home directory of the ssh user of the VM (pysnap set VM ssh-user=NAME, root by default) and nowhere else. A path with / is used as given; a relative path starts in that home directory too. With the default user, report.01.first means /root/report.01.first; with ssh-user=student it means /home/student/report.01.first. A report recorded by another user needs its full path, for example pysnap report extract first /home/student/report.01.first, and the ssh user must be allowed to read it

  • the transfer fails when it takes more than two minutes

On the serial console:

  • the VM is running and has a UART1 TCP port (see pysnap plug)

  • the command also works while pysnap connect is attached to the VM: VirtualBox serves one client, so extract asks the attached session to run the transfer on its connection. The terminal shows a message in the status line, keys are paused until the transfer ends, and afterwards the screen is cleared and a fresh prompt appears. Sessions started by an older PySnap cannot do this; detach them with Ctrl-] q first

  • the console is logged in and at a shell prompt; PySnap checks this with echo PYSNAP_$((20+22)) and stops when the answer does not arrive

  • no report recording is running: PySnap presses Ctrl-U and Enter once, and when the recording prompt appears it stops before sending any command, so nothing else ends up in the student’s report

  • a name without / is looked up in the home directory ($HOME) of the shell running on the console, that is of the user logged in there; a path with / is used as given, and a relative one starts in the current directory of that shell

  • the file is sent as base64 together with its sha256sum; PySnap verifies the checksum, writes the file under the same name into the current directory or to --output, and never replaces an existing file without --force

  • the service commands start with a space, so shells with HISTCONTROL set to ignorespace keep them out of the history, and the guest screen is cleared afterwards

  • after the copy PySnap reads the file as a report and warns when it is not one

A serial console typically runs at 115200 baud, about 11 KB/s: a report of a few kilobytes takes well under a second. The transfer fails only when no data arrives for ten seconds.

Compare Reports

The compare subcommand compares every pair of the given reports and lists signs that two reports share their origin. Paths may be report files or directories; directories are searched recursively for files named report.NN.HOST, and a file reached twice is compared once. PySnap does not know which reports belong to the same student: reports of one student legitimately share values such as the MAC address of the same VM, so the teacher decides which pairs matter.

pysnap report compare reports/
SIGNALS  reports/ivanov/report.01.first  <->  reports/petrov/report.01.first
  strong  S3  same MAC address: 08:00:27:a9:84:3a
  medium  M3  identical CPU.txt
OK       reports/ivanov/report.01.first  <->  reports/sidorov/report.01.first
OK       reports/petrov/report.01.first  <->  reports/sidorov/report.01.first

Compared 3 reports, 3 pairs: 1 with signals (strongest: 1 strong, 0 medium, 0 weak), 2 OK.

Pairs with signals come first, strongest first, and show only the signals found; other pairs take one OK line.

Code

Level

Signal

S1

strong

identical report files; the other signals are then not listed

S2

strong

identical recorded output

S3

strong

the same MAC address in both outputs (all-zero, broadcast and multicast addresses are ignored)

S4

strong

the same START_TIME (to the second) and DURATION (to the microsecond)

M1

medium

at least 20 identical consecutive keyboard delays, to the microsecond, which points at a copied timing log

M2

medium

at least three consecutive ping times (time=... ms) in the same order, or at least three shared tcpdump timestamps with microseconds; single ping times match by chance too often, since ping prints only three significant digits

M3

medium

byte-identical CPU.txt, including the BogoMIPS value measured at boot

M4

medium

at least two shared commands whose output says command not found or No such file

W1

weak

the same CPU model (not shown when CPU.txt is identical)

Unreadable paths are reported as warnings and skipped. The exit code is 0 when at least one report was read and 1 otherwise.