1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
// Copyright (c) 2018-2020, Sylabs Inc. All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the
// LICENSE.md file distributed with the sources of this project regarding your
// rights to use or distribute this software.
package layout
import (
"fmt"
"path/filepath"
"syscall"
"github.com/sylabs/singularity/v4/internal/pkg/util/fs/mount"
"github.com/sylabs/singularity/v4/pkg/sylog"
)
const (
rootFsDir = "/rootfs"
finalDir = "/final"
)
// Session directory layout manager
type Session struct {
*Manager
Layer layer
}
// Layer describes a layer interface added on top of session layout
type layer interface {
Add(*Session, *mount.System) error
Dir() string
}
// NewSession creates and returns a session directory layout manager
func NewSession(path string, fstype string, size int, system *mount.System, layer layer) (*Session, error) {
manager := &Manager{VFS: DefaultVFS}
session := &Session{Manager: manager}
if err := manager.SetRootPath(path); err != nil {
return nil, err
}
if err := manager.AddDir(rootFsDir); err != nil {
return nil, err
}
if err := manager.AddDir(finalDir); err != nil {
return nil, err
}
options := "mode=1777"
if size > 0 {
options = fmt.Sprintf("mode=1777,size=%dm", size)
}
err := system.Points.AddFS(mount.SessionTag, path, fstype, syscall.MS_NOSUID, options)
if err != nil {
return nil, err
}
if err := system.RunAfterTag(mount.SessionTag, session.createLayout); err != nil {
return nil, err
}
if layer != nil {
if err := layer.Add(session, system); err != nil {
return nil, fmt.Errorf("failed to init layer: %s", err)
}
session.Layer = layer
}
return session, nil
}
// Path returns the full path of session directory
func (s *Session) Path() string {
path, _ := s.GetPath("/")
return path
}
// FinalPath returns the full path to session final directory
func (s *Session) FinalPath() string {
if s.Layer != nil {
path, _ := s.GetPath(finalDir)
return path
}
return s.RootFsPath()
}
// OverrideDir overrides a path in the session directory, it simulates
// a bind mount.
func (s *Session) OverrideDir(path string, realpath string) {
p := path
if s.Layer != nil {
p = filepath.Join(s.Layer.Dir(), path)
}
s.overrideDir(p, realpath)
}
// RootFsPath returns the full path to session rootfs directory
func (s *Session) RootFsPath() string {
path, _ := s.GetPath(rootFsDir)
return path
}
func (s *Session) createLayout(system *mount.System) error {
// create directory for registered overridden directory
for _, tag := range mount.GetTagList() {
for _, point := range system.Points.GetByTag(tag) {
if point.Source == "" {
continue
}
// search until we find a parent overridden directory
overridden := false
for baseDir := filepath.Dir(point.Destination); baseDir != "/"; {
if _, err := s.GetOverridePath(baseDir); err == nil {
overridden = true
break
}
baseDir = filepath.Dir(baseDir)
}
if !overridden {
continue
}
dest := point.Destination
if _, err := s.GetPath(dest); err == nil {
continue
}
flags, _ := mount.ConvertOptions(point.Options)
// ignore anything which is not a bind mount point
if flags&syscall.MS_BIND == 0 {
continue
}
// check if the bind source exists
fi, err := s.VFS.Stat(point.Source)
if err != nil {
sylog.Warningf("skipping mount of: %s: %s", point.Source, err)
continue
}
if fi.IsDir() {
if err := s.AddDir(dest); err != nil {
return err
}
} else {
if err := s.AddFile(dest, nil); err != nil {
return err
}
}
}
}
return s.Create()
}
|