Skip to content

Commit 92c4c39

Browse files
committed
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 <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Than McIntosh <[email protected]> Reviewed-by: Tobias Klauser <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 748af6e commit 92c4c39

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

unix/dup3_test.go

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build freebsd || linux || netbsd || openbsd
6+
// +build freebsd linux netbsd openbsd
7+
8+
package unix_test
9+
10+
import (
11+
"os"
12+
"runtime"
13+
"testing"
14+
15+
"golang.org/x/sys/unix"
16+
)
17+
18+
func TestDup3(t *testing.T) {
19+
tempFile, err := os.CreateTemp("", "TestDup")
20+
if err != nil {
21+
t.Fatalf("CreateTemp failed: %v", err)
22+
}
23+
defer os.Remove(tempFile.Name())
24+
defer tempFile.Close()
25+
oldFd := int(tempFile.Fd())
26+
27+
// On NetBSD, it is not an error if oldFd == newFd
28+
if runtime.GOOS != "netbsd" {
29+
if got, want := unix.Dup3(oldFd, oldFd, 0), unix.EINVAL; got != want {
30+
t.Fatalf("Dup3: expected err %v, got %v", want, got)
31+
}
32+
}
33+
34+
// Create and reserve a file descriptor.
35+
// Dup3 automatically closes it before reusing it.
36+
nullFile, err := os.Open("/dev/null")
37+
if err != nil {
38+
t.Fatalf("Open failed: %v", err)
39+
}
40+
defer nullFile.Close()
41+
newFd := int(nullFile.Fd())
42+
43+
err = unix.Dup3(oldFd, newFd, 0)
44+
if err != nil {
45+
t.Fatalf("Dup3: %v", err)
46+
}
47+
48+
b1 := []byte("Test123")
49+
b2 := make([]byte, 7)
50+
_, err = unix.Write(newFd, b1)
51+
if err != nil {
52+
t.Fatalf("Write to Dup3 fd failed: %v", err)
53+
}
54+
_, err = unix.Seek(oldFd, 0, 0)
55+
if err != nil {
56+
t.Fatalf("Seek failed: %v", err)
57+
}
58+
_, err = unix.Read(oldFd, b2)
59+
if err != nil {
60+
t.Fatalf("Read back failed: %v", err)
61+
}
62+
if string(b1) != string(b2) {
63+
t.Errorf("Dup3: read %q from file, want %q", string(b2), string(b1))
64+
}
65+
}

unix/syscall_freebsd.go

+12
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,18 @@ func PtraceSingleStep(pid int) (err error) {
325325
return ptrace(PT_STEP, pid, 1, 0)
326326
}
327327

328+
func Dup3(oldfd, newfd, flags int) error {
329+
if oldfd == newfd || flags&^O_CLOEXEC != 0 {
330+
return EINVAL
331+
}
332+
how := F_DUP2FD
333+
if flags&O_CLOEXEC != 0 {
334+
how = F_DUP2FD_CLOEXEC
335+
}
336+
_, err := fcntl(oldfd, how, newfd)
337+
return err
338+
}
339+
328340
/*
329341
* Exposed directly
330342
*/

0 commit comments

Comments
 (0)