github.com/apptainer/singularity@v3.1.1+incompatible/internal/pkg/util/fs/layout/layer/overlay/overlay.go (about) 1 // Copyright (c) 2018, Sylabs Inc. All rights reserved. 2 // This software is licensed under a 3-clause BSD license. Please consult the 3 // LICENSE.md file distributed with the sources of this project regarding your 4 // rights to use or distribute this software. 5 6 package overlay 7 8 import ( 9 "fmt" 10 "path/filepath" 11 "strings" 12 "syscall" 13 14 "github.com/sylabs/singularity/internal/pkg/sylog" 15 "github.com/sylabs/singularity/internal/pkg/util/fs" 16 "github.com/sylabs/singularity/internal/pkg/util/fs/layout" 17 "github.com/sylabs/singularity/internal/pkg/util/fs/mount" 18 ) 19 20 const ( 21 lowerDir = "/overlay-lowerdir" 22 upperDir = "/overlay-upperdir" 23 workDir = "/overlay-workdir" 24 ) 25 26 // Overlay layer manager 27 type Overlay struct { 28 session *layout.Session 29 lowerDirs []string 30 upperDir string 31 workDir string 32 } 33 34 // New creates and returns an overlay layer manager 35 func New() *Overlay { 36 return &Overlay{} 37 } 38 39 // Add adds required directory in session layout 40 func (o *Overlay) Add(session *layout.Session, system *mount.System) error { 41 o.session = session 42 if err := o.session.AddDir(lowerDir); err != nil { 43 return err 44 } 45 if o.lowerDirs == nil { 46 o.lowerDirs = make([]string, 0) 47 } 48 path, _ := o.session.GetPath(lowerDir) 49 o.lowerDirs = append(o.lowerDirs, path) 50 51 return system.RunBeforeTag(mount.LayerTag, o.createOverlay) 52 } 53 54 func (o *Overlay) createOverlay(system *mount.System) error { 55 flags := uintptr(syscall.MS_NODEV) 56 o.lowerDirs = append(o.lowerDirs, o.session.RootFsPath()) 57 58 lowerdir := strings.Join(o.lowerDirs, ":") 59 err := system.Points.AddOverlay(mount.LayerTag, o.session.FinalPath(), flags, lowerdir, o.upperDir, o.workDir) 60 if err != nil { 61 return err 62 } 63 64 points := system.Points.GetByTag(mount.RootfsTag) 65 if len(points) <= 0 { 66 return fmt.Errorf("no root fs image found") 67 } 68 return o.createLayer(points[0].Destination, system) 69 } 70 71 // AddLowerDir adds a lower directory to overlay mount 72 func (o *Overlay) AddLowerDir(path string) error { 73 o.lowerDirs = append([]string{path}, o.lowerDirs...) 74 return nil 75 } 76 77 // SetUpperDir sets upper directory to overlay mount 78 func (o *Overlay) SetUpperDir(path string) error { 79 if o.upperDir != "" { 80 return fmt.Errorf("upper directory was already set") 81 } 82 o.upperDir = path 83 return nil 84 } 85 86 // GetUpperDir returns upper directory path 87 func (o *Overlay) GetUpperDir() string { 88 return o.upperDir 89 } 90 91 // SetWorkDir sets work directory to overlay mount 92 func (o *Overlay) SetWorkDir(path string) error { 93 if o.workDir != "" { 94 return fmt.Errorf("upper directory was already set") 95 } 96 o.workDir = path 97 return nil 98 } 99 100 // GetWorkDir returns work directory path 101 func (o *Overlay) GetWorkDir() string { 102 return o.workDir 103 } 104 105 // createLayer creates overlay layer based on content of root filesystem 106 // given by rootFsPath 107 func (o *Overlay) createLayer(rootFsPath string, system *mount.System) error { 108 sessionDir := o.session.Path() 109 st := new(syscall.Stat_t) 110 111 if sessionDir == "" { 112 return fmt.Errorf("can't determine session path") 113 } 114 for _, tag := range mount.GetTagList() { 115 for _, point := range system.Points.GetByTag(tag) { 116 flags, _ := mount.ConvertOptions(point.Options) 117 if flags&syscall.MS_REMOUNT != 0 { 118 continue 119 } 120 if strings.HasPrefix(point.Destination, sessionDir) { 121 continue 122 } 123 p := rootFsPath + point.Destination 124 if syscall.Stat(p, st) == nil { 125 continue 126 } 127 if point.Type == "" { 128 if err := syscall.Stat(point.Source, st); err != nil { 129 sylog.Warningf("skipping mount of %s: %s", point.Source, err) 130 continue 131 } 132 } 133 134 dest := fs.EvalRelative(point.Destination, rootFsPath) 135 136 dest = filepath.Join(lowerDir, dest) 137 if _, err := o.session.GetPath(dest); err == nil { 138 continue 139 } 140 // don't exist create it in overlay 141 switch st.Mode & syscall.S_IFMT { 142 case syscall.S_IFDIR: 143 if err := o.session.AddDir(dest); err != nil { 144 return err 145 } 146 default: 147 if point.Type == "" { 148 if err := o.session.AddFile(dest, nil); err != nil { 149 return err 150 } 151 } else { 152 if err := o.session.AddDir(dest); err != nil { 153 return err 154 } 155 } 156 } 157 } 158 } 159 return o.session.Update() 160 }