From 647472db9b0691518a9d346f707571f3fa8471ab Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 28 Aug 2023 16:55:07 -0700 Subject: [PATCH] : add two new POSIX functions. musl already added tcgetwinsize() and tcsetwinsize(), but I didn't notice. Trivial single-line inlines added to a header that's already written that way. Test: treehugger Change-Id: Iac95ea6a89f3872025c512f7e61987b81d0aafa7 --- docs/status.md | 1 + libc/bionic/termios.cpp | 4 ++ libc/include/android/legacy_termios_inlines.h | 7 +++ libc/include/bits/termios_winsize_inlines.h | 52 +++++++++++++++++++ libc/include/termios.h | 19 +++++++ libc/libc.map.txt | 2 + tests/headers/posix/termios_h.c | 12 +++++ tests/termios_test.cpp | 48 +++++++++++++++++ 8 files changed, 145 insertions(+) create mode 100644 libc/include/bits/termios_winsize_inlines.h diff --git a/docs/status.md b/docs/status.md index de2fa10cd..ad7e1c5ce 100644 --- a/docs/status.md +++ b/docs/status.md @@ -56,6 +56,7 @@ list of POSIX functions implemented by glibc but not by bionic. Current libc symbols: https://android.googlesource.com/platform/bionic/+/master/libc/libc.map.txt New libc functions in V (API level 35): + * `tcgetwinsize`, `tcsetwinsize` (POSIX Issue 8 additions). * `timespec_getres` (C23 addition). * `localtime_rz`, `mktime_z`, `tzalloc`, and `tzfree` (NetBSD extensions implemented in tzcode, and the "least non-standard" diff --git a/libc/bionic/termios.cpp b/libc/bionic/termios.cpp index 5fe8eb0e7..57b34b739 100644 --- a/libc/bionic/termios.cpp +++ b/libc/bionic/termios.cpp @@ -34,6 +34,10 @@ #define __BIONIC_TERMIOS_INLINE /* Out of line. */ #include +// POSIX added a couple more functions much later, so do the same for them. +#define __BIONIC_TERMIOS_WINSIZE_INLINE /* Out of line. */ +#include + // Actually declared in , present on all API levels. pid_t tcgetpgrp(int fd) { pid_t pid; diff --git a/libc/include/android/legacy_termios_inlines.h b/libc/include/android/legacy_termios_inlines.h index 6222786ea..a816b4048 100644 --- a/libc/include/android/legacy_termios_inlines.h +++ b/libc/include/android/legacy_termios_inlines.h @@ -43,3 +43,10 @@ #include #endif + +#if __ANDROID_API__ < 35 + +#define __BIONIC_TERMIOS_WINSIZE_INLINE static __inline +#include + +#endif diff --git a/libc/include/bits/termios_winsize_inlines.h b/libc/include/bits/termios_winsize_inlines.h new file mode 100644 index 000000000..ae246e401 --- /dev/null +++ b/libc/include/bits/termios_winsize_inlines.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include + +#include + +#if !defined(__BIONIC_TERMIOS_WINSIZE_INLINE) +#define __BIONIC_TERMIOS_WINSIZE_INLINE static __inline +#endif + +__BEGIN_DECLS + +__BIONIC_TERMIOS_WINSIZE_INLINE int tcgetwinsize(int __fd, struct winsize* _Nonnull __size) { + return ioctl(__fd, TIOCGWINSZ, __size); +} + +__BIONIC_TERMIOS_WINSIZE_INLINE int tcsetwinsize(int __fd, const struct winsize* _Nonnull __size) { + return ioctl(__fd, TIOCSWINSZ, __size); +} + +__END_DECLS diff --git a/libc/include/termios.h b/libc/include/termios.h index 853b4ebab..7abff5dae 100644 --- a/libc/include/termios.h +++ b/libc/include/termios.h @@ -149,6 +149,25 @@ int tcsetattr(int __fd, int __optional_actions, const struct termios* _Nonnull _ #endif +#if __ANDROID_API__ >= 35 +// These two functions were POSIX Issue 8 additions that we can also trivially +// implement as inlines for older OS version. + +/** + * tcgetwinsize(3) gets the window size of the given terminal. + * + * Returns 0 on success and returns -1 and sets `errno` on failure. + */ +int tcgetwinsize(int __fd, struct winsize* _Nonnull __size); + +/** + * tcsetwinsize(3) sets the window size of the given terminal. + * + * Returns 0 on success and returns -1 and sets `errno` on failure. + */ +int tcsetwinsize(int __fd, const struct winsize* _Nonnull __size); +#endif + __END_DECLS #include diff --git a/libc/libc.map.txt b/libc/libc.map.txt index e90618dfb..b3ef18557 100644 --- a/libc/libc.map.txt +++ b/libc/libc.map.txt @@ -1591,6 +1591,8 @@ LIBC_V { # introduced=VanillaIceCream mktime_z; __riscv_flush_icache; # riscv64 __riscv_hwprobe; # riscv64 + tcgetwinsize; + tcsetwinsize; timespec_getres; tzalloc; tzfree; diff --git a/tests/headers/posix/termios_h.c b/tests/headers/posix/termios_h.c index 1255c162f..0a67eaabe 100644 --- a/tests/headers/posix/termios_h.c +++ b/tests/headers/posix/termios_h.c @@ -42,6 +42,12 @@ static void termios_h() { STRUCT_MEMBER(struct termios, tcflag_t, c_lflag); STRUCT_MEMBER_ARRAY(struct termios, cc_t/*[]*/, c_cc); +#if !defined(__GLIBC__) // Our glibc is too old. + TYPE(struct winsize); + STRUCT_MEMBER(struct winsize, unsigned short, ws_row); + STRUCT_MEMBER(struct winsize, unsigned short, ws_col); +#endif + MACRO(NCCS); MACRO(VEOF); @@ -162,6 +168,12 @@ static void termios_h() { FUNCTION(tcflush, int (*f)(int, int)); FUNCTION(tcgetattr, int (*f)(int, struct termios*)); FUNCTION(tcgetsid, pid_t (*f)(int)); +#if !defined(__GLIBC__) // Our glibc is too old. + FUNCTION(tcgetwinsize, int (*f)(int, struct winsize*)); +#endif FUNCTION(tcsendbreak, int (*f)(int, int)); FUNCTION(tcsetattr, int (*f)(int, int, const struct termios*)); +#if !defined(__GLIBC__) // Our glibc is too old. + FUNCTION(tcsetwinsize, int (*f)(int, const struct winsize*)); +#endif } diff --git a/tests/termios_test.cpp b/tests/termios_test.cpp index 6290771a0..a8d589019 100644 --- a/tests/termios_test.cpp +++ b/tests/termios_test.cpp @@ -29,6 +29,8 @@ #include #include +#include +#include #include @@ -96,3 +98,49 @@ TEST(termios, cfmakeraw) { EXPECT_EQ(1, t.c_cc[VMIN]); EXPECT_EQ(0, t.c_cc[VTIME]); } + +TEST(termios, tcgetwinsize_tcsetwinsize_invalid) { +#if !defined(__GLIBC__) + winsize ws = {}; + + errno = 0; + ASSERT_EQ(-1, tcgetwinsize(-1, &ws)); + ASSERT_EQ(EBADF, errno); + + errno = 0; + ASSERT_EQ(-1, tcsetwinsize(-1, &ws)); + ASSERT_EQ(EBADF, errno); +#else + GTEST_SKIP() << "glibc too old"; +#endif +} + +TEST(termios, tcgetwinsize_tcsetwinsize) { +#if !defined(__GLIBC__) + int pty, tty; + winsize ws = {123, 456, 9999, 9999}; + ASSERT_EQ(0, openpty(&pty, &tty, nullptr, nullptr, &ws)); + + winsize actual = {}; + ASSERT_EQ(0, tcgetwinsize(tty, &actual)); + EXPECT_EQ(ws.ws_xpixel, actual.ws_xpixel); + EXPECT_EQ(ws.ws_ypixel, actual.ws_ypixel); + EXPECT_EQ(ws.ws_row, actual.ws_row); + EXPECT_EQ(ws.ws_col, actual.ws_col); + + ws = {1, 2, 3, 4}; + ASSERT_EQ(0, tcsetwinsize(tty, &ws)); + + actual = {}; + ASSERT_EQ(0, tcgetwinsize(tty, &actual)); + EXPECT_EQ(ws.ws_xpixel, actual.ws_xpixel); + EXPECT_EQ(ws.ws_ypixel, actual.ws_ypixel); + EXPECT_EQ(ws.ws_row, actual.ws_row); + EXPECT_EQ(ws.ws_col, actual.ws_col); + + close(pty); + close(tty); +#else + GTEST_SKIP() << "glibc too old"; +#endif +}