This chapter is for the person who looks after a KDOS machine once it is installed or booted from
the stick. The first half is the machine as a whole: services and periodic jobs, the login on
tty1, users and groups, storage, networking and the firewall, hardware and device access,
printing, media and time, updates, diagnosis and logs, copying and rebuilding the medium, and
tuning builds for this CPU. The second half is what each user sets up in their own home: backups,
mail, passwords and one-time codes, calendars and contacts, finding files by name, the language,
and input methods. Each task is given as the command or the file that does it, with the reason the system is
arranged that way where the reason affects what you do.
If you are new to KDOS, read Getting started first; this chapter assumes you
can open a terminal and use sudo. The mechanisms behind it are in
Boot and init and The daemons.
Two facts shape everything below:
/etc/init.d,
and every setting in this chapter is a plain file that takes effect when the program reads it.
Configuration lists every one of those files and keys.
How KDOS differs compares this with how other
distributions arrange the same things.kdos, and on the live image its password is kdos. The installer asks
for a new one. On a machine that still has the shipped password, run passwd before anything
else; sudo kdos doctor warns until you do (the check needs to read /etc/shadow, so it runs
only as root).When something is wrong, start with Diagnosing.
A service is a script in /etc/init.d named NN_name.sh, where NN is two digits that fix its
place in the boot order. At boot, init runs /etc/init.d/rcS as its sysinit entry
(Boot and init). rcS runs the
enabled scripts in numeric order with the argument start, and ksvc, the KDOS service supervisor,
keeps each long-running daemon under a process of its own and restarts it five seconds after it
exits.
You manage services with service:
service list # every service, whether it starts at boot, and its state
service status <name>
service start <name>
service stop <name>
service restart <name> # stop, wait one second, start
service enable <name> # start it at boot
service disable <name> # do not start it at boot
service is a link to ksvc, so ksvc status sshd and service status sshd do the same thing.
ksvc check <name> asks the supervisor directly whether the process it started under that name is
alive, which is how a single periodic job is checked (see Periodic jobs).
<name> is the part of the file name between the number and .sh: sshd for 70_sshd.sh. For
status, start, stop and restart, an exact name is tried first and then any service whose
name contains what you typed, so service status ssh finds sshd. enable and disable check
the same way that the service exists, but record the name exactly as you typed it, so type the full
name from service list: service disable ssh writes a marker that rcS never looks for.
Enabling and disabling is a marker file, not an edit: service disable bluetooth creates the empty
file /etc/service.disabled/bluetooth, and service enable bluetooth deletes it. Nothing in
/etc/init.d is rewritten. The live image ships one marker, sshd, so the SSH server is the one
installed service that does not start until you enable it; opening ssh in the firewall (below)
enables it. The installer writes markers for the services you turn off, and turns off CUPS and sshd
by default (see Installation).
During boot, each script’s output goes to /run/kdos-init.<name>.log and is then copied to the
console, so the first thing to read about a service that failed at boot is that file. It lives in
/run, a tmpfs, and is gone after the next reboot.
The scripts that ship, in boot order. Scripts marked (package) come with the package named and are absent if that package is removed.
| Script | What it starts |
|---|---|
01_udev |
Device management, and the coldplug that loads drivers for the hardware already present. It also creates device nodes such as /dev/uinput, /dev/uhid, /dev/snd/seq and /dev/vhost-net, whose driver loads only when a program first opens the node, so they exist before anything asks for them |
02_modules |
Modules listed in /etc/modules-load.d |
03_lvm |
LVM volume groups, activated once at boot, then any fstab entry on a logical volume checked and mounted. On a disk boot the initramfs has already activated the groups it saw; this pass catches the rest — every group on a live boot, and any on a disk that appeared after the initramfs ran. A group plugged in later is not activated automatically; run sudo vgchange -aay |
05_hostname |
The hostname |
10_sysctl |
Kernel parameters from /etc/sysctl.conf: unprivileged ping; the name of the fatal signal in the kernel log when a program crashes; the fs.protected_* link protections, which stop a user redirecting a root job’s write in /tmp onto another file; per-task delay accounting, which iotop’s IO% and htop’s delay columns read, at a small cost on every wait the kernel accounts; no ICMP redirect accepted or sent; the loose reverse-path filter; and kernel addresses hidden from every account but root |
12_zram |
Compressed swap in RAM — see Storage |
15_userdirs |
/run/user/<uid> for every account with a UID from 1000 to 65533, and a delegated cgroup subtree for each with the cpu, memory and pids controllers, which is what lets rootless podman apply a box’s memory and CPU limits (a box is the rootless container one application runs in; see the glossary) |
18_timers |
Periodic jobs: one supervised snooze per line of /etc/kdos/timers.d — see Periodic jobs |
20_dmesg, 22_syslog |
Kernel and system logging. 20_dmesg lowers the console log level to 3, so only kernel errors reach the screen. 22_syslog runs syslogd, whose /etc/syslog.conf sets secure_mode 2, so it opens no network socket: it neither accepts messages from other hosts nor forwards to one. secure_mode 1 allows forwarding to an @host action without listening. See Logs |
25_nftables |
The firewall, loaded before the network comes up — see The firewall |
30_network |
dhcpcd, the fallback DHCP client. It stays down when NetworkManager is installed and not disabled, because NetworkManager’s own DHCP client does not defer to it: two clients on one link means two leases, two default routes and two writers of /etc/resolv.conf |
31_babeld (babeld) |
Babel mesh routing, skipped until a non-empty /etc/babeld.conf exists. Open the babel firewall name for the neighbours |
35_chrony |
Time synchronisation |
40_dbus |
The system message bus. On its first start it generates /var/lib/dbus/machine-id and links /etc/machine-id to it |
41_polkitd |
polkit, the privilege broker. It starts before NetworkManager, which asks it on its first privileged call |
42_modemmanager |
ModemManager: mobile broadband modems, for NetworkManager and mmcli. Started at boot rather than on demand for the same reason as polkit |
42_networkmanager |
NetworkManager |
43_boltd (bolt) |
Thunderbolt. Only when /sys/bus/thunderbolt/devices is non-empty, it calls org.freedesktop.bolt so the bus starts boltd. A device plugged in later is handled by the bolt package’s udev rule |
44_switcheroo-control (switcheroo-control) |
net.hadess.SwitcherooControl on the system bus, which tells a launcher which GPU is discrete and what environment starts a program on it; KIO’s “run on the discrete GPU” and switcherooctl launch read it. Skipped when the machine has fewer than two GPUs |
45_avahi |
mDNS: finding printers and other machines on the local network by name |
45_seatd |
Seat management, which the desktop needs |
46_hostapd |
A wireless access point, only when /etc/hostapd/hostapd.conf exists — see An access point with hostapd |
47_pcscd |
Smart cards and security keys: the PC/SC daemon, with readers arriving through udev |
50_alsa |
Saves and restores the sound card’s mixer levels |
51_mdmonitor |
mdadm --monitor --scan --syslog: a failed member, a degraded array or a missing spare is written to the system log. Skipped when /proc/mdstat lists no array; a MAILADDR or PROGRAM line in /etc/mdadm.conf adds a route of your own |
51_lsmd (libstoragemgmt) |
The libstoragemgmt plugin daemon, which udisks2’s LSM module and lsmcli reach over /run/lsm/ipc; plugins that do not need root run as the libstoragemgmt account |
52_smartd |
Disk health: smartd polls every disk that answers SMART every half hour and logs a failing health check, bad sectors, drive errors and failed self-tests. Where no disk answers SMART — any virtual machine — it logs why and stops |
53_xfs_healer |
One xfs_healer per XFS filesystem mounted at boot. It logs the metadata damage the kernel reports and, where the filesystem’s autofsck property asks for it, has it repaired online. Skipped on a kernel without the XFS health monitor |
54_thermald |
Intel thermal management |
55_powerd |
kdos-powerd: suspend, power-off and reboot for the desktop, and a few system settings (time zone, accent, autologin, firewall names) |
55_tlp |
Laptop power management: tlp init start at boot and tlp init stop at shutdown, which apply the startup and shutdown radio settings in /etc/tlp.d. kdos-powerd runs tlp suspend and tlp resume around a suspend |
56_energyd |
Per-application energy use |
56_nut (nut) |
The UPS tools: the drivers, upsd and upsmon, or upsmon alone as a network client. Skipped unless MODE in /etc/nut/nut.conf is standalone, netserver or netclient. Open the nut firewall name to serve UPS status to other machines |
57_oomd |
Memory-pressure protection: ends the heaviest application before the machine stalls, sparing the desktop itself |
58_mountd |
Removable media for the desktop |
59_packd |
kdos-packd, which mounts application packs: signed EROFS images holding an application, runtime, base or dataset, which boxes are built over. See Packs and boxes |
60_bluetooth |
Bluetooth |
61_spacenavd (spacenavd) |
The 3D mouse daemon. It finds 3Dconnexion devices as they are plugged in and serves them on /run/spnav.sock, the socket every libspnav client (FreeCAD, OpenSCAD, KiCad, Blender) connects to. /etc/spnavrc, absent by default, sets sensitivity, axis mapping and dead zones; /usr/share/doc/spacenavd/example-spnavrc is the template. It serves no X11 client, so a program that speaks only the proprietary 3Dconnexion X protocol sees no device |
62_virtlogd (libvirt) |
libvirt’s log daemon, which keeps each guest’s console log |
63_gssd (nfs-utils) |
rpc.gssd, the Kerberos half of an NFS client, which a sec=krb5 mount needs. It mounts rpc_pipefs at /var/lib/nfs/rpc_pipefs first. Skipped until /etc/krb5.keytab exists |
63_libvirtd (libvirt) |
libvirt’s management daemon for qemu:///system. Its polkit rule lets members of the libvirt group manage guests |
64_lircd (lirc) |
The infrared remote daemon, skipped until a receiver is present (a /dev/lirc* node or an rc-core device). Its socket /run/lirc/lircd is what Kodi, VLC and other LIRC clients read |
65_brltty (brltty) |
The console screen reader, skipped until /etc/brltty.conf exists. Its speech goes straight to the sound card, so it cannot speak while a desktop session’s PipeWire holds the card. See Accessibility |
70_sshd |
The SSH server, disabled until you enable it (the image ships /etc/service.disabled/sshd). Opening ssh in the firewall enables and starts it, and closing ssh disables and stops it. Before the first start it generates every missing host key type with ssh-keygen -A |
71_snmpd (net-snmp) |
The SNMP agent, as root, skipped until a non-empty /etc/snmp/snmpd.conf exists; it logs to syslog. Open the snmp firewall name for other machines |
72_nfsd (nfs-utils) |
The NFSv4 server, skipped until /etc/exports names a share. It loads nfsd, supervises nfsdcld (the client records a restarted server needs) and nfsv4.exportd, runs exportfs -r, then starts the kernel threads with rpc.nfsd -N 3 -V 4. NFSv3 is off, so no portmapper, rpc.mountd or lock daemon runs. After editing /etc/exports, run sudo exportfs -r. Open the nfs firewall name for other machines |
73_mosquitto (mosquitto) |
The MQTT broker, as the mosquitto account, skipped until /etc/mosquitto/mosquitto.conf exists. With no configuration the broker listens on loopback only; a listener 1883 line there, plus the mqtt firewall name, lets devices on the LAN reach it |
74_prosody (prosody) |
The XMPP chat server, as the prosody account, skipped until it has an account: sudo prosodyctl adduser <user>@<host> makes the first. Clients are refused until the host has a certificate; sudo prosodyctl cert generate <host> makes a self-signed one. Open the xmpp firewall name for other machines |
75_mumble-server (mumble) |
The Mumble voice server, as the mumble-server account, skipped until its database exists: running mumble-server -supw <password> as that account makes it. Open the mumble firewall name for other machines |
76_postgresql (postgresql) |
One shared PostgreSQL server, as the postgres account, skipped until a cluster exists: sudo -u postgres initdb -D /var/lib/postgres/data makes it. It listens on loopback and on a socket in /tmp |
77_radicale (radicale) |
Radicale, the CalDAV and CardDAV server, as the radicale account, skipped until /etc/radicale/users has an account line (name: followed by a hash from openssl passwd -6). Open the caldav firewall name for other machines |
78_maddy (maddy) |
The maddy mail server, as the maddy account, skipped until /var/lib/maddy/credentials.db holds an account (running maddy creds create <address> and maddy imap-acct create <address> as the maddy account, with sudo -u maddy, makes one). Open the mail firewall name for other machines |
79_ngircd (ngircd) |
The ngIRCd chat server, as the ngircd account, skipped until a non-empty /etc/ngircd.conf exists; /usr/share/doc/ngircd/sample-ngircd.conf is the template. Open the irc firewall name for other machines |
80_cups |
Printing |
81_cups-browsed |
Printers shared on the network, added to CUPS as they appear |
82_ipp-usb |
Driverless printing and scanning over USB: each IPP-over-USB device is served on localhost as it is plugged in |
83_samba (samba) |
smbd, skipped until a non-empty /etc/samba/smb.conf exists. Open the smb firewall name for other machines |
84_minidlna (minidlna) |
MiniDLNA, the media server for televisions and players on the LAN, skipped until a non-empty /etc/minidlna.conf exists; the template is in /usr/share/doc/minidlna. Open the dlna firewall name for other machines |
85_gnuhealth (gnuhealth) |
The GNU Health server (trytond), as the gnuhealth account, skipped until /etc/gnuhealth/trytond.conf names a database uri. Open the tryton firewall name for other machines |
86_kiwix-serve |
The offline library on 127.0.0.1:8080, skipped until /var/lib/kiwix/library.xml lists an archive — see The local servers |
87_kolibri |
Kolibri, the offline curriculum, on 127.0.0.1:8081, skipped until a channel is installed |
88_llama-server |
The local language-model server on 127.0.0.1:8082, skipped until a .gguf model is under /usr/share/llama.cpp/models |
89_step-ca (step-ca) |
The step-ca certificate authority, as root, from /etc/step-ca. Skipped until /etc/step-ca/config/ca.json (from sudo STEPPATH=/etc/step-ca step ca init) and /etc/step-ca/password.txt (the CA password, mode 600) both exist. Open the https firewall name for other machines when the CA listens on 443 |
Shutdown runs the same set backwards. poweroff, reboot and shutdown ask init for runlevel 0
or 6, and /etc/init.d/rcK is the first entry of those runlevels in /etc/inittab; it runs each
enabled script with stop, in reverse order, before the remaining processes are ended, swap is
turned off and filesystems are unmounted, so a service can still save its state. A service that fails to
stop does not hold up the rest. The firewall is not stopped: it stays loaded until power-off, so
the machine is never on the network unfiltered. See
Boot and init.
A daemon that cannot do its job on this machine is skipped at boot, with a [SKIP] line saying
why, instead of being started and left to fail:
| Script | Skipped when |
|---|---|
44_switcheroo-control |
Fewer than two GPUs under /sys/class/drm |
54_thermald |
The processor is not Intel |
56_energyd |
No readable CPU energy counter (/sys/class/powercap/*/energy_uj) |
57_oomd |
/proc/pressure/memory is not writable (pressure stall information is off) |
59_packd |
The kernel cannot mount EROFS, the pack filesystem |
The check runs before the daemon starts, because a daemon that refuses to run, restarted every five seconds by its supervisor, keeps the boot from ever settling.
Some daemons can only tell for themselves that they have nothing to do: thermald knows which Intel
models it supports, and smartd finds out only by asking each disk. When one of these — thermald,
smartd, mdadm --monitor or xfs_healer — exits with a status that restarting cannot change, the
supervisor logs one line such as [KDOS] (thermald) Exited with code 2, a final status: not
restarting and leaves it stopped, and service status reports it as not running. Each script
names those final statuses when it starts its daemon (supervise --final-exit 2 …); how the
supervisor tells that exit from a crash is in
The daemons.
Twelve scripts leave nothing for the supervisor to watch: 01_udev, 02_modules, 03_lvm,
05_hostname, 10_sysctl, 12_zram, 15_userdirs, 20_dmesg, 25_nftables, 43_boltd,
50_alsa and 55_tlp. Most apply a setting and exit; 25_nftables and 12_zram hand their
result to the kernel, which keeps it. For these, service status reports what the script applied
rather than a running process: sysctl: applied, the zram device and its nominal size, whether a
firewall ruleset is loaded, the logical volumes (lvs), or TLP’s own summary (tlp-stat -s).
02_modules and 15_userdirs print nothing. Two report a process after all:
service status boltd says whether the bus has boltd running, and service status udev says
whether udevd is running, because udevd runs on its own once the script has started it.
There is no cron daemon. A periodic job is one line in a file ending .timer under
/etc/kdos/timers.d/:
NAME TIMESPEC... -- COMMAND...
Blank lines and lines starting with # are ignored. For example, the shipped update check:
update-check -H 4 -M 17 -s 8h -- kdos update check --fetch --out /var/lib/kdos/update.json
snooze is a small program that sleeps until the clock matches its options, runs a command once
and exits. At boot 18_timers starts one snooze per line under the supervisor, as the service
kdos-timer-NAME; when snooze exits after a run, the supervisor starts it again and it sleeps
until the next slot. That gives one process per job and no shared schedule file to corrupt.
service status timers shows every job, and ksvc check kdos-timer-update-check shows one.
The timespec is snooze’s own options, unchanged: -H 4 -M 17 is 04:17, -d /2 is every
second day. snooze(1) is the full reference.
Missed runs. -s sets the slack. A machine that was asleep at the slot runs the job once
when it wakes, if it wakes within the slack — once, not once per missed slot, so a laptop closed
for a fortnight does not run fourteen catch-up jobs.
-s does not cover a machine that was off. A snooze that has just started looks forward from
now, so a slot that passed before boot is missed until the next one. -t FILE changes that:
snooze then counts from that file’s modification time, and the slack covers the gap. A job that
must run even when the machine was off across its slot needs both -s and -t.
The command is a list of words, not a shell line. There is no pipe, no redirection and no &&;
a program that writes a file takes a flag naming it, which is why kdos update check has --out.
Quotes are not interpreted either: the line is split on spaces, so -- kdos notify "Good morning"
passes "Good and morning" as two arguments. A program that needs a sentence reads it from a file
of its own, which is what kdos remind does. This is what lets the table be parsed rather than run
by a shell, so a line cannot run anything its author did not write.
Errors. A line with no --, no command, or a name containing anything but letters, digits,
_ and - is reported at boot and skipped. A line whose command is not installed is skipped with
a [SKIP] line. Nothing is guessed at: a job that silently never started looks exactly like one
that has not fired yet.
The jobs that ship in the system table:
| File | Runs | When | Why then |
|---|---|---|---|
10-update-check.timer |
kdos update check --fetch --out /var/lib/kdos/update.json |
04:17, slack 8 h | Not midnight, when every other machine runs its jobs and asks the same server |
20-fstrim.timer |
fstrim -a |
12:47, slack 20 h | See below |
30-fwupd-refresh.timer (added by the fwupd package) |
fwupdmgr refresh |
13:43, slack 20 h | The firmware metadata, so fwupdmgr get-updates has something to compare against |
fstrim tells an SSD which blocks are free. The installer mounts ext4 and XFS without the
discard option, so without this job the drive’s write speed and wear degrade as it fills; btrfs
and f2fs discard on their own, and a device that cannot discard is skipped. The slot is at midday
because fstrim has no timefile to pass to -t, so a slot the machine was off for is missed — and
a desktop switched off every night would never reach an overnight one.
Put your own jobs in ~/.config/kdos/timers.d/*.timer, in the same format. Your desktop session
starts them when you log in and stops them when you log out: a job that writes into your home
directory should not outlive the login that started it. While you are logged in they repeat like
the system ones — each line runs in a loop that restarts snooze after every run.
Differences from the system table:
snooze -n rejects
is skipped silently. If a job never fires, check the line with snooze -n <timespec>, which
prints the next five times it would run.Give each job a minute of its own. A laptop that wakes after its slots have passed runs every job whose slack covers the gap at the same moment, and jobs that start together compete for one disk. That is why the backup job below sits at 03:40 and not beside the 04:17 update check.
Two jobs ship in the skeleton copied into each new home:
| File | Runs | State |
|---|---|---|
20-updatedb.timer |
kdos-updatedb at 03:05 |
Enabled — see Finding a file by name |
10-backup.timer |
kdos-backup --once at 03:40 |
Commented out: a first backup of a home directory can take hours, and should be something you chose — see Backups |
Logging in on the first console, tty1, starts the desktop. /etc/inittab gives tty1 to
kdos-getty, which loads the console font and colours and then runs kdos-login. kdos-login
reads /etc/kdos/login.conf and either logs in the account it names without asking or shows the
normal password prompt. tty2 is a plain login prompt: the recovery console to use when the
desktop does not come up.
/etc/kdos/login.conf has one key:
| Key | Does |
|---|---|
autologin |
The account tty1 logs in without a password. Shipped as autologin = kdos. Commented out, tty1 asks for a password |
Change it with kdos-users, or kdos-power autologin <user> or kdos-power autologin off
(members of wheel). Those refuse an account that cannot log in, which would leave a machine that
boots to a login nobody can complete. This is the only place the desktop account is named, and the
installer writes it when you choose a user name. If kdos-login is missing, kdos-getty starts a
plain autologin prompt itself, using the same autologin key, so a broken login program still
leaves you a console.
One account ships: kdos (UID 1000), a member of wheel, seat, users and the hardware groups
below. The installer asks for its password; on the live image it is kdos.
wheel is what sudo and polkit grant on, and what the root daemons check (through the
socket’s peer credentials) before accepting a configuration change. The sudo grant is the one
line %wheel ALL=(ALL) ALL in /etc/sudoers.d/00-sudo, which asks for your own password.
The same file keeps EDITOR, VISUAL and SUDO_EDITOR through sudo, so sudoedit and
visudo open the editor your shell names; without one they open nvim, else nano.seat alone reaches suspend, power-off, reboot and removable-media mounting. An account in
seat but not wheel can run a desktop and power it down, but cannot administer the machine.The hardware groups of the kdos account, and what removing each would silently stop:
| Group | Makes usable without root |
|---|---|
dialout |
Serial adapters, debug probes, SDRs, instruments, security keys, cameras, scanners, phones — see the udev rules |
audio |
Sound devices |
video |
The GPU’s display nodes, screen and keyboard backlight, and a monitor’s DDC/CI line |
render |
GPU rendering and compute |
input |
Input devices and game controllers’ raw HID |
kvm |
Hardware virtualisation for QEMU |
cdrom |
Optical drives |
lpadmin |
Adding and managing printers in CUPS |
tty |
Opening a virtual terminal from a backgrounded session: /dev/tty0 is 0620 root:tty, and a backgrounded session has no controlling terminal of its own, so without this group the desktop is refused a terminal |
Adding a user. kdos-users lists accounts and their groups and sets autologin; it does not
create accounts. Use the shadow tools:
sudo useradd -m -G wheel,seat,audio,video,render,input -s /bin/bash alice
sudo passwd alice
Add the other groups from the table as needed. Two things to check afterwards:
/etc/subuid and
/etc/subgid for the account; grep alice /etc/subuid shows whether useradd added one. The
shipped files give kdos the range starting at 100000 and root the one starting at 200000,
65536 IDs each, so a range added by hand for another account must not overlap those./run/user/<uid> is created by 15_userdirs at boot for the accounts that exist then. For an
account added since, run sudo service start userdirs or reboot before its first desktop login.Filesystem checks at boot. Before anything is mounted, rcS runs fsck -A -R -T -a: every
/etc/fstab filesystem with a non-zero pass number is checked and repaired where that is safe,
except the root, which the initramfs checked before mounting it. The report goes to
/run/kdos-fsck.log. A filesystem left with uncorrected errors is still mounted, and the boot
splash says so, rather than the machine stopping behind the splash; read the log and repair it by
hand from tty2. A filesystem on an LVM volume group that the initramfs did not activate is
checked and mounted later by 03_lvm, which appends to the same log.
Swap. rcS runs swapon -a at boot, after mount -a, so any swap partition or swapfile in
/etc/fstab is used. The installer can create a swapfile and writes its fstab line.
zram is compressed swap held in RAM, set up by 12_zram from /etc/kdos/zram.conf:
size = 50
algorithm = zstd
| Key | Means | Default |
|---|---|---|
size |
How much swap the device may claim to hold, as a percentage of RAM (1–90). It is not the memory the device occupies, since compressed pages live in that same RAM. A value outside 1–90 is reported and replaced with 50 | 50 |
algorithm |
The compression algorithm. One the running kernel lacks is reported, and the kernel’s default is used | zstd |
The device is used ahead of disk swap (priority 100). Once it is up, 12_zram changes two kernel
settings, and service stop zram puts both back:
vm.page-cluster is set to 0, turning off swap read-ahead, which suits a disk’s seek time
but on zram only decompresses pages nobody asked for. service stop zram restores the default of
/etc/sysctl.conf.Removable media are mounted by the kdos-mountd root daemon, which you reach through
kdos-devices (Super+F6) or the kdos-mount command. A mounted device appears under
/media/<user>/<label> (the device name when it has no label, with any character other than
letters, digits, ., _ and - removed), private to you and removed again on unmount. Every
removable mount is nosuid,nodev, and noexec by default: a setuid program on someone else’s USB
stick would otherwise be a way to become root. Create /etc/kdos/mountd.conf (not shipped) to
change that:
| Key | Effect |
|---|---|
exec = yes |
Mount removable media without noexec, so programs on them can run |
format = yes |
Allow formatting a removable device |
write = yes |
Allow writing a disk image over a whole removable disk |
The daemon never offers an internal disk, a filesystem the kernel cannot mount, anything already
mounted, anything named in /etc/fstab, or the medium the system booted from. Members of seat or
wheel may use it.
The client never names a device or a mount point: it asks for a row number from the list the daemon published, and the daemon decides the rest.
kdos-mount list # the removable devices, one numbered row each
kdos-mount mount 0 # mount row 0; prints the mount point
kdos-mount unmount 0
kdos-mount smart 0 # the disk's SMART health verdict (smartctl -H)
kdos-mount write 0 kdos.iso sdb # kdos.iso over all of sdb, read back and compared
kdos-mount shares # the network shares connected now
kdos-mount browse # file servers that answered an mDNS or NetBIOS broadcast
The same daemon unlocks a LUKS-encrypted stick, formats a device when format = yes allows it,
writes an image over a whole stick when write = yes allows it (the image is opened as you and
handed to the daemon open, and the disk’s name is typed back to confirm), and connects SMB shares,
including with a Kerberos ticket from kinit
(kdos-mount krb5 <server> <share> <user|-> <domain|->). The passphrase or share password is
typed into kdos-disks or kdos-connect, never on a command line. Every verb and refusal is in
The daemons.
Disks in the native applications. The applications ported natively (Dolphin’s device list,
GNOME Disks, K3b, the Impression image writer, the file choosers of GTK and Qt) do not use
kdos-mountd. They reach disks through udisks2, with gvfs on top for GTK. udisksd has no
service script: the system bus starts it on the first request. It mounts under
/run/media/<user>, and every request is decided by polkit, whose rule in
/etc/polkit-1/rules.d/50-kdos.rules grants mounting, unlocking, ejecting, formatting and raw
device access to members of wheel without a password. With no authentication agent to ask for a
password, an account outside wheel is refused. kdos-mountd remains the authority for the panel
and kdos-devices.
NetworkManager manages the network, with wpa_supplicant for wireless, ModemManager for mobile
broadband and a local dnsmasq for DNS. The polkit rule in /etc/polkit-1/rules.d/50-kdos.rules
lets members of wheel scan, connect, forget networks, switch the radio and share a connection
without a password. It deliberately leaves out setting the hostname, setting machine-wide DNS and
reloading NetworkManager’s configuration; those need sudo.
| Tool | For |
|---|---|
kdos-net (Super+F4) |
The desktop network manager: networks, connecting, forgetting, the hotspot |
kdos-netagent |
The passphrase box NetworkManager raises; started with the session |
nmtui |
The full text interface |
nmcli |
Scripting |
Connecting to wireless. Open kdos-net, choose the network and type the passphrase; it is
saved in the connection profile.
Any later question comes from kdos-netagent. NetworkManager never prompts by itself: when a saved
secret is missing or refused, it asks the password agents registered with it, and fails the
connection silently if none answers. So a changed wireless key, 802.1X enterprise wireless and a
VPN one-time code all arrive as a box from the agent, not from the window you started in. The agent
stores nothing; only a request that allows interaction raises a box.
DNS. NetworkManager starts a caching dnsmasq on 127.0.0.1 and ::1 and feeds it the
servers of each connection, as set by /usr/lib/NetworkManager/conf.d/10-kdos-dns.conf. DNS is
split: a VPN’s servers answer for the VPN’s own domains rather than replacing every server the
machine has. A file of the same name in /etc/NetworkManager/conf.d overrides the shipped one.
/etc/resolv.conf has one writer, resolvconf (openresolv), which NetworkManager, the fallback
dhcpcd and wg-quick all go through, so none of them overwrites another’s entries.
VPNs. OpenVPN works through NetworkManager with certificate and password authentication; PKCS#11 hardware tokens are not supported by the OpenVPN build. WireGuard works two ways:
nmcli connection import type wireguard file wg0.conf makes a NetworkManager profile, and its
DNS= servers go to the local dnsmasq for the tunnel’s domains.wg-quick up wg0 hands a DNS= line to resolvconf, which makes the tunnel’s servers the only
ones in /etc/resolv.conf until wg-quick down wg0.Web servers that ask for a Windows sign-in. libsoup, the HTTP library under WebKitGTK,
GStreamer’s network sources, GeoClue and gvfs, answers both challenges an Active Directory web
service sends. Negotiate is answered with the Kerberos ticket kinit left in your credential
cache. NTLM first tries single sign-on through Samba’s /usr/bin/ntlm_auth, which is why every
libsoup consumer installs samba; that helper signs on only from winbindd’s cached credentials,
and Samba here is built without winbind, so the attempt fails and libsoup answers NTLM itself with
the password the application asks for. libsoup’s TLS is glib-networking’s GIO
module, loaded at run time, so a system without glib-networking fails every https request at
the handshake with “TLS/SSL support not available”.
Mobile broadband is a NetworkManager connection like any other. ModemManager finds a built-in
WWAN card or a USB modem (MBIM, QMI, QRTR or AT). Connect it with
nmcli connection add type gsm ifname '*' apn <apn>, or with nmtui’s mobile broadband entry,
which offers carriers from mobile-broadband-provider-info. kdos-netagent asks for a SIM PIN.
mmcli -m any shows the modem as ModemManager sees it; members of wheel can unlock and enable a
modem and read its text messages there without sudo.
Other connection types:
| Connection | Command |
|---|---|
PPPoE (DSL), carried by pppd |
nmcli connection add type pppoe ifname ppp0 pppoe.parent <ethernet> username <user> password <password> |
| A phone’s Bluetooth tethering | nmcli connection add type bluetooth bt-type panu bluetooth.bdaddr <phone>, after pairing the phone in kdos-bt |
| A phone that offers only dial-up over Bluetooth | The same with bt-type dun, plus an APN |
kdos-net’s hotspot is the quick way to share a connection, and needs none of this. hostapd is
for a machine that is the network — an access point that stays up across reboots, with or without
an uplink:
/etc/hostapd/hostapd.conf, starting from hostapd.conf.example beside it. 46_hostapd
starts hostapd at boot only when that file exists.Tell NetworkManager to leave the wireless card alone, or both will try to drive it: create a file
in /etc/NetworkManager/conf.d containing
[keyfile]
unmanaged-devices=interface-name:<interface>
dnsmasq of your own on it for DHCP and DNS
(interface=, bind-interfaces, dhcp-range=), from an init script of your own in
/etc/init.d. bind-interfaces is required: NetworkManager’s dnsmasq already answers on
127.0.0.1:53 and ::1:53, and a second one without it tries the wildcard address, fails with
the port in use, and serves no clients.10.42.0.0/16, so add a file in /etc/nftables.d that accepts
udp dport { 53, 67 } and tcp dport 53 with iifname "<interface>" in the input chain —
and, if clients should reach anything beyond this machine, accepts forwarding from that
interface. See Adding your own rules.Three programs answer other machines. Each has a name in the firewall that must be turned on first; the shipped policy blocks them all.
| Program | Start it with | Firewall name |
|---|---|---|
| Syncthing | File Sync in the menu, which runs kdos-syncthing in a terminal and opens the web interface on 127.0.0.1:8384. Closing the terminal stops syncing |
syncthing, on both machines |
| mosh | mosh <user>@<host> from the other machine; mosh-server is started over SSH |
ssh and mosh |
| Caddy | caddy run --config /etc/caddy/Caddyfile, which serves kiwix-serve (expected on port 8080) over HTTPS on port 8443, with a certificate from Caddy’s own local authority |
caddy |
kdos-syncthing gives a user who has no Syncthing configuration one with local discovery on, and
global discovery, relays, NAT traversal and usage reporting off: two machines on one network find
each other, and nothing reaches a server outside it. An existing configuration is left as it is.
/etc/nftables.conf holds the firewall policy, and 25_nftables loads it before the network
starts, so the machine is never on the network unfiltered.
What the shipped policy does:
| Traffic | Rule |
|---|---|
| Incoming | Dropped unless a rule below accepts it |
| Forwarded | Dropped unless a rule below accepts it |
| Outgoing | Accepted |
| Replies to connections this machine opened | Accepted, incoming and forwarded |
| Invalid packets | Dropped |
| Loopback | Accepted |
| ICMPv6 | Accepted: destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, router advertisements, neighbour solicitation and advertisement |
| ICMP | Accepted: destination-unreachable, time-exceeded, parameter-problem, echo-request |
| mDNS (UDP 5353), DHCPv6 client (UDP 546) | Accepted |
| NetBIOS name replies (UDP 137 to 137) | Accepted |
DNS (UDP and TCP 53) and DHCP (UDP 67) from 10.42.0.0/16 |
Accepted |
Anything to or from 10.42.0.0/16 |
Forwarded |
DNS (UDP and TCP 53) from a podman* bridge |
Accepted |
From a podman* bridge, or to one through a published port |
Forwarded |
Why the less obvious rows are there:
10.42.0.0/16 is kdos-net’s hotspot. NetworkManager gives each shared connection a /24
from that range and runs dnsmasq on it. A packet this firewall drops cannot be let through by
NetworkManager’s own rules, so without these rows a client joins the hotspot and never gets an
address. Outside that range the ports stay closed.podman* covers rootful podman’s bridge networks — sudo podman run, rootful distrobox and
any network podman network create makes. These rows live in /etc/nftables.d/40-podman.nft.
Without them a container gets an address, reaches nothing, and cannot resolve names, because
aardvark-dns answers on the bridge’s own address. Rootless boxes forward nothing and need
neither.kdos-mount browse finds no file servers. Nothing on the image
listens on port 137.Anything that should be reachable from another machine needs a rule — sshd, a shared printer and a served offline library are all blocked by default. There are two ways, and they do not interfere with each other.
By name, with kdos-firewall (the Firewall tool in Settings, under System) or the command
kdos-power firewall:
kdos-power firewall list # every name, and whether it is on
kdos-power firewall ssh on
kdos-power firewall ssh off
| Name | Opens |
|---|---|
ssh |
TCP 22 |
http |
TCP 80 |
https |
TCP 443 |
ipp |
TCP 631 (sharing a printer) |
smb |
TCP 445 |
kiwix |
TCP 8080 (kiwix-serve) |
mdns |
UDP 5353 |
mqtt |
TCP 1883 and 8883 |
xmpp |
TCP 5222 |
nfs |
TCP 2049 |
babel |
UDP 6696 (Babel mesh routing, babeld) |
nut |
TCP 3493 (UPS status for other machines) |
snmp |
UDP 161 (the SNMP agent, snmpd) |
mumble |
TCP and UDP 64738 (a Mumble voice server) |
caldav |
TCP 5232 (Radicale’s calendars and contacts) |
mail |
TCP 25, 143, 465, 587 and 993 (Maddy) |
irc |
TCP 6667 and 6697 (ngIRCd) |
dlna |
TCP 8200, and UDP 1900 for discovery (MiniDLNA) |
tryton |
TCP 8000 (the GNU Health server) |
caddy |
TCP 8443 (the shipped Caddyfile’s site) |
mosh |
UDP 60000–61000; also needs ssh |
syncthing |
TCP and UDP 22000, and UDP 21027 for discovery |
kdeconnect |
TCP and UDP 1714–1764 (KDE Connect with a phone) |
vnc |
TCP 5900 (wayvnc; it binds 127.0.0.1 unless given an address) |
xonotic |
UDP 26000 (hosting a Xonotic game) |
Turning a name on or off needs membership of wheel. The meaning of each name is fixed inside
kdos-powerd, not in the tool you click, so no client can open a port that is not on this list.
kdos-powerd rewrites /etc/nftables.d/50-kdos-services.nft completely on every change and
reloads the firewall, so do not put your own rules in that file: they disappear at the next
toggle.
Anything else is an edit. /etc/nftables.conf carries commented examples in its input chain,
and its last line, include "/etc/nftables.d/*.nft", reads every .nft file in that directory. A
file of your own there is never touched by kdos-firewall. For example,
/etc/nftables.d/60-local.nft, opening TCP 3000 for a development server, a port no firewall
name covers:
table inet filter {
chain input {
tcp dport 3000 accept
}
}
Add to table inet filter and do not declare a table of your own. Reloading deletes and rebuilds
only inet filter, so that netavark’s inet netavark table (rootful containers’ address
translation and published ports) and NetworkManager’s nm-shared-* tables (the hotspot) survive; a
table of your own would survive too, keeping its old rules beside the new ones. Name the chain
without a type … hook line — that re-opens the existing chain, while repeating the hook declares a
second chain and the load fails.
Check, then apply:
sudo nft -c -f /etc/nftables.conf # check only
sudo service nftables start # apply
25_nftables runs the same check before loading, so a file with a mistake is refused as a whole
and the rules already loaded stay in force. sudo service nftables stop removes the inet filter
table, which leaves the machine unfiltered until the next start.
linux-firmware is installed with upstream’s own script so that the alias links drivers ask for
exist. It ships every blob an x86 kernel can request: only firmware for hardware this kernel cannot
drive is left out (see the ports catalogue). Trimming by
guessing at your hardware would fail silently, so nothing an x86 driver names is removed.
sof-firmware is separate and is needed for audio on Intel Tiger Lake and newer. It carries both
the DSP firmware and the topology files; firmware without its topology loads and produces no sound.
wireless-regdb, the table of which radio channels and power levels each country allows, is built
from upstream’s db.txt and ships with upstream’s signature. The kernel checks that signature, and
rejects an unsigned or altered database silently, leaving the radio on the restrictive world
settings: no 5 GHz DFS channels and reduced transmit power. The build verifies the signature
against the database it produced and fails on a mismatch, so an edited db.txt never ships.
The country comes from your time zone. The installer and kdos-power timezone <Area/City> both
write the zone’s country code to /etc/modprobe.d/kdos-regdom.conf as cfg80211’s
ieee80211_regdom. kdos doctor warns when the radio is still on the world domain 00, and
sudo iw reg set <CC> changes it until the next boot.
CPU microcode is applied by the kernel’s early loader, which runs before any filesystem exists, so
it is carried as an uncompressed archive in front of the initramfs: Intel’s from the intel-ucode
package and AMD’s from linux-firmware. Late loading is off in the kernel, so this is the only way
microcode is applied.
kdos doctor # whether the initramfs carries this CPU's microcode, and the running revision
The check exists because an initramfs rebuilt without microcode has no symptom: the processor keeps whatever revision the firmware loaded.
Opening a device as a normal user takes two things: membership of a group, and a udev rule that
gives that group the device. Neither works alone. The KDOS rules live in /etc/udev/rules.d:
| Rules file | Devices | Group |
|---|---|---|
70-kdos-serial.rules |
USB serial adapters — FTDI, CP210x, CH341, CDC-ACM | dialout |
70-kdos-debug.rules |
In-circuit debuggers and programmers, raw USB and HID: CMSIS-DAP from any vendor, ST-Link, J-Link, Atmel-ICE, PICkit, USBasp, USB-Blaster, XDS110, Nu-Link, KitProg and the rest of openocd’s and openFPGALoader’s cables | dialout |
70-kdos-sdr.rules |
Software-defined radio front ends: every RTL2832U stick librtlsdr knows, HackRF, Airspy, bladeRF, SDRplay and Mirics, LimeSDR, the USRP B-series, ADALM-Pluto, the FUNcube Dongles (their HID node too), Perseus, RFNM and Fobos | dialout |
70-kdos-usbtmc.rules |
USB Test & Measurement: scopes, meters, function generators — /dev/usbtmc* and the raw USB device pyvisa-py opens |
dialout |
70-kdos-sigrok.rules |
Every logic analyser, scope and meter libsigrok’s 60-libsigrok.rules marks |
dialout |
70-kdos-gpio.rules |
/dev/gpiochip*, for libgpiod’s tools and the GPIO cables of openocd and openFPGALoader |
dialout |
70-kdos-fido.rules |
FIDO2/U2F security keys, for ssh-keygen -t ed25519-sk and the fido2-* tools |
dialout |
70-kdos-camera.rules |
PTP/MTP cameras, for gphoto2 | dialout |
70-kdos-scanner.rules |
Flatbed and sheet-fed scanners, for SANE | dialout |
70-kdos-ptouch.rules |
Brother P-touch label printers, which ptouch-print drives over raw USB |
lpadmin |
70-kdos-gamepad.rules |
Game controllers’ raw HID, for SDL’s HIDAPI drivers | input |
70-kdos-i2c.rules |
The DDC/CI line of a display controller, for ddcutil |
video |
70-kdos-backlight.rules |
The panel’s brightness for kdos-osd, and the keyboard backlight where there is one |
video |
One more file there grants no group: 99-qemu-tablet.rules marks QEMU’s emulated USB tablet as a
plain pointer, so in a virtual machine the pointer is handled as a mouse rather than as a graphics
tablet or a joystick.
Packages add two more: libmtp’s rules give phones to dialout, and gpsd’s
/usr/lib/udev/rules.d/70-kdos-gpsd.rules handles GPS receivers (below).
Every rule that names a device node sets MODE="0660", readable only by the owner and group, so
other accounts on a shared machine cannot read these devices.
Some rules are deliberately narrow:
ATTRS{class}=="0x03*"). /dev/i2c-* also covers the chipset’s SMBus, where every memory
module’s configuration chip sits, and a stray write there can leave a machine that will not boot.
ddcutil ships a broader rule of its own, which its package removes.GROUP= or MODE=, because a backlight has no node in /dev and udev
discards such a rule whole. It runs chgrp video and chmod 0664 on the brightness file
instead, on the add event that 01_udev’s coldplug replays at boot.Upstream rules that grant access through a plugdev group or uaccess are not installed: there is
no plugdev group, udev turns an unknown group into root, and nothing here uses uaccess. That is
why libfido2’s 70-u2f.rules and the rules of rtl-sdr, hackrf, airspy, bladeRF, openocd and
openFPGALoader are absent, and the KDOS files above cover their devices. stlink’s are removed
because they make every ST-Link writable by every account (MODE:="0666"). Where upstream
separates identifying a device from granting it, the identification is kept and the grant is
KDOS’s: libsigrok’s 60-libsigrok.rules sets ID_SIGROK, sane-backends’ 20-sane.hwdb and
65-libsane.rules set libsane_matched, and eudev’s fido_id sets ID_SECURITY_TOKEN; each
70-kdos-* file turns its mark into the group. So the FIDO rule covers every key whose HID
descriptor declares FIDO, and the scanner rule every scanner a SANE backend supports.
Modules loaded by name. Some drivers declare nothing udev can match, so files in
/etc/modules-load.d load them at boot through 02_modules:
| File | Loads | Without it |
|---|---|---|
kdos-i2c.conf |
i2c-dev |
No /dev/i2c-*, and the i2c rule has nothing to grant |
kdos-hwmon.conf |
nct6775 (Nuvoton), it87 (ITE), drivetemp (SATA disk temperature) |
sensors and kdos-res show CPU and GPU temperatures only — no fans, voltages or board temperatures |
kdos-containers.conf |
tun, overlay |
Container networking and overlay storage |
kdos-drm.conf |
virtio_gpu, qxl, bochs, vmwgfx |
Virtual machines’ display drivers |
Each hwmon driver binds only a chip it finds; on other hardware, or where the firmware has claimed
the chip, the load fails and 02_modules logs a skip. sensors-detect is not shipped, because it
probes the SMBus by writing to it. fancontrol is shipped, and nothing starts it.
One blacklist. /etc/modprobe.d/kdos-sdr.conf blacklists dvb_usb_rtl28xxu. Otherwise the
kernel claims an RTL2832U dongle as a TV tuner when it is plugged in, and SDR programs cannot open
it even though lsusb lists it.
Software-defined radio. Each radio the SDR rule covers has its own library and tools — rtl-sdr,
hackrf, airspy and bladerf — and a SoapySDR module: soapyrtlsdr, soapyhackrf,
soapyairspy and soapybladerf, in /usr/lib/SoapySDR/modules0.8. SoapySDRUtil --find lists
what is plugged in, and a SoapySDR program reaches it, for example rtl_433 -d driver=hackrf. A
bladeRF streams nothing until its FPGA image is loaded; that image is Nuand’s and is not shipped,
so put it in ~/.config/Nuand/bladeRF/ or /etc/Nuand/bladeRF/, or let a bladeRF 2.0 load it from
its own flash. SDRplay receivers are granted but have no driver, because SDRplay’s API is a closed
library.
Drawing tablets need no group. The compositor opens them through libinput, which uses
libwacom’s database to pair the stylus with its pad, group the pad’s buttons and rings, and tell
a screen tablet from a desk one. libwacom-list-local-devices shows what it recognised. A model
missing from the database works as a plain absolute pointer. To add it, describe it in a .tablet
file under /etc/libwacom, then run libwacom-update-db --skip-systemd-hwdb-update followed by
sudo udevadm hwdb --update (the tool’s own last step would call systemd-hwdb, which this system
does not have).
GPS receivers. Plugging one in starts gpsd; no init script runs it at boot. gpsd’s
70-kdos-gpsd.rules runs gpsd.hotplug for receivers whose USB ID identifies them — u-blox,
Garmin, DeLorme, the Holux MediaTek, the Telit module — and for the kernel’s gnss devices, and
gpsdctl adds the device to a running gpsd or starts one. Upstream’s rule also matches the
generic CP2102 and ATEN serial chips, which would make gpsd probe every ESP32 board and USB serial
adapter, so it is not installed. Hand over a receiver behind a generic chip with
sudo gpsdctl add /dev/ttyUSB0; until something is added, localhost:2947 refuses connections.
Without the group and the rule, a serial programmer, development board, instrument or GPS receiver
looks like a broken cable rather than a permission problem. kdos doctor checks the serial
(/dev/ttyUSB*, /dev/ttyACM*), video capture (/dev/video*) and USBTMC (/dev/usbtmc*) nodes
that are present, lists the ones you cannot open, and names the group that owns each.
bluetoothd is started by 60_bluetooth. kdos-bt (Super+F5, or Bluetooth in Settings, under
Hardware) scans, pairs, trusts and connects devices, and registers the pairing agent: without an
agent to confirm the passkey, the service refuses to pair a keyboard. kdos-audio (Super+F3) has
a Bluetooth pane as well, for connecting a headset. bluetoothctl is the same control from a
terminal, for scripting. Which profile and codec a headset uses is PipeWire’s decision, not the
pairing tool’s; see kdos-shell.
None of these runs under the supervisor. boltd and fwupd are started by the system bus on
first use and run as root through dbus-daemon-launch-helper; libmtp and opensc are
libraries; a phone’s storage is mounted by a FUSE process of your own.
Thunderbolt. Where the firmware’s Thunderbolt security level is user or secure — the
default on most business laptops — a TB3 or TB4 dock is detected and then never authorised, so its
ports stay dead until something approves it. boltd approves a dock already enrolled: 43_boltd
starts it at boot on a machine with a Thunderbolt controller, and a udev rule starts it when a
Thunderbolt device appears later. Enrol a new dock with sudo boltctl enroll <uuid>. boltd is
built to trust wheel and ships a polkit rule for it, but that rule also requires an active
session, which nothing on KDOS provides, so the command needs sudo — see
Security model.
Firmware updates. fwupd updates the firmware of SSDs, docks and peripherals from the LVFS, the
Linux Vendor Firmware Service. Run sudo fwupdmgr get-updates to see what is available and
sudo fwupdmgr update to apply it; the metadata is refreshed daily by /etc/kdos/timers.d/30-fwupd-refresh.timer.
System firmware — the BIOS, the embedded controller, and anything the vendor ships as a UEFI
capsule — is applied at the next boot. fwupd places the capsule on the EFI system partition, which
it expects at /boot/efi (EspLocation in /etc/fwupd/fwupd.conf, matching the installer’s
fstab). Then either the firmware picks it up from disk, or the machine boots once into
fwupdx64.efi (from fwupd-efi, placed in EFI/kdos beside the kernel), which hands it over.
fwupd’s usual way of finding that partition is to ask udisks; the fwupd package is patched to
describe the FAT filesystem mounted at EspLocation from sysfs and the udev database instead. The
live image mounts no EFI partition, so there only devices updated over USB are offered. The loader is unsigned, which is
no extra restriction, since KDOS already requires Secure Boot to be off (see
Known gaps).
Phones. libmtp recognises a phone and gives its USB device to dialout. To browse its
storage, unlock the phone, set it to file transfer, and open Android File Transfer from the Start
menu, which copies to and from the phone with no mount. For a directory instead, run
aft-mtp-mount ~/Phone (from android-file-transfer); any file manager can then read ~/Phone,
and fusermount3 -u ~/Phone unmounts it. kdos-mountd does not offer MTP devices, so this is
always by hand. libmtp’s own mtp-* tools reach files by numeric ID only. gphoto2 and libgphoto2 cover still cameras in PTP
mode.
Smart cards. pcscd and ccid reach the reader, and opensc-pkcs11.so speaks PIV, CAC,
OpenPGP and national ID cards. Its opensc.module registers it with p11-kit, so openconnect accepts
a pkcs11: URI and GnuTLS programs see the card’s certificates; ssh -I /usr/lib/opensc-pkcs11.so
uses it directly. pkcs11-tool --list-slots tells you whether the card is seen at all. Members of
wheel reach smart cards without sudo.
CUPS is the print system, started by 80_cups. The installer turns it off by default, so on an
installed machine enable it before the first print job:
sudo service enable cups
sudo service start cups
kdos-print (Printers in Settings, under System) lists the queues and their jobs, and adds a
printer CUPS has discovered. It runs as you, not through a root daemon: CUPS is built with
lpadmin as its system group, so membership of lpadmin is the authority to manage printers, and
the kdos account has it. It sets a printer up only as IPP Everywhere, the driverless protocol a
printer advertises and CUPS configures without a PPD file; a printer that needs a vendor driver is
refused, and the window says so. The same from a terminal:
lpinfo -v # the device URIs CUPS can reach
lpadmin -p <name> -v <uri> -m everywhere -E # add and enable a driverless queue
lpstat -p -d # the queues, and the default
81_cups-browsed adds printers shared on the network to CUPS as they appear, and 82_ipp-usb
serves each IPP-over-USB printer on localhost as it is plugged in, so a USB printer is discovered
the same way. Sharing a printer with other machines needs the ipp name in
the firewall. How kdos-print is built is in
kdos-shell.
ffmpeg is built with the full codec set: H.264, HEVC, VP8/VP9, AV1 encode and decode, JPEG XL,
MP3, Opus, Vorbis, FLAC, LC3, subtitle burn-in, HDR tone mapping (zscale, libplacebo),
high-quality resampling (soxr), time-stretch (rubberband), SVG input (librsvg), text
recognition (the ocr filter, through tesseract), QR codes (qrencode and qrencodesrc), the
OpenCL filters (tonemap_opencl, nlmeans_opencl, unsharp_opencl, overlay_opencl and the
rest) and hardware acceleration through VA-API and Vulkan. There is one encoder per format. There
is no ffplay, because it needs SDL, and SDL depends back on ffmpeg through PipeWire.
The OpenCL filters run on Mesa’s rusticl, which offers an Intel or AMD GPU because
/etc/profile.d/50-opencl.sh sets RUSTICL_ENABLE; a machine with neither has no OpenCL device.
The build passes --enable-gpl (which x264, x265 and rubberband require) together with
--enable-version3, and ffmpeg’s configure licenses that combination as GPL version 3 or later.
Everything that links it inherits that licence. LICENSE.notice in the ffmpeg port
(ports/core/media-frameworks/ffmpeg/) is the notice a redistributor should read.
Hardware video decoding goes through VA-API, and the driver depends on the GPU:
| GPU | Driver |
|---|---|
| AMD (r600, radeonsi), NVIDIA through nouveau, virgl | Mesa’s gallium-va |
| Intel, Broadwell and newer | intel-media-driver (iHD), over intel-gmmlib |
| Intel Sandy Bridge, Ivy Bridge, Haswell | libva-intel-driver (i965) |
libva tries iHD first and falls back to i965, so each machine loads the one that serves it.
With no driver, ffmpeg and mpv silently fall back to software decoding. vainfo, from
libva-utils, lists the profiles the loaded driver offers on this machine.
mpv is the native player. Its --vo=gpu-next renderer uses Vulkan where a device answers and
OpenGL through EGL otherwise. An external subtitle in a legacy encoding — CP1251, GBK, Shift-JIS —
is detected by uchardet and converted, and libass breaks long subtitle lines where Unicode
allows (through libunibreak), not only at spaces. The mpv-mpris plugin, loaded from
/etc/mpv/scripts for every user, puts mpv on the session bus, so the media keys and the panel’s
now-playing display control it.
Optical discs. mpv opens dvd://, bd:// and cdda://, and plays a DVD’s titles and
chapters without its menus. mpd and cmus play audio CDs; cd-paranoia rips one with verified
reads, and ffmpeg -f dvdvideo -i /dev/sr0 rips a DVD title with its chapters. GStreamer has
cdiocddasrc, dvdreadsrc and rsndvdbin, and rsndvdbin plays DVD menus. CSS-encrypted DVDs
and AACS-encrypted Blu-rays do not open, and Blu-ray Java menus do not run — see
Known gaps.
Other media abilities:
cmus plays .m4a (AAC and ALAC) through its ffmpeg input, alongside its own decoders for MP3,
FLAC, Vorbis, Opus and the rest.webrtcbin is built, with ICE from libnice and SRTP from libsrtp, for
peer-to-peer media pipelines.mutool barcode reads and draws QR codes and barcodes in a page or image, through zxing-cpp.textoverlay — breaks Thai text at word boundaries found by libthai, since Thai puts no spaces
between words.Colour. lcms2 is the colour management engine, and the only thing on the host that can apply
an ICC profile.
Time zones. The zone data is a compiled zoneinfo tree that musl reads directly, built in the
“fat” format rather than “slim”. Applications in containers read the same tree, and a format they
misread would make the host and its containers disagree about local time. The tree also carries
tzdata.zi, the text form of the same release, which C++ std::chrono time zones read; without it
libstdc++ falls back to the older copy compiled into it.
The zone is set with kdos-time (Date and time in Settings, under System) or
kdos-power timezone <Area/City>, both of which need membership of wheel. kdos-powerd then
rewrites two files together: /etc/localtime, the link programs follow into the zoneinfo tree, and
/etc/profile.d/20-timezone.sh, which sets TZ for every login shell. A shell opened before the
change keeps the old TZ until it is restarted. The same change writes the wireless regulatory
country (see Firmware). On a machine where nothing has chosen a zone, rcS links
/etc/localtime to UTC at boot. The clock itself is kept by chrony (35_chrony), and kdos-time
shows whether it is synchronised.
kdos cve # which installed versions have known vulnerabilities, offline
kdos cve --json # the same, as JSON
kdos update fetch # the newest signed ports tree, over the network, as /ports
kdos update check # what the ports tree pins that is not installed, and what went wrong
kdos update apply # fetch the sources and build it all here (see A/B root slots)
kdos app install <id> # install a boxed application (to update one, see Applications below)
Vulnerabilities. kdos cve compares your installed versions against a copy of Alpine’s security
database shipped in /usr/share/kdos/secdb.txt, with no network. It exits 1 when any package is
behind a recorded fix and 0 otherwise. A package that database does not carry is counted as
unknown, not clean, and the summary says how many there are. A library a program compiles into
itself, such as the AWS-LC inside six Rust programs, is listed under bundled copies with its
version, and checked like a package. Every run prints the database’s date, and warns when it is
more than 180 days old.
Host packages are built from ports — the recipes in the KDOS source tree (see the
glossary). What counts as “an update” is a newer ports tree, so
kdos update needs one on the machine, and every image carries one at /ports: each port’s
kpkgbuild, build.sh and patches, ports/shelves, ports/sources.idx, KDOS’s own programs
under /ports/src and the book they render under /ports/docs, with no source archive. PORT_REPO in /etc/kpkg.conf names where kpkg
looks: a space-separated list of recipe directories, by default the five of that tree,
/ports/core /ports/src/system /ports/src/art /ports/src/desktop /ports/src/daemons. The KDOS
source tree keeps its recipes in the same five directories — ports/core for upstream software,
each port one shelf down in ports/core/<shelf>/<name>/, and src/system, src/art,
src/desktop and src/daemons for KDOS’s own programs. A repository is searched for a port at
<name>/ and one shelf down, never deeper; the shelves are not listed separately. For a complete
checkout of the KDOS repository at DIR:
PORT_REPO="DIR/ports/core DIR/src/system DIR/src/art DIR/src/desktop DIR/src/daemons"
A stick built with KDOS_ISO_SOURCES=1 also carries the whole tree, fetched sources included,
under /mnt/iso/sources (see kdos rebuild), whose five directories can be named
the same way. Without a ports tree kdos update check says
so and exits 2. The
ports catalogue lists every port by shelf, with the phase that builds it, and
How KDOS is built follows a port from recipe to installed
package.
| Command | Does |
|---|---|
kdos update fetch |
Downloads the latest release’s ports tree, checks its signature against /etc/kdos/keys/tree, and installs it as /ports. A tree older than the installed one is refused. --from URL or --from DIR (a stick holding kdos-ports.tar.xz and its .sig) reads it from elsewhere |
kdos update check |
Lists installed packages that differ from the ports tree, and the last problem: no tree, no network, a fetch or a build that failed. --json prints JSON; --out PATH writes that JSON to a file; --fetch runs fetch first (the nightly timer uses both, for the panel’s update badge) |
kdos update apply |
Downloads the sources of every out-of-date package, then builds and installs each one. --dry-run lists what would be built; --root DIR installs into another root |
kdos update theme |
Re-runs the theme generators for your home directory after an artwork upgrade |
Updates are built here, from source, and need the network. There is no binary package server.
kdos update fetch downloads the newer recipe tree, and kdos update apply downloads every source
it names, from the KDOS source archive first and from upstream second, each checked against the
recipe’s sha256 = before use. It fetches them all before it compiles anything, so a machine that
is offline finds out in minutes. Then it compiles every package that is behind on this machine:
a few packages take minutes, a large set (a new compiler, a browser, Qt) takes hours. fetch and
apply run as root. tree = URL or tree = DIR in /etc/kdos/update.conf sets where trees come
from instead of the latest release. The panel’s update badge counts the packages behind, and turns
to the warning colour, or to ! when nothing is behind, when the last fetch or apply failed or the
machine has no tree; hovering it says which.
A/B root slots. On a machine installed with two root slots, kdos update apply installs into
the inactive slot, which must be mounted, checks it with kpkg check (a missing file, or a
changed one outside /etc, stops it; configuration edited under /etc is listed and does not),
copies /ports into it,
then installs that slot’s kernel with kdos-bootctl deploy and marks the slot to be tried on the
next boot. The running system is not
touched, so a bad update can be rolled back by booting the other slot. If the inactive slot is not
mounted it refuses; --in-place updates the running root instead and gives up that rollback. See
Boot and init for how a tried slot is confirmed, and
Known gaps for what the updater does not do.
Applications have no separate update command. An application is a stack of images this machine
built, so rebuilding it is the update: kdos app remove <id> and then kdos app install <id>
rebuild the application’s own image. Under the shipped snapshot = auto the rebuild reads the same
Debian snapshot as before, because the pulled debian:trixie-slim is kept; its packages move to a
newer snapshot only when the catalogue names a later date or this machine pulls a newer
debian:trixie-slim. Installing an application
that is already installed builds nothing and is reported as a failure: every image is already
there, kdos-box create refuses because the box exists, and the command ends with
1 of 1 did not install. See Applications.
kdos doctor # checks kernel, hardware, session, container and desktop set-up
kdos doctor --json # the same, as JSON
kdos status # what this machine is and what it is running
kdos restarts # which running processes still use code an upgrade replaced
kdos why <thing> # what provides something, and why it is that way
kdos stutter # why the desktop hiccuped, naming the application
kdos cve # known vulnerabilities (kdos doctor --cve runs the same report)
Run kdos doctor first when something is wrong. Each line is ok, warn, or skip with a
reason: much of what it checks cannot be answered in a virtual machine, and reporting those as ok
would claim something never tested. It exits 0 when nothing warned and non-zero otherwise, in both
the text and the JSON form, so a script can act on the status alone. --cve runs the
vulnerability report instead (see Keeping it current).
The checks are grouped into sections:
| Section | Checks |
|---|---|
| Kernel | Landlock, the kernel’s unprivileged file and network sandbox that kdos sandbox uses, is present and enabled; the initramfs carries this CPU’s microcode, and the running revision |
| Hardware | The wireless regulatory database is signed and loaded, and the domain is not the world domain 00; Intel audio firmware (sof-firmware); GPU firmware; device nodes you cannot open, naming the group that owns each (see the udev rules); the boot medium |
| Boxes | The application packs |
| Session | WAYLAND_DISPLAY names a socket that exists; XDG_RUNTIME_DIR is set; kdos-comp, kdos-shell and the wlr desktop portal are running |
| Containers | The mount namespace root is /, and /etc/subuid and /etc/subgid carry your range |
| Desktop | The accent, the foot theme and the KDE palette (kdeglobals) are applied; Xwayland is reachable; the setuid bits on kdos-checkpass, kdos-resctl, newuidmap and newgidmap, and on dbus-daemon-launch-helper with group messagebus; /etc/subuid and /etc/subgid exist; kdos-powerd, kdos-energyd (or the absence of any RAPL energy counter) and kdos-oomd are running, and fcitx5 when it is installed; the compositor’s frame-timing and command sockets exist; kdos-keys and the screen-capture portal with kdos-portals.conf are installed; ~/.local/bin is on PATH |
| Security | Run as root only: whether the kdos account still has the shipped password kdos |
Without its setuid bit, kdos-checkpass cannot read /etc/shadow, so the lock screen refuses every
password and locks you out of your own session, recoverable only from tty2; the fix it prints is
chown root and chmod 4755. The shipped-password check needs to read /etc/shadow, so an
ordinary user’s run has no Security section at all rather than a check that pretends to have
looked; run sudo kdos doctor to get it, and expect the session and container checks of that run
to warn, since root has no desktop session.
service list and service status <name> show each service’s state. After an upgrade,
kdos restarts lists the running processes that still use code the upgrade replaced or removed;
each keeps the old version until it restarts. See
kdos restarts.
syslogd (from sysklogd) writes the system log. It reads the kernel’s messages itself, so there is
no separate klogd. /etc/syslog.conf routes them:
| File | Holds |
|---|---|
/var/log/messages |
Everything except authentication |
/var/log/auth.log |
Logins, sudo and other authentication |
/var/log/kern.log |
Kernel messages |
/var/log/cron |
The cron facility; nothing on the image logs there by default |
syslogd rotates each file itself at 1 MB and keeps five old copies, so no logrotate job exists.
The limit matters on the live medium, where /var/log is in RAM and an unbounded log would take
memory rather than disk. Emergency messages are also written to every logged-in terminal.
Three more places hold what the system log does not:
| Where | Holds |
|---|---|
dmesg |
The kernel’s ring buffer, including messages from before syslogd started |
/run/kdos-init.<name>.log |
The output of each service script at boot (see Services) |
/run/kdos-fsck.log |
The boot-time filesystem check (see Storage) |
A supervised daemon’s restarts and final exits ([KDOS] (name) Exited with code …) appear in its
service’s boot log.
sudo kdos clone /dev/sdb # write this medium to another stick
kdos rebuild /mnt/disk/work # run the build from a source tree on this machine
kdos clone copies the medium this system booted from onto another device, byte for byte, then
reads it back to verify. The boot arrangement is whatever the medium already carries, so the copy
boots exactly what the original boots. With no device named, it lists the devices it would accept.
| Option | Does |
|---|---|
--source <path> |
Clone an image file or another device instead of the boot medium. Required on an installed system, which has no boot medium to copy |
--extent |
Print the image’s exact length and stop |
-y, --yes |
Do not ask before overwriting. Required when not run from a terminal |
--no-probe |
Skip the counterfeit-capacity test (f3probe) |
--no-verify |
Skip the read-back, and say what that costs |
The length copied comes from the image’s own description, not from the device, so a 3 GB image on
a 64 GB stick copies 3 GB. To confirm, you type the device’s name, not y. Before writing
anything it refuses the medium the system booted from, any disk with a filesystem mounted, anything
named in /etc/fstab, and any device smaller than the image.
Before writing, f3probe tests whether the stick really has the capacity it reports — a counterfeit
stick silently wraps around and loses data. The verify drops the page cache before reading back:
otherwise the kernel would return the bytes it just wrote from memory, not what the flash stored,
and a counterfeit stick would pass.
kdos rebuild <work-directory> runs the KDOS build on a booted system, with no network. It looks
for a source tree wherever KDOS_SOURCES points, then at /mnt/iso/sources, /kdos and the
current directory, and accepts one that has script/kdosbuild.sh, ports/core, fs/etc and
src/devtools/kdosbuild.
A stick built with make build KDOS_ISO_SOURCES=1 carries a copy under /mnt/iso/sources: the
ports tree with every fetched source beside its recipe, src/, script/ and the fs/ overlay of
system files. The Makefile and the Dockerfile are not copied. kdos rebuild copies the tree to
the work directory and runs the build there, with KDOS_WORKSPACE naming the copy so that the
host phases read fs/ from it rather than from /workspace. No rebuild from a medium has yet
been run through every phase; see
Why KDOS and
The kdos command.
| Option | Does |
|---|---|
--dry-run |
Run the checks and stop |
--iso-only |
Rebuild only the image phase, 70_image, which produces the ISO |
The checks are what make it safe to start. The work directory needs about 25 GB, and is refused if
it is on a temporary or overlay filesystem: a live stick’s root is RAM, so a rebuild started there
reports gigabytes free, fills memory and dies hours in. It also stops if a compiler, make, bash,
tar or xz is missing, and warns that no ISO will be produced if mksquashfs, xorriso or
mkfs.fat is.
kdos march probe # which instruction set levels this CPU has
kdos march run lz4 # build lz4 twice and measure
kdos march report # the ledger: kept, reverted, unmeasurable
kdos march probe reports which of the x86-64 instruction set levels beyond the baseline
(x86-64-v2, -v3 and -v4) this CPU supports. kdos march run <port> builds a port with and
without -march= set to the highest of them, runs the benchmark named by the bench = line in
that port’s recipe against both builds (the median of five runs by default), and keeps the faster
flags only where the gain exceeds 3 per cent plus this machine’s own measured noise. A difference
inside the noise is recorded as reverted, and a port with no bench = line is reported as
unmeasurable. The decisions are kept in /var/lib/kdos/march.ledger, and
kdos march report lists reverted ports as prominently as kept ones. On a CPU with only the
baseline level there is nothing to measure, and it says so.
kdos-backup backs up with restic. Opened from the menu it is a window
listing the snapshots in your repository, newest first: b starts a backup (it does not wait for
it to finish) and r re-reads the repository. kdos-backup --once backs up without a window, waits
for restic, and exits 0 on success, 1 on any failure and 2 on a bad argument; that is what the
timer runs.
Set it up once:
restic -r <repo> init. It asks for a password twice and does not store
it anywhere.~/.config/kdos/backup.pass, and make it private with
chmod 600 ~/.config/kdos/backup.pass. kdos-backup refuses to run while the file is readable
by anyone else.Edit ~/.config/kdos/backup.conf (one key = value per line, # starts a comment):
| Key | Means | Repeats |
|---|---|---|
repo |
Where the repository is | No; the last line wins |
include |
A path to back up | Up to eight; more are ignored |
exclude |
A path to leave out | Up to eight; more are ignored |
password-file |
The password file, when it is not ~/.config/kdos/backup.pass |
No; the last line wins |
kdos-backup --once and check that it succeeds.backup line in ~/.config/kdos/timers.d/10-backup.timer.--once stops with a message, before touching restic, if backup.conf names no repo or no
include, or if the password file is missing or readable by others. An enabled timer with no
configuration therefore does nothing harmful.
Restoring is a restic command, run by hand so its options are in front of you:
restic -r <repo> restore <snapshot> --target <dir>. restic help restore lists the options.
Mail is four programs sharing one directory. ~/Mail is a Maildir (one file per message), and
each program is pointed at it:
| Program | Does |
|---|---|
mbsync |
Fetches: makes an IMAP mailbox and ~/Mail the same, in both directions |
notmuch |
Indexes and searches what is there. It never fetches and never sends |
aerc |
Reads and writes |
msmtp |
Sends. /usr/sbin/sendmail and /usr/bin/sendmail both link to it |
notmuch new is the one command you type. Its pre-new hook runs mbsync -a before the scan and
its post-new hook removes the new tag from what arrived, so one command fetches and indexes.
The pre-new hook steps aside (exit 0) if mbsync is not installed, ~/.mbsyncrc is unreadable,
or that file names no Channel — so an unconfigured machine still indexes. Otherwise a failed
fetch fails notmuch new too, because indexing after a fetch that did not happen would report
“0 new messages” and look like an empty inbox.
Three files to fill in, all shipped with commented examples:
| File | Holds | Mode |
|---|---|---|
~/.mbsyncrc |
The incoming (IMAP) server | 600 |
~/.msmtprc |
The outgoing (SMTP) server | 600 |
~/.config/notmuch/default/config |
Your own address | 644 |
The two mode-600 files hold, or fetch, a password: msmtp refuses to send through an .msmtprc
that carries a password line and is readable by others. The image build sets both modes in the
skeleton copied into each new home.
~/.config/aerc/accounts.conf is not shipped. aerc refuses to start with one that anyone else can
read, and its own setup wizard writes it at mode 600 the first time you run aerc, so let the
wizard do it.
Keep passwords out of all of them. pass is installed, and the templates show
PassCmd "pass show …" (mbsync) and passwordeval "pass show …" (msmtp).
Five kinds of message part are shown as text. ~/.config/aerc/aerc.conf sends each to one
script, kdos-part; plain text, delivery reports and attached messages go through aerc’s own
colorize. A type not listed gets aerc’s No filter configured card, with its :open, :save
and :pipe hints. The [filters] section replaces aerc’s whole default set rather than adding to
it, which is why the plain-text rows are written out.
| Part | Shown as |
|---|---|
| HTML | w3m -dump, which lays tables out on the grid, so marketing mail is readable |
An invitation (text/calendar) |
aerc’s calendar filter, run through gawk. It only reads: a filter runs every time a message scrolls past, and one that imported invitations would accept every meeting you looked at |
mutool draw -F txt |
|
| An image | chafa, as coloured symbols, the same in every terminal. With no filter for images, aerc would instead draw a JPEG or PNG through the terminal’s graphics protocol, which kdos-term supports |
A .docx |
docx2txt |
kdos-part saves the part to a temporary file first, because mutool opens a document by path and
cannot read a pipe.
HTML is rendered where it cannot reach the network, so a tracking image has nowhere to report to.
kdos-part first tries unshare --map-root-user --net, which runs w3m with no network at all;
where the system refuses a new user namespace, it runs w3m behind an unreachable proxy instead.
It tests whether the namespace works rather than whether the unshare program exists — aerc’s own
HTML filter checks only the program, and where namespaces are refused it shows
unshare: Operation not permitted in place of the message.
XOAUTH2 sign-in works in the three programs that talk to a server: aerc speaks it itself, msmtp
has it built in, and mbsync reaches it through cyrus-sasl and its libxoauth2.so plugin, which
the image carries. pizauth obtains and refreshes the token. The plugin takes whatever SASL returns as the password
and sends it as the token, so PassCmd is the only configuration mbsync needs:
IMAPAccount work
AuthMechs XOAUTH2
PassCmd "pizauth show work"
OAUTHBEARER is not available to mbsync: the plugin implements XOAUTH2 only. A provider that
offers only OAUTHBEARER can be read in aerc and sent to through msmtp, but has no local Maildir
— and with it no notmuch index and no offline search.
pass is the password store: one file per entry in a git repository, each encrypted with gpg.
There is no database and no format to migrate; even without pass, gpg -d reads every entry.
For a site that asks for a six-digit code, save the otpauth:// link its QR code contains, then
ask for a code when you need one:
pass otp insert site/example # paste the otpauth:// link
pass otp site/example # the code for right now
pass otp -c site/example # and copy it to the clipboard
Nothing needs enabling: pass loads its installed extensions automatically. The code comes from
oathtool, which also works on its own: oathtool --totp -b <secret>.
There is no one-time code for logging in to this machine. oath-toolkit’s PAM module is not built:
a wrong line in the login stack locks everyone out, including whoever is trying to fix it. These
codes are for other people’s websites.
Calendars and contacts are plain files, like the mail. ~/.local/share/calendars holds calendars
and ~/.local/share/contacts holds address books, each as a vdir: one directory per collection,
one .ics or .vcf file per item. That can be searched with grep, compared with diff and backed
up by copying. A file holding two events is not a valid vdir entry; use khal import to bring one
in.
| Program | Does |
|---|---|
khal |
Prints what is on: khal list today 7d, khal import invite.ics |
ikhal |
The same calendar, full screen, to move around in. This is the Calendar menu entry |
khard |
The address book: khard list, khard show, khard new |
vdirsyncer |
Keeps a server’s collection and the local vdir the same, as mbsync does for mail. Unconfigured, vdirsyncer sync does nothing and exits 0 |
khal and khard refuse to start with no store configured, so the shipped configuration names
empty ones, and the image creates both directories in each new home: khal reads every directory
under ~/.local/share/calendars/, and khard reads the one address book
~/.local/share/contacts/personal. To add a calendar, make a directory under
~/.local/share/calendars and put .ics files in it; khal discovers it with no registration.
The panel’s calendar reads the same store: days with something on are marked, and today’s events
are listed under the month. It asks khal when it opens and when you change month, and runs
nothing between those times.
Syncing with a server is vdirsyncer, configured in ~/.config/vdirsyncer/config. A pair is
two storages plus the rule for settling conflicts. There is no safe default: a wins discards the
server’s edit and b wins discards yours, so the shipped example makes you choose. Run
vdirsyncer discover once, then vdirsyncer sync whenever you like. Keep the password out of the
file with password.fetch = ["command", "pass", "show", "…"].
khard list exits 1 on an empty address book and prints Found no contacts. That is its answer
for “nothing matched”, not a failure, so a script using it must treat that exit as an empty result.
plocate searches an index instead of the disk, so a search by name across your whole home reads
one index file instead of walking the tree, as fd does.
The index is per user. A timer in ~/.config/kdos/timers.d/ rebuilds it nightly at 03:05, covering
only $HOME, and writes it to ~/.cache/kdos/plocate.db, so it can only contain paths you could
already list. LOCATE_PATH, set in /etc/profile.d/40-plocate.sh, points plocate at it, and
locate is the same program under its usual name. Run kdos-updatedb to rebuild it now.
updatedb is plocate’s, in /usr/sbin. findutils’ own locate and updatedb are not installed,
because they read and write a different index format.
Upstream plocate is a setgid program reading one shared index for the whole machine; KDOS ships neither the setgid bit nor the shared index. The reasoning is in the security model.
KDOS is in English, and only English. Every package is made without its translations: the
message catalogs, the Qt translations, the translated KDE handbooks and the translated manual pages
are removed as it is built (see
the size and language policy), so
there is no other language for a program to switch to. /etc/profile sets LANG=C.UTF-8; setting
LANG or LC_MESSAGES to another language changes no program’s menus or messages.
Writing in another language is unaffected. The fonts cover every script, the keyboard layout is yours to choose, and the input methods below type Chinese, Japanese and Korean. What is missing is listed in Known gaps.
fcitx5 is the input method engine, for typing languages that need more than a keyboard layout:
Chinese (pinyin, shuangpin and the table methods), Japanese and Korean. The session starts it by
name if it is installed. It talks to kdos-comp through input-method-v2, and is configured
through text files under ~/.config/fcitx5/ — its graphical configuration tool is Qt and is not
shipped. Ctrl+Space switches method; that is fcitx5’s own binding, and the compositor does not
claim it.
The candidate window is KDOS’s. kdos-ime starts just before fcitx5 and owns org.kde.impanel,
so the text being composed and the list of candidates are drawn like every other KDOS surface.
fcitx5 prefers that panel over its own as soon as it appears; without kdos-ime, fcitx5 draws its
own window.
Cloud pinyin is compiled out: it would send what you type to a remote service.
kdos update can install, by shelfwheel means and what is not protectedPart II — Using KDOS, chapter 10. Previous: 9. Theming · Contents · Next: 11. Accessibility