termios: fix input speed handling

traditionally, our cfsetispeed just set the output speed. this was not
conforming or reasonable behavior.

use of the input baud bits in termios c_cflag depends on kernel
support, which was added to linux along with TCSETS2 ioctl and
arbitrary-baud functionality sometime in the 2.6 series. with older
kernels, the separate input baud will not take, but this is the best
behavior we can hope for anyway, certainly better than wrongly
clobbering output baud setting.

the nonstandard cfsetspeed is now moved to a separate file, since it
no longer admits the weak alias implementation that made it
namespace-safe. it now sets the output speed, and on success, sets the
input speed to 0 (matched to output).
This commit is contained in:
Rich Felker
2025-02-22 16:44:39 -05:00
parent b6b81f697b
commit a34ca6ead1
3 changed files with 19 additions and 4 deletions
+1 -1
View File
@@ -9,5 +9,5 @@ speed_t cfgetospeed(const struct termios *tio)
speed_t cfgetispeed(const struct termios *tio)
{
return cfgetospeed(tio);
return (tio->c_cflag & CIBAUD) / (CIBAUD/CBAUD);
}
+7 -3
View File
@@ -16,7 +16,11 @@ int cfsetospeed(struct termios *tio, speed_t speed)
int cfsetispeed(struct termios *tio, speed_t speed)
{
return speed ? cfsetospeed(tio, speed) : 0;
if (speed & ~CBAUD) {
errno = EINVAL;
return -1;
}
tio->c_cflag &= ~CIBAUD;
tio->c_cflag |= speed * (CIBAUD/CBAUD);
return 0;
}
weak_alias(cfsetospeed, cfsetspeed);
+11
View File
@@ -0,0 +1,11 @@
#define _BSD_SOURCE
#include <termios.h>
#include <sys/ioctl.h>
#include <errno.h>
int cfsetspeed(struct termios *tio, speed_t speed)
{
int r = cfsetospeed(tio, speed);
if (!r) cfsetispeed(tio, 0);
return r;
}