Add uname, /uname and scp (key or masked password) in the Shell
CI / build (pull_request) Failing after 1m59s
Site / build (pull_request) Successful in 9s

- uname in the console and /uname in IRC: the firmware, its version and the chip
- scp: one file between the card and a trusted server, over SSH, with the
  device's key or a password asked (masked) in the Shell
- shared libssh helpers in src/platform/libssh_util
- README, user guide, command reference and a how-to updated

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0162FokPdvY2KsS4NBfwyWPk
This commit is contained in:
2026-10-09 19:01:36 +02:00
co-authored by Claude Sonnet 5.5
parent e707a5f2d4
commit 18285c3212
25 changed files with 730 additions and 34 deletions
+5 -1
View File
@@ -42,6 +42,8 @@ Irc | Wifi | Gnss | Gemini | Lora | Storage | Notes | Shell | System | Settings
ping <host> [count] [size] | nslookup <name> [server] | port <host> <port> | traceroute <host> | cancel is it there, does its name resolve, is its port open, which way; one at a time
tls <host> [port] | ntp [server] a TLS handshake: who the certificate is for, by whom, until when, and whether this device trusts it; a time server's clock against this one
ifconfig | arp | netstat the interfaces (Wi-Fi and the VPN), their addresses, the default route and the DNS servers; the neighbours heard; what listens and what is connected
uname the firmware, its version and the chip it is built for
scp [-f] [-P port] <file on the card> user@host:path | scp [-f] [-P port] user@host:path <file on the card> one file over SSH, with this device's key or, in the Shell, a password, to a server the SSH App already trusts; -f replaces a file on the card; `cancel` stops it
ssh user@host[:port] | ssh status | ssh stop a terminal on another machine, in the SSH App; the password is asked there, never here
vpn status | vpn up [seconds] | vpn down | vpn import [path] | vpn forget | vpn auto on|off the WireGuard tunnel (Settings > VPN); import reads /vpn/wg0.conf; with seconds, it goes down by itself
debug status | debug off [seconds] the Debug Console over Wi-Fi (Settings > Debug Console); with seconds, it comes back
@@ -58,7 +60,7 @@ get <path> | put <path> <size> <sha256> | screenshot (Debug Console only) bina
quit close the Debug Console connection
```
In **Safe Mode** (see [Crashes and Safe Mode](/dev/debug/crashes/)) only a few run: `help`, `info`, `tasks`, `net`, `reboot`, `boot other`, `wifi status`, and anything starting with `log level`, `crash`, `coredump`, `wifi add`, `debug`. Anything else answers `not available in Safe Mode`.
In **Safe Mode** (see [Crashes and Safe Mode](/dev/debug/crashes/)) only a few run: `help`, `uname`, `info`, `tasks`, `net`, `reboot`, `boot other`, `wifi status`, and anything starting with `log level`, `crash`, `coredump`, `wifi add`, `debug`. Anything else answers `not available in Safe Mode`.
## What they do
@@ -118,6 +120,8 @@ In **Safe Mode** (see [Crashes and Safe Mode](/dev/debug/crashes/)) only a few r
| `tls <host> [port]` / `ntp [server]` | A TLS handshake that checks nothing, then the certificate said in words: who it is for, who signed it, until when, its SHA-256, and whether this device's roots and the name asked for accept it (about 52 KB of heap while it runs; refused under 70 KB free). A time server's clock against the device's, with the round trip |
| `ifconfig` / `arp` / `netstat` | The interfaces (Wi-Fi and the VPN) with their addresses, MTU, which is the default route, and the DNS servers; the neighbours heard on the Wi-Fi; what listens and what is connected |
| `ssh user@host[:port]` / `ssh status` / `ssh stop` | Opens the SSH App and connects (the password is asked there, never on a console); the session's state and this device's public key; end the session |
| `scp [-f] [-P port] <file> user@host:path` / `scp [-f] [-P port] user@host:path <file>` | One file between the card and a server, with the device's key, or a password asked (masked) in the Shell, to a server the SSH App already trusts; `-f` replaces a file on the card; `cancel` stops it |
| `uname` | The firmware, its version and the chip it is built for (IRC has `/uname`) |
| `vpn status` / `vpn up [seconds]` / `vpn down` / `vpn import [path]` / `vpn forget` / `vpn auto on\|off` | The WireGuard tunnel: its state, on (for that many seconds, then off by itself: for trying a configuration from afar), off, read a `.conf` from the card (`/vpn/wg0.conf`), erase it, start with Wi-Fi. No key is ever printed |
| `debug status` / `debug off [seconds]` | The Debug Console: whether it's on, has a token and a client; switch it off. With a number of seconds, it comes back by itself after that long |
| `debug on` / `debug token <value>` / `debug token new` | USB serial only: switch it on (making a token if there's none), give it a token of 16 to 64 characters, or make a new one. The token is never printed |
+1 -1
View File
@@ -67,7 +67,7 @@ Yes, WireGuard: one tunnel to one server, set up by copying the client's `.conf`
## Can it log in to my server?
Yes, over SSH: the [SSH App](/guide/ssh/) is a terminal on another machine, with a password or with a key the device makes for itself. `vim`, `top` and `less` work. One session at a time, and not at the same time as IRC: there isn't the memory for both.
Yes, over SSH: the [SSH App](/guide/ssh/) is a terminal on another machine, with a password or with a key the device makes for itself. `vim`, `top` and `less` work. One session at a time, and not at the same time as IRC: there isn't the memory for both. `scp` in the [Shell](/guide/shell/) copies a file between the card and a server.
## How do I copy files to and from my phone?
+3
View File
@@ -31,10 +31,13 @@ You type at the bottom; <kbd>Enter</kbd> sends. A line starting with `/` is a co
| `/nick newnick` | Changes your nick |
| `/topic [text]` | Shows or sets the channel topic |
| `/names [#channel]` | Lists who is there |
| `/uname` | Shows the firmware, its version and the chip, in this buffer only: nothing is sent |
| `/quit [message]` | Disconnects and **stays disconnected** until you type something again |
| `/raw …` (or `/quote`) | Sends a line to the server as it is |
| `/settings` | The settings page |
Anyone who asks the device for its CTCP `VERSION` (`/ctcp roro VERSION` in most clients) is told `roro9stack` and the firmware version.
Each server, channel and private chat is a **buffer**. <kbd>Tab</kbd> moves to the next one, each shows how many messages are unread, and your own lines are in the accent colour. Scroll back with <kbd>Alt</kbd> + <kbd>;</kbd> (older) and <kbd>Alt</kbd> + <kbd>.</kbd> (newer). The up and down arrows (<kbd>Fn</kbd> + <kbd>;</kbd> and <kbd>.</kbd>) recall lines you sent.
## Mentions and the unread count
+3 -1
View File
@@ -21,6 +21,7 @@ Type a command and press <kbd>Enter</kbd>. `help` lists them all; the [command r
| `wifi status` | The network, the address, and where the DNS and time servers came from |
| `ls /notes` | A folder of the SD card, with sizes and dates |
| `crash` | The last crash, if there was one |
| `uname` | The firmware, its version and the chip it is built for: `roro9stack v0.22.0 xtensa-lx7 esp32s3` |
| `update check` | Whether a newer release exists |
| `lora status` | What the radio is set to and what it has heard |
@@ -45,7 +46,7 @@ The capital is the difference: every command is in small letters, every App star
## The network
For the day the network doesn't do what it should. Each of the first six takes a moment and prints as it goes; one runs at a time, and `cancel` stops it.
For the day the network doesn't do what it should. Each of the first six takes a moment and prints as it goes, and so does `scp`; one runs at a time, and `cancel` stops it.
| Command | Tells you |
|---|---|
@@ -56,6 +57,7 @@ For the day the network doesn't do what it should. Each of the first six takes a
| `tls git.twis.la` | A secure connection's certificate: who it is for, who signed it, until when, and **whether this device trusts it**. A port may follow (443 if not) |
| `ntp` | A time server's clock against this device's, and how far the server is. Another server may follow |
| `ssh user@host` | Opens the [SSH App](/guide/ssh/) and connects; `ssh status` and `ssh stop` for the session |
| `scp /notes/a.txt user@host:docs/` | One file between the card and a server, over [SSH](/guide/ssh/#copying-a-file-scp): with the device's key, or a password asked in the Shell, masked. `cancel` stops it |
| `ifconfig` | The interfaces (Wi-Fi, and the [VPN](/guide/vpn/) when it is up), their addresses, **which one is the default route**, and the DNS servers |
| `arp` | The neighbours heard on the Wi-Fi: is the gateway there at all |
| `netstat` | What the device **listens** on (updates, the Debug Console, sharing) and what is connected to it now |
+22 -1
View File
@@ -9,7 +9,7 @@ screens = ["ssh.png", "ssh-trust.png", "ssh-terminal.png", "ssh-key.png", "ssh-c
The SSH App opens a **terminal on another machine**: a server, a Raspberry Pi, a router. What you type goes there, and what its programs print is drawn here: a shell, `less`, `top`, `nano`, `vim`.
It is a client and nothing more: one session at a time, to a shell. No file transfer, no port forwarding, no jump hosts.
It is a client and nothing more: one session at a time, to a shell. No port forwarding, no jump hosts. Files go one at a time with [`scp` from the Shell](#copying-a-file-scp).
## Connecting
@@ -89,6 +89,26 @@ A session takes about **50 KB** of the device's 100 KB while it is open, and giv
See [When a connection says "not enough memory"](/howto/not-enough-memory/).
## Copying a file: scp
From the [Shell](/guide/shell/), `scp` copies **one file** between the SD card and a server, over the same SSH:
```
scp /notes/a.txt user@host:docs/a.txt the card to the server
scp user@host:/var/log/syslog /logs/ the server to the card, keeping its name
scp -P 2222 /notes/a.txt user@host: another port (-P first); a path is needed after the colon
scp -f user@host:x.txt /notes/x.txt replace a file that is on the card already
```
Paths on the card start with a slash. A path on the server is the server's own, and starts in the user's home folder when it has no slash. Only a file: no folders, no `*`.
- **The server has to be one you have already trusted** in this App (the fingerprint question above). `scp` can't ask that question, and refuses a server it doesn't know, or one whose key changed.
- **It logs in with the device's key, and asks for the password** if the server doesn't accept the key: the Shell shows the question and what you type is masked (<kbd>Back</kbd> cancels). The password is asked only in the Shell, not from a PC on the USB port or the Debug Console.
- **A download arrives under a temporary name** and takes its real one when it is all there, so a cut connection never leaves half a file. A file already there is not replaced without `-f`.
- It prints how long it took. `cancel` stops it. It needs the same 75 KB of free memory as a session, and **not while a session is open**.
See [Copy a file to or from a server](/howto/scp/).
## From the Shell
```
@@ -96,6 +116,7 @@ ssh user@host connect, in the SSH App
ssh user@host:2222 on another port
ssh status the session, and this device's public key
ssh stop end the session
scp ... copy one file, see above
```
## Keys
+1 -1
View File
@@ -1,6 +1,6 @@
+++
title = "How-tos"
description = "Short recipes for things you will want to do: move files with your phone, set up the VPN, log in to a server with the device's SSH key, take a screenshot, find out why the network doesn't work, record a track, capture radio packets, and what to try when something does not work."
description = "Short recipes for things you will want to do: move files with your phone, set up the VPN, log in to a server with the device's SSH key, copy a file to or from a server, take a screenshot, find out why the network doesn't work, record a track, capture radio packets, and what to try when something does not work."
template = "guide-index.html"
page_template = "guide-page.html"
sort_by = "weight"
+40
View File
@@ -0,0 +1,40 @@
+++
title = "Copy a file to or from a server"
description = "Send a note from the SD card to a server, or fetch a log from it, with scp in the Shell."
weight = 14
[extra]
tag = "SSH"
+++
One file at a time, between the SD card and a server you can log in to over SSH.
1. **Connect to the server once in the SSH App** (**SSH → New connection**, `user@host`) and trust its fingerprint. `scp` can't ask that question, so it only goes to servers it has met there.
2. For no password to type, put the device's key on the server: [Log in to a server without a password](/howto/ssh-key/). Without it, `scp` asks for the password.
3. Open the **Shell** and type, for a file going **to** the server:
```
scp /notes/a.txt user@host:docs/a.txt
```
or one coming **from** it, into a folder on the card (it keeps its name):
```
scp user@host:/var/log/syslog /logs/
```
You should see `scp: ... (1234 bytes) to ...`, then `scp: sent 1234 bytes in 310 ms` (or `received`).
4. If it says `password for host`, type it and press <kbd>Enter</kbd>: it shows as stars and is kept nowhere. <kbd>Back</kbd> cancels.
## If it doesn't work
| It says | Do |
|---|---|
| `is not a server this device trusts yet` | Step 1: connect once in the SSH App |
| `showed a different key than the one remembered` | The server was reinstalled, or something answers in its place. Check in the SSH App, which asks what to do |
| `exists already` | The file is on the card: add `-f` (`scp -f user@host:x /notes/x`) to replace it |
| `An SSH session is open` or `Not enough memory` | End the session (`ssh stop`), or close IRC or a Gemini page: [not enough memory](/howto/not-enough-memory/) |
| `not logged in`, `wrong password` | Three tries, then it stops. Check the user, or the key on the server |
| `a password is only asked in the Shell` | You typed it from a PC on the USB port or the Debug Console: use the Shell, or put the key on the server |
| `that isn't a plain file` | `scp` copies one file, not a folder |
Another port goes first: `scp -P 2222 /notes/a.txt user@host:a.txt`. `cancel` stops a copy that is running.
+1 -1
View File
@@ -17,7 +17,7 @@ Typing a password on a small keyboard, every time, gets old. With a key, the ser
chmod 600 ~/.ssh/authorized_keys
```
4. On the Cardputer, connect: **SSH → New connection**, `user@host`. It logs in without asking for anything.
4. On the Cardputer, connect: **SSH → New connection**, `user@host`. It logs in without asking for anything. The same key is what [`scp`](/howto/scp/) uses.
## If it still asks for a password