aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--container/autoetc.go3
-rw-r--r--container/autoetc_test.go6
-rw-r--r--container/autoroot.go13
-rw-r--r--container/autoroot_test.go6
-rw-r--r--container/init.go5
-rw-r--r--container/initbind.go14
-rw-r--r--container/initbind_test.go8
-rw-r--r--container/initdev.go11
-rw-r--r--container/initdev_test.go6
-rw-r--r--container/initmkdir.go11
-rw-r--r--container/initmkdir_test.go6
-rw-r--r--container/initoverlay.go32
-rw-r--r--container/initoverlay_test.go9
-rw-r--r--container/initplace.go8
-rw-r--r--container/initplace_test.go6
-rw-r--r--container/initproc.go12
-rw-r--r--container/initproc_test.go6
-rw-r--r--container/initremount.go11
-rw-r--r--container/initremount_test.go6
-rw-r--r--container/initsymlink.go12
-rw-r--r--container/initsymlink_test.go8
-rw-r--r--container/inittmpfs.go13
-rw-r--r--container/inittmpfs_test.go8
-rw-r--r--container/mount_test.go18
24 files changed, 162 insertions, 76 deletions
diff --git a/container/autoetc.go b/container/autoetc.go
index 44b5d761..0334ad14 100644
--- a/container/autoetc.go
+++ b/container/autoetc.go
@@ -21,6 +21,7 @@ func (f *Ops) Etc(host *Absolute, prefix string) *Ops {
type AutoEtcOp struct{ Prefix string }
+func (e *AutoEtcOp) Valid() bool { return e != nil }
func (e *AutoEtcOp) early(*setupState) error { return nil }
func (e *AutoEtcOp) apply(state *setupState) error {
if state.nonrepeatable&nrAutoEtc != 0 {
@@ -66,7 +67,7 @@ func (e *AutoEtcOp) hostRel() string { return ".host/" + e.Prefix }
func (e *AutoEtcOp) Is(op Op) bool {
ve, ok := op.(*AutoEtcOp)
- return ok && ((e == nil && ve == nil) || (e != nil && ve != nil && *e == *ve))
+ return ok && e.Valid() && ve.Valid() && *e == *ve
}
func (*AutoEtcOp) prefix() string { return "setting up" }
func (e *AutoEtcOp) String() string { return fmt.Sprintf("auto etc %s", e.Prefix) }
diff --git a/container/autoetc_test.go b/container/autoetc_test.go
index 4040fb0d..efb4b3b6 100644
--- a/container/autoetc_test.go
+++ b/container/autoetc_test.go
@@ -3,6 +3,12 @@ package container
import "testing"
func TestAutoEtcOp(t *testing.T) {
+ checkOpsValid(t, []opValidTestCase{
+ {"nil", (*AutoEtcOp)(nil), false},
+ {"zero", new(AutoEtcOp), true},
+ {"populated", &AutoEtcOp{Prefix: ":3"}, true},
+ })
+
checkOpsBuilder(t, []opsBuilderTestCase{
{"pd", new(Ops).Etc(MustAbs("/etc/"), "048090b6ed8f9ebb10e275ff5d8c0659"), Ops{
&MkdirOp{Path: MustAbs("/etc/"), Perm: 0755},
diff --git a/container/autoroot.go b/container/autoroot.go
index a7a3f33c..0de6bce7 100644
--- a/container/autoroot.go
+++ b/container/autoroot.go
@@ -28,11 +28,9 @@ type AutoRootOp struct {
resolved []Op
}
-func (r *AutoRootOp) early(state *setupState) error {
- if r.Host == nil {
- return syscall.EBADE
- }
+func (r *AutoRootOp) Valid() bool { return r != nil && r.Host != nil }
+func (r *AutoRootOp) early(state *setupState) error {
if d, err := os.ReadDir(r.Host.String()); err != nil {
return wrapErrSelf(err)
} else {
@@ -72,9 +70,10 @@ func (r *AutoRootOp) apply(state *setupState) error {
func (r *AutoRootOp) Is(op Op) bool {
vr, ok := op.(*AutoRootOp)
- return ok && ((r == nil && vr == nil) || (r != nil && vr != nil &&
- r.Host != nil && vr.Host != nil && r.Host.Is(vr.Host) &&
- r.Prefix == vr.Prefix && r.Flags == vr.Flags))
+ return ok && r.Valid() && vr.Valid() &&
+ r.Host.Is(vr.Host) &&
+ r.Prefix == vr.Prefix &&
+ r.Flags == vr.Flags
}
func (*AutoRootOp) prefix() string { return "setting up" }
func (r *AutoRootOp) String() string {
diff --git a/container/autoroot_test.go b/container/autoroot_test.go
index 5a77435e..03df7c84 100644
--- a/container/autoroot_test.go
+++ b/container/autoroot_test.go
@@ -3,6 +3,12 @@ package container
import "testing"
func TestAutoRootOp(t *testing.T) {
+ checkOpsValid(t, []opValidTestCase{
+ {"nil", (*AutoRootOp)(nil), false},
+ {"zero", new(AutoRootOp), false},
+ {"valid", &AutoRootOp{Host: MustAbs("/")}, true},
+ })
+
checkOpsBuilder(t, []opsBuilderTestCase{
{"pd", new(Ops).Root(MustAbs("/"), "048090b6ed8f9ebb10e275ff5d8c0659", BindWritable), Ops{
&AutoRootOp{
diff --git a/container/init.go b/container/init.go
index d516a3c2..663bbc83 100644
--- a/container/init.go
+++ b/container/init.go
@@ -52,6 +52,7 @@ type (
prefix() string
Is(op Op) bool
+ Valid() bool
fmt.Stringer
}
@@ -167,8 +168,8 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
via library functions after pivot_root, and implementations are expected to avoid changing
the state of the mount namespace */
for i, op := range *params.Ops {
- if op == nil {
- log.Fatalf("invalid op %d", i)
+ if op == nil || !op.Valid() {
+ log.Fatalf("invalid op at index %d", i)
}
if err := op.early(state); err != nil {
diff --git a/container/initbind.go b/container/initbind.go
index 0b34851e..e19cb5de 100644
--- a/container/initbind.go
+++ b/container/initbind.go
@@ -24,6 +24,8 @@ type BindMountOp struct {
Flags int
}
+func (b *BindMountOp) Valid() bool { return b != nil && b.Source != nil && b.Target != nil }
+
const (
// BindOptional skips nonexistent host paths.
BindOptional = 1 << iota
@@ -34,10 +36,6 @@ const (
)
func (b *BindMountOp) early(*setupState) error {
- if b.Source == nil || b.Target == nil {
- return EBADE
- }
-
if pathname, err := filepath.EvalSymlinks(b.Source.String()); err != nil {
if os.IsNotExist(err) && b.Flags&BindOptional != 0 {
// leave sourceFinal as nil
@@ -87,10 +85,10 @@ func (b *BindMountOp) apply(*setupState) error {
func (b *BindMountOp) Is(op Op) bool {
vb, ok := op.(*BindMountOp)
- return ok && ((b == nil && vb == nil) || (b != nil && vb != nil &&
- b.Source != nil && vb.Source != nil && b.Source.Is(vb.Source) &&
- b.Target != nil && vb.Target != nil && b.Target.Is(vb.Target) &&
- b.Flags == vb.Flags))
+ return ok && b.Valid() && vb.Valid() &&
+ b.Source.Is(vb.Source) &&
+ b.Target.Is(vb.Target) &&
+ b.Flags == vb.Flags
}
func (*BindMountOp) prefix() string { return "mounting" }
func (b *BindMountOp) String() string {
diff --git a/container/initbind_test.go b/container/initbind_test.go
index f0792613..bae33f8a 100644
--- a/container/initbind_test.go
+++ b/container/initbind_test.go
@@ -3,6 +3,14 @@ package container
import "testing"
func TestBindMountOp(t *testing.T) {
+ checkOpsValid(t, []opValidTestCase{
+ {"nil", (*BindMountOp)(nil), false},
+ {"zero", new(BindMountOp), false},
+ {"nil source", &BindMountOp{Target: MustAbs("/")}, false},
+ {"nil target", &BindMountOp{Source: MustAbs("/")}, false},
+ {"valid", &BindMountOp{Source: MustAbs("/"), Target: MustAbs("/")}, true},
+ })
+
checkOpsBuilder(t, []opsBuilderTestCase{
{"autoetc", new(Ops).Bind(
MustAbs("/etc/"),
diff --git a/container/initdev.go b/container/initdev.go
index 71c30f42..48d70f37 100644
--- a/container/initdev.go
+++ b/container/initdev.go
@@ -33,11 +33,9 @@ type MountDevOp struct {
Write bool
}
+func (d *MountDevOp) Valid() bool { return d != nil && d.Target != nil }
func (d *MountDevOp) early(*setupState) error { return nil }
func (d *MountDevOp) apply(state *setupState) error {
- if d.Target == nil {
- return EBADE
- }
target := toSysroot(d.Target.String())
if err := mountTmpfs(SourceTmpfsDevtmpfs, target, MS_NOSUID|MS_NODEV, 0, state.ParentPerm); err != nil {
@@ -128,9 +126,10 @@ func (d *MountDevOp) apply(state *setupState) error {
func (d *MountDevOp) Is(op Op) bool {
vd, ok := op.(*MountDevOp)
- return ok && ((d == nil && vd == nil) || (d != nil && vd != nil &&
- d.Target != nil && vd.Target != nil && d.Target.Is(vd.Target) &&
- d.Mqueue == vd.Mqueue && d.Write == vd.Write))
+ return ok && d.Valid() && vd.Valid() &&
+ d.Target.Is(vd.Target) &&
+ d.Mqueue == vd.Mqueue &&
+ d.Write == vd.Write
}
func (*MountDevOp) prefix() string { return "mounting" }
func (d *MountDevOp) String() string {
diff --git a/container/initdev_test.go b/container/initdev_test.go
index 0d6ea5af..4e23e6ba 100644
--- a/container/initdev_test.go
+++ b/container/initdev_test.go
@@ -3,6 +3,12 @@ package container
import "testing"
func TestMountDevOp(t *testing.T) {
+ checkOpsValid(t, []opValidTestCase{
+ {"nil", (*MountDevOp)(nil), false},
+ {"zero", new(MountDevOp), false},
+ {"valid", &MountDevOp{Target: MustAbs("/dev/")}, true},
+ })
+
checkOpsBuilder(t, []opsBuilderTestCase{
{"dev", new(Ops).Dev(MustAbs("/dev/"), true), Ops{
&MountDevOp{
diff --git a/container/initmkdir.go b/container/initmkdir.go
index 6153106b..54aa4f7b 100644
--- a/container/initmkdir.go
+++ b/container/initmkdir.go
@@ -4,7 +4,6 @@ import (
"encoding/gob"
"fmt"
"os"
- "syscall"
)
func init() { gob.Register(new(MkdirOp)) }
@@ -21,19 +20,17 @@ type MkdirOp struct {
Perm os.FileMode
}
+func (m *MkdirOp) Valid() bool { return m != nil && m.Path != nil }
func (m *MkdirOp) early(*setupState) error { return nil }
func (m *MkdirOp) apply(*setupState) error {
- if m.Path == nil {
- return syscall.EBADE
- }
return wrapErrSelf(os.MkdirAll(toSysroot(m.Path.String()), m.Perm))
}
func (m *MkdirOp) Is(op Op) bool {
vm, ok := op.(*MkdirOp)
- return ok && ((m == nil && vm == nil) || (m != nil && vm != nil &&
- m.Path != nil && vm.Path != nil && m.Path.Is(vm.Path) &&
- m.Perm == vm.Perm))
+ return ok && m.Valid() && vm.Valid() &&
+ m.Path.Is(vm.Path) &&
+ m.Perm == vm.Perm
}
func (*MkdirOp) prefix() string { return "creating" }
func (m *MkdirOp) String() string { return fmt.Sprintf("directory %q perm %s", m.Path, m.Perm) }
diff --git a/container/initmkdir_test.go b/container/initmkdir_test.go
index d5c6f0ba..ad326240 100644
--- a/container/initmkdir_test.go
+++ b/container/initmkdir_test.go
@@ -3,6 +3,12 @@ package container
import "testing"
func TestMkdirOp(t *testing.T) {
+ checkOpsValid(t, []opValidTestCase{
+ {"nil", (*MkdirOp)(nil), false},
+ {"zero", new(MkdirOp), false},
+ {"valid", &MkdirOp{Path: MustAbs("/.hakurei")}, true},
+ })
+
checkOpsBuilder(t, []opsBuilderTestCase{
{"etc", new(Ops).Mkdir(MustAbs("/etc/"), 0), Ops{
&MkdirOp{Path: MustAbs("/etc/")},
diff --git a/container/initoverlay.go b/container/initoverlay.go
index 81b00b9e..6822274d 100644
--- a/container/initoverlay.go
+++ b/container/initoverlay.go
@@ -53,10 +53,10 @@ type MountOverlayOp struct {
lower []string
// The upperdir is normally on a writable filesystem.
//
- // If Work is nil and Upper holds the special value [FHSRoot],
+ // If Work is nil and Upper holds the special value [AbsFHSRoot],
// an ephemeral upperdir and workdir will be set up.
//
- // If both Work and Upper are empty strings, upperdir and workdir is omitted and the overlay is mounted readonly.
+ // If both Work and Upper are nil, upperdir and workdir is omitted and the overlay is mounted readonly.
Upper *Absolute
// formatted for [OptionOverlayUpperdir], resolved, prefixed and escaped during early
upper string
@@ -68,6 +68,19 @@ type MountOverlayOp struct {
ephemeral bool
}
+func (o *MountOverlayOp) Valid() bool {
+ if o == nil {
+ return false
+ }
+ if o.Work != nil && o.Upper == nil {
+ return false
+ }
+ if slices.Contains(o.Lower, nil) {
+ return false
+ }
+ return o.Target != nil
+}
+
func (o *MountOverlayOp) early(*setupState) error {
if o.Work == nil && o.Upper != nil {
switch o.Upper.String() {
@@ -104,11 +117,7 @@ func (o *MountOverlayOp) early(*setupState) error {
}
o.lower = make([]string, len(o.Lower))
- for i, a := range o.Lower {
- if a == nil {
- return EBADE
- }
-
+ for i, a := range o.Lower { // nil checked in Valid
if v, err := filepath.EvalSymlinks(a.String()); err != nil {
return wrapErrSelf(err)
} else {
@@ -119,9 +128,6 @@ func (o *MountOverlayOp) early(*setupState) error {
}
func (o *MountOverlayOp) apply(state *setupState) error {
- if o.Target == nil {
- return EBADE
- }
target := toSysroot(o.Target.String())
if err := os.MkdirAll(target, state.ParentPerm); err != nil {
return wrapErrSelf(err)
@@ -163,10 +169,10 @@ func (o *MountOverlayOp) apply(state *setupState) error {
func (o *MountOverlayOp) Is(op Op) bool {
vo, ok := op.(*MountOverlayOp)
- return ok && ((o == nil && vo == nil) || (o != nil && vo != nil &&
- o.Target != nil && vo.Target != nil && o.Target.Is(vo.Target) &&
+ return ok && o.Valid() && vo.Valid() &&
+ o.Target.Is(vo.Target) &&
slices.EqualFunc(o.Lower, vo.Lower, func(a *Absolute, v *Absolute) bool { return a.Is(v) }) &&
- o.Upper.Is(vo.Upper) && o.Work.Is(vo.Work)))
+ o.Upper.Is(vo.Upper) && o.Work.Is(vo.Work)
}
func (*MountOverlayOp) prefix() string { return "mounting" }
func (o *MountOverlayOp) String() string {
diff --git a/container/initoverlay_test.go b/container/initoverlay_test.go
index ae4cd1bf..68377dd4 100644
--- a/container/initoverlay_test.go
+++ b/container/initoverlay_test.go
@@ -3,6 +3,15 @@ package container
import "testing"
func TestMountOverlayOp(t *testing.T) {
+ checkOpsValid(t, []opValidTestCase{
+ {"nil", (*MountOverlayOp)(nil), false},
+ {"zero", new(MountOverlayOp), false},
+ {"nil lower", &MountOverlayOp{Target: MustAbs("/"), Lower: []*Absolute{nil}}, false},
+ {"ro", &MountOverlayOp{Target: MustAbs("/"), Lower: []*Absolute{MustAbs("/")}}, true},
+ {"ro work", &MountOverlayOp{Target: MustAbs("/"), Work: MustAbs("/tmp/")}, false},
+ {"rw", &MountOverlayOp{Target: MustAbs("/"), Lower: []*Absolute{MustAbs("/")}, Upper: MustAbs("/"), Work: MustAbs("/")}, true},
+ })
+
checkOpsBuilder(t, []opsBuilderTestCase{
{"full", new(Ops).Overlay(
MustAbs("/nix/store"),
diff --git a/container/initplace.go b/container/initplace.go
index 91146948..2d98d94f 100644
--- a/container/initplace.go
+++ b/container/initplace.go
@@ -35,12 +35,9 @@ type TmpfileOp struct {
Data []byte
}
+func (t *TmpfileOp) Valid() bool { return t != nil && t.Path != nil }
func (t *TmpfileOp) early(*setupState) error { return nil }
func (t *TmpfileOp) apply(state *setupState) error {
- if t.Path == nil {
- return EBADE
- }
-
var tmpPath string
if f, err := os.CreateTemp(FHSRoot, intermediatePatternTmpfile); err != nil {
return wrapErrSelf(err)
@@ -72,7 +69,8 @@ func (t *TmpfileOp) apply(state *setupState) error {
func (t *TmpfileOp) Is(op Op) bool {
vt, ok := op.(*TmpfileOp)
- return ok && t.Path != nil && vt.Path != nil && t.Path.Is(vt.Path) &&
+ return ok && t.Valid() && vt.Valid() &&
+ t.Path.Is(vt.Path) &&
string(t.Data) == string(vt.Data)
}
func (*TmpfileOp) prefix() string { return "placing" }
diff --git a/container/initplace_test.go b/container/initplace_test.go
index e1d8163d..db3d955c 100644
--- a/container/initplace_test.go
+++ b/container/initplace_test.go
@@ -3,6 +3,12 @@ package container
import "testing"
func TestTmpfileOp(t *testing.T) {
+ checkOpsValid(t, []opValidTestCase{
+ {"nil", (*TmpfileOp)(nil), false},
+ {"zero", new(TmpfileOp), false},
+ {"valid", &TmpfileOp{Path: MustAbs("/etc/passwd")}, true},
+ })
+
checkOpsBuilder(t, []opsBuilderTestCase{
{"noref", new(Ops).Place(MustAbs("/etc/passwd"), []byte(`chronos:x:65534:65534:Hakurei:/var/empty:/bin/zsh`)), Ops{
&TmpfileOp{
diff --git a/container/initproc.go b/container/initproc.go
index d3c37535..9b9769cd 100644
--- a/container/initproc.go
+++ b/container/initproc.go
@@ -16,15 +16,11 @@ func (f *Ops) Proc(target *Absolute) *Ops {
}
// MountProcOp mounts a new instance of [FstypeProc] on container path Target.
-type MountProcOp struct {
- Target *Absolute
-}
+type MountProcOp struct{ Target *Absolute }
+func (p *MountProcOp) Valid() bool { return p != nil && p.Target != nil }
func (p *MountProcOp) early(*setupState) error { return nil }
func (p *MountProcOp) apply(state *setupState) error {
- if p.Target == nil {
- return EBADE
- }
target := toSysroot(p.Target.String())
if err := os.MkdirAll(target, state.ParentPerm); err != nil {
return wrapErrSelf(err)
@@ -35,8 +31,8 @@ func (p *MountProcOp) apply(state *setupState) error {
func (p *MountProcOp) Is(op Op) bool {
vp, ok := op.(*MountProcOp)
- return ok && ((p == nil && vp == nil) ||
- (p.Target != nil && vp.Target != nil && p.Target.Is(vp.Target)))
+ return ok && p.Valid() && vp.Valid() &&
+ p.Target.Is(vp.Target)
}
func (*MountProcOp) prefix() string { return "mounting" }
func (p *MountProcOp) String() string { return fmt.Sprintf("proc on %q", p.Target) }
diff --git a/container/initproc_test.go b/container/initproc_test.go
index fe37732f..eb55e4ec 100644
--- a/container/initproc_test.go
+++ b/container/initproc_test.go
@@ -3,6 +3,12 @@ package container
import "testing"
func TestMountProcOp(t *testing.T) {
+ checkOpsValid(t, []opValidTestCase{
+ {"nil", (*MountProcOp)(nil), false},
+ {"zero", new(MountProcOp), false},
+ {"valid", &MountProcOp{Target: MustAbs("/proc/")}, true},
+ })
+
checkOpsBuilder(t, []opsBuilderTestCase{
{"proc", new(Ops).Proc(MustAbs("/proc/")), Ops{
&MountProcOp{Target: MustAbs("/proc/")},
diff --git a/container/initremount.go b/container/initremount.go
index 77efc21d..74bea097 100644
--- a/container/initremount.go
+++ b/container/initremount.go
@@ -3,7 +3,6 @@ package container
import (
"encoding/gob"
"fmt"
- "syscall"
)
func init() { gob.Register(new(RemountOp)) }
@@ -20,20 +19,18 @@ type RemountOp struct {
Flags uintptr
}
+func (r *RemountOp) Valid() bool { return r != nil && r.Target != nil }
func (*RemountOp) early(*setupState) error { return nil }
func (r *RemountOp) apply(*setupState) error {
- if r.Target == nil {
- return syscall.EBADE
- }
return wrapErrSuffix(hostProc.remount(toSysroot(r.Target.String()), r.Flags),
fmt.Sprintf("cannot remount %q:", r.Target))
}
func (r *RemountOp) Is(op Op) bool {
vr, ok := op.(*RemountOp)
- return ok && ((r == nil && vr == nil) ||
- (r.Target != nil && vr.Target != nil && r.Target.Is(vr.Target)) &&
- r.Flags == vr.Flags)
+ return ok && r.Valid() && vr.Valid() &&
+ r.Target.Is(vr.Target) &&
+ r.Flags == vr.Flags
}
func (*RemountOp) prefix() string { return "remounting" }
func (r *RemountOp) String() string { return fmt.Sprintf("%q flags %#x", r.Target, r.Flags) }
diff --git a/container/initremount_test.go b/container/initremount_test.go
index a59160b9..db5476ec 100644
--- a/container/initremount_test.go
+++ b/container/initremount_test.go
@@ -6,6 +6,12 @@ import (
)
func TestRemountOp(t *testing.T) {
+ checkOpsValid(t, []opValidTestCase{
+ {"nil", (*RemountOp)(nil), false},
+ {"zero", new(RemountOp), false},
+ {"valid", &RemountOp{Target: MustAbs("/"), Flags: syscall.MS_RDONLY}, true},
+ })
+
checkOpsBuilder(t, []opsBuilderTestCase{
{"root", new(Ops).Remount(MustAbs("/"), syscall.MS_RDONLY), Ops{
&RemountOp{
diff --git a/container/initsymlink.go b/container/initsymlink.go
index 35805544..3060817f 100644
--- a/container/initsymlink.go
+++ b/container/initsymlink.go
@@ -26,6 +26,8 @@ type SymlinkOp struct {
Dereference bool
}
+func (l *SymlinkOp) Valid() bool { return l != nil && l.Target != nil && l.LinkName != zeroString }
+
func (l *SymlinkOp) early(*setupState) error {
if l.Dereference {
if !isAbs(l.LinkName) {
@@ -41,9 +43,6 @@ func (l *SymlinkOp) early(*setupState) error {
}
func (l *SymlinkOp) apply(state *setupState) error {
- if l.Target == nil {
- return syscall.EBADE
- }
target := toSysroot(l.Target.String())
if err := os.MkdirAll(path.Dir(target), state.ParentPerm); err != nil {
return wrapErrSelf(err)
@@ -56,9 +55,10 @@ func (l *SymlinkOp) apply(state *setupState) error {
func (l *SymlinkOp) Is(op Op) bool {
vl, ok := op.(*SymlinkOp)
- return ok && ((l == nil && vl == nil) ||
- (l.Target != nil && vl.Target != nil && l.Target.Is(vl.Target)) &&
- l.LinkName == vl.LinkName && l.Dereference == vl.Dereference)
+ return ok && l.Valid() && vl.Valid() &&
+ l.Target.Is(vl.Target) &&
+ l.LinkName == vl.LinkName &&
+ l.Dereference == vl.Dereference
}
func (*SymlinkOp) prefix() string { return "creating" }
func (l *SymlinkOp) String() string {
diff --git a/container/initsymlink_test.go b/container/initsymlink_test.go
index 1051beb0..4ae2da86 100644
--- a/container/initsymlink_test.go
+++ b/container/initsymlink_test.go
@@ -3,6 +3,14 @@ package container
import "testing"
func TestSymlinkOp(t *testing.T) {
+ checkOpsValid(t, []opValidTestCase{
+ {"nil", (*SymlinkOp)(nil), false},
+ {"zero", new(SymlinkOp), false},
+ {"nil target", &SymlinkOp{LinkName: "/run/current-system"}, false},
+ {"zero linkname", &SymlinkOp{Target: MustAbs("/run/current-system")}, false},
+ {"valid", &SymlinkOp{Target: MustAbs("/run/current-system"), LinkName: "/run/current-system", Dereference: true}, true},
+ })
+
checkOpsBuilder(t, []opsBuilderTestCase{
{"current-system", new(Ops).Link(
MustAbs("/run/current-system"),
diff --git a/container/inittmpfs.go b/container/inittmpfs.go
index 332fec89..d313a111 100644
--- a/container/inittmpfs.go
+++ b/container/inittmpfs.go
@@ -31,11 +31,9 @@ type MountTmpfsOp struct {
Perm os.FileMode
}
+func (t *MountTmpfsOp) Valid() bool { return t != nil && t.Path != nil && t.FSName != zeroString }
func (t *MountTmpfsOp) early(*setupState) error { return nil }
func (t *MountTmpfsOp) apply(*setupState) error {
- if t.Path == nil {
- return EBADE
- }
if t.Size < 0 || t.Size > math.MaxUint>>1 {
return msg.WrapErr(EBADE, fmt.Sprintf("size %d out of bounds", t.Size))
}
@@ -44,9 +42,12 @@ func (t *MountTmpfsOp) apply(*setupState) error {
func (t *MountTmpfsOp) Is(op Op) bool {
vt, ok := op.(*MountTmpfsOp)
- return ok && ((t == nil && vt == nil) ||
- (t.Path != nil && vt.Path != nil && t.Path.Is(vt.Path)) &&
- t.FSName == vt.FSName && t.Flags == vt.Flags && t.Size == vt.Size && t.Perm == vt.Perm)
+ return ok && t.Valid() && vt.Valid() &&
+ t.FSName == vt.FSName &&
+ t.Path.Is(vt.Path) &&
+ t.Flags == vt.Flags &&
+ t.Size == vt.Size &&
+ t.Perm == vt.Perm
}
func (*MountTmpfsOp) prefix() string { return "mounting" }
func (t *MountTmpfsOp) String() string { return fmt.Sprintf("tmpfs on %q size %d", t.Path, t.Size) }
diff --git a/container/inittmpfs_test.go b/container/inittmpfs_test.go
index c36820cd..c9245869 100644
--- a/container/inittmpfs_test.go
+++ b/container/inittmpfs_test.go
@@ -6,6 +6,14 @@ import (
)
func TestMountTmpfsOp(t *testing.T) {
+ checkOpsValid(t, []opValidTestCase{
+ {"nil", (*MountTmpfsOp)(nil), false},
+ {"zero", new(MountTmpfsOp), false},
+ {"nil path", &MountTmpfsOp{FSName: "tmpfs"}, false},
+ {"zero fsname", &MountTmpfsOp{Path: MustAbs("/tmp/")}, false},
+ {"valid", &MountTmpfsOp{FSName: "tmpfs", Path: MustAbs("/tmp/")}, true},
+ })
+
checkOpsBuilder(t, []opsBuilderTestCase{
{"runtime", new(Ops).Tmpfs(
MustAbs("/run/user"),
diff --git a/container/mount_test.go b/container/mount_test.go
index 4c598b3f..64cac282 100644
--- a/container/mount_test.go
+++ b/container/mount_test.go
@@ -49,6 +49,24 @@ func TestEscapeOverlayDataSegment(t *testing.T) {
}
}
+type opValidTestCase struct {
+ name string
+ op Op
+ want bool
+}
+
+func checkOpsValid(t *testing.T, testCases []opValidTestCase) {
+ t.Run("valid", func(t *testing.T) {
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ if got := tc.op.Valid(); got != tc.want {
+ t.Errorf("Valid: %v, want %v", got, tc.want)
+ }
+ })
+ }
+ })
+}
+
type opsBuilderTestCase struct {
name string
ops *Ops