github.com/sneal/packer@v0.5.2/builder/amazon/chroot/device.go (about) 1 package chroot 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strings" 9 ) 10 11 // AvailableDevice finds an available device and returns it. Note that 12 // you should externally hold a flock or something in order to guarantee 13 // that this device is available across processes. 14 func AvailableDevice() (string, error) { 15 prefix, err := devicePrefix() 16 if err != nil { 17 return "", err 18 } 19 20 letters := "fghijklmnop" 21 for _, letter := range letters { 22 device := fmt.Sprintf("/dev/%s%c", prefix, letter) 23 24 // If the block device itself, i.e. /dev/sf, exists, then we 25 // can't use any of the numbers either. 26 if _, err := os.Stat(device); err == nil { 27 continue 28 } 29 30 for i := 1; i < 16; i++ { 31 device := fmt.Sprintf("/dev/%s%c%d", prefix, letter, i) 32 if _, err := os.Stat(device); err != nil { 33 return device, nil 34 } 35 } 36 } 37 38 return "", errors.New("available device could not be found") 39 } 40 41 // devicePrefix returns the prefix ("sd" or "xvd" or so on) of the devices 42 // on the system. 43 func devicePrefix() (string, error) { 44 available := []string{"sd", "xvd"} 45 46 f, err := os.Open("/sys/block") 47 if err != nil { 48 return "", err 49 } 50 defer f.Close() 51 52 dirs, err := f.Readdirnames(-1) 53 if dirs != nil && len(dirs) > 0 { 54 for _, dir := range dirs { 55 dirBase := filepath.Base(dir) 56 for _, prefix := range available { 57 if strings.HasPrefix(dirBase, prefix) { 58 return prefix, nil 59 } 60 } 61 } 62 } 63 64 if err != nil { 65 return "", err 66 } 67 68 return "", errors.New("device prefix could not be detected") 69 }