summaryrefslogtreecommitdiff
path: root/raveos-center/raveos_center/snapshotok.py
blob: f4bd097987e9b9d9976fef53b23901587700a5ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import json
import re
import subprocess
from pathlib import Path

from raveos_center import rendszerinfo

SNAP_PAC = Path("/usr/share/libalpm/hooks/05-snap-pac-pre.hook")
TIPUSOK = {"pre": "csomagművelet előtt", "post": "csomagművelet után", "single": "kézi"}


def _futtat(parancs, ido=30):
    try:
        return subprocess.run(parancs, capture_output=True, text=True, timeout=ido)
    except (OSError, subprocess.TimeoutExpired):
        return None


def fajlrendszer():
    kimenet = _futtat(["findmnt", "-no", "FSTYPE", "/"])
    return kimenet.stdout.strip() if kimenet and kimenet.returncode == 0 else ""


def gyoker_alvolumen():
    kimenet = _futtat(["findmnt", "-no", "OPTIONS", "/"])
    if not kimenet:
        return ""
    for opcio in kimenet.stdout.strip().split(","):
        if opcio.startswith("subvol="):
            return opcio[len("subvol="):]
    return ""


def snapshots_csatolva():
    kimenet = _futtat(["findmnt", "-no", "SOURCE", "/.snapshots"])
    return bool(kimenet and kimenet.returncode == 0 and kimenet.stdout.strip())


def snap_pac():
    return SNAP_PAC.exists()


def _elem(nyers):
    tipus = nyers.get("type", "single")
    adat = nyers.get("userdata") or {}
    return {
        "szam": nyers.get("number", 0),
        "datum": (nyers.get("date") or "")[:16],
        "tipus": tipus,
        "tipus_nev": "telepítés" if adat.get("important") == "yes" and tipus == "single" else TIPUSOK.get(tipus, tipus),
        "leiras": nyers.get("description") or "",
        "pre_szam": nyers.get("pre-number"),
        "aktiv": bool(nyers.get("active")),
    }


def allapot():
    fs = fajlrendszer()
    adat = {
        "fajlrendszer": fs,
        "snapper": rendszerinfo.snapper_elerheto(),
        "snap_pac": snap_pac(),
        "alvolumen": gyoker_alvolumen(),
        "csatolva": snapshots_csatolva(),
        "lista": [],
        "hiba": "",
    }
    if fs != "btrfs" or not adat["snapper"]:
        return adat
    kimenet = _futtat(["snapper", "--jsonout", "-c", "root", "list"])
    if not kimenet or kimenet.returncode != 0:
        adat["hiba"] = (kimenet.stderr.strip() if kimenet else "") or "A snapshotok listája nem olvasható."
        return adat
    try:
        nyers = json.loads(kimenet.stdout).get("root", [])
    except ValueError:
        adat["hiba"] = "A snapper válasza nem értelmezhető."
        return adat
    adat["lista"] = [_elem(n) for n in reversed(nyers) if n.get("number", 0) != 0]
    return adat


def ervenyes_leiras(szoveg):
    return 1 <= len(szoveg) <= 80 and all(c.isalnum() or c.isspace() or c in "._:,()-" for c in szoveg)


def kernel_valtozas(szam):
    gyoker = Path(f"/.snapshots/{int(szam)}/snapshot")
    valtozasok = []
    try:
        if not (gyoker / "usr/lib/modules").is_dir():
            return None
        pkgbase_fajlok = list(gyoker.glob("usr/lib/modules/*/pkgbase"))
    except OSError:
        return None
    for pb in pkgbase_fajlok:
        try:
            nev = pb.read_text().strip()
        except OSError:
            continue
        if not re.fullmatch(r"[a-z0-9][a-z0-9._+-]*", nev):
            continue
        regi = _futtat(["pacman", "--dbpath", str(gyoker / "var/lib/pacman"), "-Q", nev])
        most = _futtat(["pacman", "-Q", nev])
        regi_v = regi.stdout.split()[1] if regi and regi.returncode == 0 and len(regi.stdout.split()) > 1 else ""
        most_v = most.stdout.split()[1] if most and most.returncode == 0 and len(most.stdout.split()) > 1 else ""
        if regi_v and regi_v != most_v:
            cache = any(
                not p.name.endswith(".sig") for p in Path("/var/cache/pacman/pkg").glob(f"{nev}-{regi_v}-*.pkg.tar.*")
            )
            valtozasok.append({"nev": nev, "regi": regi_v, "most": most_v, "cache": cache})
    return valtozasok


def snapper_telepitheto(adat):
    return adat["fajlrendszer"] == "btrfs" and not adat["snapper"] and adat["alvolumen"] == "/@" and adat["csatolva"]