2025-09-29 15:21:20 +03:00

167 lines
3.8 KiB
Go

package main
import (
"encoding/json"
"fmt"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"time"
"kisekinopureya.com.tr/updater/internal/archive"
"kisekinopureya.com.tr/updater/internal/logger"
mountfilesystem "kisekinopureya.com.tr/updater/internal/mountFilesystem"
"kisekinopureya.com.tr/updater/internal/plymouth"
)
type BlockDevice struct {
Name string `json:"name"`
Type string `json:"type"`
PartType string `json:"parttype"`
Children []BlockDevice `json:"children,omitempty"`
}
type LSBLK struct {
BlockDevices []BlockDevice `json:"blockdevices"`
}
type partitionScheme struct {
EfiDevice string
RootfsDevice string
DmVerityDevice string
//VarDevice string
}
var efiUUID string = "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"
var rootfsUUID string = "4f68bce3-e8cd-4db1-96e7-fbcaf984b709"
var dmverityUUID string = "2c7357ed-ebd2-46d9-aec1-23d437ec2bf5"
//var varUUID string = "4d21b016-b534-45c2-a9fb-5c16e091fd2d"
func findByPartType(devices []BlockDevice, target string) string {
for attempt := 1; attempt <= 3; attempt++ {
for _, dev := range devices {
if dev.PartType != "" && dev.PartType == target {
return dev.Name
}
if len(dev.Children) > 0 {
if found := findByPartType(dev.Children, target); found != "" {
return found
}
}
}
if attempt < 3 {
time.Sleep(10 * time.Second)
}
}
return ""
}
func populatePartitionScheme() partitionScheme {
var generatedScheme partitionScheme = partitionScheme{}
cmd := exec.Command("lsblk", "-J", "-o", "NAME,TYPE,PARTTYPE")
blockDeviceTypes, err := cmd.Output()
if err != nil {
log.Panic(err)
}
var lsblk LSBLK
if err := json.Unmarshal(blockDeviceTypes, &lsblk); err != nil {
log.Panic(err)
}
generatedScheme.EfiDevice = findByPartType(lsblk.BlockDevices, efiUUID)
generatedScheme.RootfsDevice = findByPartType(lsblk.BlockDevices, rootfsUUID)
generatedScheme.DmVerityDevice = findByPartType(lsblk.BlockDevices, dmverityUUID)
return generatedScheme
}
func patchImage(imageFile string, partition string, name string) {
cmd := exec.Command("dd", "if="+imageFile, "of="+"/dev/"+partition, "bs=4M")
plymouth.ShowPlymouthMessage("Patching " + name + " partition")
if err := cmd.Run(); err != nil {
log.Panic(err)
}
}
func CopyFile(source, destPath string) error {
in, err := os.Open(source)
if err != nil {
log.Panic(err)
}
defer in.Close()
if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
log.Panic(err)
}
out, err := os.Create(destPath)
if err != nil {
log.Panic(err)
}
defer out.Close()
if _, err := io.Copy(out, in); err != nil {
log.Panic(err)
}
if err := out.Sync(); err != nil {
log.Panic(err)
}
return nil
}
func main() {
logger.InitializeLogger("/mnt/var/log/patcher")
if len(os.Args) != 2 {
fmt.Printf("Usage: %s <metadata>\n", os.Args[0])
os.Exit(1)
}
f, err := os.Open(os.Args[1])
if err != nil {
panic(err)
}
defer f.Close()
var meta archive.Output
if err := json.NewDecoder(f).Decode(&meta); err != nil {
panic(err)
}
currentPartitionScheme := populatePartitionScheme()
fileCount := len(meta.Files)
// before 20 and after 80 will be filled by initramfs
leftProgress := 60/fileCount + 20
for _, f := range meta.Files {
plymouth.ShowPlymouthProgress(leftProgress)
leftProgress += leftProgress
imageFile := f.Name
imageType := f.Type
switch imageType {
case "rootfs":
patchImage(imageFile, currentPartitionScheme.RootfsDevice, imageType)
case "dm-verity":
patchImage(imageFile, currentPartitionScheme.DmVerityDevice, imageType)
case "kernel":
mountPath := "/updates-tmp/efi"
kernelDir := "/EFI/Linux"
mountfilesystem.MountFileSystem("/dev/"+currentPartitionScheme.EfiDevice, mountPath, "vfat", 0, "")
CopyFile(imageFile, mountPath+kernelDir+"/kernel.efi")
mountfilesystem.UnmountFileSystem(mountPath)
default:
}
}
}