All checks were successful
		
		
	
	Test / Create distribution (push) Successful in 32s
				
			Test / Sandbox (push) Successful in 2m19s
				
			Test / Hakurei (push) Successful in 3m9s
				
			Test / Hpkg (push) Successful in 3m53s
				
			Test / Sandbox (race detector) (push) Successful in 4m2s
				
			Test / Hakurei (race detector) (push) Successful in 4m43s
				
			Test / Flake checks (push) Successful in 1m23s
				
			This package will also hold syscall lookup tables for seccomp. Signed-off-by: Ophestra <cat@gensokyo.uk>
		
			
				
	
	
		
			180 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			180 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package hst
 | |
| 
 | |
| import (
 | |
| 	"encoding/gob"
 | |
| 	"strings"
 | |
| 
 | |
| 	"hakurei.app/container/check"
 | |
| 	"hakurei.app/container/comp"
 | |
| 	"hakurei.app/container/fhs"
 | |
| )
 | |
| 
 | |
| func init() { gob.Register(new(FSBind)) }
 | |
| 
 | |
| // FilesystemBind is the type string of a bind mount point.
 | |
| const FilesystemBind = "bind"
 | |
| 
 | |
| // FSBind represents a host to container bind mount.
 | |
| type FSBind struct {
 | |
| 	// Pathname in the container mount namespace. Same as Source if nil.
 | |
| 	Target *check.Absolute `json:"dst,omitempty"`
 | |
| 	// Pathname in the init mount namespace. Must not be nil.
 | |
| 	Source *check.Absolute `json:"src"`
 | |
| 	// Do not remount Target read-only.
 | |
| 	// This has no effect if Source is mounted read-only in the init mount namespace.
 | |
| 	Write bool `json:"write,omitempty"`
 | |
| 	// Allow access to devices (special files) on Target, implies Write.
 | |
| 	Device bool `json:"dev,omitempty"`
 | |
| 	// Create Source as a directory in the init mount namespace if it does not exist.
 | |
| 	Ensure bool `json:"ensure,omitempty"`
 | |
| 	// Silently skip this mount point if Source does not exist in the init mount namespace.
 | |
| 	Optional bool `json:"optional,omitempty"`
 | |
| 
 | |
| 	/* Enable special behaviour:
 | |
| 	For autoroot: Target must be [fhs.Root].
 | |
| 	For autoetc:  Target must be [fhs.Etc]. */
 | |
| 	Special bool `json:"special,omitempty"`
 | |
| }
 | |
| 
 | |
| // IsAutoRoot returns whether this FSBind has autoroot behaviour enabled.
 | |
| func (b *FSBind) IsAutoRoot() bool {
 | |
| 	return b.Valid() && b.Special && b.Target.String() == fhs.Root
 | |
| }
 | |
| 
 | |
| // IsAutoEtc returns whether this FSBind has autoetc behaviour enabled.
 | |
| func (b *FSBind) IsAutoEtc() bool {
 | |
| 	return b.Valid() && b.Special && b.Target.String() == fhs.Etc
 | |
| }
 | |
| 
 | |
| func (b *FSBind) Valid() bool {
 | |
| 	if b == nil || b.Source == nil {
 | |
| 		return false
 | |
| 	}
 | |
| 	if b.Ensure && b.Optional {
 | |
| 		return false
 | |
| 	}
 | |
| 	if b.Special {
 | |
| 		if b.Target == nil {
 | |
| 			return false
 | |
| 		} else {
 | |
| 			switch b.Target.String() {
 | |
| 			case fhs.Root, fhs.Etc:
 | |
| 				break
 | |
| 
 | |
| 			default:
 | |
| 				return false
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| func (b *FSBind) Path() *check.Absolute {
 | |
| 	if !b.Valid() {
 | |
| 		return nil
 | |
| 	}
 | |
| 	if b.Target == nil {
 | |
| 		return b.Source
 | |
| 	}
 | |
| 	return b.Target
 | |
| }
 | |
| 
 | |
| func (b *FSBind) Host() []*check.Absolute {
 | |
| 	if !b.Valid() {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return []*check.Absolute{b.Source}
 | |
| }
 | |
| 
 | |
| func (b *FSBind) Apply(z *ApplyState) {
 | |
| 	if !b.Valid() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	target := b.Target
 | |
| 	if target == nil {
 | |
| 		target = b.Source
 | |
| 	}
 | |
| 	var flags int
 | |
| 	if b.Write {
 | |
| 		flags |= comp.BindWritable
 | |
| 	}
 | |
| 	if b.Device {
 | |
| 		flags |= comp.BindDevice | comp.BindWritable
 | |
| 	}
 | |
| 	if b.Ensure {
 | |
| 		flags |= comp.BindEnsure
 | |
| 	}
 | |
| 	if b.Optional {
 | |
| 		flags |= comp.BindOptional
 | |
| 	}
 | |
| 
 | |
| 	switch {
 | |
| 	case b.IsAutoRoot():
 | |
| 		z.Root(b.Source, flags)
 | |
| 
 | |
| 	case b.IsAutoEtc():
 | |
| 		z.Etc(b.Source, z.AutoEtcPrefix)
 | |
| 
 | |
| 	default:
 | |
| 		z.Bind(b.Source, target, flags)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (b *FSBind) String() string {
 | |
| 	if !b.Valid() {
 | |
| 		return "<invalid>"
 | |
| 	}
 | |
| 
 | |
| 	var flagSym string
 | |
| 	if b.Device {
 | |
| 		flagSym = "d"
 | |
| 	} else if b.Write {
 | |
| 		flagSym = "w"
 | |
| 	}
 | |
| 
 | |
| 	if b.Special {
 | |
| 		switch {
 | |
| 		case b.IsAutoRoot():
 | |
| 			prefix := "autoroot"
 | |
| 			if flagSym != "" {
 | |
| 				prefix += ":" + flagSym
 | |
| 			}
 | |
| 			if b.Source.String() != fhs.Root {
 | |
| 				return prefix + ":" + b.Source.String()
 | |
| 			}
 | |
| 			return prefix
 | |
| 
 | |
| 		case b.IsAutoEtc():
 | |
| 			return "autoetc:" + b.Source.String()
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	g := 4 + len(b.Source.String())
 | |
| 	if b.Target != nil {
 | |
| 		g += len(b.Target.String())
 | |
| 	}
 | |
| 
 | |
| 	expr := new(strings.Builder)
 | |
| 	expr.Grow(g)
 | |
| 	expr.WriteString(flagSym)
 | |
| 
 | |
| 	switch {
 | |
| 	case b.Ensure:
 | |
| 		expr.WriteString("-")
 | |
| 
 | |
| 	case b.Optional:
 | |
| 		expr.WriteString("+")
 | |
| 
 | |
| 	default:
 | |
| 		expr.WriteString("*")
 | |
| 	}
 | |
| 
 | |
| 	expr.WriteString(b.Source.String())
 | |
| 	if b.Target != nil {
 | |
| 		expr.WriteString(":" + b.Target.String())
 | |
| 	}
 | |
| 
 | |
| 	return expr.String()
 | |
| }
 |