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  }