Snapshoty systemu plików dla HackerOS — btrfs i ext4, wzorowane na snapper.
Napisane w H#, budowane przez bit, GUI w Silver.
- działa w tle (usługa systemd); przy każdym starcie robi snapshot „boot” i usuwa stare snapshoty wg reguł użytkownika,
- wiele konfiguracji (
root,home, …) — każda z własnymi regułami, jak w snapperze, - diff dwóch snapshotów (lub snapshotu i działającego systemu), przeglądanie snapshotu i przywracanie pojedynczych plików/katalogów bez pełnego rollbacku,
- rollback całego systemu + wpisy w GRUB-ie startujące jądro z danego snapshotu,
- limity miejsca: min. wolne %, max. % dysku zajęte przez snapshoty (btrfs qgroups /
duna ext4), awaryjne czyszczenie, - automatyczne sprzątanie starych rootów po rollbacku (
@.before-rollback-*), - kopie zewnętrzne:
btrfs send/receivelubrsyncna drugi dysk albo przez SSH, - powiadomienia (notify-send + journald + plik logu) i ikona w trayu,
- CLI (
hackeros-snapshots) + GUI (hackeros-snapshots-gui): lista z przewijaniem, ekran diff, przeglądarka plików, ustawienia, kreator instalacji, operacje w tle.
Status: kod nie był kompilowany ani uruchamiany. Nie ma go czym zbudować w środowisku, w którym powstał (brak toolchaina H# i SDL2). Co zostało sprawdzone: parsery diffa i logika przywracania na prawdziwym
rsync/awk(sh tests/run.sh, 6 testów przechodzi), komendy shellowe, które program składa (rsync, find, du, sed, date), oraz statycznie cały kod H# — własnym linterem (istnienie funkcji między modułami, liczba argumentów, deklaracjemod, klucze konfiguracji, kolejność definicji, balansis/end). Nie sprawdzono: kompilacji H#, działania na btrfs (btrfs send/receive, qgroups, rollback), GRUB-a, GUI w Silverze. Przed użyciem:h# check src/main.h#i test na maszynie wirtualnej (patrz „Testowanie”).
bit # buduje cache/build/release/hackeros-snapshots
(cd gui && bit) # opcjonalnie GUI (najpierw natywne shimy Silvera, patrz gui/README.md)
sudo ./packaging/install.sh
sudo hackeros-snapshots init # pokazuje CO zostanie zmienione, pyta o zgodę, przygotowuje magazyn
sudo systemctl enable --now hackeros-snapshots
hackeros-snapshots-gui # albo zakładka „Setup” zamiast init w terminaluZależności: btrfs-progs (btrfs) lub rsync (ext4, diff, przywracanie), util-linux, grub (opcjonalnie),
polkit + libnotify-bin (GUI/powiadomienia), yad (ikona w trayu).
| btrfs | ext4 | |
|---|---|---|
| snapshot | read-only subwolumin, natychmiastowy | drzewo rsync z twardymi linkami (--link-dest) |
magazyn root |
osobny subwolumin @snapshots na /.snapshots |
katalog /.snapshots |
| magazyn innych configów | zagnieżdżony subwolumin <źródło>/.snapshots |
katalog <źródło>/.snapshots |
rollback root |
zamiana subwolumina root (@ → @.before-rollback-<data>) |
rsync --delete snapshot → / |
| rollback innych configów | rsync --delete (zamontowanego subwolumina nie da się podmienić) |
rsync --delete |
| diff | btrfs send --no-data | btrfs receive --dump (tylko metadane, szybkie; wymaga roota) |
rsync -n -i |
| miejsce zajęte przez snapshot | qgroups (exclusive) |
du -sm od najnowszego |
Układ magazynu (jak snapper): <store>/<id>/snapshot + <store>/<id>/info.
Dla każdej włączonej konfiguracji: snapshot boot → czyszczenie (liczba / wiek / miejsce, stare rooty po rollbacku) → kopia zewnętrzna → odświeżenie GRUB-a.
Potem co minutę: czy należy się snapshot timeline (po nim czyszczenie i kopia zewnętrzna). Konfigi są czytane na nowo w każdej pętli.
keep_boot,keep_timeline,keep_manual,keep_prepost(pary pre/post),max_age_days,max_usage_percent— snapshoty mogą zająć najwyżej tyle % dysku (najstarsze idą pierwsze; btrfs: wymaga qgroups —initje włącza; ext4: liczoneduprzy starcie i przycleanup, bo przechodzi po wszystkich drzewach),- nigdy nie są usuwane: przypięte (
pin) ikeep_minnajnowszych.
Przed każdym snapshotem: jeśli wolne < min_free_percent (domyślnie 10) → (gdy emergency_cleanup) kasowane są najstarsze nieprzypięte snapshoty, aż będzie dość miejsca; jeśli nadal za mało — snapshot nie powstaje i dostajesz powiadomienie. Demon dodatkowo ostrzega, gdy do progu zostało < 5 p.p.
Po rollbacku poprzedni root zostaje jako @.before-rollback-<data>. Sprząta je roots::prune (przy starcie, przy cleanup, roots prune):
kasuje starsze niż rollback_root_days (14) i wszystko ponad keep_rollback_roots (3) najnowszych. Root, który jest jeszcze zamontowany (rollback zrobiony, reboot nie), nigdy nie jest ruszany.
Do restartu blokowany jest drugi rollback i automatyczne snapshoty roota.
Podmenu HackerOS Snapshots z wpisami Restore: snapshot #N …. Wpis startuje init=/usr/lib/hackeros-snapshots/restore-init hsnap.restore=N; ten skrypt (PID 1, przed systemd) woła hackeros-snapshots rollback N --offline i na btrfs restartuje, na ext4 bootuje dalej.
Każdy snapshot pamięta kver (jądro z chwili wykonania). Wpis wybiera: (1) vmlinuz+initrd z samego snapshotu (/boot wewnątrz snapshotu), (2) tę samą wersję z bieżącego /boot, (3) najnowsze jądro (zaznaczone w tytule). Tylko dla configu root.
hackeros-snapshots diff 5 8 # co zmieniło się między #5 a #8 (+ dodane - usunięte ~ zmienione > przemianowane)
sudo hackeros-snapshots diff 5 # #5 → system teraz
hackeros-snapshots browse 5 /etc # zawartość katalogu w snapshocie
sudo hackeros-snapshots restore 5 /etc/fstab /home/ja/dokumenty # z kopią tego, co nadpisane
→ kopie zapasowe: /var/lib/hackeros-snapshots/restore-backups/<config>-<id>-<czas>/
hackeros-snapshots restore 5 /etc/fstab --to /tmp/odzysk # wypakuj obok, nic nie nadpisującOpcje: --method send|rsync, --deep (porównuje zawartość sumami kontrolnymi — wolne), --delete (katalog dokładnie jak w snapshocie), --no-backup, --porcelain.
Bez roota diff idzie przez rsync i nie zobaczy plików nieczytelnych dla użytkownika.
sudo hackeros-snapshots config create home --source /home # /home musi być subwoluminem (btrfs) albo katalogiem (ext4)
sudo hackeros-snapshots -c home init
hackeros-snapshots -c home list
sudo hackeros-snapshots cleanup --allPliki: config.hk = root (tu też globalne: grub, notify_level, log_file), configs.d/<nazwa>.hk = reszta.
Wykluczenia (excludes=/var/log,/var/cache): ext4 → rsync --exclude; btrfs → ścieżki są wycinane z zapisywalnej kopii, która potem dostaje ro (można to zrobić „za darmo”, robiąc z katalogu zagnieżdżony subwolumin). Przy rollbacku roota wykluczone ścieżki są przenoszone ze starego rootu (cp --reflink), więc nie znikają.
sudo hackeros-snapshots config apply offsite=true offsite_target=root@nas:/backups/hsnap offsite_types=manual,boot
sudo hackeros-snapshots offsite test | run | prune | statusbtrfs: przyrostowy btrfs send -p <poprzedni skopiowany> | btrfs receive (cel musi być btrfs; przez SSH potrzebny root na zdalnej maszynie i klucz). ext4: rsync --link-dest. Na celu: <cel>/<config>/<id>/snapshot. offsite_keep = ile kopii zostaje. Odzyskiwanie: btrfs send | btrfs receive w drugą stronę (albo rsync) — ręcznie.
notify_level: off / errors (domyślnie) / all. Błąd snapshotu, brak miejsca, nieudana kopia zewnętrzna → notify-send do każdej zalogowanej sesji + journalctl -t hackeros-snapshots + /var/log/hackeros-snapshots.log (sam się obraca przy 1 MB).
hackeros-snapshots tray (autostart po instalacji, wymaga yad): ikona pokazuje stan (dysk / ostrzeżenie / błąd), podpowiedź liczbę snapshotów, menu: otwórz GUI, zrób snapshot, posprzątaj. Stan zapisuje demon w /run/hackeros-snapshots/status.
Zakładki: Snapshots (przewijana lista, wybór → porównaj / przeglądaj / przypnij / przywróć / usuń), Diff (klik w zmianę → przywróć ten plik z A lub B), Browse, Settings, Offsite, Setup (kreator: wybór systemu plików → podgląd zmian → zastosuj → uruchom usługę).
Wszystko, co wymaga roota, działa jako zadanie w tle (pkexec hackeros-snapshots …), więc okno nie zamiera.
Silver v0.2 nie ma listy z przewijaniem ani timera. GUI radzi sobie tak: każdy ekran to jeden generowany HTML (load_html_str), a strona przewija się w całości — lista ma dowolną długość (po 100 wierszy, „Show more”). Do Silvera dołożyłem małą łatkę (vendor/silver-hsnap.patch, tylko src/app.h#): okresowy on_tick, id klikniętego elementu w stanie (_click) i ograniczenie przewijania do wysokości treści. Bez tick_every Silver zachowuje się jak oryginał. vendor/silver to kompletny Silver z tą łatką; gui/Bit.hk bierze go przez path.
Format .hk: ! komentarz, [sekcja], -> klucz => wartość. Domyślny plik: data/config.hk (generowany ze schematu w src/config.h# — nowy klucz to jedna linia tam). hackeros-snapshots config keys wypisuje wszystkie.
src/ CLI + demon (H#): main cli config snap store retention usage manager diff roots offsite grub setup daemon tray notify fsinfo paths util ui
gui/ GUI: src/ (main views jobs backend), frontend/style.css
vendor/ silver/ (Silver + łatka) i silver-hsnap.patch
data/ unit systemd, hook GRUB, restore-init, hook apt, polkit, skrypty awk (diff), config.hk, .desktop (GUI, tray)
tests/ run.sh — testy parserów diffa i przywracania (sh, awk, rsync)
packaging/ install.sh, uninstall.sh
- Niesprawdzone kompilatorem ani na btrfs/GRUB (patrz status wyżej). Składnia H# opiera się na kodzie
bitv0.0.1 i README H# v0.9. - btrfs: wymagany układ z subwoluminem root (
@); przy/= top-level rollback jest odrzucany.btrfs sendw diffie wymaga, by oba snapshoty były potomkami tego samego subwolumina (tak jest) — inaczej program spada dorsync. - ext4: snapshoty i dane są na jednej partycji → to nie backup (użyj offsite).
max_usage_percentliczonedujest wolne (nice/ionice idle), robi się przy starcie icleanup, nie co godzinę. - Wykluczenia btrfs kosztują usunięcie referencji z kopii przy każdym snapshocie (metadane, nie dane) — dla ogromnych katalogów lepszy zagnieżdżony subwolumin.
- Kopia zewnętrzna: pierwsze wysłanie jest pełne (cały root); odzyskiwanie z niej jest ręczne.
- Rollback
home(i innych configów) robirsync --deletena żywym katalogu — zamknij programy, które go używają. - Ikona w trayu zależy od
yad; bez niego zostają same powiadomienia. - GUI: dialogi potwierdzeń wymagają shimu
tinyfiledialogsSilvera; wpisane pole można wyczyścić tylko wpisując-. - Restore z GRUB-a bez
/bootw snapshocie i bez tej wersji w/bootużyje najnowszego jądra.
sh tests/run.sh— parsery i przywracanie (bez toolchaina).- VM z btrfs (
@,@home) i druga z ext4, HackerOS/Debian z GRUB-em;bit && sudo ./packaging/install.sh && sudo hackeros-snapshots init. create, zmień/usuń plik,diff <id>,restore <id> /ścieżka;rollback <id>+ reboot;roots list.sudo update-grub, w GRUB-ieHackerOS Snapshots → Restore: snapshot #N(sprawdź, że jądro się zgadza:uname -r).config set keep_boot 1i kilka restartów → został jeden snapshotboot;config set min_free_percent 90→ snapshot odmówiony + powiadomienie.config create home --source /home,-c home init,offsite testna drugim dysku (btrfs) / przez SSH.
GPL-3.0 — patrz LICENSE. vendor/silver ma własną licencję (vendor/silver/LICENSE).