From 9ffab7e3fa034452a2f6b81509f49c7f22e9dc5e Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 4 Aug 2025 21:41:59 +0200 Subject: [PATCH] sockets: make NewUnixSocket, WithChown, WithChmod unix-only The WithChown and WithChmod options are not supported on Windows. We could provide stubs in future, but let's start with not including them. Signed-off-by: Sebastiaan van Stijn --- sockets/unix_socket.go | 25 -------------------- sockets/unix_socket_test.go | 32 ------------------------- sockets/unix_socket_unix.go | 26 +++++++++++++++++++++ sockets/unix_socket_unix_test.go | 36 +++++++++++++++++++++++++---- sockets/unix_socket_windows_test.go | 18 +++++++++++---- 5 files changed, 71 insertions(+), 66 deletions(-) diff --git a/sockets/unix_socket.go b/sockets/unix_socket.go index be6aa713..e736f71d 100644 --- a/sockets/unix_socket.go +++ b/sockets/unix_socket.go @@ -55,26 +55,6 @@ import ( // SockOption sets up socket file's creating option type SockOption func(string) error -// WithChown modifies the socket file's uid and gid -func WithChown(uid, gid int) SockOption { - return func(path string) error { - if err := os.Chown(path, uid, gid); err != nil { - return err - } - return nil - } -} - -// WithChmod modifies socket file's access mode. -func WithChmod(mask os.FileMode) SockOption { - return func(path string) error { - if err := os.Chmod(path, mask); err != nil { - return err - } - return nil - } -} - // NewUnixSocketWithOpts creates a unix socket with the specified options. // By default, socket permissions are 0000 (i.e.: no access for anyone); pass // WithChmod() and WithChown() to set the desired ownership and permissions. @@ -102,8 +82,3 @@ func NewUnixSocketWithOpts(path string, opts ...SockOption) (net.Listener, error return l, nil } - -// NewUnixSocket creates a unix socket with the specified path and group. -func NewUnixSocket(path string, gid int) (net.Listener, error) { - return NewUnixSocketWithOpts(path, WithChown(0, gid), WithChmod(0o660)) -} diff --git a/sockets/unix_socket_test.go b/sockets/unix_socket_test.go index cfa2996a..0ad58a1e 100644 --- a/sockets/unix_socket_test.go +++ b/sockets/unix_socket_test.go @@ -3,7 +3,6 @@ package sockets import ( "fmt" "net" - "os" "testing" ) @@ -31,34 +30,3 @@ func runTest(t *testing.T, path string, l net.Listener, echoStr string) { t.Fatal(fmt.Errorf("msg may lost")) } } - -// TestNewUnixSocket run under root user. -func TestNewUnixSocket(t *testing.T) { - if os.Getuid() != 0 { - t.Skip("requires root") - } - gid := os.Getgid() - path := "/tmp/test.sock" - echoStr := "hello" - l, err := NewUnixSocket(path, gid) - if err != nil { - t.Fatal(err) - } - defer func() { _ = l.Close() }() - runTest(t, path, l, echoStr) -} - -func TestUnixSocketWithOpts(t *testing.T) { - socketFile, err := os.CreateTemp("", "test*.sock") - if err != nil { - t.Fatal(err) - } - _ = socketFile.Close() - defer func() { _ = os.Remove(socketFile.Name()) }() - - l := createTestUnixSocket(t, socketFile.Name()) - defer func() { _ = l.Close() }() - - echoStr := "hello" - runTest(t, socketFile.Name(), l, echoStr) -} diff --git a/sockets/unix_socket_unix.go b/sockets/unix_socket_unix.go index 3fbc982e..a41a7165 100644 --- a/sockets/unix_socket_unix.go +++ b/sockets/unix_socket_unix.go @@ -4,9 +4,35 @@ package sockets import ( "net" + "os" "syscall" ) +// WithChown modifies the socket file's uid and gid +func WithChown(uid, gid int) SockOption { + return func(path string) error { + if err := os.Chown(path, uid, gid); err != nil { + return err + } + return nil + } +} + +// WithChmod modifies socket file's access mode. +func WithChmod(mask os.FileMode) SockOption { + return func(path string) error { + if err := os.Chmod(path, mask); err != nil { + return err + } + return nil + } +} + +// NewUnixSocket creates a unix socket with the specified path and group. +func NewUnixSocket(path string, gid int) (net.Listener, error) { + return NewUnixSocketWithOpts(path, WithChown(0, gid), WithChmod(0o660)) +} + func listenUnix(path string) (net.Listener, error) { // net.Listen does not allow for permissions to be set. As a result, when // specifying custom permissions ("WithChmod()"), there is a short time diff --git a/sockets/unix_socket_unix_test.go b/sockets/unix_socket_unix_test.go index ae2e7321..5fedcd50 100644 --- a/sockets/unix_socket_unix_test.go +++ b/sockets/unix_socket_unix_test.go @@ -3,20 +3,26 @@ package sockets import ( - "net" "os" "syscall" "testing" ) -func createTestUnixSocket(t *testing.T, path string) (listener net.Listener) { +func TestUnixSocketWithOpts(t *testing.T) { + socketFile, err := os.CreateTemp("", "test*.sock") + if err != nil { + t.Fatal(err) + } + _ = socketFile.Close() + defer func() { _ = os.Remove(socketFile.Name()) }() + uid, gid := os.Getuid(), os.Getgid() perms := os.FileMode(0660) - l, err := NewUnixSocketWithOpts(path, WithChown(uid, gid), WithChmod(perms)) + l, err := NewUnixSocketWithOpts(socketFile.Name(), WithChown(uid, gid), WithChmod(perms)) if err != nil { t.Fatal(err) } - p, err := os.Stat(path) + p, err := os.Stat(socketFile.Name()) if err != nil { t.Fatal(err) } @@ -28,5 +34,25 @@ func createTestUnixSocket(t *testing.T, path string) (listener net.Listener) { t.Fatalf("unexpected file ownership: expected: %d:%d, got: %d:%d", uid, gid, stat.Uid, stat.Gid) } } - return l + + defer func() { _ = l.Close() }() + + echoStr := "hello" + runTest(t, socketFile.Name(), l, echoStr) +} + +// TestNewUnixSocket run under root user. +func TestNewUnixSocket(t *testing.T) { + if os.Getuid() != 0 { + t.Skip("requires root") + } + gid := os.Getgid() + path := "/tmp/test.sock" + echoStr := "hello" + l, err := NewUnixSocket(path, gid) + if err != nil { + t.Fatal(err) + } + defer func() { _ = l.Close() }() + runTest(t, path, l, echoStr) } diff --git a/sockets/unix_socket_windows_test.go b/sockets/unix_socket_windows_test.go index e68aca0b..79bdb8c6 100644 --- a/sockets/unix_socket_windows_test.go +++ b/sockets/unix_socket_windows_test.go @@ -1,14 +1,24 @@ package sockets import ( - "net" + "os" "testing" ) -func createTestUnixSocket(t *testing.T, path string) (listener net.Listener) { - l, err := NewUnixSocketWithOpts(path) +func TestUnixSocketWithOpts(t *testing.T) { + socketFile, err := os.CreateTemp("", "test*.sock") if err != nil { t.Fatal(err) } - return l + _ = socketFile.Close() + defer func() { _ = os.Remove(socketFile.Name()) }() + + l, err := NewUnixSocketWithOpts(socketFile.Name()) + if err != nil { + t.Fatal(err) + } + defer func() { _ = l.Close() }() + + echoStr := "hello" + runTest(t, socketFile.Name(), l, echoStr) }