package bwrap import ( "encoding/gob" "os" "strconv" ) func init() { gob.Register(new(PermConfig[SymlinkConfig])) gob.Register(new(PermConfig[*TmpfsConfig])) gob.Register(new(OverlayConfig)) } type PositionalArg int func (p PositionalArg) Unwrap() string { return positionalArgs[p] } const ( Tmpfs PositionalArg = iota Symlink Bind BindTry DevBind DevBindTry ROBind ROBindTry Chmod Dir RemountRO Procfs DevTmpfs Mqueue Perms Size OverlaySrc Overlay TmpOverlay ROOverlay ) var positionalArgs = [...]string{ Tmpfs: "--tmpfs", Symlink: "--symlink", Bind: "--bind", BindTry: "--bind-try", DevBind: "--dev-bind", DevBindTry: "--dev-bind-try", ROBind: "--ro-bind", ROBindTry: "--ro-bind-try", Chmod: "--chmod", Dir: "--dir", RemountRO: "--remount-ro", Procfs: "--proc", DevTmpfs: "--dev", Mqueue: "--mqueue", Perms: "--perms", Size: "--size", OverlaySrc: "--overlay-src", Overlay: "--overlay", TmpOverlay: "--tmp-overlay", ROOverlay: "--ro-overlay", } type PermConfig[T FSBuilder] struct { // set permissions of next argument // (--perms OCTAL) Mode *os.FileMode `json:"mode,omitempty"` // path to get the new permission // (--bind-data, --file, etc.) Inner T `json:"path"` } func (p *PermConfig[T]) Path() string { return p.Inner.Path() } func (p *PermConfig[T]) Len() int { if p.Mode != nil { return p.Inner.Len() + 2 } else { return p.Inner.Len() } } func (p *PermConfig[T]) Append(args *[]string) { if p.Mode != nil { *args = append(*args, Perms.Unwrap(), strconv.FormatInt(int64(*p.Mode), 8)) } p.Inner.Append(args) } type TmpfsConfig struct { // set size of tmpfs // (--size BYTES) Size int `json:"size,omitempty"` // mount point of new tmpfs // (--tmpfs DEST) Dir string `json:"dir"` } func (t *TmpfsConfig) Path() string { return t.Dir } func (t *TmpfsConfig) Len() int { if t.Size > 0 { return 4 } else { return 2 } } func (t *TmpfsConfig) Append(args *[]string) { if t.Size > 0 { *args = append(*args, Size.Unwrap(), strconv.Itoa(t.Size)) } *args = append(*args, Tmpfs.Unwrap(), t.Dir) } type OverlayConfig struct { /* read files from SRC in the following overlay (--overlay-src SRC) */ Src []string `json:"src,omitempty"` /* mount overlayfs on DEST, with RWSRC as the host path for writes and WORKDIR an empty directory on the same filesystem as RWSRC (--overlay RWSRC WORKDIR DEST) if nil, mount overlayfs on DEST, with writes going to an invisible tmpfs (--tmp-overlay DEST) if either strings are empty, mount overlayfs read-only on DEST (--ro-overlay DEST) */ Persist *[2]string `json:"persist,omitempty"` /* --overlay RWSRC WORKDIR DEST --tmp-overlay DEST --ro-overlay DEST */ Dest string `json:"dest"` } func (o *OverlayConfig) Path() string { return o.Dest } func (o *OverlayConfig) Len() int { // (--tmp-overlay DEST) or (--ro-overlay DEST) p := 2 // (--overlay RWSRC WORKDIR DEST) if o.Persist != nil && o.Persist[0] != "" && o.Persist[1] != "" { p = 4 } return p + len(o.Src)*2 } func (o *OverlayConfig) Append(args *[]string) { // --overlay-src SRC for _, src := range o.Src { *args = append(*args, OverlaySrc.Unwrap(), src) } if o.Persist != nil { if o.Persist[0] != "" && o.Persist[1] != "" { // --overlay RWSRC WORKDIR *args = append(*args, Overlay.Unwrap(), o.Persist[0], o.Persist[1]) } else { // --ro-overlay *args = append(*args, ROOverlay.Unwrap()) } } else { // --tmp-overlay *args = append(*args, TmpOverlay.Unwrap()) } // DEST *args = append(*args, o.Dest) } type SymlinkConfig [2]string func (s SymlinkConfig) Path() string { return s[1] } func (s SymlinkConfig) Len() int { return 3 } func (s SymlinkConfig) Append(args *[]string) { *args = append(*args, Symlink.Unwrap(), s[0], s[1]) } type ChmodConfig map[string]os.FileMode func (c ChmodConfig) Len() int { return len(c) } func (c ChmodConfig) Append(args *[]string) { for path, mode := range c { *args = append(*args, Chmod.Unwrap(), strconv.FormatInt(int64(mode), 8), path) } }