97 lines
2.3 KiB
Go

// Copyright (c) 2020 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License-AGPL.txt in the project root for license information.
package quota
import (
"bufio"
"io"
"os"
"os/exec"
"strings"
"golang.org/x/xerrors"
)
// mountPoint represents an entry in a proc mounts file
type mountPoint struct {
Device string
Path string
FS string
Opts string
}
// findmountPointFromProc calls FindmountPoint with /proc/mounts
func findMountPointFromProc(dir string) (res *mountPoint, err error) {
f, err := os.OpenFile("/proc/self/mounts", os.O_RDONLY, 0)
if err != nil {
return nil, xerrors.Errorf("cannot find mount point: %w", err)
}
defer f.Close()
return findMountPoint(f, dir)
}
// findmountPoint finds the mount entry for a directory
func findMountPoint(mountFile io.Reader, dir string) (res *mountPoint, err error) {
res = &mountPoint{}
scanner := bufio.NewScanner(mountFile)
for scanner.Scan() {
line := scanner.Text()
fields := strings.Fields(line)
if len(fields) < 4 {
continue
}
if mp := fields[1]; strings.HasPrefix(dir, mp) && len(mp) > len(res.Path) {
res.Device = fields[0]
res.Path = fields[1]
res.FS = fields[2]
res.Opts = fields[3]
}
}
if err = scanner.Err(); err != nil {
res = nil
return
}
if res.Path == "" {
res = nil
}
return
}
// findLoopdevInLosetupOutput expects out to be the output of "losetup -a".
// It searches for lodev in that output and returns the backing filename.
// If the lodev isn't found it returns an empty string.
func findLoopdevInLosetupOutput(lodev string, out []byte) (fn string) {
lines := strings.Split(string(out), "\n")
for _, l := range lines {
fields := strings.Fields(l)
if len(fields) != 3 {
continue
}
if fields[0] != lodev+":" {
continue
}
return fields[2]
}
return ""
}
// findLoopdevBacking runs "losetup -a" and uses findLoopdevInLosetupOutput
// to find the backing file of the lodev. If the lodev isn't found, this function
// returns an empty string and nil error.
func findLoopdevBacking(lodev string) (fn string, err error) {
out, err := exec.Command("losetup", "-a").CombinedOutput()
if err != nil {
return "", xerrors.Errorf("cannot run losetup: %w: %s", err, string(out))
}
return findLoopdevInLosetupOutput(lodev, out), nil
}