Go

Go on z/OS

Go on z/OS

This group is a space for open discussions and sharing technical information, and also provides a connection to the wider Go open source community for anyone who is interested in Go on z/OS

 View Only
  • 1.  Termios struct

    Posted Mon April 28, 2025 01:31 AM

    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
    ------------------------------


  • 2.  RE: Termios struct

    Posted Mon April 28, 2025 11:33 AM


    ------------------------------
    Bill O'Farrell
    Senior Technical Manger, Go on z/OS
    ------------------------------



  • 3.  RE: Termios struct

    Posted Tue April 29, 2025 09:22 AM
    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
    ------------------------------