Skip to content

Commit 123459f

Browse files
jlee3227gopherbot
authored andcommitted
unix: update z/OS implementation of fcntl and mmap
- Add a wrapper function around fcntl to handle different operation types and new fcntl implementation that accepts uintptr as an arg. - Add support for calling mmap/munmap with address pointers. - Add accompanying tests for new functions. Change-Id: If5e77aa4cf2cccfd431de4f3bd0c5014a761e167 GitHub-Last-Rev: 07e32a4 GitHub-Pull-Request: #216 Reviewed-on: https://go-review.googlesource.com/c/sys/+/610296 Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Auto-Submit: Dmitri Shuralyov <[email protected]> TryBot-Bypass: Dmitri Shuralyov <[email protected]>
1 parent df4a4da commit 123459f

File tree

5 files changed

+213
-26
lines changed

5 files changed

+213
-26
lines changed

unix/mmap_zos_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,17 @@ func TestMmap(t *testing.T) {
7272
t.Fatalf("Munmap: %v", err)
7373
}
7474
}
75+
76+
func TestMmapPtr(t *testing.T) {
77+
p, err := unix.MmapPtr(-1, 0, nil, uintptr(2*unix.Getpagesize()),
78+
unix.PROT_READ|unix.PROT_WRITE, unix.MAP_ANON|unix.MAP_PRIVATE)
79+
if err != nil {
80+
t.Fatalf("MmapPtr: %v", err)
81+
}
82+
83+
*(*byte)(p) = 42
84+
85+
if err := unix.MunmapPtr(p, uintptr(2*unix.Getpagesize())); err != nil {
86+
t.Fatalf("MunmapPtr: %v", err)
87+
}
88+
}

unix/syscall_zos_s390x.go

+41
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,16 @@ func Munmap(b []byte) (err error) {
768768
return mapper.Munmap(b)
769769
}
770770

771+
func MmapPtr(fd int, offset int64, addr unsafe.Pointer, length uintptr, prot int, flags int) (ret unsafe.Pointer, err error) {
772+
xaddr, err := mapper.mmap(uintptr(addr), length, prot, flags, fd, offset)
773+
return unsafe.Pointer(xaddr), err
774+
}
775+
776+
func MunmapPtr(addr unsafe.Pointer, length uintptr) (err error) {
777+
return mapper.munmap(uintptr(addr), length)
778+
}
779+
780+
771781
//sys Gethostname(buf []byte) (err error) = SYS___GETHOSTNAME_A
772782
//sysnb Getgid() (gid int)
773783
//sysnb Getpid() (pid int)
@@ -3115,3 +3125,34 @@ func legacy_Mkfifoat(dirfd int, path string, mode uint32) (err error) {
31153125
//sys Posix_openpt(oflag int) (fd int, err error) = SYS_POSIX_OPENPT
31163126
//sys Grantpt(fildes int) (rc int, err error) = SYS_GRANTPT
31173127
//sys Unlockpt(fildes int) (rc int, err error) = SYS_UNLOCKPT
3128+
3129+
func fcntlAsIs(fd uintptr, cmd int, arg uintptr) (val int, err error) {
3130+
runtime.EnterSyscall()
3131+
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS_FCNTL<<4, uintptr(fd), uintptr(cmd), arg)
3132+
runtime.ExitSyscall()
3133+
val = int(r0)
3134+
if int64(r0) == -1 {
3135+
err = errnoErr2(e1, e2)
3136+
}
3137+
return
3138+
}
3139+
3140+
func Fcntl(fd uintptr, cmd int, op interface{}) (ret int, err error) {
3141+
switch op.(type) {
3142+
case *Flock_t:
3143+
err = FcntlFlock(fd, cmd, op.(*Flock_t))
3144+
if err != nil {
3145+
ret = -1
3146+
}
3147+
return
3148+
case int:
3149+
return FcntlInt(fd, cmd, op.(int))
3150+
case *F_cnvrt:
3151+
return fcntlAsIs(fd, cmd, uintptr(unsafe.Pointer(op.(*F_cnvrt))))
3152+
case unsafe.Pointer:
3153+
return fcntlAsIs(fd, cmd, uintptr(op.(unsafe.Pointer)))
3154+
default:
3155+
return -1, EINVAL
3156+
}
3157+
return
3158+
}

unix/syscall_zos_test.go

+151-25
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package unix_test
88

99
import (
10+
"bytes"
1011
"errors"
1112
"flag"
1213
"fmt"
@@ -202,7 +203,7 @@ func TestSignalNum(t *testing.T) {
202203

203204
func TestFcntlInt(t *testing.T) {
204205
t.Parallel()
205-
file, err := os.Create(filepath.Join(t.TempDir(), "TestFnctlInt"))
206+
file, err := os.Create(filepath.Join(t.TempDir(), t.Name()))
206207
if err != nil {
207208
t.Fatal(err)
208209
}
@@ -217,10 +218,27 @@ func TestFcntlInt(t *testing.T) {
217218
}
218219
}
219220

221+
func TestFcntlInt2(t *testing.T) {
222+
t.Parallel()
223+
file, err := os.Create(filepath.Join(t.TempDir(), t.Name()))
224+
if err != nil {
225+
t.Fatal(err)
226+
}
227+
defer file.Close()
228+
f := file.Fd()
229+
flags, err := unix.Fcntl(f, unix.F_GETFD, 0)
230+
if err != nil {
231+
t.Fatal(err)
232+
}
233+
if flags&unix.FD_CLOEXEC == 0 {
234+
t.Errorf("flags %#x do not include FD_CLOEXEC", flags)
235+
}
236+
}
237+
220238
// TestFcntlFlock tests whether the file locking structure matches
221239
// the calling convention of each kernel.
222240
func TestFcntlFlock(t *testing.T) {
223-
name := filepath.Join(os.TempDir(), "TestFcntlFlock")
241+
name := filepath.Join(t.TempDir(), "TestFcntlFlock")
224242
fd, err := unix.Open(name, unix.O_CREAT|unix.O_RDWR|unix.O_CLOEXEC, 0)
225243
if err != nil {
226244
t.Fatalf("Open failed: %v", err)
@@ -236,6 +254,23 @@ func TestFcntlFlock(t *testing.T) {
236254
}
237255
}
238256

257+
func TestFcntlFlock2(t *testing.T) {
258+
name := filepath.Join(t.TempDir(), "TestFcntlFlock2")
259+
fd, err := unix.Open(name, unix.O_CREAT|unix.O_RDWR|unix.O_CLOEXEC, 0)
260+
if err != nil {
261+
t.Fatalf("Open failed: %v", err)
262+
}
263+
defer unix.Unlink(name)
264+
defer unix.Close(fd)
265+
flock := unix.Flock_t{
266+
Type: unix.F_RDLCK,
267+
Start: 0, Len: 0, Whence: 1,
268+
}
269+
if v, err := unix.Fcntl(uintptr(fd), unix.F_GETLK, &flock); err != nil {
270+
t.Fatalf("FcntlFlock failed: %d %v", v, err)
271+
}
272+
}
273+
239274
// TestPassFD tests passing a file descriptor over a Unix socket.
240275
//
241276
// This test involved both a parent and child process. The parent
@@ -249,8 +284,6 @@ func TestPassFD(t *testing.T) {
249284
return
250285
}
251286

252-
tempDir := t.TempDir()
253-
254287
fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0)
255288
if err != nil {
256289
t.Fatalf("Socketpair: %v", err)
@@ -262,7 +295,7 @@ func TestPassFD(t *testing.T) {
262295
defer writeFile.Close()
263296
defer readFile.Close()
264297

265-
cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir)
298+
cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", t.TempDir())
266299
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
267300
if lp := os.Getenv("LD_LIBRARY_PATH"); lp != "" {
268301
cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+lp)
@@ -371,7 +404,7 @@ func passFDChild() {
371404
}
372405
}
373406

374-
// TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage,
407+
// TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage, ParseOneSocketControlMessage,
375408
// and ParseUnixRights are able to successfully round-trip lists of file descriptors.
376409
func TestUnixRightsRoundtrip(t *testing.T) {
377410
testCases := [...][][]int{
@@ -399,6 +432,23 @@ func TestUnixRightsRoundtrip(t *testing.T) {
399432
if len(scms) != len(testCase) {
400433
t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms)
401434
}
435+
436+
var c int
437+
for len(b) > 0 {
438+
hdr, data, remainder, err := unix.ParseOneSocketControlMessage(b)
439+
if err != nil {
440+
t.Fatalf("ParseOneSocketControlMessage: %v", err)
441+
}
442+
if scms[c].Header != hdr || !bytes.Equal(scms[c].Data, data) {
443+
t.Fatal("expected SocketControlMessage header and data to match")
444+
}
445+
b = remainder
446+
c++
447+
}
448+
if c != len(scms) {
449+
t.Fatalf("expected %d SocketControlMessages; got %d", len(scms), c)
450+
}
451+
402452
for i, scm := range scms {
403453
gotFds, err := unix.ParseUnixRights(&scm)
404454
if err != nil {
@@ -474,6 +524,12 @@ func TestRlimit(t *testing.T) {
474524
if err != nil {
475525
t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err)
476526
}
527+
528+
// make sure RLIM_INFINITY can be assigned to Rlimit members
529+
_ = unix.Rlimit{
530+
Cur: unix.RLIM_INFINITY,
531+
Max: unix.RLIM_INFINITY,
532+
}
477533
}
478534

479535
func TestSeekFailure(t *testing.T) {
@@ -497,9 +553,9 @@ func TestSetsockoptString(t *testing.T) {
497553
}
498554

499555
func TestDup(t *testing.T) {
500-
file, err := os.Create(filepath.Join(t.TempDir(), "TestDup"))
556+
file, err := os.Create(filepath.Join(t.TempDir(), t.Name()))
501557
if err != nil {
502-
t.Fatalf("Tempfile failed: %v", err)
558+
t.Fatal(err)
503559
}
504560
defer file.Close()
505561
f := int(file.Fd())
@@ -654,25 +710,21 @@ func touch(t *testing.T, name string) {
654710
}
655711

656712
// chtmpdir changes the working directory to a new temporary directory and
657-
// provides a cleanup function. Used when PWD is read-only.
658-
func chtmpdir(t *testing.T) func() {
713+
// sets up a cleanup function. Used when PWD is read-only.
714+
func chtmpdir(t *testing.T) {
715+
t.Helper()
659716
oldwd, err := os.Getwd()
660717
if err != nil {
661-
t.Fatalf("chtmpdir: %v", err)
662-
}
663-
d, err := os.MkdirTemp("", "test")
664-
if err != nil {
665-
t.Fatalf("chtmpdir: %v", err)
718+
t.Fatal(err)
666719
}
667-
if err := os.Chdir(d); err != nil {
668-
t.Fatalf("chtmpdir: %v", err)
720+
if err := os.Chdir(t.TempDir()); err != nil {
721+
t.Fatal(err)
669722
}
670-
return func() {
723+
t.Cleanup(func() {
671724
if err := os.Chdir(oldwd); err != nil {
672-
t.Fatalf("chtmpdir: %v", err)
725+
t.Fatal(err)
673726
}
674-
os.RemoveAll(d)
675-
}
727+
})
676728
}
677729

678730
func TestLegacyMountUnmount(t *testing.T) {
@@ -2993,7 +3045,7 @@ func TestUnlinkat(t *testing.T) {
29933045
}
29943046

29953047
func TestRenameat(t *testing.T) {
2996-
defer chtmpdir(t)()
3048+
chtmpdir(t)
29973049

29983050
from, to := "renamefrom", "renameto"
29993051

@@ -3016,7 +3068,7 @@ func TestRenameat(t *testing.T) {
30163068
}
30173069

30183070
func TestRenameat2(t *testing.T) {
3019-
defer chtmpdir(t)()
3071+
chtmpdir(t)
30203072

30213073
from, to := "renamefrom", "renameto"
30223074

@@ -3050,7 +3102,7 @@ func TestRenameat2(t *testing.T) {
30503102
}
30513103

30523104
func TestFchmodat(t *testing.T) {
3053-
defer chtmpdir(t)()
3105+
chtmpdir(t)
30543106

30553107
touch(t, "file1")
30563108
err := os.Symlink("file1", "symlink1")
@@ -3148,7 +3200,7 @@ func compareStat_t(t *testing.T, otherStat string, st1, st2 *unix.Stat_t) {
31483200
}
31493201

31503202
func TestFstatat(t *testing.T) {
3151-
defer chtmpdir(t)()
3203+
chtmpdir(t)
31523204

31533205
touch(t, "file1")
31543206

@@ -3749,3 +3801,77 @@ func TestConsole2modify(t *testing.T) {
37493801

37503802
t.Logf("Got %s %x\n", unix.ZosEbcdicBytesToString(modstr[:], true), cmsg_cmd)
37513803
}
3804+
func TestTty(t *testing.T) {
3805+
ptmxfd, err := unix.Posix_openpt(unix.O_RDWR)
3806+
if err != nil {
3807+
t.Fatalf("Posix_openpt %+v\n", err)
3808+
}
3809+
t.Logf("ptmxfd %v\n", ptmxfd)
3810+
3811+
// convert to EBCDIC
3812+
cvtreq := unix.F_cnvrt{Cvtcmd: unix.SETCVTON, Pccsid: 0, Fccsid: 1047}
3813+
if _, err = unix.Fcntl(uintptr(ptmxfd), unix.F_CONTROL_CVT, &cvtreq); err != nil {
3814+
t.Fatalf("fcntl F_CONTROL_CVT %+v\n", err)
3815+
}
3816+
p := os.NewFile(uintptr(ptmxfd), "/dev/ptmx")
3817+
if p == nil {
3818+
t.Fatalf("NewFile %d /dev/ptmx failed\n", ptmxfd)
3819+
}
3820+
3821+
// In case of error after this point, make sure we close the ptmx fd.
3822+
defer func() {
3823+
if err != nil {
3824+
_ = p.Close() // Best effort.
3825+
}
3826+
}()
3827+
sname, err := unix.Ptsname(ptmxfd)
3828+
if err != nil {
3829+
t.Fatalf("Ptsname %+v\n", err)
3830+
}
3831+
t.Logf("sname %v\n", sname)
3832+
3833+
_, err = unix.Grantpt(ptmxfd)
3834+
if err != nil {
3835+
t.Fatalf("Grantpt %+v\n", err)
3836+
}
3837+
3838+
if _, err = unix.Unlockpt(ptmxfd); err != nil {
3839+
t.Fatalf("Unlockpt %+v\n", err)
3840+
}
3841+
3842+
ptsfd, err := syscall.Open(sname, os.O_RDWR|syscall.O_NOCTTY, 0)
3843+
if err != nil {
3844+
t.Fatalf("Open %s %+v\n", sname, err)
3845+
}
3846+
if _, err = unix.Fcntl(uintptr(ptsfd), unix.F_CONTROL_CVT, &cvtreq); err != nil {
3847+
3848+
t.Fatalf("fcntl F_CONTROL_CVT ptsfd %+v\n", err)
3849+
3850+
}
3851+
3852+
tt := os.NewFile(uintptr(ptsfd), sname)
3853+
if err != nil {
3854+
t.Fatalf("NewFile %d %+v %+v\n", ptsfd, sname, err)
3855+
}
3856+
text := []byte("11111111")
3857+
3858+
n, err := tt.Write(text)
3859+
if err != nil {
3860+
t.Fatalf("ptsfd Write %+v\n", err)
3861+
}
3862+
t.Logf("bytes %d\n", n)
3863+
3864+
var buffer [1024]byte
3865+
3866+
n, err = p.Read(buffer[:n])
3867+
if err != nil {
3868+
t.Fatalf("ptmx read %+v\n", err)
3869+
}
3870+
t.Logf("Buffer %+v\n", buffer[:n])
3871+
3872+
if !bytes.Equal(text, buffer[:n]) {
3873+
t.Fatalf("Expected %+v, read %+v\n", text, buffer[:n])
3874+
3875+
}
3876+
3877+
}

unix/xattr_zos_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
)
1515

1616
func TestXattr(t *testing.T) {
17-
defer chtmpdir(t)()
17+
chtmpdir(t)
1818

1919
f := "xattr1"
2020
touch(t, f)

unix/ztypes_zos_s390x.go

+6
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,12 @@ type Flock_t struct {
377377
Pid int32
378378
}
379379

380+
type F_cnvrt struct {
381+
Cvtcmd int32
382+
Pccsid int16
383+
Fccsid int16
384+
}
385+
380386
type Termios struct {
381387
Cflag uint32
382388
Iflag uint32

0 commit comments

Comments
 (0)