Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240411165556.GB4163@brightrain.aerifal.cx>
Date: Thu, 11 Apr 2024 12:55:56 -0400
From: Rich Felker <dalias@...c.org>
To: musl@...ts.openwall.com
Subject: Re: making termios BOTHER speeds work

On Thu, Apr 11, 2024 at 10:24:56AM -0400, Rich Felker wrote:
> Since it's come up again, I'm looking at what it would take to get
> support for custom baud rates in termios working. This topic is
> something of a mess, as it involves discrepancies between our termios
> structure and the kernel termios/termios2 structures.
> 
> Szabolcs Nagy did some of the initial research on the mismatched
> definitions in 2016: https://www.openwall.com/lists/musl/2016/04/26/3
> 
> Basically, it looks like what happened was that we tried to match the
> glibc generic ABI (an early goal of lots of stuff in musl) as long as
> it lined up with the kernel termios (not termios2) ioctl structure,
> but deviated when it wouldn't (powerpc had c_line and c_cc order
> flipped and we followed kernel on that), and didn't do glibc
> arch-specific mistakes (like mips omitting the __c_[io]speed fields).
> 
> If we had used the kernel value of NCCS everywhere, rather than the
> inflated glibc value of 32, we could add BOTHER support just by
> attempting TCSETS2 using the caller's termios structure, and only
> falling back if it doesn't work. In theory we *could* change to do
> this now. The __c_[io]speed members are not in the public namespace,
> and NCCS could be reduced to accommodate them as long as the overall
> struct size was preserved. This might be ~ugly~ for programs built
> with the old NCCS of 32, which might copy c_cc past its new end, but
> they'd just be moving stuff to/from the reserved speed fields they
> couldn't yet be using. The worst part about this seems to be that we'd
> be introducing more arch-specific versions of bits/termios.h, since
> the "generic" definition we have now actually has different layout
> depending on the arch's alignment requirements. I think this only
> affects m68k (where it's 2 rather than 4 byte alignment for int), so
> maybe it's not a big deal to add just one.
> 
> The alternative is to only use the caller-provided termios in-place in
> the case where we can get by without termios2 interfaces: that is,
> when either BOTHER is not set (classic POSIX baud flags), or TCSETS2
> is not defined (plain termios already supports BOTHER for this arch).
> Otherwise, translate to a kernel termios2 form, which really requires
> nothing other than knowing an arch-defined offset for the speed
> fields.
> 
> For going the other direction (tcgetattr) it's even easier: we're
> allowed to clobber the caller buffer, so just try TCGETS2 and move the
> speeds from their kernel offset into the libc member offsset.
> 
> I think this second approach is probably better, but I'm open to
> reasons why it might not be.

One thing I hadn't even considered yet is how the application is
expected to set custom speeds. We don't expose BOTHER, and while we
could expose it and put the c_[io]speed members in the public
namespace for direct access, it's not clear that this is the right way
to do it.

glibc's approach seems to be having cfset[io]speed accept values other
than the symbolic B constants, which POSIX allows and mentions in the
RATIONALE: 

    There is nothing to prevent an implementation accepting as an
    extension a number (such as 126), and since the encoding of the
    Bxxx symbols is not specified, this can be done to avoid
    introducing ambiguity.

https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html

This seems like it's the better approach. It does have values 0-15 and
4096-4111 as impossible-to-set because they overlap with B constants,
but these are not useful speeds.

Of course it might be useful to look at what applications expect to be
able to do.

Looking at the existing code, it seems like Linux already had separate
input baud encoded in the bits of c_cflag (CIBAUD mask), but we're not
using that. It's not yet clear to me whether these work and whether we
should be using them.

POSIX is also unhelpful/wrong on how to determine if "split baud" is
supported. The RATIONALE for cfgetispeed says:

    Setting the input baud rate to zero was a mechanism to allow for
    split baud rates. Clarifications in this volume of POSIX.1-2017
    have made it possible to determine whether split rates are
    supported and to support them without having to treat zero as a
    special case.

However, tcgetattr specifies:

    If the terminal device supports different input and output baud
    rates, the baud rates stored in the termios structure returned by
    tcgetattr() shall reflect the actual baud rates, even if they are
    equal. If differing baud rates are not supported, the rate
    returned as the output baud rate shall be the actual baud rate. If
    the terminal device does not support split baud rates, the input
    baud rate stored in the termios structure shall be the output rate
    (as one of the symbolic values).

Which clearly gives the *same behavior* in both the case where split
rates are supported but the same, and the case where split rates are
not supported. I have no idea what they intended here.

I think before this can move forward we need to have a better
understanding of what POSIX is supposed to require here and what Linux
actually does.

Rich

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.