Stage 6: server image with a console installer (0.4.0)
- server/ profile and build-iso.sh [desktop|server]; make iso-server, make qemu-server, run-qemu.sh --serial; login on tty and ttyS0 - das-server: SSH, chrony, NetworkManager/dhcpcd, Docker with Compose, nftables (closed except SSH, own table), fail2ban reading socklog, sshd without root passwords, Docker log rotation, tools - das-server-install: dialog installer in Ukrainian and English, or unattended with --config; GPT + Btrfs subvolumes, GRUB for UEFI and BIOS, serial console, SSH key with optional keys-only logins - das-install-common: mount-source and postinstall shared with Calamares - dsv: runit service manager (list, enable, disable, start, stop, restart, status, logs) with bash completion, also on the desktop - das-update split into a subpackage without GTK; the window and tray icon move to /usr/libexec/das/das-update-gui - das-snapper-setup enables dbus, which snapper needs - TODO: ISO size review with measured numbers and options Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
# Das OS build entry points. Everything except QEMU runs in the Void builder container.
|
||||
|
||||
.PHONY: help packages iso qemu qemu-bios qemu-disk test clean
|
||||
.PHONY: help packages iso iso-server qemu qemu-bios qemu-disk qemu-server test clean
|
||||
|
||||
help:
|
||||
@echo "make packages build srcpkgs/* into the local repository (out/hostdir/binpkgs)"
|
||||
@echo "make iso build packages, then the live ISO (out/iso)"
|
||||
@echo "make iso-server build packages, then the server ISO (out/iso)"
|
||||
@echo "make qemu boot the newest ISO in QEMU with UEFI"
|
||||
@echo "make qemu-bios boot the newest ISO in QEMU with legacy BIOS"
|
||||
@echo "make qemu-disk boot with a 20 GB virtual disk attached (for installer tests)"
|
||||
@echo "make qemu-server boot the newest server ISO on a serial console, with the disk"
|
||||
@echo "make test run Go tests"
|
||||
@echo "make clean remove build output (keeps download caches)"
|
||||
|
||||
@@ -17,6 +19,9 @@ packages:
|
||||
iso: packages
|
||||
scripts/builder.sh /work/scripts/container/build-iso.sh
|
||||
|
||||
iso-server: packages
|
||||
scripts/builder.sh /work/scripts/container/build-iso.sh server
|
||||
|
||||
qemu:
|
||||
scripts/run-qemu.sh
|
||||
|
||||
@@ -26,6 +31,9 @@ qemu-bios:
|
||||
qemu-disk:
|
||||
scripts/run-qemu.sh --disk
|
||||
|
||||
qemu-server:
|
||||
scripts/run-qemu.sh --serial --disk
|
||||
|
||||
test:
|
||||
cd srcpkgs/das-theme/files/xfwm4gen && go test ./...
|
||||
cd srcpkgs/das-tools/files/src && go test ./...
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
## Das OS
|
||||
### _A light, friendly Void Linux–based desktop with Xfce and a Ukrainian touch_
|
||||
### _A light, friendly Void Linux–based desktop with Xfce and a Ukrainian touch, plus a console server edition_
|
||||
|
||||
[](https://voidlinux.org) [](https://xfce.org) [](https://docs.voidlinux.org/config/services/) [](https://go.dev) [](#)
|
||||
[](https://voidlinux.org) [](https://xfce.org) [](https://docs.voidlinux.org/config/services/) [](https://go.dev) [](https://www.docker.com) [](#)
|
||||
|
||||
🇺🇦 [Українська версія](README_ua.md)
|
||||
|
||||
### 💡 Purpose
|
||||
Void Linux is fast, simple and independent: runit instead of systemd, and its own xbps package manager. Out of the box, though, it is a bare system, and getting it ready for daily use takes hours of setup. Das OS builds a live ISO that boots straight into a configured Xfce desktop and installs it with a graphical installer. It has its own look, a Ukrainian interface and keyboard layout, the usual desktop apps and Btrfs snapshots that let a broken update be undone. Everything Das OS adds comes from its own xbps packages, so the setup can be reproduced and updated like any other package.
|
||||
Void Linux is fast, simple and independent: runit instead of systemd, and its own xbps package manager. Out of the box, though, it is a bare system, and getting it ready for daily use takes hours of setup. Das OS builds a live ISO that boots straight into a configured Xfce desktop and installs it with a graphical installer. It has its own look, a Ukrainian interface and keyboard layout, the usual desktop apps and Btrfs snapshots that let a broken update be undone. Everything Das OS adds comes from its own xbps packages, so the setup can be reproduced and updated like any other package. A second, console-only ISO installs a server with SSH, a firewall, fail2ban and Docker set up, on the same Btrfs layout with snapshots.
|
||||
|
||||
### 📃 Features
|
||||
- [Live ISO](#LiveISO) that boots on UEFI and BIOS straight into the desktop
|
||||
@@ -14,6 +14,8 @@ Void Linux is fast, simple and independent: runit instead of systemd, and its ow
|
||||
- [Snapshots and rollback](#Snapshots): hourly Btrfs snapshots, bootable from the GRUB menu
|
||||
- [System update](#Update) with a snapshot taken before it: a window, a tray icon and a terminal mode
|
||||
- [Welcome window](#Welcome) at the first login: language, home folders, updates and help
|
||||
- [Server image](#Server): a console live ISO with a text installer, SSH, firewall, fail2ban and Docker
|
||||
- [Service manager](#Services) `dsv`: enable, start and read the logs of runit services, like systemctl
|
||||
- [Das OS look](#Look): light and dark themes, generated window frames, wallpapers and logo
|
||||
- [Desktop defaults](#Defaults) for Xfce that don't overwrite stock files
|
||||
- [Own package repository](#Repository) built by xbps-src from in-tree templates
|
||||
@@ -25,6 +27,7 @@ Void Linux is fast, simple and independent: runit instead of systemd, and its ow
|
||||
- **Light** – no systemd, plus Xfce, LightDM and PipeWire, so it runs well on older laptops too.
|
||||
- **Nothing hidden** – all customisations ship as ordinary xbps packages, so `xbps-query -f das-settings` shows exactly what changed.
|
||||
- **Users keep control** – defaults live in `/etc/xdg/das`, so a user's own settings always take precedence and upgrades never reset them.
|
||||
- **One base for desktop and server** – both images share the packages, the disk layout, snapshots and `das-update`, so a server is updated and rolled back the same way as a laptop.
|
||||
- **Builds anywhere** – the build runs in a Void container, so the host can be Mint, Ubuntu or Fedora.
|
||||
|
||||
### 📱 Screenshots
|
||||
@@ -62,12 +65,12 @@ Void Linux is fast, simple and independent: runit instead of systemd, and its ow
|
||||
<tr>
|
||||
<td align="center"><img src="images/welcome.png" width="300" alt="Welcome window" /></td>
|
||||
<td align="center"><img src="images/update.png" width="300" alt="System update" /></td>
|
||||
<td></td>
|
||||
<td align="center"><img src="images/server-installer.png" width="300" alt="Server installer" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><i>Welcome window</i></td>
|
||||
<td align="center"><i>System update</i></td>
|
||||
<td></td>
|
||||
<td align="center"><i>Server installer</i></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -88,7 +91,7 @@ Void Linux is fast, simple and independent: runit instead of systemd, and its ow
|
||||
- The interface is in Ukrainian by default, with the Kyiv time zone and Das OS branding and slides.
|
||||
- The disk can be erased automatically or partitioned by hand. Btrfs is the default, ext4 and XFS are also available. On UEFI machines it creates a 512 MiB EFI partition.
|
||||
- It copies the clean live image (`/dev/mapper/live-base`), without the live user and its boot-time settings.
|
||||
- After copying, it builds locales for the chosen language, removes the virtual machine guest tools on real hardware, sets up snapshots, builds the initramfs and installs GRUB.
|
||||
- After copying, it builds locales for the chosen language, keeps only the guest tools of the hypervisor it runs in (none on real hardware), sets up snapshots, builds the initramfs and installs GRUB.
|
||||
- When it finishes, it removes itself and the packages that only it needed.
|
||||
- Disk encryption is not offered yet.
|
||||
|
||||
@@ -108,7 +111,8 @@ Void Linux is fast, simple and independent: runit instead of systemd, and its ow
|
||||
- When it finishes, it shows the snapshot number and how to roll back to it, and asks for a reboot when the kernel, glibc, runit or other core packages were updated.
|
||||
- The *System update* window lists the packages with the installed and new versions and shows the xbps output. The privileged part runs through pkexec (polkit action `ua.org.das.update`).
|
||||
- In the background it checks for updates 2 minutes after login and then every 6 hours, without root. The tray icon and a notification appear only when updates are available. A click opens the window, and a right click opens a menu with *Check now*. The check is off in the live session.
|
||||
- `das-update --cli` does the same in a terminal (servers, ssh). It asks before installing (`-y` skips the question) and runs itself again through sudo.
|
||||
- `das-update --cli` does the same in a terminal (servers, ssh). It asks before installing (`-y` skips the question) and runs itself again through sudo. Without a display it works in the terminal even without `--cli`.
|
||||
- The command itself is the `das-update` package without GTK, the window and the tray icon are `/usr/libexec/das/das-update-gui` from `das-tools`.
|
||||
|
||||
#### Welcome window<a id='Welcome' />
|
||||
**_`das-welcome` opens at the first login and gathers the first steps in one place._**
|
||||
@@ -118,6 +122,25 @@ Void Linux is fast, simple and independent: runit instead of systemd, and its ow
|
||||
- It links to the system update, Xfce settings and help.
|
||||
- It opens by itself only once. The *Show at login* check box keeps it opening at every login.
|
||||
|
||||
#### Server image<a id='Server' />
|
||||
**_A console-only live ISO that installs a Das OS server with SSH, a firewall and Docker ready to use._**
|
||||
- `dasos-server-<version>-x86_64.iso` boots on UEFI and BIOS with a login on the screen and on the serial console (`ttyS0`, 115200), so it also works through IPMI, VPS consoles and `qemu -nographic`. Log in as `live` with the password `live`, then run `sudo das-server-install`.
|
||||
- The installer asks in Ukrainian or English: the disk, server name, administrator and password, an SSH key (and whether password logins stay allowed), time zone, console layout, language and network (dhcpcd or NetworkManager). `das-server-install --config FILE` installs without questions, see `/usr/share/examples/das-server-installer/install.conf`.
|
||||
- It uses the same GPT and Btrfs layout as the desktop installer, so snapshots, the *Das OS snapshots* boot menu and `snapper-rollback` work the same way. GRUB is installed for UEFI (also at the fallback path) or BIOS, on the serial console too when the installer was started there.
|
||||
- The administrator gets sudo through `wheel` and is in the `docker` and `socklog` groups. root has no password.
|
||||
- The installed system runs `sshd`, `chronyd`, `nftables`, `fail2ban`, `docker`, `socklog` and the chosen network service.
|
||||
- nftables lets in only SSH, ICMP and DHCPv6 (`/etc/nftables.conf`). The rules live in their own table `inet das`, so reloading them keeps the Docker and fail2ban rules. Ports that containers publish pass through Docker's own rules.
|
||||
- fail2ban bans addresses that keep failing SSH logins, reading the socklog log. sshd doesn't accept root password logins.
|
||||
- Tools: Docker with Compose, lazydocker, lazygit, Midnight Commander, tmux, htop, Python 3, curl, `das-update --cli` and `dsv`. There are no graphical libraries.
|
||||
|
||||
#### Service manager<a id='Services' />
|
||||
**_`dsv` manages runit services the way systemctl does on systemd distributions._**
|
||||
- `dsv list` shows every service in `/etc/sv`: whether it is enabled, its state, PID and uptime.
|
||||
- `dsv enable NAME` starts a service at boot (a link in the default runlevel) and starts it now. `dsv disable NAME` does the opposite.
|
||||
- `dsv start|stop|restart|status NAME` wrap `sv` and print the new state.
|
||||
- `dsv logs NAME [-f]` shows the service's own svlogd log or, for services that log to syslog, their lines collected by socklog.
|
||||
- It runs itself through sudo when it needs root and has bash completion. It is on the desktop too.
|
||||
|
||||
#### Das OS look<a id='Look' />
|
||||
**_A modern minimal style with a blue and yellow eight-petal star from Ukrainian embroidery._**
|
||||
- The GTK themes `DasOS` and `DasOS-Dark` build on adw-gtk3 and add the Das OS accent colours. They also style the Xfce panel, which adw-gtk3 leaves black.
|
||||
@@ -137,28 +160,31 @@ Void Linux is fast, simple and independent: runit instead of systemd, and its ow
|
||||
**_Every Das OS file is installed and updated by xbps._**
|
||||
- `srcpkgs/das-theme` contains the themes, xfwm4 frames, wallpapers and logo.
|
||||
- `srcpkgs/das-settings` contains the Xfce, LightDM and session defaults.
|
||||
- `srcpkgs/das-tools` contains `das-update` and `das-welcome` (Go, GTK 3 through gotk3) with their menu entries, autostart entries and polkit action.
|
||||
- `srcpkgs/das-tools` contains `das-welcome` and the update window and tray icon (Go, GTK 3 through gotk3) with their menu and autostart entries. Its subpackage `das-update` is the update command and polkit action, without GTK.
|
||||
- `srcpkgs/das-snapshots` contains the snapper configuration, `das-snapper-setup` and the dracut module for booting snapshots.
|
||||
- `srcpkgs/das-installer` contains the Calamares settings, branding and installation scripts. It exists only on the live ISO.
|
||||
- `srcpkgs/das-installer` contains the Calamares settings and branding, `srcpkgs/das-server-installer` the console installer. The steps both share (`mount-source`, `postinstall`) are in `srcpkgs/das-install-common`. They exist only on the live ISOs.
|
||||
- `srcpkgs/das-server` is the server metapackage with the nftables, fail2ban, sshd and Docker defaults. `srcpkgs/dsv` contains the service manager.
|
||||
- `srcpkgs/calamares`, `srcpkgs/adw-gtk3` and `srcpkgs/font-jetbrains-mono` package upstream releases that Void does not have.
|
||||
- `make packages` lays the templates over a shallow clone of void-packages and builds them with `xbps-src` into `out/hostdir/binpkgs`. The ISO build installs them from there.
|
||||
|
||||
#### Containerised build<a id='Build' />
|
||||
**_The whole build runs in a Docker container, so only Docker and QEMU are needed on the host._**
|
||||
1. `make packages` builds the local xbps repository.
|
||||
2. `make iso` builds the packages and then the ISO with `void-mklive`, using the profile in `live/` (package list, services, root file system overlay).
|
||||
3. `make qemu` boots the newest ISO with UEFI. `make qemu-bios` uses legacy BIOS, and `make qemu-disk` also attaches a 20 GB virtual disk to install on.
|
||||
2. `make iso` builds the packages and then the ISO with `void-mklive`, using the profile in `live/` (package list, services, root file system overlay). `make iso-server` does the same for the server profile in `server/`.
|
||||
3. `make qemu` boots the newest ISO with UEFI. `make qemu-bios` uses legacy BIOS, and `make qemu-disk` also attaches a 20 GB virtual disk to install on. `make qemu-server` boots the server ISO with the disk on a serial console in the terminal (Ctrl-A X quits).
|
||||
|
||||
### 🚀 Building the application
|
||||
Requirements: Linux with Docker (the user must be in the `docker` group), QEMU and OVMF for testing, and Go 1.24+ with the GTK 3 development files for `make test`. About 10 GB of free disk space.
|
||||
```shell
|
||||
make iso # build packages and the live ISO (the first run downloads ~2 GB)
|
||||
make qemu # boot it in QEMU with UEFI
|
||||
make iso-server # build packages and the server ISO
|
||||
make qemu-server # boot it on a serial console with a disk to install on
|
||||
make test # run Go tests
|
||||
make clean # remove build output, keep the download cache
|
||||
```
|
||||
The ISO appears in `out/iso/dasos-<version>-x86_64.iso`. Write it to a USB stick with `dd` or Ventoy.
|
||||
The ISOs appear in `out/iso/dasos-<version>-x86_64.iso` and `out/iso/dasos-server-<version>-x86_64.iso`. Write them to a USB stick with `dd` or Ventoy.
|
||||
|
||||
**Note:** Das OS is an early version (0.3.0). A server image, the developer profile and signed repository hosting are planned for upcoming stages. Until the repository is hosted, an installed system gets updates from Void only. Das OS is based on Void Linux but is not affiliated with it.
|
||||
**Note:** Das OS is an early version (0.4.0). The developer profile, smaller ISOs and signed repository hosting are planned for upcoming stages. Until the repository is hosted, an installed system gets updates from Void only. Das OS is based on Void Linux but is not affiliated with it.
|
||||
|
||||
###### _Made by -=:dAs:=-_
|
||||
|
||||
+39
-13
@@ -1,12 +1,12 @@
|
||||
## Das OS
|
||||
### _Легкий і дружній десктоп на базі Void Linux з Xfce та українським колоритом_
|
||||
### _Легкий і дружній десктоп на базі Void Linux з Xfce та українським колоритом, а також консольна серверна версія_
|
||||
|
||||
[](https://voidlinux.org) [](https://xfce.org) [](https://docs.voidlinux.org/config/services/) [](https://go.dev) [](#)
|
||||
[](https://voidlinux.org) [](https://xfce.org) [](https://docs.voidlinux.org/config/services/) [](https://go.dev) [](https://www.docker.com) [](#)
|
||||
|
||||
🇬🇧 [English version](README.md)
|
||||
|
||||
### 💡 Призначення
|
||||
Void Linux швидкий, простий і незалежний: runit замість systemd і власний менеджер пакетів xbps. Проте з коробки це гола система, і щоб довести її до щоденного використання, треба кілька годин налаштовувати. Das OS збирає live-образ ISO, який одразу завантажується в налаштований десктоп Xfce і встановлюється графічним інсталятором. У ньому власне оформлення, український інтерфейс і розкладка, звичні програми та знімки Btrfs, які дозволяють скасувати невдале оновлення. Усе, що додає Das OS, постачається власними xbps-пакетами, тож налаштування можна відтворити й оновлювати, як будь-який інший пакет.
|
||||
Void Linux швидкий, простий і незалежний: runit замість systemd і власний менеджер пакетів xbps. Проте з коробки це гола система, і щоб довести її до щоденного використання, треба кілька годин налаштовувати. Das OS збирає live-образ ISO, який одразу завантажується в налаштований десктоп Xfce і встановлюється графічним інсталятором. У ньому власне оформлення, український інтерфейс і розкладка, звичні програми та знімки Btrfs, які дозволяють скасувати невдале оновлення. Усе, що додає Das OS, постачається власними xbps-пакетами, тож налаштування можна відтворити й оновлювати, як будь-який інший пакет. Другий, консольний ISO встановлює сервер із налаштованими SSH, файрволом, fail2ban і Docker на тій самій розмітці Btrfs зі знімками.
|
||||
|
||||
### 📃 Можливості
|
||||
- [Live ISO](#LiveISO), що завантажується з UEFI і BIOS одразу в робочий стіл
|
||||
@@ -14,6 +14,8 @@ Void Linux швидкий, простий і незалежний: runit зам
|
||||
- [Знімки й відкат](#Snapshots): щогодинні знімки Btrfs, які можна завантажити з меню GRUB
|
||||
- [Оновлення системи](#Update) зі знімком перед ним: вікно, значок у треї та консольний режим
|
||||
- [Вікно привітання](#Welcome) під час першого входу: мова, теки, оновлення та довідка
|
||||
- [Серверний образ](#Server): консольний live ISO з текстовим інсталятором, SSH, файрволом, fail2ban і Docker
|
||||
- [Керування службами](#Services) `dsv`: вмикати, запускати й читати журнали служб runit, як systemctl
|
||||
- [Оформлення Das OS](#Look): світла й темна теми, згенеровані рамки вікон, шпалери та логотип
|
||||
- [Налаштування за замовчуванням](#Defaults) для Xfce, які не перезаписують стандартні файли
|
||||
- [Власний репозиторій пакетів](#Repository), який xbps-src збирає з шаблонів у дереві проєкту
|
||||
@@ -25,6 +27,7 @@ Void Linux швидкий, простий і незалежний: runit зам
|
||||
- **Легкість** – без systemd, а з Xfce, LightDM і PipeWire система добре працює навіть на старих ноутбуках.
|
||||
- **Нічого прихованого** – усі зміни постачаються звичайними xbps-пакетами, і `xbps-query -f das-settings` показує, що саме змінено.
|
||||
- **Контроль у користувача** – налаштування за замовчуванням лежать у `/etc/xdg/das`, тож власні налаштування користувача завжди мають пріоритет і не скидаються після оновлень.
|
||||
- **Одна основа для десктопа й сервера** – обидва образи мають спільні пакети, розмітку диска, знімки й `das-update`, тож сервер оновлюється й відкочується так само, як ноутбук.
|
||||
- **Збирається будь-де** – збирання відбувається в контейнері Void, тому хостом може бути Mint, Ubuntu чи Fedora.
|
||||
|
||||
### 📱 Скріншоти
|
||||
@@ -62,12 +65,12 @@ Void Linux швидкий, простий і незалежний: runit зам
|
||||
<tr>
|
||||
<td align="center"><img src="images/welcome.png" width="300" alt="Вікно привітання" /></td>
|
||||
<td align="center"><img src="images/update.png" width="300" alt="Оновлення системи" /></td>
|
||||
<td></td>
|
||||
<td align="center"><img src="images/server-installer.png" width="300" alt="Серверний інсталятор" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><i>Вікно привітання</i></td>
|
||||
<td align="center"><i>Оновлення системи</i></td>
|
||||
<td></td>
|
||||
<td align="center"><i>Серверний інсталятор</i></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -88,7 +91,7 @@ Void Linux швидкий, простий і незалежний: runit зам
|
||||
- Інтерфейс за замовчуванням український, часовий пояс Києва, з брендингом і слайдами Das OS.
|
||||
- Диск можна очистити автоматично або розмітити вручну. За замовчуванням Btrfs, також доступні ext4 і XFS. На комп'ютерах з UEFI створюється EFI-розділ на 512 МіБ.
|
||||
- Копіюється чистий live-образ (`/dev/mapper/live-base`), без live-користувача і його налаштувань завантаження.
|
||||
- Після копіювання інсталятор збирає локалі для вибраної мови, на реальному залізі прибирає гостьові інструменти віртуальних машин, налаштовує знімки, збирає initramfs і встановлює GRUB.
|
||||
- Після копіювання інсталятор збирає локалі для вибраної мови, лишає гостьові інструменти лише того гіпервізора, у якому працює (на реальному залізі — жодних), налаштовує знімки, збирає initramfs і встановлює GRUB.
|
||||
- Наприкінці інсталятор видаляє себе й пакети, потрібні лише йому.
|
||||
- Шифрування диска поки не пропонується.
|
||||
|
||||
@@ -108,7 +111,8 @@ Void Linux швидкий, простий і незалежний: runit зам
|
||||
- Після завершення показує номер знімка й те, як до нього повернутися, і просить перезавантажитися, якщо оновилися ядро, glibc, runit чи інші ключові пакети.
|
||||
- Вікно *Оновлення системи* показує список пакетів зі встановленою і новою версіями та вивід xbps. Частина, якій потрібні права root, запускається через pkexec (дія polkit `ua.org.das.update`).
|
||||
- У фоні перевіряє оновлення через 2 хвилини після входу, а далі кожні 6 годин, без прав root. Значок у треї й сповіщення з'являються лише тоді, коли є оновлення. Клік відкриває вікно, правий клік — меню з пунктом *Перевірити зараз*. У live-сесії перевірка вимкнена.
|
||||
- `das-update --cli` робить те саме в терміналі (сервери, ssh). Перед встановленням питає підтвердження (`-y` його пропускає) і сам перезапускається через sudo.
|
||||
- `das-update --cli` робить те саме в терміналі (сервери, ssh). Перед встановленням питає підтвердження (`-y` його пропускає) і сам перезапускається через sudo. Без графічного дисплея працює в терміналі й без `--cli`.
|
||||
- Сама команда — пакет `das-update` без GTK, а вікно й значок у треї — `/usr/libexec/das/das-update-gui` з `das-tools`.
|
||||
|
||||
#### Вікно привітання<a id='Welcome' />
|
||||
**_`das-welcome` відкривається під час першого входу і збирає перші кроки в одному місці._**
|
||||
@@ -118,6 +122,25 @@ Void Linux швидкий, простий і незалежний: runit зам
|
||||
- Містить посилання на оновлення системи, налаштування Xfce і довідку.
|
||||
- Сам відкривається лише один раз. Прапорець *Показувати під час входу* залишає його на кожен вхід.
|
||||
|
||||
#### Серверний образ<a id='Server' />
|
||||
**_Консольний live ISO, що встановлює сервер Das OS з готовими до роботи SSH, файрволом і Docker._**
|
||||
- `dasos-server-<версія>-x86_64.iso` завантажується з UEFI і BIOS із входом і на екрані, і на послідовній консолі (`ttyS0`, 115200), тож працює й через IPMI, консолі VPS та `qemu -nographic`. Увійдіть як `live` з паролем `live` і запустіть `sudo das-server-install`.
|
||||
- Інсталятор питає українською або англійською: диск, ім'я сервера, адміністратора й пароль, SSH-ключ (і чи лишати вхід за паролем), часовий пояс, розкладку консолі, мову та мережу (dhcpcd або NetworkManager). `das-server-install --config ФАЙЛ` встановлює без запитань, приклад — `/usr/share/examples/das-server-installer/install.conf`.
|
||||
- Розмітка GPT і Btrfs та сама, що в десктопному інсталяторі, тож знімки, меню *Das OS snapshots* і `snapper-rollback` працюють так само. GRUB встановлюється для UEFI (також за запасним шляхом) або BIOS, а якщо інсталятор запущено з послідовної консолі, то й на неї.
|
||||
- Адміністратор отримує sudo через `wheel` і входить у групи `docker` та `socklog`. У root немає пароля.
|
||||
- Встановлена система запускає `sshd`, `chronyd`, `nftables`, `fail2ban`, `docker`, `socklog` і вибрану мережеву службу.
|
||||
- nftables пропускає лише SSH, ICMP і DHCPv6 (`/etc/nftables.conf`). Правила лежать у власній таблиці `inet das`, тож їх перезавантаження не чіпає правил Docker і fail2ban. Порти, які публікують контейнери, проходять через власні правила Docker.
|
||||
- fail2ban блокує адреси, з яких раз у раз не вдається увійти по SSH, читаючи журнал socklog. sshd не приймає вхід root за паролем.
|
||||
- Інструменти: Docker з Compose, lazydocker, lazygit, Midnight Commander, tmux, htop, Python 3, curl, `das-update --cli` і `dsv`. Графічних бібліотек немає.
|
||||
|
||||
#### Керування службами<a id='Services' />
|
||||
**_`dsv` керує службами runit так, як systemctl у дистрибутивах із systemd._**
|
||||
- `dsv list` показує всі служби з `/etc/sv`: чи ввімкнена, стан, PID і час роботи.
|
||||
- `dsv enable НАЗВА` запускає службу під час завантаження (посилання в типовому рівні запуску) і одразу запускає її. `dsv disable НАЗВА` робить навпаки.
|
||||
- `dsv start|stop|restart|status НАЗВА` — обгортки над `sv`, які показують новий стан.
|
||||
- `dsv logs НАЗВА [-f]` показує власний журнал служби (svlogd) або, для служб, що пишуть у syslog, їхні рядки, зібрані socklog.
|
||||
- Сам перезапускається через sudo, коли потрібні права root, і має автодоповнення bash. Є й на десктопі.
|
||||
|
||||
#### Оформлення Das OS<a id='Look' />
|
||||
**_Сучасний мінімалізм із синьо-жовтою восьмипелюстковою зіркою з української вишивки._**
|
||||
- GTK-теми `DasOS` і `DasOS-Dark` побудовані на adw-gtk3 і додають акцентні кольори Das OS. Вони також оформлюють панель Xfce, яку adw-gtk3 лишає чорною.
|
||||
@@ -137,28 +160,31 @@ Void Linux швидкий, простий і незалежний: runit зам
|
||||
**_Кожен файл Das OS встановлює й оновлює xbps._**
|
||||
- `srcpkgs/das-theme` містить теми, рамки xfwm4, шпалери й логотип.
|
||||
- `srcpkgs/das-settings` містить налаштування Xfce, LightDM і сесії.
|
||||
- `srcpkgs/das-tools` містить `das-update` і `das-welcome` (Go, GTK 3 через gotk3) з пунктами меню, автозапуском і дією polkit.
|
||||
- `srcpkgs/das-tools` містить `das-welcome`, вікно оновлення і значок у треї (Go, GTK 3 через gotk3) з пунктами меню й автозапуском. Його підпакет `das-update` — сама команда оновлення й дія polkit, без GTK.
|
||||
- `srcpkgs/das-snapshots` містить конфігурацію snapper, `das-snapper-setup` і dracut-модуль для завантаження знімків.
|
||||
- `srcpkgs/das-installer` містить налаштування Calamares, брендинг і скрипти встановлення. Він є лише на live-ISO.
|
||||
- `srcpkgs/das-installer` містить налаштування й брендинг Calamares, `srcpkgs/das-server-installer` — консольний інсталятор. Спільні для обох кроки (`mount-source`, `postinstall`) лежать у `srcpkgs/das-install-common`. Вони є лише на live-ISO.
|
||||
- `srcpkgs/das-server` — серверний метапакет із налаштуваннями nftables, fail2ban, sshd і Docker. `srcpkgs/dsv` містить керування службами.
|
||||
- `srcpkgs/calamares`, `srcpkgs/adw-gtk3` і `srcpkgs/font-jetbrains-mono` пакують релізи, яких немає у Void.
|
||||
- `make packages` накладає шаблони на неглибокий клон void-packages і збирає їх через `xbps-src` в `out/hostdir/binpkgs`. Збирання ISO встановлює їх звідти.
|
||||
|
||||
#### Збирання в контейнері<a id='Build' />
|
||||
**_Усе збирання відбувається в Docker-контейнері, тож на хості потрібні лише Docker і QEMU._**
|
||||
1. `make packages` збирає локальний xbps-репозиторій.
|
||||
2. `make iso` збирає пакети, а потім ISO через `void-mklive` за профілем у `live/` (список пакетів, сервіси, оверлей кореневої файлової системи).
|
||||
3. `make qemu` завантажує найновіший ISO з UEFI. `make qemu-bios` використовує старий BIOS, а `make qemu-disk` ще й підключає віртуальний диск на 20 ГБ для встановлення.
|
||||
2. `make iso` збирає пакети, а потім ISO через `void-mklive` за профілем у `live/` (список пакетів, сервіси, оверлей кореневої файлової системи). `make iso-server` робить те саме для серверного профілю в `server/`.
|
||||
3. `make qemu` завантажує найновіший ISO з UEFI. `make qemu-bios` використовує старий BIOS, а `make qemu-disk` ще й підключає віртуальний диск на 20 ГБ для встановлення. `make qemu-server` завантажує серверний ISO з диском на послідовній консолі прямо в терміналі (вихід — Ctrl-A X).
|
||||
|
||||
### 🚀 Збирання застосунку
|
||||
Вимоги: Linux із Docker (користувач має бути в групі `docker`), QEMU та OVMF для тестування, Go 1.24+ і файли розробки GTK 3 для `make test`. Приблизно 10 ГБ вільного місця.
|
||||
```shell
|
||||
make iso # зібрати пакети й live-ISO (перший запуск завантажує ~2 ГБ)
|
||||
make qemu # запустити його в QEMU з UEFI
|
||||
make iso-server # зібрати пакети й серверний ISO
|
||||
make qemu-server # запустити його на послідовній консолі з диском для встановлення
|
||||
make test # запустити Go-тести
|
||||
make clean # видалити результати збирання, зберегти кеш завантажень
|
||||
```
|
||||
ISO з'являється в `out/iso/dasos-<версія>-x86_64.iso`. Записати його на флешку можна через `dd` або Ventoy.
|
||||
ISO з'являються в `out/iso/dasos-<версія>-x86_64.iso` і `out/iso/dasos-server-<версія>-x86_64.iso`. Записати їх на флешку можна через `dd` або Ventoy.
|
||||
|
||||
**Примітка:** Das OS — рання версія (0.3.0). Серверний образ, профіль розробника та підписаний репозиторій на хостингу заплановані на наступні етапи. Поки репозиторій не розміщено на хостингу, встановлена система отримує оновлення лише з Void. Das OS базується на Void Linux, але не пов'язана з ним офіційно.
|
||||
**Примітка:** Das OS — рання версія (0.4.0). Профіль розробника, менші ISO та підписаний репозиторій на хостингу заплановані на наступні етапи. Поки репозиторій не розміщено на хостингу, встановлена система отримує оновлення лише з Void. Das OS базується на Void Linux, але не пов'язана з ним офіційно.
|
||||
|
||||
###### _Made by -=:dAs:=-_
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Das OS — що зробити далі
|
||||
|
||||
Стан на 2026-10-19: версія 0.3.0, етапи 1–5 готові (live ISO, власний репозиторій, оформлення, інсталятор Calamares зі знімками Btrfs, Go-утиліти `das-update` і `das-welcome`). Далі: серверний образ (етап 6).
|
||||
Стан на 2026-10-19: версія 0.4.0, етапи 1–6 готові (live ISO, власний репозиторій, оформлення, інсталятор Calamares зі знімками Btrfs, Go-утиліти `das-update` і `das-welcome`, серверний образ з консольним інсталятором). Далі: рішення щодо розміру ISO, потім профіль розробника (етап 7).
|
||||
|
||||
## Етап 5. Go-утиліти (готово, лишилися перевірки)
|
||||
- [x] `das-update`: вікно, значок у треї (лише коли є оновлення), консольний режим `--cli`, знімок snapper pre/post, встановлення через pkexec, підказка про відкат.
|
||||
@@ -9,22 +9,33 @@
|
||||
- [x] Тести `go test ./...` (`make test` і під час збирання пакета).
|
||||
- [x] Перевірено у встановленій системі на Btrfs (QEMU, UEFI): оновлення з вікна й `--cli` створює пару знімків pre/post, вони з'являються в меню GRUB, завантаження в знімок і `snapper-rollback` повертають попередню версію пакета; вибір мови в `das-welcome` діє після перезавантаження.
|
||||
- [x] Виправлено після перевірки: версія в Calamares береться з `VERSION`; значок у треї ховається, коли оновлення встановлено поза ним (стежить за базою пакетів xbps); інструменти VirtualBox прибираються з не-VirtualBox машин (у KVM було повідомлення при кожному вході); live-сесія не блокує екран під час встановлення.
|
||||
- [ ] Перевірити в наступному live ISO, що екран більше не блокується (властивості xfconf звірено з двійковими файлами).
|
||||
- [x] Live ISO 0.4.0: екран не блокується під час встановлення.
|
||||
- [ ] Вікно автентифікації polkit (`xfce-polkit`) англійською: перекласти або замінити агент.
|
||||
- [ ] Повідомити авторів xdg-user-dirs про помилку з `XDG_DATA_DIRS`.
|
||||
- [ ] Пункт «Профіль розробника» в `das-welcome` (разом з етапом 7).
|
||||
|
||||
## Етап 6. Серверний образ
|
||||
## Етап 6. Серверний образ (готово, лишився розмір ISO)
|
||||
Live ISO без графіки з консольним інсталятором: `dasos-server-<версія>-x86_64.iso`.
|
||||
- [ ] Профіль `server/` поруч із `live/` (`packages.x86_64`, `services`, `include/`); параметризувати `scripts/container/build-iso.sh` профілем; ціль `make iso-server`. Kernel cmdline з `console=tty0 console=ttyS0` для серійної консолі.
|
||||
- [ ] Метапакет `das-server`: openssh, chrony, dhcpcd (NetworkManager/nmtui на вибір), das-snapshots, docker (без podman), nftables, fail2ban, python3, lazydocker, lazygit, mc, tmux, htop, socklog-void.
|
||||
- [ ] Налаштування в `das-server`: nftables «закрито все, крім SSH», jail sshd для fail2ban, sshd без входу root за паролем.
|
||||
- [ ] `dsv` (das services): керування службами runit замість systemctl (`list`, `enable`, `disable`, `start`, `stop`, `restart`, `status`, `logs`): посилання `/etc/sv/X` → `/var/service`, логи через socklog/svlogd. Знадобиться й на десктопі.
|
||||
- [ ] `das-server-install`: TUI-інсталятор на `dialog` (диск, ім'я хоста, користувач, SSH-ключ, часовий пояс, розкладка). Розмітка GPT: ESP + Btrfs з тими ж підтомами, що й у Calamares (`@`, `@snapshots`…); копіювання з `live-base` (перевикористати `mount-source`); GRUB для UEFI і BIOS.
|
||||
- [ ] Винести спільну частину `postinstall` (локалі, `/tmp`, гостьові інструменти VM, `das-snapper-setup`, переписування ядер) в окремий скрипт для обох інсталяторів.
|
||||
- [ ] `scripts/run-qemu.sh --serial` (`-nographic`) для перевірки серверного ISO.
|
||||
- [ ] Перевірка: встановлення в QEMU, вхід по SSH, `docker run hello-world`, знімок snapper перед `das-update --cli`.
|
||||
- [ ] Наостанок — розмір ISO: виміряти обидва образи, знайти, що займає найбільше (розміри пакетів через `xbps-query`, прошивки `linux-firmware-*`, локалі, документація, `-devel`-пакети, гостьові інструменти VM, компресія squashfs `xz`/`zstd`), і вирішити, що й як зменшити.
|
||||
- [x] Профіль `server/` поруч із `live/`; `build-iso.sh [desktop|server]`, цілі `make iso-server` і `make qemu-server`. Kernel cmdline `console=tty0 console=ttyS0,115200`, вхід і на послідовній консолі.
|
||||
- [x] Метапакет `das-server`: openssh, chrony, dhcpcd, NetworkManager, docker + docker-compose, nftables, fail2ban, socklog-void, python3, curl, lazydocker, lazygit, mc, tmux, htop, das-snapshots, das-update, dsv.
|
||||
- [x] Налаштування: nftables «закрито все, крім SSH» (лише своя таблиця `inet das`, правила Docker і fail2ban не чіпає), jail sshd через nftables з розбором журналу socklog, sshd `PermitRootLogin prohibit-password`, журнали Docker з ротацією (`local`).
|
||||
- [x] `dsv`: `list`, `status`, `enable`, `disable`, `start`, `stop`, `restart`, `logs [-f]`, автодоповнення bash; є й на десктопі.
|
||||
- [x] `das-update` окремим підпакетом без GTK (вікно й трей — `/usr/libexec/das/das-update-gui` у `das-tools`).
|
||||
- [x] `das-server-install`: TUI на `dialog` українською й англійською (диск, ім'я, користувач і пароль, SSH-ключ і заборона паролів, часовий пояс, розкладка, мова, dhcpcd/NetworkManager) і режим без запитань `--config`. GPT + Btrfs з тими ж підтомами, GRUB для UEFI (і запасний `BOOTX64.EFI`) та BIOS.
|
||||
- [x] Спільний пакет `das-install-common` (`mount-source`, `postinstall`) для обох інсталяторів; `das-snapper-setup` вмикає `dbus`, без нього snapper не працює.
|
||||
- [x] `scripts/run-qemu.sh --serial`.
|
||||
- [x] Перевірено в QEMU: встановлення через TUI на UEFI (з SSH-ключем) і BIOS (з паролем, NetworkManager, `ua-utf`), вхід по SSH лише за ключем, `docker run hello-world`, опублікований порт nginx, fail2ban бачить невдалі входи, `das-update --cli` зі знімками pre/post, `dsv`.
|
||||
- [ ] Перевірити `das-server-install --config` (код той самий, що й у TUI, окремо не запускався).
|
||||
- [ ] Розмір ISO: огляд зроблено (нижче), чекає рішення, що саме зменшувати.
|
||||
|
||||
### Розмір ISO (0.4.0): десктоп 1,96 ГБ, сервер 1,57 ГБ
|
||||
З чого складається: `initrd` 233 МБ і squashfs 1584 / 1215 МБ (xz). Прошивки в Void уже стиснуті zstd, тож xz їх майже не зменшує.
|
||||
- [ ] `initrd` live-образу: 157 МБ у ньому — прошивки GPU (NVIDIA 109 МБ, amdgpu 28 МБ) для раннього KMS. Без драйверів `nouveau`/`amdgpu`/`radeon`/`i915`/`xe` у live-initrd: ≈ −150 МБ в обох ISO. Драйвери все одно завантажаться з кореневої системи.
|
||||
- [ ] Сервер: без `linux-firmware-nvidia`, `sof-firmware`, `alsa-firmware` (GPU і звук): ≈ −160 МБ. Через `mklive -g` і `ignorepkg` у `das-server`, щоб оновлення не повертали їх.
|
||||
- [ ] Переклади `/usr/share/locale` (265 МБ на десктопі, 98 МБ на сервері) лише для uk і en через `noextract` у xbps: ≈ −60…80 МБ на десктопі. Мінус: інші мови інтерфейсу доведеться доставляти перевстановленням пакетів.
|
||||
- [ ] squashfs з блоком 1 МБ і фільтром BCJ x86 замість 128 КБ: ≈ −5 %.
|
||||
- [ ] Десктоп: зайві варіанти Papirus (`ePapirus*`, `Papirus-Light`) з 294 МБ іконок; з'ясувати, хто тягне gtk4, flite, ghostscript.
|
||||
- Не чіпати: Firefox (299 МБ), ядро й модулі (180 МБ), LLVM для Mesa (141 МБ), мережеві прошивки (442 МБ, Wi-Fi та мережеві карти).
|
||||
|
||||
## Етап 7. Профіль розробника
|
||||
- [ ] Метапакет `das-dev`: go, git, docker, podman, vscode.
|
||||
@@ -40,7 +51,7 @@ Live ISO без графіки з консольним інсталятором:
|
||||
- [ ] `/etc/xbps.d/das.conf` у встановленій системі, щоб пакети `das-*` оновлювалися. Зараз встановлена система бачить лише репозиторій Void.
|
||||
|
||||
## Інсталятор
|
||||
- [ ] Перевірити встановлення на старий BIOS (MBR, `grub-install --target=i386-pc`).
|
||||
- [ ] Перевірити встановлення десктопа на старий BIOS (MBR, `grub-install --target=i386-pc`); серверний інсталятор на BIOS перевірено.
|
||||
- [ ] Перевірити на реальному залізі: видалення гостьових інструментів VM, Wi-Fi, NVIDIA/AMD.
|
||||
- [ ] Шифрування диска (LUKS): `luksbootkeyfile`, crypttab, dracut, `GRUB_ENABLE_CRYPTODISK`.
|
||||
- [ ] Перевірити ручну розмітку з Btrfs (чи створюються підтоми) і встановлення на ext4/XFS (знімки мають вимкнутися без помилок).
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
@@ -66,3 +66,4 @@ das-settings
|
||||
das-snapshots
|
||||
das-theme
|
||||
das-tools
|
||||
dsv
|
||||
|
||||
@@ -1,11 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
# Builds the Das OS live ISO with void-mklive from the profile in live/.
|
||||
# Builds a Das OS live ISO with void-mklive from a profile directory:
|
||||
# build-iso.sh the desktop image from live/
|
||||
# build-iso.sh server the console server image from server/
|
||||
# Runs inside the builder container, see scripts/builder.sh.
|
||||
set -euo pipefail
|
||||
|
||||
profile=${1:-desktop}
|
||||
repo=/work/out/hostdir/binpkgs
|
||||
version=$(< /work/VERSION)
|
||||
iso=/work/out/iso/dasos-${version}-x86_64.iso
|
||||
|
||||
case $profile in
|
||||
desktop)
|
||||
dir=/work/live
|
||||
iso=/work/out/iso/dasos-${version}-x86_64.iso
|
||||
title="Das OS"
|
||||
locale=uk_UA.UTF-8
|
||||
cmdline="live.user=live quiet loglevel=3"
|
||||
;;
|
||||
server)
|
||||
dir=/work/server
|
||||
iso=/work/out/iso/dasos-server-${version}-x86_64.iso
|
||||
title="Das OS Server"
|
||||
locale=en_US.UTF-8
|
||||
# Both consoles: a screen and a serial line (IPMI, VPS consoles, QEMU -nographic).
|
||||
# mklive starts a login on ttyS0 when it sees console=ttyS0.
|
||||
cmdline="live.user=live loglevel=4 console=tty0 console=ttyS0,115200"
|
||||
;;
|
||||
*)
|
||||
echo "build-iso: unknown profile '$profile' (desktop, server)" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if ! compgen -G "$repo/*-repodata" >/dev/null; then
|
||||
echo "build-iso: the local package repository is missing, run 'make packages' first" >&2
|
||||
@@ -21,22 +46,25 @@ work=$(mktemp -d)
|
||||
mkdir -p /work/out/iso
|
||||
trap 'rm -rf "$work"; chown -R "$HOST_UID:$HOST_GID" /work/out/iso' EXIT
|
||||
|
||||
# Root file system overlay: static files from live/include plus generated links
|
||||
# Root file system overlay: static files from <profile>/include plus generated links
|
||||
include=$work/include
|
||||
cp -a /work/live/include "$include"
|
||||
mkdir -p "$include/etc"
|
||||
[[ -d $dir/include ]] && cp -a "$dir/include/." "$include"
|
||||
ln -sf /usr/share/zoneinfo/Europe/Kyiv "$include/etc/localtime"
|
||||
# PipeWire as the sound server, wired up the same way as Void's own live images
|
||||
mkdir -p "$include"/etc/xdg/autostart "$include"/etc/pipewire/pipewire.conf.d "$include"/etc/alsa/conf.d
|
||||
ln -sf /usr/share/applications/pipewire.desktop "$include"/etc/xdg/autostart/
|
||||
ln -sf /usr/share/examples/wireplumber/10-wireplumber.conf "$include"/etc/pipewire/pipewire.conf.d/
|
||||
ln -sf /usr/share/examples/pipewire/20-pipewire-pulse.conf "$include"/etc/pipewire/pipewire.conf.d/
|
||||
ln -sf /usr/share/alsa/alsa.conf.d/50-pipewire.conf "$include"/etc/alsa/conf.d/
|
||||
ln -sf /usr/share/alsa/alsa.conf.d/99-pipewire-default.conf "$include"/etc/alsa/conf.d/
|
||||
# The installer shows the Das OS version, which lives in VERSION, not in the package
|
||||
branding=usr/share/calamares/branding/dasos
|
||||
mkdir -p "$include/$branding"
|
||||
sed -e "s/@VERSION@/$version/g" -e "s/@SHORT_VERSION@/${version%.*}/g" \
|
||||
"/work/srcpkgs/das-installer/files/calamares/branding/dasos/branding.desc" >"$include/$branding/branding.desc"
|
||||
if [[ $profile == desktop ]]; then
|
||||
# PipeWire as the sound server, wired up the same way as Void's own live images
|
||||
mkdir -p "$include"/etc/xdg/autostart "$include"/etc/pipewire/pipewire.conf.d "$include"/etc/alsa/conf.d
|
||||
ln -sf /usr/share/applications/pipewire.desktop "$include"/etc/xdg/autostart/
|
||||
ln -sf /usr/share/examples/wireplumber/10-wireplumber.conf "$include"/etc/pipewire/pipewire.conf.d/
|
||||
ln -sf /usr/share/examples/pipewire/20-pipewire-pulse.conf "$include"/etc/pipewire/pipewire.conf.d/
|
||||
ln -sf /usr/share/alsa/alsa.conf.d/50-pipewire.conf "$include"/etc/alsa/conf.d/
|
||||
ln -sf /usr/share/alsa/alsa.conf.d/99-pipewire-default.conf "$include"/etc/alsa/conf.d/
|
||||
# The installer shows the Das OS version, which lives in VERSION, not in the package
|
||||
branding=usr/share/calamares/branding/dasos
|
||||
mkdir -p "$include/$branding"
|
||||
sed -e "s/@VERSION@/$version/g" -e "s/@SHORT_VERSION@/${version%.*}/g" \
|
||||
"/work/srcpkgs/das-installer/files/calamares/branding/dasos/branding.desc" >"$include/$branding/branding.desc"
|
||||
fi
|
||||
|
||||
# mklive's dracut module creates the live user, hostname and passwords at boot.
|
||||
# Rebrand its defaults in this container's copy (the image itself stays untouched).
|
||||
@@ -49,8 +77,9 @@ for pattern in 'echo void-live >' 'voidlinux'; do
|
||||
done
|
||||
sed -i -e 's/echo void-live >/echo dasos >/' -e 's/voidlinux/live/g' "$adduser"
|
||||
# mklive copies its /etc/issue (Void live logins) into the image, and the
|
||||
# installer copies the image to disk, so use a neutral Das OS one.
|
||||
cp /work/live/branding/issue /opt/void-mklive/data/issue
|
||||
# installers copy the image to disk, so use a Das OS one (the server's tells
|
||||
# how to log in to the live system; its installer writes a neutral one).
|
||||
cp "$dir/branding/issue" /opt/void-mklive/data/issue
|
||||
|
||||
rsvg-convert /work/live/branding/splash.svg --output "$work/splash.png"
|
||||
rm -f "$iso"
|
||||
@@ -60,11 +89,11 @@ SPLASH_IMAGE=$work/splash.png ./mklive.sh \
|
||||
-a x86_64 \
|
||||
-r "$repo" \
|
||||
-c /var/cache/xbps \
|
||||
-p "$(read_list /work/live/packages.x86_64)" \
|
||||
-S "$(read_list /work/live/services)" \
|
||||
-p "$(read_list "$dir/packages.x86_64")" \
|
||||
-S "$(read_list "$dir/services")" \
|
||||
-I "$include" \
|
||||
-l uk_UA.UTF-8 \
|
||||
-l "$locale" \
|
||||
-k us \
|
||||
-T "Das OS" \
|
||||
-C "live.user=live quiet loglevel=3" \
|
||||
-T "$title" \
|
||||
-C "$cmdline" \
|
||||
-o "$iso"
|
||||
|
||||
@@ -41,6 +41,11 @@ for dir in /work/srcpkgs/*/; do
|
||||
echo "warning: $name is now in void-packages, consider dropping our template" >&2
|
||||
fi
|
||||
rm -rf "$vp/srcpkgs/$name"
|
||||
# A subpackage is a link to its source package's directory and is built with it
|
||||
if [[ -L ${dir%/} ]]; then
|
||||
as_builder ln -s "$(readlink "${dir%/}")" "$vp/srcpkgs/$name"
|
||||
continue
|
||||
fi
|
||||
as_builder cp -rL "$dir" "$vp/srcpkgs/$name"
|
||||
names+=("$name")
|
||||
done
|
||||
|
||||
+17
-8
@@ -1,16 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
# Boots a Das OS ISO in QEMU (KVM when available).
|
||||
#
|
||||
# Usage: scripts/run-qemu.sh [--bios] [--disk] [path/to/image.iso]
|
||||
# --bios boot with legacy BIOS instead of UEFI
|
||||
# --disk attach out/qemu/disk.qcow2 (20 GB, created on first use) to test installing
|
||||
# Without a path the newest ISO in out/iso is used.
|
||||
# Usage: scripts/run-qemu.sh [--bios] [--disk] [--serial] [path/to/image.iso]
|
||||
# --bios boot with legacy BIOS instead of UEFI
|
||||
# --disk attach out/qemu/disk.qcow2 (20 GB, created on first use) to test installing
|
||||
# --serial no window: the serial console in this terminal (server ISO), Ctrl-A X quits
|
||||
# Without a path the newest desktop ISO in out/iso is used (server ISO with --serial).
|
||||
set -euo pipefail
|
||||
|
||||
root=$(cd "$(dirname "$0")/.." && pwd)
|
||||
state=$root/out/qemu
|
||||
firmware=uefi
|
||||
disk=false
|
||||
serial=false
|
||||
iso=""
|
||||
|
||||
die() {
|
||||
@@ -22,8 +24,9 @@ for arg in "$@"; do
|
||||
case $arg in
|
||||
--bios) firmware=bios ;;
|
||||
--disk) disk=true ;;
|
||||
--serial) serial=true ;;
|
||||
-h | --help)
|
||||
sed -n '2,8s/^# \{0,1\}//p' "$0"
|
||||
sed -n '2,9s/^# \{0,1\}//p' "$0"
|
||||
exit 0
|
||||
;;
|
||||
-*) die "unknown option: $arg" ;;
|
||||
@@ -32,17 +35,23 @@ for arg in "$@"; do
|
||||
done
|
||||
|
||||
if [[ -z $iso ]]; then
|
||||
iso=$(ls -t "$root"/out/iso/*.iso 2>/dev/null | head -n 1) || true
|
||||
pattern="dasos-[0-9]*.iso"
|
||||
[[ $serial == true ]] && pattern="dasos-server-*.iso"
|
||||
iso=$(ls -t "$root"/out/iso/$pattern 2>/dev/null | head -n 1) || true
|
||||
fi
|
||||
[[ -n $iso && -f $iso ]] || die "no ISO found, run 'make iso' first"
|
||||
|
||||
args=(
|
||||
-machine q35 -smp 4 -m 4096
|
||||
-device virtio-vga -display gtk,zoom-to-fit=on
|
||||
-device virtio-net-pci,netdev=net0 -netdev user,id=net0
|
||||
-device qemu-xhci -device usb-tablet
|
||||
-cdrom "$iso" -boot order=d
|
||||
)
|
||||
if [[ $serial == true ]]; then
|
||||
# The guest's ttyS0 and the QEMU monitor share this terminal
|
||||
args+=(-nographic -serial mon:stdio)
|
||||
else
|
||||
args+=(-device virtio-vga -display gtk,zoom-to-fit=on -device qemu-xhci -device usb-tablet)
|
||||
fi
|
||||
|
||||
if [[ -w /dev/kvm ]]; then
|
||||
args+=(-accel kvm -cpu host)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
Das OS Server \r (\l)
|
||||
|
||||
Log in as "live" with the password "live", then run: sudo das-server-install
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Packages added to the Void base-system in the server live image.
|
||||
|
||||
# Das OS Server: SSH, firewall, Docker, tools (see srcpkgs/das-server)
|
||||
das-server
|
||||
|
||||
# Installer and the disk tools it uses, also kept by the installed system
|
||||
das-server-installer
|
||||
btrfs-progs
|
||||
cryptsetup
|
||||
dosfstools
|
||||
efibootmgr
|
||||
gptfdisk
|
||||
grub
|
||||
grub-x86_64-efi
|
||||
parted
|
||||
sudo
|
||||
xfsprogs
|
||||
|
||||
# Virtual machine guests
|
||||
qemu-ga
|
||||
@@ -0,0 +1,3 @@
|
||||
# runit services enabled in the live image (/etc/sv/<name>). The installer
|
||||
# enables the server's own services on the installed system.
|
||||
dhcpcd
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Das
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+14
-7
@@ -1,6 +1,7 @@
|
||||
#!/bin/sh
|
||||
# Finish a Das OS installation. Calamares runs this inside the target system
|
||||
# after users, locale and display manager are configured, before GRUB.
|
||||
# Finish a Das OS installation. The installers (Calamares, das-server-install)
|
||||
# run this inside the target system after users and locale are configured,
|
||||
# before GRUB.
|
||||
set -eu
|
||||
|
||||
msg() { echo "das-postinstall: $*"; }
|
||||
@@ -33,16 +34,22 @@ case $machine in
|
||||
*QEMU* | *KVM*) unused="virtualbox-ose-guest" ;;
|
||||
*) unused="spice-vdagent qemu-ga virtualbox-ose-guest" ;;
|
||||
esac
|
||||
msg "removing guest tools not needed here: $unused"
|
||||
case $unused in
|
||||
installed=""
|
||||
for pkg in $unused; do
|
||||
xbps-query "$pkg" >/dev/null 2>&1 && installed="$installed $pkg"
|
||||
done
|
||||
case $installed in
|
||||
*spice-vdagent*) rm -f /etc/runit/runsvdir/default/spice-vdagentd ;;
|
||||
esac
|
||||
case $unused in
|
||||
case $installed in
|
||||
# The live image replaces this autostart file, so xbps keeps it as modified
|
||||
*virtualbox*) rm -f /etc/xdg/autostart/vboxclient.desktop ;;
|
||||
esac
|
||||
# shellcheck disable=SC2086
|
||||
xbps-remove -Ry $unused || true
|
||||
if [ -n "$installed" ]; then
|
||||
msg "removing guest tools not needed here:$installed"
|
||||
# shellcheck disable=SC2086
|
||||
xbps-remove -Ry $installed || true
|
||||
fi
|
||||
|
||||
# Snapper, hourly snapshots and the GRUB snapshot menu (Btrfs only).
|
||||
das-snapper-setup
|
||||
@@ -0,0 +1,15 @@
|
||||
# Template file for 'das-install-common'
|
||||
pkgname=das-install-common
|
||||
version=0.1.0
|
||||
revision=1
|
||||
depends="das-snapshots dracut rsync"
|
||||
short_desc="Das OS installer steps shared by the desktop and server installers"
|
||||
maintainer="Das <anry.das@gmail.com>"
|
||||
license="MIT"
|
||||
homepage="https://git.das.org.ua/das/Das-OS"
|
||||
|
||||
do_install() {
|
||||
vinstall ${FILESDIR}/mount-source 755 usr/libexec/das/installer
|
||||
vinstall ${FILESDIR}/postinstall 755 usr/libexec/das/installer
|
||||
vlicense ${FILESDIR}/LICENSE
|
||||
}
|
||||
@@ -8,3 +8,4 @@ update_system: false
|
||||
operations:
|
||||
- try_remove:
|
||||
- das-installer
|
||||
- das-install-common
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Template file for 'das-installer'
|
||||
pkgname=das-installer
|
||||
version=0.2.0
|
||||
version=0.3.0
|
||||
revision=1
|
||||
depends="calamares das-snapshots das-theme sudo"
|
||||
depends="calamares das-install-common das-theme sudo"
|
||||
short_desc="Das OS installer: Calamares configuration and branding for the live ISO"
|
||||
maintainer="Das <anry.das@gmail.com>"
|
||||
license="MIT"
|
||||
@@ -13,8 +13,6 @@ do_install() {
|
||||
vmkdir usr/share/calamares
|
||||
vcopy "${FILESDIR}/calamares/*" usr/share/calamares
|
||||
vbin ${FILESDIR}/das-install
|
||||
vinstall ${FILESDIR}/postinstall 755 usr/libexec/das/installer
|
||||
vinstall ${FILESDIR}/mount-source 755 usr/libexec/das/installer
|
||||
vinstall ${FILESDIR}/installer-icon 755 usr/libexec/das/installer
|
||||
vinstall ${FILESDIR}/das-installer.desktop 644 usr/share/applications
|
||||
vinstall ${FILESDIR}/das-installer-icon.desktop 644 etc/xdg/autostart
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Das
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+582
@@ -0,0 +1,582 @@
|
||||
#!/bin/bash
|
||||
# das-server-install - console installer for Das OS Server.
|
||||
#
|
||||
# Usage: das-server-install [--config FILE]
|
||||
#
|
||||
# Asks its questions with dialog and installs the live image on a disk:
|
||||
# GPT with an EFI or BIOS boot partition and Btrfs with the same subvolumes
|
||||
# as the desktop installer, so snapshots and rollback work the same way.
|
||||
# With --config it asks nothing and takes the answers from FILE (see
|
||||
# /usr/share/examples/das-server-installer/install.conf).
|
||||
set -Eeuo pipefail
|
||||
|
||||
log=/tmp/das-server-install.log
|
||||
target=/mnt/das-target
|
||||
source_root=/run/das-installer/root
|
||||
libexec=/usr/libexec/das/installer
|
||||
|
||||
# Answers; a config file sets the same variables
|
||||
DISK=""
|
||||
HOST_NAME=dasos-server
|
||||
USER_NAME=""
|
||||
USER_PASSWORD=""
|
||||
SSH_KEY=""
|
||||
SSH_PASSWORDS=yes
|
||||
TIMEZONE=Europe/Kyiv
|
||||
KEYMAP=us
|
||||
LOCALE=en_US.UTF-8
|
||||
NETWORK=dhcpcd
|
||||
ERASE_DISK=no
|
||||
|
||||
lang=en
|
||||
[[ ${LANG:-} == uk* ]] && lang=uk
|
||||
|
||||
# t KEY: the message in the installer's language
|
||||
t() {
|
||||
local key=$1
|
||||
if [[ $lang == uk ]]; then
|
||||
case $key in
|
||||
title) echo "Встановлення Das OS Server" ;;
|
||||
lang) echo "Мова встановлення:" ;;
|
||||
disk) echo "Диск для встановлення. Усі дані на ньому буде знищено." ;;
|
||||
nodisk) echo "Не знайдено дисків для встановлення." ;;
|
||||
host) echo "Ім'я сервера (латинські літери, цифри, дефіс):" ;;
|
||||
badhost) echo "Неправильне ім'я сервера." ;;
|
||||
user) echo "Ім'я користувача-адміністратора (вхід через sudo, root вимкнено):" ;;
|
||||
baduser) echo "Неправильне ім'я: малі латинські літери, цифри, _ та -, не root." ;;
|
||||
pass) echo "Пароль користувача:" ;;
|
||||
pass2) echo "Ще раз той самий пароль:" ;;
|
||||
badpass) echo "Паролі порожні або не збігаються." ;;
|
||||
key) echo "Публічний ключ SSH для входу (вставте рядок ssh-ed25519 ... або залиште порожнім):" ;;
|
||||
badkey) echo "Це не схоже на публічний ключ SSH." ;;
|
||||
nopass) echo "Заборонити вхід по SSH за паролем (лише за ключем)?" ;;
|
||||
tz) echo "Часовий пояс (наприклад, Europe/Kyiv, UTC):" ;;
|
||||
badtz) echo "Немає такого часового поясу." ;;
|
||||
keymap) echo "Розкладка клавіатури в консолі:" ;;
|
||||
locale) echo "Мова системи:" ;;
|
||||
net) echo "Мережа:" ;;
|
||||
net_dhcpcd) echo "dhcpcd: DHCP на всіх інтерфейсах (просто)" ;;
|
||||
net_nm) echo "NetworkManager: налаштування через nmtui (Wi-Fi, статичні адреси)" ;;
|
||||
summary) echo "Перевірте налаштування:" ;;
|
||||
erase) echo "УСІ ДАНІ НА ДИСКУ %s БУДЕ ЗНИЩЕНО. Продовжити?" ;;
|
||||
cancel) echo "Встановлення скасовано." ;;
|
||||
s_source) echo "Підготовка образу системи..." ;;
|
||||
s_disk) echo "Розмітка диска %s..." ;;
|
||||
s_copy) echo "Копіювання системи (кілька хвилин)..." ;;
|
||||
s_config) echo "Налаштування системи..." ;;
|
||||
s_post) echo "Локалі, знімки, initramfs (кілька хвилин)..." ;;
|
||||
s_boot) echo "Встановлення завантажувача..." ;;
|
||||
finished) echo "Das OS Server встановлено. Вийміть інсталяційний носій і перезавантажте сервер.\n\nВхід: %s, далі sudo. Служби: dsv list. Оновлення: das-update." ;;
|
||||
reboot) echo "Перезавантажити зараз?" ;;
|
||||
failed) echo "Помилка встановлення. Журнал: %s" ;;
|
||||
root) echo "Інсталятор треба запускати від root (sudo das-server-install)." ;;
|
||||
yes) echo "так" ;;
|
||||
no) echo "ні" ;;
|
||||
esac
|
||||
else
|
||||
case $key in
|
||||
title) echo "Das OS Server installation" ;;
|
||||
lang) echo "Installation language:" ;;
|
||||
disk) echo "Disk to install to. All data on it will be erased." ;;
|
||||
nodisk) echo "No disks to install to were found." ;;
|
||||
host) echo "Server name (Latin letters, digits, hyphen):" ;;
|
||||
badhost) echo "Invalid server name." ;;
|
||||
user) echo "Administrator user name (uses sudo, root login is disabled):" ;;
|
||||
baduser) echo "Invalid name: lowercase Latin letters, digits, _ and -, not root." ;;
|
||||
pass) echo "User password:" ;;
|
||||
pass2) echo "The same password again:" ;;
|
||||
badpass) echo "The passwords are empty or do not match." ;;
|
||||
key) echo "SSH public key to log in with (paste the ssh-ed25519 ... line, or leave empty):" ;;
|
||||
badkey) echo "This does not look like an SSH public key." ;;
|
||||
nopass) echo "Disable SSH password login (keys only)?" ;;
|
||||
tz) echo "Time zone (for example Europe/Kyiv, UTC):" ;;
|
||||
badtz) echo "No such time zone." ;;
|
||||
keymap) echo "Console keyboard layout:" ;;
|
||||
locale) echo "System language:" ;;
|
||||
net) echo "Network:" ;;
|
||||
net_dhcpcd) echo "dhcpcd: DHCP on all interfaces (simple)" ;;
|
||||
net_nm) echo "NetworkManager: set up with nmtui (Wi-Fi, static addresses)" ;;
|
||||
summary) echo "Check the settings:" ;;
|
||||
erase) echo "ALL DATA ON %s WILL BE ERASED. Continue?" ;;
|
||||
cancel) echo "Installation cancelled." ;;
|
||||
s_source) echo "Preparing the system image..." ;;
|
||||
s_disk) echo "Partitioning %s..." ;;
|
||||
s_copy) echo "Copying the system (a few minutes)..." ;;
|
||||
s_config) echo "Configuring the system..." ;;
|
||||
s_post) echo "Locales, snapshots, initramfs (a few minutes)..." ;;
|
||||
s_boot) echo "Installing the boot loader..." ;;
|
||||
finished) echo "Das OS Server is installed. Remove the installation medium and reboot.\n\nLog in as %s, then use sudo. Services: dsv list. Updates: das-update." ;;
|
||||
reboot) echo "Reboot now?" ;;
|
||||
failed) echo "Installation failed. Log: %s" ;;
|
||||
root) echo "The installer must run as root (sudo das-server-install)." ;;
|
||||
yes) echo "yes" ;;
|
||||
no) echo "no" ;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
interactive=1
|
||||
dialog_ui() {
|
||||
local labels=()
|
||||
if [[ $lang == uk ]]; then
|
||||
labels=(--ok-label "Гаразд" --cancel-label "Скасувати" --yes-label "Так" --no-label "Ні")
|
||||
fi
|
||||
dialog --backtitle "Das OS Server" --title "$(t title)" "${labels[@]}" "$@" 3>&1 1>&2 2>&3
|
||||
}
|
||||
|
||||
# Shows a step in the dialog, or prints it when installing from a config file
|
||||
step() {
|
||||
if [[ -n $interactive ]]; then
|
||||
dialog --backtitle "Das OS Server" --title "$(t title)" --infobox "$1" 5 70
|
||||
echo "==> $1" >>"$log"
|
||||
else
|
||||
echo "==> $1" | tee -a "$log"
|
||||
fi
|
||||
}
|
||||
|
||||
fail() {
|
||||
trap - ERR
|
||||
local msg
|
||||
# shellcheck disable=SC2059
|
||||
msg=$(printf "$(t failed)" "$log")
|
||||
if [[ -n $interactive ]]; then
|
||||
dialog --backtitle "Das OS Server" --title "$(t title)" --msgbox "$msg\n\n$(tail -n 12 "$log" | sed 's/\\/\\\\/g')" 22 76 || true
|
||||
clear
|
||||
fi
|
||||
echo "das-server-install: $msg" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
cancelled() {
|
||||
[[ -n $interactive ]] && clear
|
||||
t cancel
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Questions -------------------------------------------------------------
|
||||
|
||||
# Disks that can be installed to: not read-only, not the live medium
|
||||
list_disks() {
|
||||
local live="" dev
|
||||
if dev=$(blkid -L VOID_LIVE 2>/dev/null); then
|
||||
live=$(lsblk -no PKNAME "$dev" 2>/dev/null | head -n 1)
|
||||
[[ -n $live ]] && live=/dev/$live || live=$dev
|
||||
fi
|
||||
lsblk -dpno NAME,TYPE,RO,SIZE,MODEL | while read -r name type ro size model; do
|
||||
[[ $type == disk && $ro == 0 && $name != "$live" ]] || continue
|
||||
[[ $name == /dev/zram* || $name == /dev/loop* ]] && continue
|
||||
printf '%s\t%s %s\n' "$name" "$size" "${model:-}"
|
||||
done
|
||||
}
|
||||
|
||||
ask_language() {
|
||||
local choice
|
||||
choice=$(dialog --backtitle "Das OS Server" --title "Das OS Server" \
|
||||
--default-item "$lang" --menu "Language / Мова:" 10 50 2 \
|
||||
en "English" uk "Українська" 3>&1 1>&2 2>&3) || cancelled
|
||||
lang=$choice
|
||||
if [[ $lang == uk ]]; then
|
||||
LOCALE=uk_UA.UTF-8
|
||||
# The default console font has no Cyrillic (a font needs a Unicode table,
|
||||
# .psfu); there is no font to set on serial or ssh
|
||||
case $(tty) in /dev/tty[0-9]*) setfont cyr-sun16 2>/dev/null || true ;; esac
|
||||
fi
|
||||
}
|
||||
|
||||
ask_disk() {
|
||||
local items=() name desc
|
||||
while IFS=$'\t' read -r name desc; do
|
||||
items+=("$name" "$desc")
|
||||
done < <(list_disks)
|
||||
if [[ ${#items[@]} -eq 0 ]]; then
|
||||
dialog_ui --msgbox "$(t nodisk)" 7 60 || true
|
||||
cancelled
|
||||
fi
|
||||
DISK=$(dialog_ui --menu "$(t disk)" 15 70 6 "${items[@]}") || cancelled
|
||||
}
|
||||
|
||||
valid_host() {
|
||||
[[ $1 =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$ ]]
|
||||
}
|
||||
|
||||
valid_user() {
|
||||
[[ $1 =~ ^[a-z_][a-z0-9_-]{0,31}$ ]] || return 1
|
||||
case $1 in root | live | nobody | daemon | bin | sys) return 1 ;; esac
|
||||
}
|
||||
|
||||
valid_key() {
|
||||
[[ -z $1 || $1 =~ ^(ssh-(ed25519|rsa|dss)|ecdsa-sha2-[a-z0-9]+|sk-[a-z0-9@.-]+)\ [A-Za-z0-9+/=]+ ]]
|
||||
}
|
||||
|
||||
ask_host() {
|
||||
while :; do
|
||||
HOST_NAME=$(dialog_ui --inputbox "$(t host)" 8 60 "$HOST_NAME") || cancelled
|
||||
valid_host "$HOST_NAME" && return
|
||||
dialog_ui --msgbox "$(t badhost)" 6 50 || true
|
||||
done
|
||||
}
|
||||
|
||||
ask_user() {
|
||||
local p1 p2
|
||||
while :; do
|
||||
USER_NAME=$(dialog_ui --inputbox "$(t user)" 9 60 "$USER_NAME") || cancelled
|
||||
valid_user "$USER_NAME" && break
|
||||
dialog_ui --msgbox "$(t baduser)" 7 60 || true
|
||||
done
|
||||
while :; do
|
||||
p1=$(dialog_ui --insecure --passwordbox "$(t pass)" 8 60) || cancelled
|
||||
p2=$(dialog_ui --insecure --passwordbox "$(t pass2)" 8 60) || cancelled
|
||||
if [[ -n $p1 && $p1 == "$p2" ]]; then
|
||||
USER_PASSWORD=$p1
|
||||
return
|
||||
fi
|
||||
dialog_ui --msgbox "$(t badpass)" 6 50 || true
|
||||
done
|
||||
}
|
||||
|
||||
ask_ssh() {
|
||||
while :; do
|
||||
SSH_KEY=$(dialog_ui --inputbox "$(t key)" 10 76 "$SSH_KEY") || cancelled
|
||||
valid_key "$SSH_KEY" && break
|
||||
dialog_ui --msgbox "$(t badkey)" 6 50 || true
|
||||
done
|
||||
SSH_PASSWORDS=yes
|
||||
if [[ -n $SSH_KEY ]] && dialog_ui --yesno "$(t nopass)" 7 60; then
|
||||
SSH_PASSWORDS=no
|
||||
fi
|
||||
}
|
||||
|
||||
ask_system() {
|
||||
while :; do
|
||||
TIMEZONE=$(dialog_ui --inputbox "$(t tz)" 8 60 "$TIMEZONE") || cancelled
|
||||
[[ -f /usr/share/zoneinfo/$TIMEZONE ]] && break
|
||||
dialog_ui --msgbox "$(t badtz)" 6 50 || true
|
||||
done
|
||||
KEYMAP=$(dialog_ui --default-item "$KEYMAP" --menu "$(t keymap)" 15 50 7 \
|
||||
us "English (US)" ua-utf "Українська" uk "English (UK)" de-latin1 "Deutsch" \
|
||||
fr-latin1 "Français" pl2 "Polski") || cancelled
|
||||
LOCALE=$(dialog_ui --default-item "$LOCALE" --menu "$(t locale)" 10 50 2 \
|
||||
en_US.UTF-8 "English" uk_UA.UTF-8 "Українська") || cancelled
|
||||
NETWORK=$(dialog_ui --default-item "$NETWORK" --menu "$(t net)" 10 76 2 \
|
||||
dhcpcd "$(t net_dhcpcd)" NetworkManager "$(t net_nm)") || cancelled
|
||||
}
|
||||
|
||||
confirm() {
|
||||
local key pw msg
|
||||
key=$(t no)
|
||||
pw=$(t yes)
|
||||
[[ -n $SSH_KEY ]] && key=$(t yes)
|
||||
[[ $SSH_PASSWORDS == no ]] && pw=$(t no)
|
||||
dialog_ui --no-collapse --msgbox "$(t summary)
|
||||
|
||||
Disk: $DISK
|
||||
Host: $HOST_NAME
|
||||
User: $USER_NAME
|
||||
SSH key: $key
|
||||
SSH passwords: $pw
|
||||
Time zone: $TIMEZONE
|
||||
Keyboard: $KEYMAP
|
||||
Language: $LOCALE
|
||||
Network: $NETWORK" 18 60 || cancelled
|
||||
# shellcheck disable=SC2059
|
||||
msg=$(printf "$(t erase)" "$DISK")
|
||||
dialog_ui --defaultno --yesno "$msg" 7 60 || cancelled
|
||||
ERASE_DISK=yes
|
||||
}
|
||||
|
||||
# --- Installation ----------------------------------------------------------
|
||||
|
||||
# part N: the device of partition N on $DISK
|
||||
part() {
|
||||
lsblk -lnpo NAME,TYPE "$DISK" | awk '$2 == "part" { print $1 }' | sed -n "${1}p"
|
||||
}
|
||||
|
||||
in_target() {
|
||||
chroot "$target" "$@"
|
||||
}
|
||||
|
||||
# Undo mounts from an earlier attempt or a failure
|
||||
unmount_target() {
|
||||
if mountpoint -q "$target"; then
|
||||
umount -R "$target" || umount -Rl "$target"
|
||||
fi
|
||||
}
|
||||
|
||||
uefi() {
|
||||
[[ -d /sys/firmware/efi ]]
|
||||
}
|
||||
|
||||
serial_console() {
|
||||
grep -q 'console=ttyS0' /proc/cmdline
|
||||
}
|
||||
|
||||
partition() {
|
||||
local efi root
|
||||
unmount_target
|
||||
wipefs -a "$DISK"
|
||||
sgdisk --zap-all "$DISK"
|
||||
if uefi; then
|
||||
sgdisk -n 1:0:+512M -t 1:ef00 -c 1:EFI -n 2:0:0 -t 2:8300 -c 2:dasos "$DISK"
|
||||
else
|
||||
# GRUB on BIOS keeps its core image in a small partition on GPT
|
||||
sgdisk -n 1:0:+1M -t 1:ef02 -c 1:bios -n 2:0:0 -t 2:8300 -c 2:dasos "$DISK"
|
||||
fi
|
||||
partprobe "$DISK" 2>/dev/null || true
|
||||
udevadm settle
|
||||
efi=$(part 1)
|
||||
root=$(part 2)
|
||||
[[ -b $root ]] || return 1
|
||||
|
||||
uefi && mkfs.vfat -F 32 -n EFI "$efi"
|
||||
mkfs.btrfs -f -L dasos "$root"
|
||||
|
||||
# The same subvolumes as the Calamares configuration (mount.conf)
|
||||
mkdir -p "$target"
|
||||
mount "$root" "$target"
|
||||
for sv in @ @home @snapshots @var_log @var_cache_xbps; do
|
||||
btrfs subvolume create "$target/$sv"
|
||||
done
|
||||
umount "$target"
|
||||
|
||||
local opts=noatime,compress=zstd:1
|
||||
mount -o "$opts,subvol=@" "$root" "$target"
|
||||
mkdir -p "$target"/{home,.snapshots,var/log,var/cache/xbps}
|
||||
mount -o "$opts,subvol=@home" "$root" "$target/home"
|
||||
mount -o "$opts,subvol=@snapshots" "$root" "$target/.snapshots"
|
||||
mount -o "$opts,subvol=@var_log" "$root" "$target/var/log"
|
||||
mount -o "$opts,subvol=@var_cache_xbps" "$root" "$target/var/cache/xbps"
|
||||
if uefi; then
|
||||
mkdir -p "$target/boot/efi"
|
||||
mount -o umask=0077 "$efi" "$target/boot/efi"
|
||||
fi
|
||||
}
|
||||
|
||||
copy_system() {
|
||||
# No --sparse: GRUB can't read kernels with Btrfs holes (see postinstall)
|
||||
rsync -aHAX --numeric-ids "$source_root/" "$target/"
|
||||
}
|
||||
|
||||
write_fstab() {
|
||||
local root_uuid efi_uuid opts=noatime,compress=zstd:1
|
||||
root_uuid=$(blkid -s UUID -o value "$(part 2)")
|
||||
{
|
||||
echo "# <file system> <dir> <type> <options> <dump> <pass>"
|
||||
echo "UUID=$root_uuid / btrfs $opts,subvol=@ 0 0"
|
||||
echo "UUID=$root_uuid /home btrfs $opts,subvol=@home 0 0"
|
||||
echo "UUID=$root_uuid /.snapshots btrfs $opts,subvol=@snapshots 0 0"
|
||||
echo "UUID=$root_uuid /var/log btrfs $opts,subvol=@var_log 0 0"
|
||||
echo "UUID=$root_uuid /var/cache/xbps btrfs $opts,subvol=@var_cache_xbps 0 0"
|
||||
if uefi; then
|
||||
efi_uuid=$(blkid -s UUID -o value "$(part 1)")
|
||||
echo "UUID=$efi_uuid /boot/efi vfat defaults,umask=0077 0 2"
|
||||
fi
|
||||
} >"$target/etc/fstab"
|
||||
}
|
||||
|
||||
mount_chroot() {
|
||||
mount -t proc proc "$target/proc"
|
||||
mount -t sysfs sys "$target/sys"
|
||||
mount --rbind /dev "$target/dev"
|
||||
mount -t tmpfs tmpfs "$target/run"
|
||||
if uefi; then
|
||||
mount -t efivarfs efivarfs "$target/sys/firmware/efi/efivars" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# set_rc VAR VALUE: sets VAR in /etc/rc.conf, uncommenting Void's example line
|
||||
set_rc() {
|
||||
local rc=$target/etc/rc.conf
|
||||
if grep -q "^#\?$1=" "$rc"; then
|
||||
sed -i "s|^#\?$1=.*|$1=\"$2\"|" "$rc"
|
||||
else
|
||||
echo "$1=\"$2\"" >>"$rc"
|
||||
fi
|
||||
}
|
||||
|
||||
enable_service() {
|
||||
ln -sfn "/etc/sv/$1" "$target/etc/runit/runsvdir/default/$1"
|
||||
}
|
||||
|
||||
disable_service() {
|
||||
rm -f "$target/etc/runit/runsvdir/default/$1"
|
||||
}
|
||||
|
||||
configure() {
|
||||
local home
|
||||
|
||||
# The live image's /etc/issue tells how to log in to the live system
|
||||
printf 'Das OS Server \\r (\\l)\n\n' >"$target/etc/issue"
|
||||
echo "$HOST_NAME" >"$target/etc/hostname"
|
||||
if ! grep -q "[[:space:]]$HOST_NAME\$" "$target/etc/hosts"; then
|
||||
printf '127.0.1.1\t%s\n' "$HOST_NAME" >>"$target/etc/hosts"
|
||||
fi
|
||||
echo "LANG=$LOCALE" >"$target/etc/locale.conf"
|
||||
ln -sfn "/usr/share/zoneinfo/$TIMEZONE" "$target/etc/localtime"
|
||||
set_rc KEYMAP "$KEYMAP"
|
||||
set_rc HARDWARECLOCK UTC
|
||||
[[ $LOCALE == uk* || $KEYMAP == ua* ]] && set_rc FONT cyr-sun16
|
||||
|
||||
# The administrator: sudo through wheel, root has no password
|
||||
in_target useradd -m -s /bin/bash -G wheel,docker,socklog "$USER_NAME"
|
||||
# -c: Void's PAM stack for chpasswd only has pam_permit for passwords, so
|
||||
# without it nothing is written (Void's own installer does the same)
|
||||
printf '%s:%s\n' "$USER_NAME" "$USER_PASSWORD" | in_target chpasswd -c SHA512
|
||||
in_target passwd -l root >/dev/null
|
||||
echo "%wheel ALL=(ALL:ALL) ALL" >"$target/etc/sudoers.d/10-wheel"
|
||||
chmod 440 "$target/etc/sudoers.d/10-wheel"
|
||||
|
||||
if [[ -n $SSH_KEY ]]; then
|
||||
home=$target/home/$USER_NAME
|
||||
install -d -m 700 "$home/.ssh"
|
||||
echo "$SSH_KEY" >"$home/.ssh/authorized_keys"
|
||||
chmod 600 "$home/.ssh/authorized_keys"
|
||||
in_target chown -R "$USER_NAME:$USER_NAME" "/home/$USER_NAME/.ssh"
|
||||
fi
|
||||
if [[ $SSH_PASSWORDS == no ]]; then
|
||||
printf '%s\n' "# Written by das-server-install: SSH keys only" \
|
||||
"PasswordAuthentication no" "KbdInteractiveAuthentication no" \
|
||||
>"$target/etc/ssh/sshd_config.d/40-das-keys-only.conf"
|
||||
fi
|
||||
|
||||
for sv in sshd chronyd nftables fail2ban docker socklog-unix nanoklogd; do
|
||||
enable_service "$sv"
|
||||
done
|
||||
if [[ $NETWORK == NetworkManager ]]; then
|
||||
disable_service dhcpcd
|
||||
enable_service dbus
|
||||
enable_service NetworkManager
|
||||
else
|
||||
enable_service dhcpcd
|
||||
fi
|
||||
serial_console && enable_service agetty-ttyS0
|
||||
return 0
|
||||
}
|
||||
|
||||
install_bootloader() {
|
||||
local grub=$target/etc/default/grub cmdline="loglevel=4"
|
||||
serial_console && cmdline+=" console=tty0 console=ttyS0,115200"
|
||||
sed -i -e '/^GRUB_DISTRIBUTOR=/d' -e '/^GRUB_CMDLINE_LINUX_DEFAULT=/d' -e '/^GRUB_TIMEOUT=/d' \
|
||||
-e '/^GRUB_TERMINAL/d' -e '/^GRUB_SERIAL_COMMAND=/d' -e '/^GRUB_DISABLE_OS_PROBER=/d' "$grub"
|
||||
{
|
||||
echo 'GRUB_DISTRIBUTOR="Das OS"'
|
||||
echo "GRUB_CMDLINE_LINUX_DEFAULT=\"$cmdline\""
|
||||
echo 'GRUB_TIMEOUT=5'
|
||||
echo 'GRUB_DISABLE_OS_PROBER=true'
|
||||
if serial_console; then
|
||||
echo 'GRUB_TERMINAL="console serial"'
|
||||
echo 'GRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200"'
|
||||
fi
|
||||
} >>"$grub"
|
||||
|
||||
if uefi; then
|
||||
in_target grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=dasos
|
||||
# Also at the fallback path, for firmware that forgets boot entries
|
||||
in_target grub-install --target=x86_64-efi --efi-directory=/boot/efi --removable --no-nvram
|
||||
else
|
||||
in_target grub-install --target=i386-pc "$DISK"
|
||||
fi
|
||||
}
|
||||
|
||||
finish() {
|
||||
# The first snapshot, also shown in the boot menu (like Calamares' shellprocess@snapshot)
|
||||
in_target snapper --no-dbus -c root create -d "Fresh install" -c number --userdata important=yes || true
|
||||
in_target grub-mkconfig -o /boot/grub/grub.cfg
|
||||
# The installer is not needed on the installed system
|
||||
in_target xbps-remove -y das-server-installer das-install-common || true
|
||||
sync
|
||||
}
|
||||
|
||||
# Any failing command stops the installation with the log (set -E: also
|
||||
# inside functions; "f || fail" would switch set -e off within f).
|
||||
install_system() {
|
||||
: >"$log"
|
||||
trap fail ERR
|
||||
step "$(t s_source)"
|
||||
"$libexec/mount-source" >>"$log" 2>&1
|
||||
# shellcheck disable=SC2059
|
||||
step "$(printf "$(t s_disk)" "$DISK")"
|
||||
partition >>"$log" 2>&1
|
||||
step "$(t s_copy)"
|
||||
copy_system >>"$log" 2>&1
|
||||
step "$(t s_config)"
|
||||
write_fstab >>"$log" 2>&1
|
||||
mount_chroot >>"$log" 2>&1
|
||||
configure >>"$log" 2>&1
|
||||
step "$(t s_post)"
|
||||
in_target "$libexec/postinstall" >>"$log" 2>&1
|
||||
step "$(t s_boot)"
|
||||
install_bootloader >>"$log" 2>&1
|
||||
finish >>"$log" 2>&1
|
||||
unmount_target >>"$log" 2>&1
|
||||
trap - ERR
|
||||
}
|
||||
|
||||
load_config() {
|
||||
local file=$1
|
||||
[[ -r $file ]] || {
|
||||
echo "das-server-install: cannot read $file" >&2
|
||||
exit 1
|
||||
}
|
||||
# shellcheck source=/dev/null
|
||||
. "$file"
|
||||
interactive=""
|
||||
local bad=""
|
||||
[[ -b $DISK ]] || bad+=" DISK"
|
||||
valid_host "$HOST_NAME" || bad+=" HOST_NAME"
|
||||
valid_user "$USER_NAME" || bad+=" USER_NAME"
|
||||
[[ -n $USER_PASSWORD ]] || bad+=" USER_PASSWORD"
|
||||
valid_key "$SSH_KEY" || bad+=" SSH_KEY"
|
||||
[[ $SSH_PASSWORDS == yes || ( $SSH_PASSWORDS == no && -n $SSH_KEY ) ]] || bad+=" SSH_PASSWORDS"
|
||||
[[ -f /usr/share/zoneinfo/$TIMEZONE ]] || bad+=" TIMEZONE"
|
||||
[[ $NETWORK == dhcpcd || $NETWORK == NetworkManager ]] || bad+=" NETWORK"
|
||||
[[ $ERASE_DISK == yes ]] || bad+=" ERASE_DISK"
|
||||
if [[ -n $bad ]]; then
|
||||
echo "das-server-install: invalid or missing in $file:$bad" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
exec sudo --preserve-env=LANG "$0" "$@"
|
||||
fi
|
||||
case ${1:-} in
|
||||
--config)
|
||||
load_config "${2:?--config needs a file}"
|
||||
;;
|
||||
-h | --help)
|
||||
sed -n '2,11s/^# \{0,1\}//p' "$0"
|
||||
exit 0
|
||||
;;
|
||||
"") ;;
|
||||
*)
|
||||
echo "das-server-install: unknown option $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ -n $interactive ]]; then
|
||||
ask_language
|
||||
ask_disk
|
||||
ask_host
|
||||
ask_user
|
||||
ask_ssh
|
||||
ask_system
|
||||
confirm
|
||||
fi
|
||||
install_system
|
||||
|
||||
if [[ -n $interactive ]]; then
|
||||
local msg
|
||||
# shellcheck disable=SC2059
|
||||
msg=$(printf "$(t finished)" "$USER_NAME")
|
||||
if dialog_ui --yesno "$msg\n\n$(t reboot)" 12 70; then
|
||||
reboot
|
||||
fi
|
||||
clear
|
||||
else
|
||||
echo "==> done, log: $log"
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -0,0 +1,20 @@
|
||||
# Answers for an unattended Das OS Server installation:
|
||||
# sudo das-server-install --config install.conf
|
||||
# The file is read by bash. Every value is checked before anything is done.
|
||||
|
||||
# The disk to install to; it is erased completely
|
||||
DISK=/dev/vda
|
||||
ERASE_DISK=no # must be "yes" to install
|
||||
|
||||
HOST_NAME=dasos-server
|
||||
USER_NAME=admin # gets sudo; root login stays disabled
|
||||
USER_PASSWORD=change-me
|
||||
|
||||
# A public key for SSH logins (optional), and whether passwords stay allowed
|
||||
SSH_KEY=""
|
||||
SSH_PASSWORDS=yes # "no" requires SSH_KEY
|
||||
|
||||
TIMEZONE=Europe/Kyiv
|
||||
KEYMAP=us # console layout: us, ua-utf, uk, de-latin1, ...
|
||||
LOCALE=en_US.UTF-8 # or uk_UA.UTF-8
|
||||
NETWORK=dhcpcd # or NetworkManager
|
||||
@@ -0,0 +1,16 @@
|
||||
# Template file for 'das-server-installer'
|
||||
pkgname=das-server-installer
|
||||
version=0.1.0
|
||||
revision=1
|
||||
depends="bash dialog das-install-common btrfs-progs dosfstools gptfdisk parted
|
||||
rsync util-linux grub grub-x86_64-efi efibootmgr"
|
||||
short_desc="Das OS Server console installer for the live ISO"
|
||||
maintainer="Das <anry.das@gmail.com>"
|
||||
license="MIT"
|
||||
homepage="https://git.das.org.ua/das/Das-OS"
|
||||
|
||||
do_install() {
|
||||
vbin ${FILESDIR}/das-server-install
|
||||
vsconf ${FILESDIR}/install.conf
|
||||
vlicense ${FILESDIR}/LICENSE
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Das
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"log-driver": "local"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# Das OS: ban addresses that keep failing SSH logins, through nftables.
|
||||
[DEFAULT]
|
||||
banaction = nftables-multiport
|
||||
banaction_allports = nftables-allports
|
||||
|
||||
[sshd]
|
||||
enabled = true
|
||||
backend = polling
|
||||
# socklog-void collects auth messages here. svlogd starts each line with a
|
||||
# UTC time stamp; the pattern also consumes the facility and the syslog date
|
||||
# that follow it, so the sshd filter sees "sshd-session[pid]: ...":
|
||||
# 2026-10-19T17:25:46.09500 auth.info: Oct 19 20:25:46 sshd-session[1154]: Invalid user ...
|
||||
logpath = /var/log/socklog/secure/current
|
||||
datepattern = ^%%Y-%%m-%%dT%%H:%%M:%%S\.%%f(?: \S+: \S+ +\d+ \S+)?
|
||||
logtimezone = UTC
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/usr/sbin/nft -f
|
||||
# Das OS server firewall: incoming connections are closed except SSH.
|
||||
#
|
||||
# Only the "das" table is replaced, so loading this file again
|
||||
# (dsv restart nftables) keeps the rules of Docker and fail2ban.
|
||||
# Ports that Docker containers publish (-p 8080:80) pass through Docker's
|
||||
# own forwarding rules, not the input chain below.
|
||||
|
||||
table inet das
|
||||
delete table inet das
|
||||
|
||||
table inet das {
|
||||
chain input {
|
||||
type filter hook input priority filter; policy drop;
|
||||
|
||||
ct state established,related accept
|
||||
ct state invalid drop
|
||||
iif lo accept
|
||||
meta l4proto { icmp, ipv6-icmp } accept
|
||||
# DHCPv6 answers come from the router's link-local address
|
||||
ip6 saddr fe80::/10 udp dport dhcpv6-client accept
|
||||
# Containers may reach services on the host (DNS, a database...)
|
||||
iifname "docker0" accept
|
||||
iifname "br-*" accept
|
||||
|
||||
tcp dport ssh accept
|
||||
|
||||
# Open more ports here, then: dsv restart nftables
|
||||
# tcp dport { http, https } accept
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# Das OS server defaults, see sshd_config(5). sshd keeps the first value it
|
||||
# reads, so a file sorted before this one (40-local.conf) overrides it.
|
||||
PermitRootLogin prohibit-password
|
||||
X11Forwarding no
|
||||
@@ -0,0 +1,24 @@
|
||||
# Template file for 'das-server'
|
||||
pkgname=das-server
|
||||
version=0.1.0
|
||||
revision=1
|
||||
depends="openssh chrony dhcpcd NetworkManager docker docker-compose nftables
|
||||
fail2ban socklog-void python3 curl lazydocker lazygit mc tmux htop
|
||||
das-snapshots das-update dsv"
|
||||
short_desc="Das OS server: packages and secure defaults for SSH, firewall and Docker"
|
||||
maintainer="Das <anry.das@gmail.com>"
|
||||
license="MIT"
|
||||
homepage="https://git.das.org.ua/das/Das-OS"
|
||||
conf_files="
|
||||
/etc/nftables.conf
|
||||
/etc/fail2ban/jail.d/das.conf
|
||||
/etc/ssh/sshd_config.d/50-das.conf
|
||||
/etc/docker/daemon.json"
|
||||
|
||||
do_install() {
|
||||
vinstall ${FILESDIR}/nftables.conf 644 etc
|
||||
vinstall ${FILESDIR}/fail2ban-das.conf 644 etc/fail2ban/jail.d das.conf
|
||||
vinstall ${FILESDIR}/sshd-das.conf 644 etc/ssh/sshd_config.d 50-das.conf
|
||||
vinstall ${FILESDIR}/docker-daemon.json 644 etc/docker daemon.json
|
||||
vlicense ${FILESDIR}/LICENSE
|
||||
}
|
||||
@@ -43,7 +43,9 @@ if [ -f "$cfg" ] && ! grep -q '^GRUB_BTRFS_SUBMENUNAME=' "$cfg"; then
|
||||
fi
|
||||
|
||||
# Hourly snapshots come from cron, and grub-btrfs adds them to the boot menu.
|
||||
for sv in cronie grub-btrfs; do
|
||||
# snapper talks to snapperd over the system bus (the server has no desktop
|
||||
# that would enable dbus).
|
||||
for sv in dbus cronie grub-btrfs; do
|
||||
ln -sfn "/etc/sv/$sv" "/etc/runit/runsvdir/default/$sv"
|
||||
done
|
||||
msg "snapshots are enabled"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Template file for 'das-snapshots'
|
||||
pkgname=das-snapshots
|
||||
version=0.1.0
|
||||
version=0.2.0
|
||||
revision=1
|
||||
depends="btrfs-progs cronie dracut grub-btrfs snapper snapper-rollback"
|
||||
short_desc="Das OS Btrfs snapshots: snapper setup, boot menu entries and rollback"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// Command das-update-gui is the desktop part of das-update, installed as
|
||||
// /usr/libexec/das/das-update-gui by das-tools. das-update starts it when a
|
||||
// display is available, so servers get das-update without GTK.
|
||||
//
|
||||
// das-update-gui window that lists and installs updates
|
||||
// das-update-gui --tray background check, shows a tray icon when updates are available
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
"dasos/tools/internal/i18n"
|
||||
)
|
||||
|
||||
func main() {
|
||||
tray := flag.Bool("tray", false, "check for updates in the background")
|
||||
lang := flag.String("lang", "", "message language, e.g. uk_UA.UTF-8")
|
||||
flag.Parse()
|
||||
if *lang != "" {
|
||||
i18n.SetLang(*lang)
|
||||
}
|
||||
if *tray {
|
||||
os.Exit(runTray())
|
||||
}
|
||||
os.Exit(runWindow())
|
||||
}
|
||||
+9
-8
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
"dasos/tools/internal/i18n"
|
||||
"dasos/tools/internal/system"
|
||||
"dasos/tools/internal/update"
|
||||
"dasos/tools/internal/xbps"
|
||||
)
|
||||
|
||||
@@ -265,20 +266,20 @@ func (w *window) startInstall() {
|
||||
for sc.Scan() {
|
||||
line := sc.Text()
|
||||
switch {
|
||||
case strings.HasPrefix(line, markStep):
|
||||
line = "\n==> " + strings.TrimPrefix(line, markStep)
|
||||
case strings.HasPrefix(line, markSnapshot):
|
||||
n, _ := strconv.Atoi(strings.TrimPrefix(line, markSnapshot))
|
||||
case strings.HasPrefix(line, update.MarkStep):
|
||||
line = "\n==> " + strings.TrimPrefix(line, update.MarkStep)
|
||||
case strings.HasPrefix(line, update.MarkSnapshot):
|
||||
n, _ := strconv.Atoi(strings.TrimPrefix(line, update.MarkSnapshot))
|
||||
glib.IdleAdd(func() { w.snapshot = n })
|
||||
line = i18n.T("update.snapshot", n)
|
||||
case line == markReboot:
|
||||
case line == update.MarkReboot:
|
||||
reboot = true
|
||||
continue
|
||||
case line == markUpToDate:
|
||||
case line == update.MarkUpToDate:
|
||||
upToDate = true
|
||||
continue
|
||||
case strings.HasPrefix(line, markError):
|
||||
failure = strings.TrimPrefix(line, markError)
|
||||
case strings.HasPrefix(line, update.MarkError):
|
||||
failure = strings.TrimPrefix(line, update.MarkError)
|
||||
}
|
||||
glib.IdleAdd(func() { w.appendLog(line + "\n") })
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
// Command das-update updates Das OS with a snapper snapshot taken before
|
||||
// the update, so a broken update can be rolled back from the boot menu.
|
||||
//
|
||||
// das-update window that lists and installs updates
|
||||
// das-update the update window on a desktop, otherwise the same as --cli
|
||||
// das-update --tray background check, shows a tray icon when updates are available
|
||||
// das-update --cli the same in a terminal (servers, ssh); -y skips the question
|
||||
// das-update --cli update in a terminal (servers, ssh); -y skips the question
|
||||
// das-update --apply the privileged part, started by the window through pkexec
|
||||
//
|
||||
// The window and the tray icon are a separate program from das-tools
|
||||
// (guiPath), so this one has no GTK dependency.
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -42,27 +45,42 @@ func main() {
|
||||
case *cli:
|
||||
os.Exit(runCLI(*yes))
|
||||
case *tray:
|
||||
os.Exit(runTray())
|
||||
// Nothing to show without the desktop part
|
||||
if haveGUI() {
|
||||
execGUI()
|
||||
}
|
||||
default:
|
||||
os.Exit(runWindow())
|
||||
if haveGUI() && haveDisplay() {
|
||||
execGUI()
|
||||
}
|
||||
os.Exit(runCLI(*yes))
|
||||
}
|
||||
}
|
||||
|
||||
// Machine-readable lines that --apply prints for the window, among the
|
||||
// plain output of xbps.
|
||||
const (
|
||||
markStep = "@@step "
|
||||
markSnapshot = "@@snapshot "
|
||||
markReboot = "@@reboot"
|
||||
markUpToDate = "@@uptodate"
|
||||
markError = "@@error "
|
||||
)
|
||||
// guiPath is the window and tray icon program from das-tools.
|
||||
const guiPath = "/usr/libexec/das/das-update-gui"
|
||||
|
||||
func haveGUI() bool {
|
||||
_, err := os.Stat(guiPath)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func haveDisplay() bool {
|
||||
return os.Getenv("DISPLAY") != "" || os.Getenv("WAYLAND_DISPLAY") != ""
|
||||
}
|
||||
|
||||
// execGUI replaces this process with the graphical part, passing the
|
||||
// arguments on. It returns only when that fails.
|
||||
func execGUI() {
|
||||
err := syscall.Exec(guiPath, append([]string{guiPath}, os.Args[1:]...), os.Environ())
|
||||
fmt.Fprintln(os.Stderr, "das-update:", err)
|
||||
}
|
||||
|
||||
type markReporter struct{ w io.Writer }
|
||||
|
||||
func (r markReporter) Step(title string) { fmt.Fprintln(r.w, markStep+title) }
|
||||
func (r markReporter) Step(title string) { fmt.Fprintln(r.w, update.MarkStep+title) }
|
||||
func (r markReporter) Output() io.Writer { return r.w }
|
||||
func (r markReporter) Snapshot(n int) { fmt.Fprintf(r.w, "%s%d\n", markSnapshot, n) }
|
||||
func (r markReporter) Snapshot(n int) { fmt.Fprintf(r.w, "%s%d\n", update.MarkSnapshot, n) }
|
||||
|
||||
func runApply() int {
|
||||
if os.Geteuid() != 0 {
|
||||
@@ -74,13 +92,13 @@ func runApply() int {
|
||||
r := markReporter{os.Stdout}
|
||||
res, err := update.System().Apply(context.Background(), r)
|
||||
if err != nil {
|
||||
fmt.Println(markError + err.Error())
|
||||
fmt.Println(update.MarkError + err.Error())
|
||||
return 1
|
||||
}
|
||||
if len(res.Updates) == 0 {
|
||||
fmt.Println(markUpToDate)
|
||||
fmt.Println(update.MarkUpToDate)
|
||||
} else if res.Reboot {
|
||||
fmt.Println(markReboot)
|
||||
fmt.Println(update.MarkReboot)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package update
|
||||
|
||||
// Machine-readable lines that "das-update --apply" prints among the plain
|
||||
// output of xbps, for the window that runs it through pkexec.
|
||||
const (
|
||||
MarkStep = "@@step "
|
||||
MarkSnapshot = "@@snapshot "
|
||||
MarkReboot = "@@reboot"
|
||||
MarkUpToDate = "@@uptodate"
|
||||
MarkError = "@@error "
|
||||
)
|
||||
@@ -1,18 +1,19 @@
|
||||
# Template file for 'das-tools'
|
||||
# In-tree package: Go sources are in files/src (FILESDIR).
|
||||
pkgname=das-tools
|
||||
version=0.2.0
|
||||
version=0.3.0
|
||||
revision=1
|
||||
create_wrksrc=yes
|
||||
# Like build_style=go: the Go linker decides about PIE, xbps-src must not check it
|
||||
nopie=yes
|
||||
hostmakedepends="go pkg-config"
|
||||
makedepends="gtk+3-devel"
|
||||
depends="dbus libnotify polkit sudo xdg-user-dirs xdg-utils"
|
||||
short_desc="Das OS tools: das-update (updates with snapshots) and das-welcome"
|
||||
depends="das-update>=${version}_${revision} dbus libnotify polkit xdg-user-dirs xdg-utils"
|
||||
short_desc="Das OS desktop tools: update window and tray icon, das-welcome"
|
||||
maintainer="Das <anry.das@gmail.com>"
|
||||
license="MIT"
|
||||
homepage="https://git.das.org.ua/das/Das-OS"
|
||||
subpackages="das-update"
|
||||
|
||||
do_build() {
|
||||
cp -rL "${FILESDIR}/src/." .
|
||||
@@ -24,6 +25,7 @@ do_build() {
|
||||
|
||||
do_install() {
|
||||
vbin bin/das-update
|
||||
vinstall bin/das-update-gui 755 usr/libexec/das
|
||||
vbin bin/das-welcome
|
||||
vinstall "${FILESDIR}/data/das-update.desktop" 644 usr/share/applications
|
||||
vinstall "${FILESDIR}/data/das-welcome.desktop" 644 usr/share/applications
|
||||
@@ -32,3 +34,13 @@ do_install() {
|
||||
vinstall "${FILESDIR}/data/ua.org.das.update.policy" 644 usr/share/polkit-1/actions
|
||||
vlicense "${FILESDIR}/LICENSE"
|
||||
}
|
||||
|
||||
# Without GTK, for servers: the window and the tray icon stay in das-tools.
|
||||
das-update_package() {
|
||||
short_desc="Das OS updates with a snapper snapshot to roll back to"
|
||||
depends="sudo"
|
||||
pkg_install() {
|
||||
vmove usr/bin/das-update
|
||||
vmove usr/share/polkit-1
|
||||
}
|
||||
}
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
das-tools
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Das
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Executable
+279
@@ -0,0 +1,279 @@
|
||||
#!/bin/bash
|
||||
# dsv - manage runit services on Das OS, the way systemctl does elsewhere.
|
||||
#
|
||||
# A service is a directory /etc/sv/<name>; it is enabled (started at boot) by
|
||||
# linking it into the default runlevel, which runsvdir watches through
|
||||
# /var/service. Logs come from the service's own svlogd directory or, for
|
||||
# services that log to syslog, from socklog.
|
||||
set -euo pipefail
|
||||
|
||||
sv_dir=/etc/sv
|
||||
runlevel=/etc/runit/runsvdir/default
|
||||
# Outside a running system (a chroot, an image) /var/service may not exist
|
||||
service_dir=/var/service
|
||||
[[ -d $service_dir ]] || service_dir=$runlevel
|
||||
socklog=/var/log/socklog
|
||||
|
||||
if [[ ${LANG:-} == uk* || ${LC_ALL:-} == uk* || ${LC_MESSAGES:-} == uk* ]]; then
|
||||
uk=1
|
||||
else
|
||||
uk=""
|
||||
fi
|
||||
|
||||
# say UKRAINIAN ENGLISH: prints the message in the user's language
|
||||
say() {
|
||||
if [[ -n $uk ]]; then echo "$1"; else echo "$2"; fi
|
||||
}
|
||||
|
||||
die() {
|
||||
say "dsv: $1" "dsv: $2" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
usage() {
|
||||
if [[ -n $uk ]]; then
|
||||
cat <<'EOF'
|
||||
Використання: dsv КОМАНДА [СЛУЖБА...]
|
||||
|
||||
list усі служби: чи ввімкнена, стан, PID, час роботи
|
||||
status СЛУЖБА... стан служби (sv status)
|
||||
enable СЛУЖБА... запускати під час завантаження й запустити зараз
|
||||
disable СЛУЖБА... не запускати під час завантаження й зупинити
|
||||
start|stop|restart СЛУЖБА...
|
||||
запустити, зупинити, перезапустити
|
||||
logs СЛУЖБА [-f] журнал служби (-f: стежити за новими рядками)
|
||||
|
||||
Служби — каталоги в /etc/sv. Без команди виконується list.
|
||||
EOF
|
||||
else
|
||||
cat <<'EOF'
|
||||
Usage: dsv COMMAND [SERVICE...]
|
||||
|
||||
list all services: enabled or not, state, PID, uptime
|
||||
status SERVICE... service state (sv status)
|
||||
enable SERVICE... start at boot and start now
|
||||
disable SERVICE... do not start at boot and stop now
|
||||
start|stop|restart SERVICE...
|
||||
start, stop, restart
|
||||
logs SERVICE [-f] the service log (-f: follow new lines)
|
||||
|
||||
Services are the directories in /etc/sv. Without a command, runs list.
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
# Service states live in root-only supervise directories
|
||||
need_root() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
exec sudo "$0" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
check_service() {
|
||||
[[ -d $sv_dir/$1 ]] || die "немає служби '$1' (див. ls $sv_dir)" "no service '$1' (see ls $sv_dir)"
|
||||
}
|
||||
|
||||
is_enabled() {
|
||||
[[ -e $runlevel/$1 || -L $runlevel/$1 ]]
|
||||
}
|
||||
|
||||
# Waits up to 10 s for runsvdir to pick up a new link (it rescans every 5 s)
|
||||
wait_supervised() {
|
||||
local i
|
||||
for ((i = 0; i < 20; i++)); do
|
||||
[[ -e $service_dir/$1/supervise/ok ]] && return 0
|
||||
sleep 0.5
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# row NAME ENABLED STATE PID UPTIME: one line of the list. printf pads by
|
||||
# bytes, ${#s} counts characters, so Cyrillic columns stay aligned.
|
||||
row() {
|
||||
local s widths=(24 9 6 8) i=0
|
||||
for s in "$1" "$2" "$3" "$4"; do
|
||||
printf '%s%*s ' "$s" $((widths[i] - ${#s})) ''
|
||||
i=$((i + 1))
|
||||
done
|
||||
printf '%s\n' "$5"
|
||||
}
|
||||
|
||||
cmd_list() {
|
||||
local dir name enabled state pid time line
|
||||
row "$(say СЛУЖБА SERVICE)" "$(say УВІМКН. ENABLED)" "$(say СТАН STATE)" PID "$(say ПРАЦЮЄ UPTIME)"
|
||||
for dir in "$sv_dir"/*/; do
|
||||
name=$(basename "$dir")
|
||||
enabled=$(say ні no)
|
||||
state=-
|
||||
pid=-
|
||||
time=-
|
||||
if is_enabled "$name"; then
|
||||
enabled=$(say так yes)
|
||||
# "run: /var/service/sshd: (pid 812) 3600s; run: log: ..."
|
||||
line=$(sv status "$service_dir/$name" 2>/dev/null || true)
|
||||
state=${line%%:*}
|
||||
[[ $line =~ \(pid\ ([0-9]+)\) ]] && pid=${BASH_REMATCH[1]}
|
||||
[[ $line =~ \ ([0-9]+)s ]] && time=$(human_time "${BASH_REMATCH[1]}")
|
||||
[[ -n $state ]] || state='?'
|
||||
fi
|
||||
row "$name" "$enabled" "$state" "$pid" "$time"
|
||||
done
|
||||
}
|
||||
|
||||
# human_time SECONDS: 3d4h, 2h5m, 7m, 42s
|
||||
human_time() {
|
||||
local s=$1
|
||||
if ((s >= 86400)); then
|
||||
echo "$((s / 86400))d$((s % 86400 / 3600))h"
|
||||
elif ((s >= 3600)); then
|
||||
echo "$((s / 3600))h$((s % 3600 / 60))m"
|
||||
elif ((s >= 60)); then
|
||||
echo "$((s / 60))m"
|
||||
else
|
||||
echo "${s}s"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_status() {
|
||||
local name rc=0
|
||||
for name in "$@"; do
|
||||
check_service "$name"
|
||||
if is_enabled "$name"; then
|
||||
sv status "$service_dir/$name" || rc=1
|
||||
else
|
||||
say "$name: вимкнена (dsv enable $name)" "$name: disabled (dsv enable $name)"
|
||||
fi
|
||||
done
|
||||
return $rc
|
||||
}
|
||||
|
||||
cmd_enable() {
|
||||
local name
|
||||
for name in "$@"; do
|
||||
check_service "$name"
|
||||
if is_enabled "$name"; then
|
||||
say "$name: уже ввімкнена" "$name: already enabled"
|
||||
continue
|
||||
fi
|
||||
ln -s "$sv_dir/$name" "$runlevel/$name"
|
||||
say "$name: увімкнена" "$name: enabled"
|
||||
# runsvdir starts it within 5 s. Right after "dsv disable" its runsv is
|
||||
# still there with the service stopped, so ask for "up" as well.
|
||||
if [[ $service_dir == /var/service ]] && wait_supervised "$name"; then
|
||||
sv -v up "$service_dir/$name" || true
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
cmd_disable() {
|
||||
local name
|
||||
for name in "$@"; do
|
||||
check_service "$name"
|
||||
if ! is_enabled "$name"; then
|
||||
say "$name: уже вимкнена" "$name: already disabled"
|
||||
continue
|
||||
fi
|
||||
# Stop it first: runsv only notices the removed link at runsvdir's next scan
|
||||
[[ $service_dir == /var/service ]] && sv down "$service_dir/$name" 2>/dev/null || true
|
||||
rm "$runlevel/$name"
|
||||
say "$name: вимкнена" "$name: disabled"
|
||||
done
|
||||
}
|
||||
|
||||
cmd_control() {
|
||||
local action=$1 name rc=0
|
||||
shift
|
||||
for name in "$@"; do
|
||||
check_service "$name"
|
||||
if ! is_enabled "$name"; then
|
||||
say "$name: вимкнена, спершу: dsv enable $name" "$name: disabled, first: dsv enable $name" >&2
|
||||
rc=1
|
||||
continue
|
||||
fi
|
||||
# -v waits for the new state (up to 7 s) and prints it
|
||||
sv -v "$action" "$service_dir/$name" || rc=1
|
||||
done
|
||||
return $rc
|
||||
}
|
||||
|
||||
# The log directory of a service whose log/run starts svlogd, if any
|
||||
svlogd_dir() {
|
||||
local run=$sv_dir/$1/log/run words w
|
||||
[[ -r $run ]] || return 1
|
||||
grep -q svlogd "$run" || return 1
|
||||
read -ra words < <(grep -m1 svlogd "$run")
|
||||
for w in "${words[@]}"; do
|
||||
[[ $w == /* && -d $w ]] && echo "$w" && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
cmd_logs() {
|
||||
local name=${1:-} follow="" dir
|
||||
[[ -n $name ]] || die "вкажіть службу: dsv logs СЛУЖБА [-f]" "name a service: dsv logs SERVICE [-f]"
|
||||
[[ ${2:-} == -f ]] && follow=1
|
||||
check_service "$name"
|
||||
|
||||
if dir=$(svlogd_dir "$name"); then
|
||||
if [[ -n $follow ]]; then
|
||||
exec tail -n 50 -F "$dir/current"
|
||||
fi
|
||||
cat "$dir"/@*.[su] "$dir/current" 2>/dev/null | tail -n 200
|
||||
return
|
||||
fi
|
||||
|
||||
# Services without their own log write to syslog (vlogger -t <name>, or the
|
||||
# daemon itself as "<name>[pid]:" or "<name>-<helper>[pid]:", like
|
||||
# sshd-session), which socklog sorts into directories by facility.
|
||||
if ! compgen -G "$socklog/*/current" >/dev/null; then
|
||||
die "у $name немає власного журналу, а syslog не записується; увімкніть socklog: dsv enable socklog-unix nanoklogd" \
|
||||
"$name has no log of its own and syslog is not recorded; enable socklog: dsv enable socklog-unix nanoklogd"
|
||||
fi
|
||||
local pattern="[[:space:]]${name}(-[a-z]+)?(\[[0-9]+\])?:"
|
||||
if [[ -n $follow ]]; then
|
||||
tail -q -n 0 -F "$socklog"/*/current | grep --line-buffered -E "$pattern"
|
||||
else
|
||||
# A message can be in several directories (e.g. "everything" and "secure")
|
||||
cat "$socklog"/*/@*.[su] "$socklog"/*/current 2>/dev/null | grep -E "$pattern" | sort -u | tail -n 200 ||
|
||||
say "$name: у syslog немає записів (служба може писати лише в консоль runit)" \
|
||||
"$name: no syslog entries (the service may only write to the runit console)"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd=${1:-list}
|
||||
[[ $# -gt 0 ]] && shift
|
||||
|
||||
case $cmd in
|
||||
list | ls)
|
||||
need_root list "$@"
|
||||
cmd_list
|
||||
;;
|
||||
status)
|
||||
[[ $# -gt 0 ]] || die "вкажіть службу" "name a service"
|
||||
need_root status "$@"
|
||||
cmd_status "$@"
|
||||
;;
|
||||
enable | disable | start | stop | restart)
|
||||
[[ $# -gt 0 ]] || die "вкажіть службу" "name a service"
|
||||
need_root "$cmd" "$@"
|
||||
case $cmd in
|
||||
enable) cmd_enable "$@" ;;
|
||||
disable) cmd_disable "$@" ;;
|
||||
start) cmd_control up "$@" ;;
|
||||
stop) cmd_control down "$@" ;;
|
||||
restart) cmd_control restart "$@" ;;
|
||||
esac
|
||||
;;
|
||||
logs | log)
|
||||
# socklog's logs are readable by root and the socklog group only
|
||||
[[ -r $socklog/messages/current ]] || need_root logs "$@"
|
||||
cmd_logs "$@"
|
||||
;;
|
||||
-h | --help | help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
usage >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,32 @@
|
||||
# bash completion for dsv
|
||||
# shellcheck shell=bash
|
||||
_dsv() {
|
||||
local cur=${COMP_WORDS[COMP_CWORD]} cmd=${COMP_WORDS[1]:-}
|
||||
if ((COMP_CWORD == 1)); then
|
||||
mapfile -t COMPREPLY < <(compgen -W "list status enable disable start stop restart logs help" -- "$cur")
|
||||
return
|
||||
fi
|
||||
case $cmd in
|
||||
enable)
|
||||
# services that are not enabled yet
|
||||
local all=() s
|
||||
for s in /etc/sv/*/; do
|
||||
s=${s%/}
|
||||
s=${s##*/}
|
||||
[[ -e /etc/runit/runsvdir/default/$s ]] || all+=("$s")
|
||||
done
|
||||
mapfile -t COMPREPLY < <(compgen -W "${all[*]}" -- "$cur")
|
||||
;;
|
||||
disable | start | stop | restart)
|
||||
mapfile -t COMPREPLY < <(compgen -W "$(ls /etc/runit/runsvdir/default 2>/dev/null)" -- "$cur")
|
||||
;;
|
||||
status | logs | log)
|
||||
if [[ $cmd == logs* ]] && ((COMP_CWORD == 3)); then
|
||||
mapfile -t COMPREPLY < <(compgen -W "-f" -- "$cur")
|
||||
else
|
||||
mapfile -t COMPREPLY < <(compgen -W "$(ls /etc/sv 2>/dev/null)" -- "$cur")
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
complete -F _dsv dsv
|
||||
@@ -0,0 +1,15 @@
|
||||
# Template file for 'dsv'
|
||||
pkgname=dsv
|
||||
version=0.1.0
|
||||
revision=1
|
||||
depends="bash runit sudo"
|
||||
short_desc="Das OS service manager: enable, start and read logs of runit services"
|
||||
maintainer="Das <anry.das@gmail.com>"
|
||||
license="MIT"
|
||||
homepage="https://git.das.org.ua/das/Das-OS"
|
||||
|
||||
do_install() {
|
||||
vbin ${FILESDIR}/dsv
|
||||
vcompletion ${FILESDIR}/dsv.bash-completion bash
|
||||
vlicense ${FILESDIR}/LICENSE
|
||||
}
|
||||
Reference in New Issue
Block a user