aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/sandbox/mount.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-02-28 14:56:08 +0900
committerOphestra <cat@gensokyo.uk>2025-02-28 14:56:08 +0900
commit4de404971341a5cebab88cad6233965362fdeb4c (patch)
tree04799c7ed03ab63cedeec404757b511d4a003cdd /test/sandbox/mount.go
parent2d4cabe7860cb7ef7aa5bb6a3c21153e624d61b6 (diff)
test/sandbox: wrap libc getmntent
For checking mounts outcome. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'test/sandbox/mount.go')
-rw-r--r--test/sandbox/mount.go134
1 files changed, 134 insertions, 0 deletions
diff --git a/test/sandbox/mount.go b/test/sandbox/mount.go
new file mode 100644
index 00000000..9c279f87
--- /dev/null
+++ b/test/sandbox/mount.go
@@ -0,0 +1,134 @@
+package sandbox
+
+/*
+#include <stdlib.h>
+#include <stdio.h>
+#include <mntent.h>
+
+const char *F_PROC_MOUNTS = "";
+const char *F_SET_TYPE = "r";
+*/
+import "C"
+
+import (
+ "fmt"
+ "runtime"
+ "sync"
+ "unsafe"
+)
+
+type Mntent struct {
+ /* name of mounted filesystem */
+ FSName string `json:"fsname"`
+ /* filesystem path prefix */
+ Dir string `json:"dir"`
+ /* mount type (see mntent.h) */
+ Type string `json:"type"`
+ /* mount options (see mntent.h) */
+ Opts string `json:"opts"`
+ /* dump frequency in days */
+ Freq int `json:"freq"`
+ /* pass number on parallel fsck */
+ Passno int `json:"passno"`
+}
+
+func (e *Mntent) String() string {
+ return fmt.Sprintf("%s %s %s %s %d %d",
+ e.FSName, e.Dir, e.Type, e.Opts, e.Freq, e.Passno)
+}
+
+func IterMounts(name string, f func(e *Mntent)) error {
+ m := new(mounts)
+ m.p = name
+ if err := m.open(); err != nil {
+ return err
+ }
+
+ for m.scan() {
+ e := new(Mntent)
+ m.copy(e)
+ f(e)
+ }
+
+ m.close()
+ return m.Err()
+}
+
+type mounts struct {
+ p string
+ f *C.FILE
+ mu sync.RWMutex
+
+ ent *C.struct_mntent
+ err error
+}
+
+func (m *mounts) open() error {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ if m.f != nil {
+ panic("open called twice")
+ }
+
+ if m.p == "" {
+ m.p = "/proc/mounts"
+ }
+
+ name := C.CString(m.p)
+ f, err := C.setmntent(name, C.F_SET_TYPE)
+ C.free(unsafe.Pointer(name))
+
+ if f == nil {
+ return err
+ }
+ m.f = f
+ runtime.SetFinalizer(m, (*mounts).close)
+ return err
+}
+
+func (m *mounts) close() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ if m.f == nil {
+ panic("close called before open")
+ }
+
+ C.endmntent(m.f)
+ runtime.SetFinalizer(m, nil)
+}
+
+func (m *mounts) scan() bool {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ if m.f == nil {
+ panic("invalid file")
+ }
+
+ m.ent, m.err = C.getmntent(m.f)
+ return m.ent != nil
+}
+
+func (m *mounts) Err() error {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+
+ return m.err
+}
+
+func (m *mounts) copy(v *Mntent) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+
+ if m.ent == nil {
+ panic("invalid entry")
+ }
+ v.FSName = C.GoString(m.ent.mnt_fsname)
+ v.Dir = C.GoString(m.ent.mnt_dir)
+ v.Type = C.GoString(m.ent.mnt_type)
+ v.Opts = C.GoString(m.ent.mnt_opts)
+ v.Freq = int(m.ent.mnt_freq)
+ v.Passno = int(m.ent.mnt_passno)
+}