aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/internal/mountinfo
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-10-06 22:23:20 +0900
committerOphestra <cat@gensokyo.uk>2026-10-06 23:09:19 +0900
commita9e2749f6654d0aa07b274a45c9177d10323f80a (patch)
tree291f5b23a67af036cbe5d374b3d3fb0240fc438c /test/internal/mountinfo
parent19f36491f2e2a5029ac396c10408d653cad6c81b (diff)
internal/testsuite: move from test
This structure is a lot less clumsy than the old nix-centric layout. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'test/internal/mountinfo')
-rw-r--r--test/internal/mountinfo/mountinfo.go177
-rw-r--r--test/internal/mountinfo/mountinfo_guard.go15
-rw-r--r--test/internal/mountinfo/mountinfo_test.go146
3 files changed, 0 insertions, 338 deletions
diff --git a/test/internal/mountinfo/mountinfo.go b/test/internal/mountinfo/mountinfo.go
deleted file mode 100644
index 19892cd2..00000000
--- a/test/internal/mountinfo/mountinfo.go
+++ /dev/null
@@ -1,177 +0,0 @@
-// Package mountinfo provides util-linux bindings for parsing
-// proc_pid_mountinfo(5).
-//
-// This package must never be used outside integration tests, a much better
-// implementation can be found in package vfs.
-//
-// Attempting to import this package outside testing causes the resulting
-// program to panic.
-package mountinfo
-
-/*
-#cgo linux pkg-config: --static mount
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <libmount.h>
-
-const char *HAKUREI_MOUNTINFO_PATH = "/proc/self/mountinfo";
-*/
-import "C"
-
-import (
- "errors"
- "fmt"
- "runtime"
- "unsafe"
-)
-
-var (
- // ErrParse is returned by [Open] when encountering a bad record.
- ErrParse = errors.New("invalid mountinfo record")
- // ErrIter is returned by [Open] if an iterator cannot be allocated.
- ErrIter = errors.New("cannot allocate iterator")
- // ErrIterAdvance is stored when the iterator is unable to advance.
- ErrIterAdvance = errors.New("unable to advance iterator")
-)
-
-type (
- // Iter refers to libmnt iterator state.
- Iter struct {
- // Last stored error.
- err error
- // Whether iteration has concluded.
- ok bool
- // Whether Close had already been called.
- closed bool
-
- tb *C.struct_libmnt_table
- itr *C.struct_libmnt_iter
-
- fs *C.struct_libmnt_fs
- }
-
- // Entry represents deterministic mountinfo parts of a libmnt_fs entry.
- Entry struct {
- // mount ID: a unique ID for the mount (may be reused after umount(2)).
- ID int `json:"id"`
- // parent ID: the ID of the parent mount (or of self for the root of
- // this mount namespace's mount tree).
- Parent int `json:"parent"`
- // root: the pathname of the directory in the filesystem which forms the
- // root of this mount.
- Root string `json:"root"`
- // mount point: the pathname of the mount point relative to the
- // process's root directory.
- Target string `json:"target"`
- // mount options: per-mount options (see mount(2)).
- VfsOptstr string `json:"vfs_optstr"`
- // filesystem type: the filesystem type in the form "type[.subtype]".
- FsType string `json:"fstype"`
- // mount source: filesystem-specific information or "none".
- Source string `json:"source"`
- // super options: per-superblock options (see mount(2)).
- FsOptstr string `json:"fs_optstr"`
- }
-)
-
-// Copy populates v with the current record.
-func (m *Iter) Copy(v *Entry) {
- if m.fs == nil {
- panic("invalid entry")
- }
- v.ID = int(C.mnt_fs_get_id(m.fs))
- v.Parent = int(C.mnt_fs_get_parent_id(m.fs))
- v.Root = C.GoString(C.mnt_fs_get_root(m.fs))
- v.Target = C.GoString(C.mnt_fs_get_target(m.fs))
- v.VfsOptstr = C.GoString(C.mnt_fs_get_vfs_options(m.fs))
- v.FsType = C.GoString(C.mnt_fs_get_fstype(m.fs))
- v.Source = C.GoString(C.mnt_fs_get_source(m.fs))
- v.FsOptstr = C.GoString(C.mnt_fs_get_fs_options(m.fs))
-}
-
-// Err returns the saved iterator error.
-func (m *Iter) Err() error { return m.err }
-
-// Open opens a mountinfo document. If name is an empty string, the mountinfo
-// document of the current process is opened instead.
-func Open(name string) (*Iter, error) {
- var m Iter
- if name == "" {
- m.tb = C.mnt_new_table_from_file(C.HAKUREI_MOUNTINFO_PATH)
- } else {
- _name := C.CString(name)
- m.tb = C.mnt_new_table_from_file(_name)
- C.free(unsafe.Pointer(_name))
- }
- if m.tb == nil {
- return nil, ErrParse
- }
- m.itr = C.mnt_new_iter(C.MNT_ITER_FORWARD)
- if m.itr == nil {
- C.mnt_unref_table(m.tb)
- return nil, ErrIter
- }
- m.ok = true
-
- runtime.SetFinalizer(&m, (*Iter).Close)
- return &m, nil
-}
-
-// Close frees the iterator.
-func (m *Iter) Close() {
- if m.closed {
- return
- }
- if m.tb == nil {
- panic("unref called before open")
- }
-
- C.mnt_unref_table(m.tb)
- C.mnt_free_iter(m.itr)
- m.closed = true
- runtime.SetFinalizer(m, nil)
-}
-
-// Reset resets the iterator to the first record for reuse.
-func (m *Iter) Reset() {
- if m.err != nil {
- panic("attempting to reset a faulted iterator")
- }
- m.ok = true
- C.mnt_reset_iter(m.itr, -1)
-}
-
-// Next advances the iterator to the next record. The record may be copied if
-// Next returns true.
-func (m *Iter) Next() bool {
- if !m.ok || m.err != nil {
- return false
- }
-
- r := C.mnt_table_next_fs(m.tb, m.itr, &m.fs)
- if r < 0 {
- m.err = ErrIterAdvance
- }
- m.ok = r == 0
- return m.ok
-}
-
-// EqualWithIgnore compares e with want, ignoring fields with the specified
-// ignore value.
-func (e *Entry) EqualWithIgnore(want *Entry, ignore string) bool {
- return (e.ID == want.ID || want.ID == -1) &&
- (e.Parent == want.Parent || want.Parent == -1) &&
- (e.Root == want.Root || want.Root == ignore) &&
- (e.Target == want.Target || want.Target == ignore) &&
- (e.VfsOptstr == want.VfsOptstr || want.VfsOptstr == ignore) &&
- (e.FsType == want.FsType || want.FsType == ignore) &&
- (e.Source == want.Source || want.Source == ignore) &&
- (e.FsOptstr == want.FsOptstr || want.FsOptstr == ignore)
-}
-
-// String returns a text representation of e loosely following the kernel format.
-func (e *Entry) String() string {
- return fmt.Sprintf("%d %d %s %s %s %s %s %s",
- e.ID, e.Parent, e.Root, e.Target, e.VfsOptstr, e.FsType, e.Source, e.FsOptstr)
-}
diff --git a/test/internal/mountinfo/mountinfo_guard.go b/test/internal/mountinfo/mountinfo_guard.go
deleted file mode 100644
index aaf63ac4..00000000
--- a/test/internal/mountinfo/mountinfo_guard.go
+++ /dev/null
@@ -1,15 +0,0 @@
-//go:build !testsuite && !tester
-
-package mountinfo
-
-import (
- "os"
- "testing"
-)
-
-func init() {
- if !testing.Testing() {
- println("package mountinfo imported in non-testsuite program")
- os.Exit(1)
- }
-}
diff --git a/test/internal/mountinfo/mountinfo_test.go b/test/internal/mountinfo/mountinfo_test.go
deleted file mode 100644
index 45cfdf5f..00000000
--- a/test/internal/mountinfo/mountinfo_test.go
+++ /dev/null
@@ -1,146 +0,0 @@
-package mountinfo_test
-
-import (
- "os"
- "path/filepath"
- "testing"
-
- "hakurei.app/test/internal/mountinfo"
-)
-
-func TestMountinfo(t *testing.T) {
- testCases := []struct {
- name string
-
- sample string
- want []*mountinfo.Entry
- }{
- {"util-linux", `15 20 0:3 / /proc rw,relatime - proc /proc rw
-16 20 0:15 / /sys rw,relatime - sysfs /sys rw
-17 20 0:5 / /dev rw,relatime - devtmpfs udev rw,size=1983516k,nr_inodes=495879,mode=755
-18 17 0:10 / /dev/pts rw,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=000
-19 17 0:16 / /dev/shm rw,relatime - tmpfs tmpfs rw
-20 1 8:4 / / rw,noatime - ext3 /dev/sda4 rw,errors=continue,user_xattr,acl,barrier=0,data=ordered
-21 16 0:17 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,mode=755
-22 21 0:18 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd
-23 21 0:19 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpuset
-24 21 0:20 / /sys/fs/cgroup/ns rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,ns
-25 21 0:21 / /sys/fs/cgroup/cpu rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpu
-26 21 0:22 / /sys/fs/cgroup/cpuacct rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpuacct
-27 21 0:23 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory
-28 21 0:24 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,devices
-29 21 0:25 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,freezer
-30 21 0:26 / /sys/fs/cgroup/net_cls rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,net_cls
-31 21 0:27 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,blkio
-32 16 0:28 / /sys/kernel/security rw,relatime - autofs systemd-1 rw,fd=22,pgrp=1,timeout=300,minproto=5,maxproto=5,direct
-33 17 0:29 / /dev/hugepages rw,relatime - autofs systemd-1 rw,fd=23,pgrp=1,timeout=300,minproto=5,maxproto=5,direct
-34 16 0:30 / /sys/kernel/debug rw,relatime - autofs systemd-1 rw,fd=24,pgrp=1,timeout=300,minproto=5,maxproto=5,direct
-35 15 0:31 / /proc/sys/fs/binfmt_misc rw,relatime - autofs systemd-1 rw,fd=25,pgrp=1,timeout=300,minproto=5,maxproto=5,direct
-36 17 0:32 / /dev/mqueue rw,relatime - autofs systemd-1 rw,fd=26,pgrp=1,timeout=300,minproto=5,maxproto=5,direct
-37 15 0:14 / /proc/bus/usb rw,relatime - usbfs /proc/bus/usb rw
-38 33 0:33 / /dev/hugepages rw,relatime - hugetlbfs hugetlbfs rw
-39 36 0:12 / /dev/mqueue rw,relatime - mqueue mqueue rw
-40 20 8:6 / /boot rw,noatime - ext3 /dev/sda6 rw,errors=continue,barrier=0,data=ordered
-41 20 253:0 / /home/kzak rw,noatime - ext4 /dev/mapper/kzak-home rw,barrier=1,data=ordered
-42 35 0:34 / /proc/sys/fs/binfmt_misc rw,relatime - binfmt_misc none rw
-43 16 0:35 / /sys/fs/fuse/connections rw,relatime - fusectl fusectl rw
-44 41 0:36 / /home/kzak/.gvfs rw,nosuid,nodev,relatime - fuse.gvfs-fuse-daemon gvfs-fuse-daemon rw,user_id=500,group_id=500
-45 20 0:37 / /var/lib/nfs/rpc_pipefs rw,relatime - rpc_pipefs sunrpc rw
-47 20 0:38 / /mnt/sounds rw,relatime - cifs //foo.home/bar/ rw,unc=\\foo.home\bar,username=kzak,domain=SRGROUP,uid=0,noforceuid,gid=0,noforcegid,addr=192.168.111.1,posixpaths,serverino,acl,rsize=16384,wsize=57344
-49 20 0:56 / /mnt/test/foobar rw,relatime,nosymfollow shared:323 - tmpfs tmpfs rw`, []*mountinfo.Entry{
- e(15, 20, "/", "/proc", "rw,relatime", "proc", "/proc", "rw"),
- e(16, 20, "/", "/sys", "rw,relatime", "sysfs", "/sys", "rw"),
- e(17, 20, "/", "/dev", "rw,relatime", "devtmpfs", "udev", "rw,size=1983516k,nr_inodes=495879,mode=755"),
- e(18, 17, "/", "/dev/pts", "rw,relatime", "devpts", "devpts", "rw,gid=5,mode=620,ptmxmode=000"),
- e(19, 17, "/", "/dev/shm", "rw,relatime", "tmpfs", "tmpfs", "rw"),
- e(20, 1, "/", "/", "rw,noatime", "ext3", "/dev/sda4", "rw,errors=continue,user_xattr,acl,barrier=0,data=ordered"),
- e(21, 16, "/", "/sys/fs/cgroup", "rw,nosuid,nodev,noexec,relatime", "tmpfs", "tmpfs", "rw,mode=755"),
- e(22, 21, "/", "/sys/fs/cgroup/systemd", "rw,nosuid,nodev,noexec,relatime", "cgroup", "cgroup", "rw,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd"),
- e(23, 21, "/", "/sys/fs/cgroup/cpuset", "rw,nosuid,nodev,noexec,relatime", "cgroup", "cgroup", "rw,cpuset"),
- e(24, 21, "/", "/sys/fs/cgroup/ns", "rw,nosuid,nodev,noexec,relatime", "cgroup", "cgroup", "rw,ns"),
- e(25, 21, "/", "/sys/fs/cgroup/cpu", "rw,nosuid,nodev,noexec,relatime", "cgroup", "cgroup", "rw,cpu"),
- e(26, 21, "/", "/sys/fs/cgroup/cpuacct", "rw,nosuid,nodev,noexec,relatime", "cgroup", "cgroup", "rw,cpuacct"),
- e(27, 21, "/", "/sys/fs/cgroup/memory", "rw,nosuid,nodev,noexec,relatime", "cgroup", "cgroup", "rw,memory"),
- e(28, 21, "/", "/sys/fs/cgroup/devices", "rw,nosuid,nodev,noexec,relatime", "cgroup", "cgroup", "rw,devices"),
- e(29, 21, "/", "/sys/fs/cgroup/freezer", "rw,nosuid,nodev,noexec,relatime", "cgroup", "cgroup", "rw,freezer"),
- e(30, 21, "/", "/sys/fs/cgroup/net_cls", "rw,nosuid,nodev,noexec,relatime", "cgroup", "cgroup", "rw,net_cls"),
- e(31, 21, "/", "/sys/fs/cgroup/blkio", "rw,nosuid,nodev,noexec,relatime", "cgroup", "cgroup", "rw,blkio"),
- e(32, 16, "/", "/sys/kernel/security", "rw,relatime", "autofs", "systemd-1", "rw,fd=22,pgrp=1,timeout=300,minproto=5,maxproto=5,direct"),
- e(33, 17, "/", "/dev/hugepages", "rw,relatime", "autofs", "systemd-1", "rw,fd=23,pgrp=1,timeout=300,minproto=5,maxproto=5,direct"),
- e(34, 16, "/", "/sys/kernel/debug", "rw,relatime", "autofs", "systemd-1", "rw,fd=24,pgrp=1,timeout=300,minproto=5,maxproto=5,direct"),
- e(35, 15, "/", "/proc/sys/fs/binfmt_misc", "rw,relatime", "autofs", "systemd-1", "rw,fd=25,pgrp=1,timeout=300,minproto=5,maxproto=5,direct"),
- e(36, 17, "/", "/dev/mqueue", "rw,relatime", "autofs", "systemd-1", "rw,fd=26,pgrp=1,timeout=300,minproto=5,maxproto=5,direct"),
- e(37, 15, "/", "/proc/bus/usb", "rw,relatime", "usbfs", "/proc/bus/usb", "rw"),
- e(38, 33, "/", "/dev/hugepages", "rw,relatime", "hugetlbfs", "hugetlbfs", "rw"),
- e(39, 36, "/", "/dev/mqueue", "rw,relatime", "mqueue", "mqueue", "rw"),
- e(40, 20, "/", "/boot", "rw,noatime", "ext3", "/dev/sda6", "rw,errors=continue,barrier=0,data=ordered"),
- e(41, 20, "/", "/home/kzak", "rw,noatime", "ext4", "/dev/mapper/kzak-home", "rw,barrier=1,data=ordered"),
- e(42, 35, "/", "/proc/sys/fs/binfmt_misc", "rw,relatime", "binfmt_misc", "none", "rw"),
- e(43, 16, "/", "/sys/fs/fuse/connections", "rw,relatime", "fusectl", "fusectl", "rw"),
- e(44, 41, "/", "/home/kzak/.gvfs", "rw,nosuid,nodev,relatime", "fuse.gvfs-fuse-daemon", "gvfs-fuse-daemon", "rw,user_id=500,group_id=500"),
- e(45, 20, "/", "/var/lib/nfs/rpc_pipefs", "rw,relatime", "rpc_pipefs", "sunrpc", "rw"),
- e(47, 20, "/", "/mnt/sounds", "rw,relatime", "cifs", "//foo.home/bar/", "rw,unc=\\\\foo.home\\bar,username=kzak,domain=SRGROUP,uid=0,noforceuid,gid=0,noforcegid,addr=192.168.111.1,posixpaths,serverino,acl,rsize=16384,wsize=57344"),
- e(49, 20, "/", "/mnt/test/foobar", "rw,relatime,nosymfollow", "tmpfs", "tmpfs", "rw"),
- }},
- }
-
- for _, tc := range testCases {
- name := filepath.Join(t.TempDir(), "sample")
- if err := os.WriteFile(name, []byte(tc.sample), 0400); err != nil {
- t.Fatalf("cannot write sample: %v", err)
- }
-
- t.Run(tc.name, func(t *testing.T) {
- m, err := mountinfo.Open(name)
- if err != nil {
- t.Fatalf("Open: error = %v", err)
- }
- t.Cleanup(m.Close)
-
- i := 0
- var ent mountinfo.Entry
- for m.Next() {
- m.Copy(&ent)
-
- if i == len(tc.want) {
- t.Errorf("Next: got more than %d entries", i)
- t.FailNow()
- }
- if !ent.EqualWithIgnore(tc.want[i], "\x00") {
- t.Errorf("Next: entry %d\n got: %#v\nwant: %#v", i,
- ent, &tc.want[i])
- t.FailNow()
- } else {
- t.Logf("%s", &ent)
- }
-
- i++
- }
-
- if err = m.Err(); err != nil {
- t.Fatalf("Err: %v", err)
- }
- })
-
- if err := os.Remove(name); err != nil {
- t.Fatalf("cannot remove %q: %v", name, err)
- }
- }
-}
-
-func e(
- id, parent int,
- root, target, vfsOptstr string,
- fsType, source, fsOptstr string,
-) *mountinfo.Entry {
- return &mountinfo.Entry{
- ID: id,
- Parent: parent,
- Root: root,
- Target: target,
- VfsOptstr: vfsOptstr,
- FsType: fsType,
- Source: source,
- FsOptstr: fsOptstr,
- }
-}