github.com/criyle/go-sandbox@v0.10.3/pkg/mount/mount_linux.go (about)

     1  package mount
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"syscall"
     8  )
     9  
    10  // Mount calls mount syscall
    11  func (m *Mount) Mount() error {
    12  	if err := ensureMountTargetExists(m.Source, m.Target); err != nil {
    13  		return fmt.Errorf("mkdir: %w", err)
    14  	}
    15  	if err := syscall.Mount(m.Source, m.Target, m.FsType, m.Flags, m.Data); err != nil {
    16  		return fmt.Errorf("mount: %w", err)
    17  	}
    18  	// Read-only bind mount need to be remounted
    19  	const bindRo = syscall.MS_BIND | syscall.MS_RDONLY
    20  	if m.Flags&bindRo == bindRo {
    21  		if err := syscall.Mount("", m.Target, m.FsType, m.Flags|syscall.MS_REMOUNT, m.Data); err != nil {
    22  			return fmt.Errorf("remount: %w", err)
    23  		}
    24  	}
    25  	return nil
    26  }
    27  
    28  // IsBindMount returns if it is a bind mount
    29  func (m Mount) IsBindMount() bool {
    30  	return m.Flags&syscall.MS_BIND == syscall.MS_BIND
    31  }
    32  
    33  // IsReadOnly returns if it is a readonly mount
    34  func (m Mount) IsReadOnly() bool {
    35  	return m.Flags&syscall.MS_RDONLY == syscall.MS_RDONLY
    36  }
    37  
    38  // IsTmpFs returns if the fsType is tmpfs
    39  func (m Mount) IsTmpFs() bool {
    40  	return m.FsType == "tmpfs"
    41  }
    42  
    43  func ensureMountTargetExists(source, target string) error {
    44  	isFile := false
    45  	if fi, err := os.Stat(source); err == nil {
    46  		isFile = !fi.IsDir()
    47  	}
    48  	dir := target
    49  	if isFile {
    50  		dir = filepath.Dir(target)
    51  	}
    52  	if err := os.MkdirAll(dir, 0755); err != nil {
    53  		return err
    54  	}
    55  	if isFile {
    56  		if err := syscall.Mknod(target, 0755, 0); err != nil {
    57  			// double check if file exists
    58  			f, err1 := os.Lstat(target)
    59  			if err1 == nil && f.Mode().IsRegular() {
    60  				return nil
    61  			}
    62  			return err
    63  		}
    64  	}
    65  	return nil
    66  }
    67  
    68  func (m Mount) String() string {
    69  	switch {
    70  	case m.Flags&syscall.MS_BIND == syscall.MS_BIND:
    71  		flag := "rw"
    72  		if m.Flags&syscall.MS_RDONLY == syscall.MS_RDONLY {
    73  			flag = "ro"
    74  		}
    75  		return fmt.Sprintf("bind[%s:%s:%s]", m.Source, m.Target, flag)
    76  
    77  	case m.FsType == "tmpfs":
    78  		return fmt.Sprintf("tmpfs[%s]", m.Target)
    79  
    80  	case m.FsType == "proc":
    81  		return "proc[ro]"
    82  
    83  	default:
    84  		return fmt.Sprintf("mount[%s,%s:%s:%x,%s]", m.FsType, m.Source, m.Target, m.Flags, m.Data)
    85  	}
    86  }