mirror of
https://github.com/golang/sys.git
synced 2026-02-08 11:46:04 +03:00
unix: add Dup3 on FreeBSD
Other BSDs provide dup3(2) syscall, on FreeBSD it is implemented as libc function using fcntl(2). This CL adds similar Go implementation. Fixes golang/go#55935 Change-Id: I9c6d762415c7bed5442966a7fcbf9a6f8dfdaf2a Reviewed-on: https://go-review.googlesource.com/c/sys/+/470675 TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Ian Lance Taylor <iant@google.com> Reviewed-by: Than McIntosh <thanm@google.com> Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com> Reviewed-by: Ian Lance Taylor <iant@google.com>
This commit is contained in:
65
unix/dup3_test.go
Normal file
65
unix/dup3_test.go
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build freebsd || linux || netbsd || openbsd
|
||||
// +build freebsd linux netbsd openbsd
|
||||
|
||||
package unix_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func TestDup3(t *testing.T) {
|
||||
tempFile, err := os.CreateTemp("", "TestDup")
|
||||
if err != nil {
|
||||
t.Fatalf("CreateTemp failed: %v", err)
|
||||
}
|
||||
defer os.Remove(tempFile.Name())
|
||||
defer tempFile.Close()
|
||||
oldFd := int(tempFile.Fd())
|
||||
|
||||
// On NetBSD, it is not an error if oldFd == newFd
|
||||
if runtime.GOOS != "netbsd" {
|
||||
if got, want := unix.Dup3(oldFd, oldFd, 0), unix.EINVAL; got != want {
|
||||
t.Fatalf("Dup3: expected err %v, got %v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
// Create and reserve a file descriptor.
|
||||
// Dup3 automatically closes it before reusing it.
|
||||
nullFile, err := os.Open("/dev/null")
|
||||
if err != nil {
|
||||
t.Fatalf("Open failed: %v", err)
|
||||
}
|
||||
defer nullFile.Close()
|
||||
newFd := int(nullFile.Fd())
|
||||
|
||||
err = unix.Dup3(oldFd, newFd, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("Dup3: %v", err)
|
||||
}
|
||||
|
||||
b1 := []byte("Test123")
|
||||
b2 := make([]byte, 7)
|
||||
_, err = unix.Write(newFd, b1)
|
||||
if err != nil {
|
||||
t.Fatalf("Write to Dup3 fd failed: %v", err)
|
||||
}
|
||||
_, err = unix.Seek(oldFd, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("Seek failed: %v", err)
|
||||
}
|
||||
_, err = unix.Read(oldFd, b2)
|
||||
if err != nil {
|
||||
t.Fatalf("Read back failed: %v", err)
|
||||
}
|
||||
if string(b1) != string(b2) {
|
||||
t.Errorf("Dup3: read %q from file, want %q", string(b2), string(b1))
|
||||
}
|
||||
}
|
||||
@@ -325,6 +325,18 @@ func PtraceSingleStep(pid int) (err error) {
|
||||
return ptrace(PT_STEP, pid, 1, 0)
|
||||
}
|
||||
|
||||
func Dup3(oldfd, newfd, flags int) error {
|
||||
if oldfd == newfd || flags&^O_CLOEXEC != 0 {
|
||||
return EINVAL
|
||||
}
|
||||
how := F_DUP2FD
|
||||
if flags&O_CLOEXEC != 0 {
|
||||
how = F_DUP2FD_CLOEXEC
|
||||
}
|
||||
_, err := fcntl(oldfd, how, newfd)
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
* Exposed directly
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user