Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions .github/workflows/trigger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,26 @@ on:
- ci-work
workflow_dispatch:

# A label event that neither starts nor stops a run is skipped by
# check-trigger, keep those in a group of their own so they cannot cancel
# a run in progress. Adding 'ci:skip' does share the group, on purpose,
# to stop a build that is no longer wanted.
concurrency:
group: ci-${{ github.event.pull_request.number || github.ref }}
group: ci-${{ github.event.pull_request.number || github.ref }}${{ (github.event.action == 'labeled' && github.event.label.name != 'ci:main' && github.event.label.name != 'ci:skip') && '-label' || '' }}
cancel-in-progress: true

jobs:
# Gate all builds through this check to prevent wasted runs. Only run on
# 'labeled' events when the label is actually 'ci:main'. Concurrency control
# above handles canceling the 'opened' event when 'labeled' arrives quickly
# above handles canceling the 'opened' event when 'ci:main' arrives quickly
# after (e.g., when creating a PR with ci:main already attached). See #1154.
#
# A PR labeled 'ci:skip' builds nothing, for changes that cannot affect
# the image, e.g. a ChangeLog fixup after someone else's branch landed.
check-trigger:
if: |
startsWith(github.repository, 'kernelkit/') &&
!contains(github.event.pull_request.labels.*.name, 'ci:skip') &&
(github.event_name != 'pull_request' ||
github.event.action != 'labeled' ||
github.event.label.name == 'ci:main')
Expand Down
43 changes: 30 additions & 13 deletions board/common/rootfs/usr/bin/dir
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@

dir()
{
path=$1

if [ -z "$COLUMS" ]; then
TTY=$(resize)
eval "$TTY"
fi
path=${1%/}
[ -n "$path" ] || path=/

printf "\033[7m%-*s\033[0m\n" "$COLUMNS" "$path directory"
if [ -d "$path" ]; then
Expand All @@ -18,14 +14,35 @@ dir()
echo
}

if [ -d "$1" ]; then
dir "$1"
else
# Directories copy(1) can read and write, and the user is likely to
# browse. The TFTP root follows the server when it is enabled.
locations()
{
if [ "$USER" = "root" ]; then
dir "$HOME"
echo "$HOME"
else
dir "/home/$USER"
echo "/home/$USER"
fi
dir "/cfg"
dir "/log"
echo "/cfg"
sed -n 's/^tftp-root=//p' /etc/dnsmasq.d/tftp.conf 2>/dev/null || true
echo "/var/lib/tftpboot"
echo "/media"
echo "/log"
}

# resize(1) talks to the terminal, so it has to run before any pipeline
# that would hand it something else on stdin
if [ -z "$COLUMNS" ]; then
TTY=$(resize)
eval "$TTY"
fi
: "${COLUMNS:=80}"

if [ -n "$1" ]; then
dir "$1"
else
# The configured TFTP root may well be the default one
for path in $(locations | awk '!seen[$0]++'); do
[ -d "$path" ] && dir "$path"
done
fi
1 change: 1 addition & 0 deletions board/common/rootfs/usr/lib/tmpfiles.d/tftp.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
d /var/lib/tftpboot 2775 root wheel
20 changes: 20 additions & 0 deletions doc/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ All notable changes to the project are documented in this file.

### Added

- The CLI accepts an unambiguous prefix of a command name, e.g. `sh int`
for `show interface`
- Add `/system/advanced` for low-level system customization, issue #463:
- `rc.d`: user scripts stored in the configuration, run once at boot
after the startup configuration has been applied, in the order listed
Expand All @@ -33,6 +35,14 @@ All notable changes to the project are documented in this file.
statistics` replaces `dhcp-server clear-statistics`. `set datetime` now
also accepts free-form input, e.g., `14:05`, and echoes the ISO-8601
value it sets
- The CLI `remove` command now offers the startup configuration, and
warns that removing it leaves the system booting factory defaults
- Add CLI `rename` command, for renaming or moving a file without
copying it, e.g. `rename startup-config backup` to keep a
configuration before starting over. Directories in the destination
are created as needed
- The CLI completes file system paths with Tab, for `copy`, `rename`,
`remove`, and `dir`, limited to the directories those commands accept
- The CLI `configure` command takes an optional path to start in a
sub-context directly, e.g., `configure system authentication`
- `/bin/sh` is now provided by Busybox ash instead of Bash, speeding up
Expand All @@ -43,6 +53,16 @@ All notable changes to the project are documented in this file.
editor, show mesh peers on the WiFi and interface status pages, and add
an editor section for access point roaming (802.11k/r/v, band steering,
OKC).
- Add TFTP server for network boot and device provisioning, issue #1542.
Read-only, serving `/var/lib/tftpboot` or a directory on USB media, with
optional per-client subdirectories. `show tftp` lists the files served,
see [TFTP Server](tftp.md)
- Add network boot parameters to the DHCP server: `boot file`,
`server-address`, and `server-name` at global, subnet, or host scope,
sent in the BOOTP header fields and as options 66/67
- The CLI `copy` and `remove` commands now also accept files in
`/var/lib`, `/var/tmp`, and `/tmp`. Files written there are
world-readable. The `.cfg` extension is only added for files in `/cfg`

### Fixes

Expand Down
1 change: 1 addition & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ regression test system solely relies on NETCONF and RESTCONF.
- [Network Configuration](networking.md)
- [Wi-Fi](wifi.md)
- [DHCP Server](dhcp.md)
- [TFTP Server](tftp.md)
- [Syslog Support](syslog.md)
- **Infix In-Depth**
- [Boot Procedure](boot.md)
Expand Down
8 changes: 8 additions & 0 deletions doc/developers-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,14 @@ $ git submodule update --init
> in the GUI for your fork for this purpose. A cronjob on your server
> of choice can do this for you with the [GitHub CLI tool][7].

CI on a pull request is controlled with two labels. With neither, the
minimal images are built and the default tests run.

- `ci:main` builds the full images and runs the complete test suite
- `ci:skip` builds nothing, for changes that cannot affect the image,
e.g. a ChangeLog fixup after another branch landed. Adding it to an
open pull request also stops a build already running

[^1]: Organizations should make sure to lock the `main` (or `master`)
branch of their clones to ensure members do not accidentally merge
changes there. Keeping these branches in sync with upstream Infix
Expand Down
33 changes: 33 additions & 0 deletions doc/dhcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,39 @@ admin@example:/config/dhcp-server/subnet/192.168.2.0/24/> <b>leave</b>
</code></pre>


## Network Boot

Devices that boot over the network, or fall back to it when their own
firmware is damaged, learn the name of the boot file and the address of
the TFTP server from the DHCP server. These are set with `boot`, which
can be given globally, per subnet, or per static host. The most
specific scope wins.

<pre class="cli"><code>admin@example:/config/dhcp-server/> <b>edit subnet 192.168.2.0/24</b>
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/> <b>set boot file fallback.itb</b>
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/> <b>leave</b>
</code></pre>

By default the server address handed out is the system's own address
on the interface facing the client, matching the built-in
[TFTP server](tftp.md). Set `boot server-address` to point clients at
another server instead.

The boot file and server address are sent both in the BOOTP header
fields, which BOOTP clients, bootloaders like U-Boot, and PXE ROMs read,
and as DHCP options 66 and 67 to clients that request them. The two
options cannot be set in the `option` list when `boot` is used.

To hand a single device a different image, e.g., during a staged
rollout, set `boot` on its static host entry:

<pre class="cli"><code>admin@example:/config/dhcp-server/subnet/192.168.2.0/24/> <b>edit host 192.168.2.10</b>
admin@example:/config/dhcp-server/…/192.168.2.10/> <b>set match mac-address 00:11:22:33:44:55</b>
admin@example:/config/dhcp-server/…/192.168.2.10/> <b>set boot file staging.itb</b>
admin@example:/config/dhcp-server/…/192.168.2.10/> <b>leave</b>
</code></pre>


## Monitoring

View active leases and server statistics:
Expand Down
100 changes: 100 additions & 0 deletions doc/tftp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
TFTP Server
===========

The TFTP server hands out files to devices on the local network, for
example a fallback boot image for devices whose own firmware partition
has failed, or configuration files for IP phones and similar equipment.
It is read-only, so clients cannot upload files.

Files are served from a root directory, by default `/var/lib/tftpboot`.
This directory is persistent on all supported boards and writable by
admin users, so files can be placed there from the CLI or a shell. A
directory on USB media, e.g., `/media/usb/tftp`, can be used instead.

> [!IMPORTANT]
> Only world-readable files are served. Files copied with the CLI
> `copy` command are made world-readable automatically, files copied
> from a shell must be given mode `0644` or similar.


## Basic Configuration

<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>set tftp enabled true</b>
admin@example:/config/> <b>leave</b>
</code></pre>

The server listens on all interfaces by default. To restrict it to a
subset, list the interfaces to serve on:

<pre class="cli"><code>admin@example:/config/> <b>edit tftp</b>
admin@example:/config/tftp/> <b>set interface eth1</b>
admin@example:/config/tftp/> <b>set interface eth2</b>
admin@example:/config/tftp/> <b>leave</b>
</code></pre>

When the firewall is enabled, the `tftp` service must also be allowed
in the zone facing the clients, see [Firewall](firewall.md).


## Uploading Files

Files can be fetched to the TFTP root with the `copy` command from any
of the supported remote sources, or copied from USB media. A directory
destination keeps the source file name:

<pre class="cli"><code>admin@example:/> <b>copy tftp://192.168.1.1/fallback.itb /var/lib/tftpboot/</b>
admin@example:/> <b>copy /media/usb/phones.cfg /var/lib/tftpboot/</b>
admin@example:/> <b>dir /var/lib/tftpboot</b>
/var/lib/tftpboot directory
fallback.itb phones.cfg
</code></pre>

Files are removed with the `remove` command, which asks for
confirmation:

<pre class="cli"><code>admin@example:/> <b>remove /var/lib/tftpboot/phones.cfg</b>
Remove /var/lib/tftpboot/phones.cfg, are you sure? (y/N)? y
</code></pre>


## Per-Client Directories

Some devices, IP phones in particular, expect a configuration file with
a fixed name that differs per device. With `client-directory` set, the
server first looks for the requested file in a subdirectory of the root
named after the client, and falls back to the root itself if there is
none:

<pre class="cli"><code>admin@example:/config/tftp/> <b>set client-directory mac</b>
</code></pre>

With this setting a request for `config.xml` from the device with MAC
address `00:11:22:33:44:55` is answered with
`/var/lib/tftpboot/00-11-22-33-44-55/config.xml` if that file exists,
otherwise with `/var/lib/tftpboot/config.xml`. Use `ip` instead of
`mac` to name the directories after the client IP address.


## Network Boot

Devices that boot over the network learn the boot file name and TFTP
server address from the DHCP server. See [Network Boot](dhcp.md#network-boot)
in the DHCP server documentation for how to hand these out.


## Monitoring

<pre class="cli"><code>admin@example:/> <b>show tftp</b>
Root directory : /var/lib/tftpboot
Interfaces : all
Client directory : none

<span class="header">NAME SIZE MODIFIED </span>
fallback.itb 7.0M 2026-09-18 05:18
phones.cfg 812B 2026-09-17 12:00
</code></pre>

The file list is the operational view of the root directory and shows
only files the server can actually hand out. A file missing from the
list is either not world-readable or outside the configured root.
3 changes: 2 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ nav:
- Network Calculator: cli/netcalc.md
- Network Monitoring: cli/tcpdump.md
- Quickstart Guide: cli/quick.md
- Text Editor: cli/text-editor.md
- Text Editor: cli/edit.md
- Upgrading: cli/upgrade.md
- Docker Containers: container.md
- Networking:
Expand All @@ -49,6 +49,7 @@ nav:
- DHCP Server: dhcp.md
- NTP Server: ntp.md
- PTP (IEEE 1588/802.1AS): ptp.md
- TFTP Server: tftp.md
- System:
- Boot Procedure: boot.md
- Configuration: system.md
Expand Down
6 changes: 0 additions & 6 deletions package/bin/bin.mk
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,4 @@ define BIN_BUILD_PYTHON
endef
BIN_POST_INSTALL_TARGET_HOOKS += BIN_BUILD_PYTHON

define BIN_INSTALL_BASH_COMPLETION
install -D $(@D)/bash_completion.d/show \
$(TARGET_DIR)/etc/bash_completion.d/show
endef
BIN_POST_INSTALL_TARGET_HOOKS += BIN_INSTALL_BASH_COMPLETION

$(eval $(autotools-package))
2 changes: 1 addition & 1 deletion package/klish/klish.hash
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Locally calculated
sha256 9d9d33b873917ca5d0bdcc47a36d2fd385971ab0c045d1472fcadf95ee5bcf5b LICENCE
sha256 be6548a5a4f8c35906b02ea0ccb64cdd94d48bfe7133801353fbf658aa33d5c0 klish-8dca4da70a7794d5f4e0b047724bfe9e2088ebf3-git4.tar.gz
sha256 f8c944f5a11a07044a50ed2520c192e56b555e4e931e41403b4e7f9da45560d6 klish-5880300b23ea7378a4af186d510a61be64dfd630-git4.tar.gz
2 changes: 1 addition & 1 deletion package/klish/klish.mk
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#
################################################################################

KLISH_VERSION = 8dca4da70a7794d5f4e0b047724bfe9e2088ebf3
KLISH_VERSION = 5880300b23ea7378a4af186d510a61be64dfd630
KLISH_SITE = https://github.com/kernelkit/klish.git
#KLISH_VERSION = tags/3.0.0
#KLISH_SITE = https://src.libcode.org/pkun/klish.git
Expand Down
7 changes: 4 additions & 3 deletions src/bin/.gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
*~
*.o
copy
erase
files
/copy
/erase
/files
/rename

/aclocal.m4
/autom4te.cache/
Expand Down
12 changes: 10 additions & 2 deletions src/bin/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
DISTCLEANFILES = *~ *.d
ACLOCAL_AMFLAGS = -I m4

bin_PROGRAMS = copy erase files
bin_PROGRAMS = copy erase files rename
sbin_SCRIPTS = support

# Bash completion
bashcompdir = $(datadir)/bash-completion/completions
dist_bashcomp_DATA = copy.bash
dist_bashcomp_DATA = bash_completion.d/copy bash_completion.d/erase \
bash_completion.d/rename bash_completion.d/rpc \
bash_completion.d/show

copy_SOURCES = copy.c util.c util.h
copy_CPPFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE
Expand All @@ -20,6 +22,12 @@ erase_CFLAGS = -W -Wall -Wextra
erase_CFLAGS += $(libite_CFLAGS) $(sysrepo_CFLAGS)
erase_LDADD = $(libite_LIBS) $(sysrepo_LIBS)

rename_SOURCES = rename.c util.c util.h
rename_CPPFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE
rename_CFLAGS = -W -Wall -Wextra
rename_CFLAGS += $(libite_CFLAGS) $(sysrepo_CFLAGS)
rename_LDADD = $(libite_LIBS) $(sysrepo_LIBS)

files_SOURCES = files.c util.c util.h
files_CPPFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE
files_CFLAGS = -W -Wall -Wextra
Expand Down
Loading
Loading