Vanilla-OS / ABRoot

ABRoot is a utility that provides full immutability and atomicity to a Linux system, by transacting between two root filesystems. Updates are performed using OCI images, to ensure that the system is always in a consistent state.
http://abroot.vanillaos.org/
GNU General Public License v3.0
309 stars 24 forks source link

fix[close #280]: /tmp becomes readonly when running out of space during operation #313

Closed mirkobrombin closed 3 months ago

mirkobrombin commented 3 months ago

The new code checks if the volume of the destination folder, during the RootFS export, has enough space to host the image.

How did I test:

package main

import (
    "bytes"
    "errors"
    "fmt"
    "os"
    "os/exec"
    "strconv"
    "strings"
    "syscall"
)

func getDirSize(path string) (int64, error) {
    cmd := exec.Command("du", "-s", "-b", path)
    var out bytes.Buffer
    cmd.Stdout = &out
    err := cmd.Run()
    if err != nil {
        return 0, err
    }

    output := strings.Fields(out.String())
    if len(output) == 0 {
        return 0, errors.New("failed to get directory size")
    }

    size, err := strconv.ParseInt(output[0], 10, 64)
    if err != nil {
        return 0, err
    }

    return size, nil
}

func main() {
    dest := "/usr/"
    mountDir := "/home/mirko/Data/Games"

    mountDirStat, err := os.Stat(mountDir)
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    var mountDirSize int64
    if mountDirStat.IsDir() {
        mountDirSize, err = getDirSize(mountDir)
        if err != nil {
            fmt.Printf("Error: %v\n", err)
            return
        }
    } else {
        mountDirSize = mountDirStat.Size()
    }

    var stat syscall.Statfs_t
    err = syscall.Statfs(dest, &stat)
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    availableSpace := stat.Bavail * uint64(stat.Bsize)

    if uint64(mountDirSize) > availableSpace {
        err := errors.New("not enough space in disk")
        fmt.Printf("Error: %v\n", err)
        return
    }

    fmt.Println("Enough space in disk")
}

for instance, my /Data/Games folder is 217.8 GB.

mirkobrombin commented 3 months ago

Well there is no reliable solution to check for those changes. Making a diff takes definitely more time (and it is an inefficient way), introducing an huge downside.

taukakao commented 3 months ago

We could use this PR in another way tho. Installing an image that is larger than 50% of the entire space will always break upgrades so it would probably be a good idea to check for that.

So instead of checking if the content is larger than the remaining space, we could check if the content is larger than 50% of the entire space. It would be a seperate issue though and should maybe be done in a different PR.