github.com/system-transparency/u-root@v6.0.1-0.20190919065413-ed07a650de4c+incompatible/pkg/loop/loop_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 provides an interface to interacting with Linux loop devices.
     6  //
     7  // A loop device exposes a regular file as if it were a block device.
     8  package loop
     9  
    10  import (
    11  	"github.com/u-root/u-root/pkg/mount"
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  // Loop represents a regular file exposed as a loop block device.
    16  //
    17  // Loop implements mount.Mounter.
    18  type Loop struct {
    19  	// Dev is the loop device path.
    20  	Dev string
    21  
    22  	// Source is the regular file to use as a block device.
    23  	Source string
    24  
    25  	// FSType is the file system to use when mounting the block device.
    26  	FSType string
    27  
    28  	// Data is the data to pass to mount(2).
    29  	Data string
    30  
    31  	// Mounted indicates whether the device has been mounted.
    32  	Mounted bool
    33  
    34  	// dir is the directory the block device was mounted on.
    35  	dir string
    36  }
    37  
    38  // New initializes a Loop struct and allocates a loop device to it.
    39  //
    40  // source is the file to use as a loop block device. fstype the file system
    41  // name. data is the data argument to the mount(2) syscall.
    42  func New(source, fstype string, data string) (mount.Mounter, error) {
    43  	devicename, err := FindDevice()
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	if err := SetFile(devicename, source); err != nil {
    48  		return nil, err
    49  	}
    50  	return &Loop{
    51  		Dev:    devicename,
    52  		Source: source,
    53  		FSType: fstype,
    54  		Data:   data,
    55  	}, nil
    56  }
    57  
    58  // Mount mounts the provided source file, with type fstype, and flags and data options
    59  // (which are usually 0 and ""), using the allocated loop device.
    60  func (l *Loop) Mount(path string, flags uintptr) error {
    61  	l.dir = path
    62  	if err := unix.Mount(l.Dev, path, l.FSType, flags, l.Data); err != nil {
    63  		return err
    64  	}
    65  	l.Mounted = true
    66  	return nil
    67  }
    68  
    69  const forceUnmount = unix.MNT_FORCE | unix.MNT_DETACH
    70  
    71  // Unmount unmounts and frees a loop. If it is mounted, it will try to unmount it.
    72  // If the unmount fails, we try to free it anyway, after trying a more
    73  // forceful unmount.
    74  func (l *Loop) Unmount(flags int) error {
    75  	if l.Mounted {
    76  		if err := unix.Unmount(l.dir, flags); err != nil {
    77  			unix.Unmount(l.dir, flags|forceUnmount)
    78  		}
    79  	}
    80  	return ClearFile(l.Dev)
    81  }