github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/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 const ( 15 // Loop ioctl commands --- we will commandeer 0x4C ('L') 16 _LOOP_SET_CAPACITY = 0x4C07 17 _LOOP_CHANGE_FD = 0x4C06 18 _LOOP_GET_STATUS64 = 0x4C05 19 _LOOP_SET_STATUS64 = 0x4C04 20 _LOOP_GET_STATUS = 0x4C03 21 _LOOP_SET_STATUS = 0x4C02 22 _LOOP_CLR_FD = 0x4C01 23 _LOOP_SET_FD = 0x4C00 24 _LO_NAME_SIZE = 64 25 _LO_KEY_SIZE = 32 26 27 // /dev/loop-control interface 28 _LOOP_CTL_ADD = 0x4C80 29 _LOOP_CTL_REMOVE = 0x4C81 30 _LOOP_CTL_GET_FREE = 0x4C82 31 ) 32 33 // FindDevice finds an unused loop device and returns its /dev/loopN path. 34 func FindDevice() (string, error) { 35 cfd, err := os.OpenFile("/dev/loop-control", os.O_RDWR, 0644) 36 if err != nil { 37 return "", err 38 } 39 defer cfd.Close() 40 41 number, err := GetFree(int(cfd.Fd())) 42 if err != nil { 43 return "", err 44 } 45 return fmt.Sprintf("/dev/loop%d", number), nil 46 } 47 48 // ClearFD clears the loop device associated with file descriptor fd. 49 func ClearFD(fd int) error { 50 return unix.IoctlSetInt(fd, _LOOP_CLR_FD, 0) 51 } 52 53 // GetFree finds a free loop device /dev/loopN. 54 // 55 // fd must be a loop control device. 56 // 57 // It returns the number of the free loop device /dev/loopN. 58 // The _LOOP_CTL_GET_FREE does not follow the rules. Values 59 // of 0 or greater are the number of the device; less than 60 // zero is an error. 61 // So you can not use unix.IoctlGetInt as it assumes the return 62 // value is stored in a pointer in the normal style. Yuck. 63 func GetFree(fd int) (int, error) { 64 r1, _, err := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), _LOOP_CTL_GET_FREE, 0) 65 if err == 0 { 66 return int(r1), nil 67 } 68 return 0, err 69 } 70 71 // SetFD associates a loop device lfd with a regular file ffd. 72 func SetFD(lfd, ffd int) error { 73 return unix.IoctlSetInt(lfd, _LOOP_SET_FD, ffd) 74 } 75 76 // SetFile associates loop device "devicename" with regular file "filename" 77 func SetFile(devicename, filename string) error { 78 mode := os.O_RDWR 79 file, err := os.OpenFile(filename, mode, 0644) 80 if err != nil { 81 mode = os.O_RDONLY 82 file, err = os.OpenFile(filename, mode, 0644) 83 if err != nil { 84 return err 85 } 86 } 87 defer file.Close() 88 89 device, err := os.OpenFile(devicename, mode, 0644) 90 if err != nil { 91 return err 92 } 93 defer device.Close() 94 95 return SetFD(int(device.Fd()), int(file.Fd())) 96 } 97 98 // ClearFile clears the fd association of the loop device "devicename". 99 func ClearFile(devicename string) error { 100 device, err := os.Open(devicename) 101 if err != nil { 102 return err 103 } 104 defer device.Close() 105 106 return ClearFD(int(device.Fd())) 107 }