github.com/demonoid81/containerd@v1.3.4/snapshots/devmapper/losetup/losetup.go (about) 1 // +build linux 2 3 /* 4 Copyright The containerd Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package losetup 20 21 import ( 22 "os/exec" 23 "strings" 24 25 "github.com/pkg/errors" 26 ) 27 28 // FindAssociatedLoopDevices returns a list of loop devices attached to a given image 29 func FindAssociatedLoopDevices(imagePath string) ([]string, error) { 30 output, err := losetup("--list", "--output", "NAME", "--associated", imagePath) 31 if err != nil { 32 return nil, errors.Wrapf(err, "failed to get loop devices: '%s'", output) 33 } 34 35 if output == "" { 36 return []string{}, nil 37 } 38 39 items := strings.Split(output, "\n") 40 if len(items) <= 1 { 41 return []string{}, nil 42 } 43 44 // Skip header with column names 45 return items[1:], nil 46 } 47 48 // AttachLoopDevice finds first available loop device and associates it with an image. 49 func AttachLoopDevice(imagePath string) (string, error) { 50 return losetup("--find", "--show", imagePath) 51 } 52 53 // DetachLoopDevice detaches loop devices 54 func DetachLoopDevice(loopDevice ...string) error { 55 args := append([]string{"--detach"}, loopDevice...) 56 _, err := losetup(args...) 57 return err 58 } 59 60 // RemoveLoopDevicesAssociatedWithImage detaches all loop devices attached to a given sparse image 61 func RemoveLoopDevicesAssociatedWithImage(imagePath string) error { 62 loopDevices, err := FindAssociatedLoopDevices(imagePath) 63 if err != nil { 64 return err 65 } 66 67 for _, loopDevice := range loopDevices { 68 if err = DetachLoopDevice(loopDevice); err != nil { 69 return err 70 } 71 } 72 73 return nil 74 } 75 76 // losetup is a wrapper around losetup command line tool 77 func losetup(args ...string) (string, error) { 78 data, err := exec.Command("losetup", args...).CombinedOutput() 79 output := string(data) 80 if err != nil { 81 return "", errors.Wrapf(err, "losetup %s\nerror: %s\n", strings.Join(args, " "), output) 82 } 83 84 return strings.TrimSuffix(output, "\n"), err 85 }