github.com/craftyguy/u-root@v1.0.0/pkg/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 "syscall" 11 ) 12 13 const ( 14 /* 15 * IOCTL commands --- we will commandeer 0x4C ('L') 16 */ 17 LOOP_SET_CAPACITY = 0x4C07 18 LOOP_CHANGE_FD = 0x4C06 19 LOOP_GET_STATUS64 = 0x4C05 20 LOOP_SET_STATUS64 = 0x4C04 21 LOOP_GET_STATUS = 0x4C03 22 LOOP_SET_STATUS = 0x4C02 23 LOOP_CLR_FD = 0x4C01 24 LOOP_SET_FD = 0x4C00 25 LO_NAME_SIZE = 64 26 LO_KEY_SIZE = 32 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. 34 func FindDevice() (name string, err 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 if number, err := CtlGetFree(cfd.Fd()); err != nil { 42 return "", err 43 } else { 44 return fmt.Sprintf("/dev/loop%d", number), nil 45 } 46 47 } 48 49 // ClearFd clears the loop device associated with filedescriptor fd. 50 func ClearFd(fd uintptr) error { 51 if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, LOOP_CLR_FD, 0); err != 0 { 52 return err 53 } 54 55 return nil 56 } 57 58 // CtlGetFree finds a free loop device querying the loop control device pointed 59 // by fd. It returns the number of the free loop device /dev/loopX 60 func CtlGetFree(fd uintptr) (uintptr, error) { 61 number, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, LOOP_CTL_GET_FREE, 0) 62 if err != 0 { 63 return 0, err 64 } 65 return number, nil 66 } 67 68 // SetFd associates a loop device pointed by lfd with a regular file pointed by ffd. 69 func SetFd(lfd, ffd uintptr) error { 70 _, _, err := syscall.Syscall(syscall.SYS_IOCTL, lfd, LOOP_SET_FD, ffd) 71 if err != 0 { 72 return err 73 } 74 75 return nil 76 } 77 78 // SetFdFiles associates loop device "devicename" with regular file "filename" 79 func SetFdFiles(devicename, filename string) error { 80 mode := os.O_RDWR 81 file, err := os.OpenFile(filename, mode, 0644) 82 if err != nil { 83 mode = os.O_RDONLY 84 file, err = os.OpenFile(filename, mode, 0644) 85 if err != nil { 86 return err 87 } 88 } 89 defer file.Close() 90 91 device, err := os.OpenFile(devicename, mode, 0644) 92 if err != nil { 93 return err 94 } 95 defer device.Close() 96 97 return SetFd(device.Fd(), file.Fd()) 98 } 99 100 // ClearFdFile clears the loop device "devicename" 101 func ClearFdFile(devicename string) error { 102 device, err := os.Open(devicename) 103 if err != nil { 104 return err 105 } 106 defer device.Close() 107 108 return ClearFd(device.Fd()) 109 }