github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/pkg/securelaunch/helpers.go (about)

     1  // Copyright 2019 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 securelaunch takes integrity measurements before launching the target system.
     6  package securelaunch
     7  
     8  import (
     9  	"fmt"
    10  	"io/ioutil"
    11  	"log"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  
    16  	"github.com/u-root/u-root/pkg/boot/diskboot"
    17  	"github.com/u-root/u-root/pkg/storage"
    18  )
    19  
    20  /* used to store all block devices returned from a call to storage.GetBlockStats */
    21  var storageBlkDevices []storage.BlockDev
    22  
    23  /*
    24   * if kernel cmd line has uroot.uinitargs=-d, debug fn is enabled.
    25   * kernel cmdline is checked in sluinit.
    26   */
    27  var Debug = func(string, ...interface{}) {}
    28  
    29  /*
    30   * WriteToFile writes a byte slice to a target file on an
    31   * already mounted disk and returns the target file path.
    32   *
    33   * defFileName is default dst file name, only used if user doesn't provide one.
    34   */
    35  func WriteToFile(data []byte, dst, defFileName string) (string, error) {
    36  
    37  	// make sure dst is an absolute file path
    38  	if !filepath.IsAbs(dst) {
    39  		return "", fmt.Errorf("dst =%s Not an absolute path ", dst)
    40  	}
    41  
    42  	// target is the full absolute path where []byte will be written to
    43  	target := dst
    44  	dstInfo, err := os.Stat(dst)
    45  	if err == nil && dstInfo.IsDir() {
    46  		Debug("No file name provided. Adding it now. old target=%s", target)
    47  		target = filepath.Join(dst, defFileName)
    48  		Debug("New target=%s", target)
    49  	}
    50  
    51  	Debug("target=%s", target)
    52  	err = ioutil.WriteFile(target, data, 0644)
    53  	if err != nil {
    54  		return "", fmt.Errorf("failed to write date to file =%s, err=%v", target, err)
    55  	}
    56  	Debug("WriteToFile exit w success data written to target=%s", target)
    57  	return target, nil
    58  }
    59  
    60  /*
    61   * GetMountedFilePath returns a file path corresponding to a <device_identifier>:<path> user input format.
    62   * <device_identifier> may be a Linux block device identifier like sda or a FS UUID.
    63   *
    64   * NOTE: Caller's responsbility to unmount this..use return var mountPath to unmount in caller.
    65   */
    66  func GetMountedFilePath(inputVal string, flags uintptr) (string, string, error) {
    67  	s := strings.Split(inputVal, ":")
    68  	if len(s) != 2 {
    69  		return "", "", fmt.Errorf("%s: Usage: <block device identifier>:<path>", inputVal)
    70  	}
    71  
    72  	// s[0] can be sda or UUID. if UUID, then we need to find its name
    73  	deviceId := s[0]
    74  	if !strings.HasPrefix(deviceId, "sd") {
    75  		if e := getBlkInfo(); e != nil {
    76  			return "", "", fmt.Errorf("getBlkInfo err=%s", e)
    77  		}
    78  		devices := storage.PartitionsByFsUUID(storageBlkDevices, s[0]) // []BlockDev
    79  		for _, device := range devices {
    80  			Debug("device =%s with fsuuid=%s", device.Name, s[0])
    81  			deviceId = device.Name
    82  		}
    83  	}
    84  
    85  	devicePath := filepath.Join("/dev", deviceId) // assumes deviceId is sda, devicePath=/dev/sda
    86  	Debug("Attempting to mount %s", devicePath)
    87  	dev, err := diskboot.FindDevice(devicePath, flags) // FindDevice fn mounts devicePath=/dev/sda.
    88  	if err != nil {
    89  		return "", "", fmt.Errorf("failed to mount %v , flags=%v, err=%v", devicePath, flags, err)
    90  	}
    91  
    92  	Debug("Mounted %s", devicePath)
    93  	fPath := filepath.Join(dev.MountPoint.Path, s[1]) // mountPath=/tmp/path/to/target/file if /dev/sda mounted on /tmp
    94  	return fPath, dev.MountPoint.Path, nil
    95  }
    96  
    97  /*
    98   * getBlkInfo calls storage package to get information on all block devices.
    99   * The information is stored in a global variable 'storageBlkDevices'
   100   * If the global variable is already non-zero, we skip the call to storage package.
   101   *
   102   * In debug mode, it also prints names and UUIDs for all devices.
   103   */
   104  func getBlkInfo() error {
   105  	if len(storageBlkDevices) == 0 {
   106  		var err error
   107  		storageBlkDevices, err = storage.GetBlockStats()
   108  		if err != nil {
   109  			log.Printf("getBlkInfo: storage.GetBlockStats err=%v. Exiting", err)
   110  			return err
   111  		}
   112  	}
   113  
   114  	for k, d := range storageBlkDevices {
   115  		Debug("block device #%d, Name=%s, FsUUID=%s", k, d.Name, d.FsUUID)
   116  	}
   117  	return nil
   118  }