anatol / booster

Fast and secure initramfs generator
MIT License
505 stars 45 forks source link

Improve fsck handling #249

Open r0l1 opened 11 months ago

r0l1 commented 11 months ago

Quote from fsck man:

The exit code returned by fsck is the sum of the following conditions: 0 - No errors 1 - File system errors corrected 2 - System should be rebooted 4 - File system errors left uncorrected 8 - Operational error 16 - Usage or syntax error 32 - Fsck canceled by user request 128 - Shared library error The exit code returned when multiple file systems are checked is the bit-wise OR of the exit codes for each file system that is checked.

Current code:


func fsck(dev string) error {
    if _, err := os.Stat("/usr/bin/fsck"); !os.IsNotExist(err) {
        cmd := exec.Command("/usr/bin/fsck", "-y", dev)
        if verbosityLevel >= levelDebug {
            cmd.Stdout = os.Stdout
        }
        if err := cmd.Run(); err != nil {
            if err, ok := err.(*exec.ExitError); ok {
                if err.ExitCode()&^0x1 != 0 {
                    // bit 1 means errors were corrected successfully which is good
                    return unwrapExitError(err)
                }
                return nil
            }

            return fmt.Errorf("fsck for %s: unknown error %v", dev, err)
        }
    }

    return nil
}

My personal improved code

// TODO: check which filesystem type it is and select the correct fsck utility.
func fsck(dev string) (err error) {
    output, err := exec.Command("/usr/bin/fsck.ext4", "-y", dev).CombinedOutput()
    if err == nil {
        debug("fsck output: %s", string(output))
        return
    }

    if err, ok := err.(*exec.ExitError); ok {
        switch err.ExitCode() {
        case 0:
            return nil
        case 1: // File system errors corrected
            severe("fsck corrected filesystem errors: %s", string(output))
            return nil
        case 2: // File system errors corrected, system should be rebooted
            severe("fsck corrected filesystem errors: %s", string(output))
            syscall.Sync()
            fmt.Println("Reboot required")
            time.Sleep(3 * time.Second)
            return syscall.Reboot(syscall.LINUX_REBOOT_CMD_RESTART)
        }
    }
    return fmt.Errorf("fsck for %s: unknown error %v\n%s", dev, err, string(output))
}