github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/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  		// To be able to build both Paravirtual and HVM images, the unnumbered
    31  		// device and the first numbered one must be available.
    32  		// E.g. /dev/xvdf  and  /dev/xvdf1
    33  		numbered_device := fmt.Sprintf("%s%d", device, 1)
    34  		if _, err := os.Stat(numbered_device); err != nil {
    35  			return device, nil
    36  		}
    37  	}
    38  
    39  	return "", errors.New("available device could not be found")
    40  }
    41  
    42  // devicePrefix returns the prefix ("sd" or "xvd" or so on) of the devices
    43  // on the system.
    44  func devicePrefix() (string, error) {
    45  	available := []string{"sd", "xvd"}
    46  
    47  	f, err := os.Open("/sys/block")
    48  	if err != nil {
    49  		return "", err
    50  	}
    51  	defer f.Close()
    52  
    53  	dirs, err := f.Readdirnames(-1)
    54  	if dirs != nil && len(dirs) > 0 {
    55  		for _, dir := range dirs {
    56  			dirBase := filepath.Base(dir)
    57  			for _, prefix := range available {
    58  				if strings.HasPrefix(dirBase, prefix) {
    59  					return prefix, nil
    60  				}
    61  			}
    62  		}
    63  	}
    64  
    65  	if err != nil {
    66  		return "", err
    67  	}
    68  
    69  	return "", errors.New("device prefix could not be detected")
    70  }