Firstly, the LE version is exposed; I assume because its name is capitalized.
Regardless, syscall.Termios is still incorrect and will not function if you attempt to use it to invoke the Tcgetattr or Tcsetattr services. As I mentioned, in the x/sys/unix package, where Tcgetattr or Tcsetattr interfaces to SYS_TCGETATTR and SYS_TCSETATTR are defined, a unix.Termios is defined as well, but the first four fields are, as I mentioned above in a different order from the IBM Go on z/OS supplied syscall.Termios definition.
This comes up only because the Go package I am working with, where I am trying to use Tcgetattr and Tcsetattr, does not want us to import golang.org/x/sys/unix. That means we have to copy the implementations from the unix package and place them directly in their package. Take a look at https://github.com/creack/pty/blob/master/pty_zos.go. You'll see that the implementor of that module copied the generated source for z/OS support from the unix package to be able to invoke SYS_POSIX_OPENPT, SYS_FCNTL, SYS___PTSNAME, SYS_GRANTPT and SYS_UNLOCKPT.
I did the same with SYS_TCGETATTR and SYS_TCSETATTR, and it worked when I defined a termios struct within that source code, copied from unix.Termios:
type termios struct {
Cflag uint32
Iflag uint32
Lflag uint32
Oflag uint32
Cc [11]uint8
}
func tcgetattr(fildes int, termptr *termios) (err error) {
r0, _, e1 := runtime.CallLeFuncWithErr(runtime.GetZosLibVec()+syscall.SYS_TCGETATTR<<4, uintptr(fildes), uintptr(unsafe.Pointer(termptr)))
if int64(r0) == -1 {
err = syscall.Errno(e1)
}
return
}
func tcsetattr(fildes int, when int, termptr *termios) (err error) {
r0, _, e1 := runtime.CallLeFuncWithErr(runtime.GetZosLibVec()+syscall.SYS_TCSETATTR<<4, uintptr(fildes), uintptr(when), uintptr(unsafe.Pointer(termptr)))
if int64(r0) == -1 {
err = syscall.Errno(e1)
}
return
}
I then had the thought that syscall.Termios should be used instead of "hardcoding" the definition in the source file. I tried it, but I kept getting "weird results", that being because the service itself expected them to be in the same order as the termios.h C header file (show earlier), but they were not. They were in the order as the corresponding header file on Linux, which is different order from z/OS.
So, from what you are saying, it sounds to me now that both syscall.Termios and syscall.Termios_LE (perhaps renamed to syscall.termios_LE) should both be re-ordered to be in the same order as the C header file shows.
------------------------------
Frank Swarbrick
------------------------------
Original Message:
Sent: Mon April 28, 2025 11:33 AM
From: Bill O'Farrell
Subject: Termios struct
Hi Frank! The "LE" version should not be exposed. If you can declare Termios publicly (if it has all the members of termios.h) then there is no need for the "LE" version. We only copy structures when the "common" version cannot be reconciled with the z/OS header version in the sense that it breaks existing programs. e.g. missing public members in the structure that we have to emulate. (edited)
------------------------------
Bill O'Farrell
Senior Technical Manger, Go on z/OS
Original Message:
Sent: Mon April 28, 2025 01:30 AM
From: Frank Swarbrick
Subject: Termios struct
Something I noticed... In the x/sys/unix package, for z/OS there is an explicit definition of the Termios struct type. This is even though the z/OS syscall std library already has one called Termios, and additionally one called Termios.LE. The one in the unix package is defined differently than either of those, however. Specifically:
type Termios struct {
Cflag uint32
Iflag uint32
Lflag uint32
Oflag uint32
Cc [11]uint8
}
The ones in the z/OS syscall package are as follows:
type Termios struct {
Iflag uint32
Oflag uint32
Cflag uint32
Lflag uint32
Line uint8
Cc [32]uint8
_ [3]byte
Ispeed uint32
Ospeed uint32
}
type Termios_LE struct {
Iflag uint32
Oflag uint32
Cflag uint32
Lflag uint32
Cc [11]uint8
}
As you can see, the flags in the unix version are in this order: C,I,L,O, while the flags in syscall are I,O,C,L. The latter is how they are defined in Linux (and I imagine other platforms). However, it appears that CILO is the way they are defined on z/OS. See the following definition from /usr/include/termios.h:
struct termios {
tcflag_t c_cflag; /* control modes */
tcflag_t c_iflag; /* input modes */
tcflag_t c_lflag; /* local modes */
tcflag_t c_oflag; /* output modes */
cc_t c_cc[NCCS]; /* control chars */
};
So, my guess is that, at the very least, syscall.Termios_LE should be defined in the same order as unix.Termios. Then, in the unix package, for z/OS we probably should have "private" versions that use syscall.Termios_LE, i.e.:
//sys tcgetattr(fildes int, termptr *syscall.Termios_LE) (err error) = SYS_TCGETATTR
//sys tcsetattr(fildes int, when int, termptr *syscall.Termios_LE) (err error) = SYS_TCSETATTR
While the public versions would be explicitly defined (as below), calling the *syscall.Termios LE() method and *syscall.Termios_LE Linux() method, as appropriate.
func Tcgetattr(fildes int, termptr *syscall.Termios) (err error)
func Tcsetattr(fildes int, when int, termptr *syscall.Termios) (err error)
Or something like that. Just something to consider.
------------------------------
Frank Swarbrick
------------------------------