github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/mount/loop/losetup_linux.go (about) 1 // Copyright 2018 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package loop 6 7 import ( 8 "fmt" 9 "os" 10 11 "golang.org/x/sys/unix" 12 ) 13 14 // FindDevice finds an unused loop device and returns its /dev/loopN path. 15 func FindDevice() (string, error) { 16 cfd, err := os.OpenFile("/dev/loop-control", os.O_RDWR, 0o644) 17 if err != nil { 18 return "", err 19 } 20 defer cfd.Close() 21 22 number, err := GetFree(int(cfd.Fd())) 23 if err != nil { 24 return "", err 25 } 26 return fmt.Sprintf("/dev/loop%d", number), nil 27 } 28 29 // ClearFD clears the loop device associated with file descriptor fd. 30 func ClearFD(fd int) error { 31 return unix.IoctlSetInt(fd, unix.LOOP_CLR_FD, 0) 32 } 33 34 // GetFree finds a free loop device /dev/loopN. 35 // 36 // fd must be a loop control device. 37 // 38 // It returns the number of the free loop device /dev/loopN. 39 // The _LOOP_CTL_GET_FREE does not follow the rules. Values 40 // of 0 or greater are the number of the device; less than 41 // zero is an error. 42 // So you can not use unix.IoctlGetInt as it assumes the return 43 // value is stored in a pointer in the normal style. Yuck. 44 func GetFree(fd int) (int, error) { 45 return unix.IoctlRetInt(fd, unix.LOOP_CTL_GET_FREE) 46 } 47 48 // SetFD associates a loop device lfd with a regular file ffd. 49 func SetFD(lfd, ffd int) error { 50 return unix.IoctlSetInt(lfd, unix.LOOP_SET_FD, ffd) 51 } 52 53 // SetFile associates loop device "devicename" with regular file "filename" 54 func SetFile(devicename, filename string) error { 55 mode := os.O_RDWR 56 file, err := os.OpenFile(filename, mode, 0o644) 57 if err != nil { 58 mode = os.O_RDONLY 59 file, err = os.OpenFile(filename, mode, 0o644) 60 if err != nil { 61 return err 62 } 63 } 64 defer file.Close() 65 66 device, err := os.OpenFile(devicename, mode, 0o644) 67 if err != nil { 68 return err 69 } 70 defer device.Close() 71 72 return SetFD(int(device.Fd()), int(file.Fd())) 73 } 74 75 // ClearFile clears the fd association of the loop device "devicename". 76 func ClearFile(devicename string) error { 77 device, err := os.Open(devicename) 78 if err != nil { 79 return err 80 } 81 defer device.Close() 82 83 return ClearFD(int(device.Fd())) 84 }