You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
subgraph-oz/fs/cleanup.go

116 lines
2.3 KiB

package fs
import (
"errors"
"github.com/op/go-logging"
"io/ioutil"
"sort"
"strings"
"syscall"
)
func (fs *Filesystem) Cleanup() error {
if fs.base == "" {
msg := "cannot Cleanup() filesystem, fs.base is empty"
fs.log.Warning(msg)
return errors.New(msg)
}
fs.log.Info("Cleanup() called on filesystem at root %s", fs.root)
for {
mnts, err := getMountsBelow(fs.base)
if err != nil {
return err
}
if len(mnts) == 0 {
return nil
}
atLeastOne, lastErr := mnts.unmountAll(fs.log)
if !atLeastOne {
return lastErr
}
}
}
func (mnts mountEntries) unmountAll(log *logging.Logger) (bool, error) {
reterr := error(nil)
atLeastOne := false
for _, m := range mnts {
if err := syscall.Unmount(m.dir, 0); err != nil {
log.Warning("Failed to unmount mountpoint %s: %v", m.dir, err)
reterr = err
} else {
atLeastOne = true
}
}
return atLeastOne, reterr
}
type mountEntry struct {
src string
dir string
fs string
options string
}
type mountEntries []*mountEntry
func (m mountEntries) Len() int { return len(m) }
func (m mountEntries) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
func (m mountEntries) Less(i, j int) bool { return m[i].depth() > m[j].depth() }
func (me mountEntry) depth() int { return strings.Count(me.dir, "/") }
func getMountsBelow(base string) (mountEntries, error) {
mnts, err := getProcMounts()
if err != nil {
return nil, err
}
sort.Sort(mnts)
var filtered mountEntries
for _, m := range mnts {
if strings.HasPrefix(m.dir, base) {
filtered = append(filtered, m)
}
}
return filtered, nil
}
func (m mountEntries) contains(dir string) bool {
for _, mnt := range m {
if dir == mnt.dir {
return true
}
}
return false
}
func getProcMounts() (mountEntries, error) {
lines, err := readProcMounts()
if err != nil {
return nil, err
}
var entries mountEntries
for _, line := range lines {
parts := strings.Fields(line)
if len(parts) >= 4 {
entries = append(entries, &mountEntry{
src: parts[0],
dir: parts[1],
fs: parts[2],
options: parts[3],
})
}
}
return entries, nil
}
func readProcMounts() ([]string, error) {
content, err := ioutil.ReadFile("/proc/mounts")
if err != nil {
return nil, err
}
return strings.Split(string(content), "\n"), nil
}