Austin Group Defect Tracker

Aardvark Mark III


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0001151 [1003.1(2016)/Issue7+TC2] System Interfaces Editorial Enhancement Request 2017-06-19 16:41 2017-09-14 07:42
Reporter Clausecker View Status public  
Assigned To
Priority normal Resolution Open  
Status New  
Name Robert Clausecker
Organization Fraunhofer Fokus
User Reference
Section termios.h, signal.h, 2.4.3 "Signal Actions", 11.2 "Parameters that Can be Set", new sections tcgetsize and tcsetsize
Page Number 414, 333, 494, 212
Line Number 13877, 11115, 16845–16879, 7040
Interp Status ---
Final Accepted Text
Summary 0001151: Introduce new signal SIGWINCH and functions tcsetsize(), tcgetsize() to get/set terminal window size
Description This proposal aims to standardize the broadly available signal SIGWINCH
and an extension to termios to query and set the terminal window size.
This extension is designed to be easily implementable in terms of the
TIOCGWINSZ and TIOCSWINSZ ioctl() calls available on many UNIX-like
systems. This proposal does not contain an extension to the stty
utility as that is already considered in the scope of [bug 1053]. This
proposal introduces new functions tcgetsize() and tcsetsize() instead of
introducing the ioctl() calls TIOCGWINSZ and TIOCSWINSZ as POSIX
generally does not standardize the ioctl() except for the STREAMS
interface.

The desired action is rather large and posted both inline and as an attachment to the bug report in case the bug tracker garbles it.

[bug 1053]: http://austingroupbugs.net/view.php?id=1053 [^]
Desired Action Extensions to termios.h
=======================

A new subsection named "The winsize structure" is added to the header
termios.h right after the section "The termios structure." The type
"unsigned short" follows historical convention. Perhaps the comittee
wishes to instead introduce appropriate integer types for the structure
members instead. This might be useful for implementations aiming to
support terminals with more than 65535 horizontal or vertical pixels.

    The winsize Structure
    ---------------------

    The <termios.h> header shall define the winsize structure, which
    shall include at least the following members:

        unsigned short ws_row rows, in characters.
        unsigned short ws_col columns, in characters.
        unsigned short ws_xpixel horizontal size, in pixels.
        unsigned short ws_ypixel vertical size, in pixels.

    In all members named in this volume of POSIX.1 2008, a value of 0
    shall indicate that the value is unknown.

Furthermore, the list of declared functions shall be amended with the
following two entries:

    int tcgetsize(int, struct winsize *);
    int tcsetsize(int, const struct winsize *);

The section "CHANGE HISTORY" shall be amended appropriately.

Extensions to signal.h
======================

The table of signals shall be amended with the following entry:

    Signal: SIGWINCH
    Default Action: I
    Description: Window size changed.

The entry shall be added immediately after the entry for SIGUSR1.

The section "CHANGE HISTORY" shall be amended appropriately.

Extensions to §2.4.3 Signal Actions
===================================

The list of async-signal-safe functions shall be amended by the
functions tcgetsize() and tcsetsize().

New function "tcgetsize"
========================

A new page "tcgetsize" shall be added to the list of system interfaces.
Its text is analogous to that of tcgetattr and shall be as follows:

    NAME

        tcgetsize -- get the window size associated with a terminal

    SYNOPSIS

        #include <termio.h>

        int tcgetsize(int fildes, struct winsize *winsize_p);

    DESCRIPTION

        The tcgetsize() function shall get the window size associated
        with the terminal referred to by fildes and store them in the
        winsize structure pointed to by winsize_p. The fildes
        argument is an open file descriptor associated with a terminal.
        The winsize_p argument is a pointer to a winsize structure.

        It is implementation defined whether the window size associated
        with a terminal refers to the actual size and resolution of the
        terminal connected to the communication port associated with the
        terminal.

        The tcgetsize() operation is allowed from any process.

    RETURN VALUE

        Upon succesful completion, 0 shall be returned. Otherwise, -1
        shall be returned and errno set to indicate the error.

    ERRORS

        The tcgetsize() function shall fail if:

        [EBADF]
            The fildes argument is not a valid file descriptor.
        [ENOTTY]
            The file associated with fildes is not a terminal.

    EXAMPLES

        The following example demonstrates how tcgetsize can be used
        in conjunction with a handler for SIGWINCH to keep track of the
        terminal window size associated with the standard error stream.

        #include <stdio.h>
        #include <signal.h>
        #include <termios.h>
        #include <unistd.h>

        static struct winsize ws;

        static void winch_handler(int signum)
        {

            (void)signum;

            if (tcgetsize(STDERR_FILENO, &ws) == -1)
                /* Handle error. */
        }

        int main()
        {
            struct sigaction sa;

            sa.sa_handler = winch_handler;
            sigemptyset(&sa.sa_mask);
            sa.sa_flags = 0;
            sigaction(SIGWINCH, &sa, NULL);

            for (winch_handler(SIGWINCH); ; pause())
                printf("row = %3d, col = %3d, xpixel = %4d, ypixel = %4d\n",
                    ws.ws_row, ws.ws_col, ws.ws_xpixel, ws.ws_ypixel);
        }

    APPLICATION USAGE

        None.

    RATIONALE

        The tcgetsize() function is provided to allow applications to
        query the current size of a terminal window. This is necessary
        for applications intended to be run in terminal emulators whose
        window size can be changed at runtime. A SIGWINCH signal is
        delivered to a terminal's process group whenever its window size
        is changed. By installing a signal handler for SIGWINCH, a
        process can detect the resizing of its controlling terminal and
        take action, e.g. by redrawing its user interface to the new
        size.

    FUTURE DIRECTIONS

        None.

    SEE ALSO

        tcsetsize, <termios.h>

The "CHANGE HISTORY" section shall be filled in appropriately.

New function "tcsetsize"
========================

A new page "tcsetsize" shall be added to the list of system interfaces.
Its text is analogous to that of tcsetattr and shall be as follows:

    NAME

        tcsetsize -- set the window size associated with a terminal

    SYNOPSIS

        #include <termios.h>

        int tcsetsize(int fildes, const struct winsize *winsize_p);

    DESCRIPTION

        The tcsetsize() function shall set the window size associated
        with the terminal referred to by the open file descriptor
        fildes (an open file descriptor associated with a terminal)
        from the winsize structure referenced by winsize_p. The
        change shall occur immediately.

        If the terminal size was changed succesfully, a SIGWINCH shall
        be delivered to the foreground process group associated with the
        terminal. If the terminal is a slave pseudo-terminal, a
        SIGWINCH shall also be delivered to the foreground process group
        of the associated master pseudo-terminal. Similarly, if the
        terminal is a master pseudo-terminal, a SIGWINCH shall be
        delivered to the foreground process group of the associated
        slave pseudo-terminal. No signal shall be delivered if the
        terminal size and resolution were changed to the same value they
        had before the tcsetsize() call. If the foreground process
        groups of master and slave pseudo-terminals are the same, only
        one SIGWINCH shall be delivered to the process group. If one of
        the mentioned foreground process groups does not exist, the
        corresponding signal shall not be delivered.

        The tcsetsize() function shall return successfully if it was
        able to alter the terminal size or resolution.

        It is implementation defined whether changing the window size of
        a terminal causes any changes in the size or resolution of the
        terminal emulator's graphical output.

        The effect of tcsetsize() is undefined if the value of the
        winsize structure pointed to by winsize_p was not derived
        from the result of a call to tcgetsize() on fildes; an
        application should only modify only fields defined by this
        volume of POSIX.1-2008 between the call to tcgetsize() and
        tcsetsize(), leaving all other fields unmodified.

        No actions defined by this volume of POSIX.1-2008, other than a
        call to tcsetsize(), a close of the last file descriptor in
        the system associated with this terminal device, or an open of
        the first file descriptor in the system associated with this
        terminal device (using the O_TTY_INIT flag if it is non-zero and
        the device is not a pseudo-terminal), shall cause any of the
        terminal attributes defined by this volume of POSIX.1-2008 to
        change.

    RETURN VALUE

        Upon successful completion, 0 shall be returned. Otherwise, -1
        shall be returned and errno set to indicate the error.

    ERRORS

        The tcsetsize() shall fail if:

        [EBADF]
            The fildes argument is not a valid file descriptor.
        [EINVAL]
            An attempt was made to change an attribute represented in
            the winsize structure to an unsupported value.
        [ENOTTY]
            The file associated with fildes is not a terminal.

    EXAMPLES

        None.

    APPLICATION USAGE

        If the window of a graphical terminal emulator is resized, the
        terminal emulator should invoke tcsetsize() to relay the new
        window size and resolution to the slave's foreground process
        group.

        If a process attached to the slave of a graphical terminal
        emulator's pseudo-terminal calls tcsetsize(), the terminal
        emulator should attempt to change the window size and resolution
        to reflect the requested terminal size.

    RATIONALE

        None.

    FUTURE DIRECTIONS

        None.

    SEE ALSO

        tcgetsize, <termios.h>

The "CHANGE HISTORY" section shall be filled in appropriately.

New section §11.2.7 Window Size
===============================

Immediately after §11.2.6 "Special Control Characters," a new section
named "Window Size" shall be added with the following text:

    11.2.7 Window Size

    Routines that need to query or set the terminal window size shall do
    so by using the winsize structure as defined in the <termios.h>
    header.

    Since the winsize structure may include additional members, the
    structure should never be initialized directly by the application as
    this may cause the terminal to behave in a non-conforming manner.
    When opening a terminal device (other than a pseudo-terminal) that
    is not already open in any process, it should be opened with the
    O_TTY_INIT flag before initializing the structure using tcgetsize()
    to ensure that any non-standard elements of the termios structure
    are set to values that result in conforming behavior of the terminal
    interface.

    The members of the winsize structure include (but are not limited
    to):

    +----------------+-------------+----------------------------+
    | Member Type | Member Name | Description |
    +----------------+-------------+----------------------------+
    | unsigned short | ws_row | rows, in characters |
    | unsigned short | ws_col | columns, in characters |
    | unsigned short | ws_xpixel | horizontal size, in pixels |
    | unsigned short | ws_ypixel | vertical size, in pixels |
    +----------------+-------------+----------------------------+

    For each member, a value of 0 indicates that the size is unknown.

    A program can query the window size associated with a terminal using
    the tcgetsize() function and alter the window size using the
    tcsetsize() function. Updating the window size causes a SIGWINCH to
    be delivered to the terminal's foreground process group if any.

    It is implementation-defined whether the window size associated with
    a terminal actually corresponds to the physical size and resolution
    of the physical or virtual terminal device connected to the
    terminal's communication port. If it does correspond, changing the
    size or resolution of the terminal device causes a SIGWINCH to be
    sent to the foreground process group of the terminal.
Tags No tags attached.
Attached Files txt file icon sigwinch-proposal.txt [^] (12,847 bytes) 2017-06-19 16:41
c file icon sigwinch_example.c [^] (2,133 bytes) 2017-06-29 09:12
txt file icon sigwinch-proposal.2.txt [^] (9,590 bytes) 2017-08-31 09:19
c file icon sigwinch_example.2.c [^] (1,750 bytes) 2017-09-14 07:41

- Relationships
related to 0001053New 1003.1(2013)/Issue7+TC1 Add a "size" mode to stty(1) 

-  Notes
(0003786)
shware_systems (reporter)
2017-06-19 17:32
edited on: 2017-08-17 15:24

Extensions to termios.h
=======================

A new subsection named "The winsize_t structure" is added to the header
termios.h right after the section "The termios structure." The type
"unsigned short" follows historical convention. Perhaps the committee
wishes to instead introduce appropriate integer types for the structure
members instead. This might be useful for implementations aiming to
support terminals with more than 65535 horizontal or vertical pixels.

    The winsize_t Structure
    ---------------------

    The <termios.h> header shall define the winsize_t structure, which
    shall include at least the following members:

        unsigned long ws_row rows, in characters.
        unsigned long ws_col columns, in characters.
[XSI] or [UP]
        unsigned long ws_xpixel horizontal size, in pixels, if supported.
        unsigned long ws_ypixel vertical size, in pixels, if supported.
[x]

    In all members named in this volume of POSIX.1 2008, a value of 0
    shall indicate that the value is unknown.
===
Additional edits after as winsize an app reserved identifier, *_t standard / implementation reserved. Use of termios as a type identifier a grandfathered allowance.
Changed to long as display arrays can have now over 65k chars or pixels easily enough with UHD 4k resolutions, yet be logically a single terminal. The future is already here, iow. :-)
Option group added as base POSIX will still only require support for char array or line oriented devices, not pixel or vector based. This was part of Bug 1053 discussion. Moving any added support for vectors or pixels to the base is an Issue 9 matter.
Errors for tcsetsize() is missing ENOSUP as a 'may fail' entry, also discussed, for terminals that have fixed dimensions.
Believe additional text related to LINES and COLUMNS env. variables also desirable.

(0003787)
EdSchouten (reporter)
2017-06-19 18:06

Why call it winsize_t, as opposed to 'struct winsize', which is the current convention?
(0003788)
shware_systems (reporter)
2017-06-19 18:11

Because other applications may use winsize for other purposes, as struct tag or other context.
(0003789)
Clausecker (reporter)
2017-06-19 18:43

struct winsize is the historic name for this structure, used since at least 1989. Renaming it might cause more problems than it solves. Note that tcsetsize and tcgetsize aren't reserved by POSIX either (probably by mistake).

Mandating unsigned long as the type for the members is a bad idea as this contradicts existing implementations. All implementations I checked use unsigned short for this type. As I already mentioned, introducing a typedef windim_t might be a good compromise between compatibility and future expansions.

I don't see how adding ENOTSUP might be a good idea. If the terminal's size cannot be changed, an implementation may either decide to make size changes have no effect (this might be a good idea for serial ports where the device driver cannot change the terminal but e.g. login(8) might want to set up the window size with information from the termcap database) or decide that each other possible terminal size is invalid, returning EINVAL.

Changing the terminal size to itself should never cause an error, even on a fixed-size terminal. Perhaps that invariant should be specified, too.
(0003791)
geoffclare (manager)
2017-06-20 09:22

There are some signal-related problems with the example code.

1. The winch_handler() function needs to save errno on entry and restore it before returning.

2. Having the tcgetsize() call in winch_handler() write directly to the static structure is undefined behaviour. To meet the requirements of the current standard it would have to write to a local structure and then copy each member to a separate static value of type volatile sig_atomic_t. However, since (if accepted) this will go into Issue 8 it may be better to use the new C11 lock-free atomic objects.

3. In main() if a second SIGWINCH arrives during execution of the loop, printf() could end up printing some old and some new values. The code should block SIGWINCH before the loop, and should use sigsuspend() instead of pause().

In addition to correcting the example code, there should be some discussion of points 2 and 3 in the APPLICATION USAGE section, plus a mention that multi-threaded processes should use sigwait() instead of a signal handler.
(0003797)
shware_systems (reporter)
2017-06-22 10:36

Renaming it is required by XSH 2.2.2 Namespaces, afaik, whatever problems ensue. Last it was discussed new identifiers to be standardized were being drawn from the namespace reserved to implementations by the C standard since C89 or with prefixes / suffixes reserved by POSIX and C to implementations, for additions to any of the standard libraries.

That those platforms used a file-scope-visible identifier reserved to applications with winsize is therefore their lookout, not the standard's, and this is not an exception from before Issue 1 or C89 that I see. Whether the interfaces should be posix_get/setsize() or posix_tcget/setsize() is open to debate, perhaps. As proposed what's there is usable if controlled by a visibility macro, to maintain backwards compatibility, but I forgot to add that part to the note.

As apparently no platform is using winsize_t, using longs has no known backwards compatibility considerations for this functionality. Imo bug reports should have been filed over a decade ago with those platforms to obsolete the interfaces where the structure members are shorts, as being short sighted, for collateral issues. I agree use of an opaque type is plausible, but this has the overhead of adding min and max constant specifications too and still obsoletes that structure.

ENOTSUP being returned is a case where the signal would not be generated because no attempt to access the device is being performed. This would be different from a device accepting a set command that has only one valid value, but may have side effects such as doing a form feed or clear screen, so the signal should be generated. This would return EINVAL if another value was passed in, I'd expect.
(0003798)
geoffclare (manager)
2017-06-22 16:45

I see a problem with this part of the tcsetsize() description:
If the terminal is a slave pseudo-terminal, a SIGWINCH shall also be delivered to the foreground process group of the associated master pseudo-terminal. Similarly, if the terminal is a master pseudo-terminal, a SIGWINCH shall be delivered to the foreground process group of the associated slave pseudo-terminal.

Currently the standard does not require the master side to provide a terminal interface nor require that it can have a controlling process or process groups. All it requires of the master is (XBD 3.308) "Anything written on the master device is presented to the slave as an input and anything written on the slave device is presented as an input on the master side."

How best to solve this depends on whether existing applications expect the master side to be a terminal and for what reason (e.g. is it always just in order to receive SIGWINCH when the slave side changes size).
(0003799)
Don Cragun (manager)
2017-06-22 16:52

From the text in this proposal, I don't understand whether a user or application using these interfaces is expected to change the value assigned to ws_xpixel at the same time the value of ws_row is changed (and vice versa) and to change the value assigned to ws_ypixel at the same time the value of ws_col is changed (and vice versa); whether a user or application is only expected to use one pair of these values and never look at or change the other set (and, if so, how to know which pair of values to use to achieve whatever different affects are to be expected from using the two pairs of values); nor whether or not there is any relationship between the ws_row and ws_col values and the ws_[xy]pixel values.

If a user calls tcgetsize() and modifies ws_col and ws_row without changing ws_[xy]pixel before calling tcsetsize() to alter those values, is the system expected to modify the pixel values as a side effect of the call? Should it return an error in this case since the pixel values no longer correlate to the row and col values? Should an application always set the pixel values to 0 if the row/col values are changed and set the row/col values to 0 if the pixel values are changed?

Would the submitter of this bug please add a note with additional text indicating the relationships between these pairs of values, an explanation of what each pair of values is intended to do, and advice for readers of the standard so they know which values to use and which values to modify for the intended use cases of each pair of values?
(0003800)
Clausecker (reporter)
2017-06-22 20:53

> There are some signal-related problems with the example code.

It perhaps might be a good idea to omit the example then as I don't see how to make the example be strictly correct without being overly complicated at the same time.

> Currently the standard does not require the master side to provide a terminal interface nor require that it can have a controlling process or process groups. All it requires of the master is (XBD 3.308) "Anything written on the master device is presented to the slave as an input and anything written on the slave device is presented as an input on the master side."

Reading various kernel source again, this seems to be an exclusive Linux feature. Perhaps this paragraph should be removed or replaced with a paragraph allowing SIGWINCH to be delivered to an implementation defined set of additional processes.

> Would the submitter of this bug please add a note with additional text indicating the relationships between these pairs of values, an explanation of what each pair of values is intended to do, and advice for readers of the standard so they know which values to use and which values to modify for the intended use cases of each pair of values?

This seems to differ between implementation. The general use case for tcsetsize() seems to be for terminal emulators or the kernel's virtual console to set the current terminal size. If I understood the Linux source code correctly, the kernel ignores ws_xpixel and ws_ypixel and treats zeroes as “no change”. Then it tries to find a video mode that has the desired number of rows and columns and changes to that. In Solaris, I have not found any place where a call to tcsetsize() causes a video mode change, though some comments in common/io/ptem.c seem to suggest that it once did. On FreeBSD I have not found such code either, though, changing the video mode does change the terminal window size as reported by ioctl(TIOCGWINSZ, ...); and a SIGWINCH is delivered.

> If a user calls tcgetsize() and modifies ws_col and ws_row without changing ws_[xy]pixel before calling tcsetsize() to alter those values, is the system expected to modify the pixel values as a side effect of the call? Should it return an error in this case since the pixel values no longer correlate to the row and col values? Should an application always set the pixel values to 0 if the row/col values are changed and set the row/col values to 0 if the pixel values are changed?

Note that on real hardware, rows/columns do not determine resolution. It is possible that the console driver supports more than one video mode for the same number of rows and columns, e.g. two modes with different aspect ratios. However, I do not know any implementation that considers ws_[xy]pixel when setting the terminal window size. I wrote that it is implementation defined if tcsetsize() actually changes the terminals resolution (as opposed to merely adjusting the value returned by tcgetsize()) because the behaviour differs among operating systems.
(0003804)
geoffclare (manager)
2017-06-29 09:20

I have created an updated example program with the points from Note: 0003791 fixed, and attached it as sigwinch_example.c

The code above the "cut here" line is for testing purposes, and wouldn't be included in the standard.

It uses sig_atomic_t because that is what's in the current standard and also because C11 lock-free atomic objects are optional in C11, so will likely be optional in Issue 8. We could include a "Note to Reviewers" that says the code should perhaps be updated to use C11 lock-free atomic objects if they are mandated by Issue 8.
(0003818)
geoffclare (manager)
2017-08-17 16:37

An additional change that is needed is to add ws_ as a reserved prefix for <termios.h> in the first table in XSH 2.2.2 (after c_, B[0-9], TC).
(0003820)
Clausecker (reporter)
2017-08-31 09:24

Attached as sigwinch-proposal.2.txt is an updated version of the proposal. The following changes were made:

* As discussed in the telco, ws_xpixel and ws_ypixel were removed from the proposal.
* Some typographic errors were corrected.
* The faulty example code for tcgetsize() was removed.
* An application usage not indicating correct use of tcgetsize() in conjunction with SIGWINCH was added.
* The language about the delivery of SIGWINCH on call of tcsetsize() to pseudo-terminals was removed and replaced by more general language.
* The prefix ws_ was marked as reserved.
* The functions tcsetsize() and tcgetsize() were marked as async-signal-safe.
(0003854)
geoffclare (manager)
2017-09-14 07:42

I have attached an updated version of my example program as sigwinch_example.2.c which omits the pixel fields.

- Issue History
Date Modified Username Field Change
2017-06-19 16:41 Clausecker New Issue
2017-06-19 16:41 Clausecker File Added: sigwinch-proposal.txt
2017-06-19 16:41 Clausecker Name => Robert Clausecker
2017-06-19 16:41 Clausecker Organization => Fraunhofer Fokus
2017-06-19 16:41 Clausecker Section => termios.h, signal.h, 2.4.3 "Signal Actions", 11.2 "Parameters that Can be Set", new sections tcgetsize and tcsetsize
2017-06-19 16:41 Clausecker Page Number => 414, 333, 494, 212
2017-06-19 16:41 Clausecker Line Number => 13877, 11115, 16845–16879, 7040
2017-06-19 17:32 shware_systems Note Added: 0003786
2017-06-19 17:33 shware_systems Note Edited: 0003786
2017-06-19 18:06 EdSchouten Note Added: 0003787
2017-06-19 18:11 shware_systems Note Added: 0003788
2017-06-19 18:43 Clausecker Note Added: 0003789
2017-06-20 09:22 geoffclare Note Added: 0003791
2017-06-22 10:36 shware_systems Note Added: 0003797
2017-06-22 15:04 geoffclare Relationship added related to 0001053
2017-06-22 15:46 shware_systems Note Edited: 0003786
2017-06-22 16:45 geoffclare Note Added: 0003798
2017-06-22 16:52 Don Cragun Note Added: 0003799
2017-06-22 20:53 Clausecker Note Added: 0003800
2017-06-29 09:12 geoffclare File Added: sigwinch_example.c
2017-06-29 09:20 geoffclare Note Added: 0003804
2017-08-17 15:18 shware_systems Note Edited: 0003786
2017-08-17 15:24 shware_systems Note Edited: 0003786
2017-08-17 16:37 geoffclare Note Added: 0003818
2017-08-31 09:19 Clausecker File Added: sigwinch-proposal.2.txt
2017-08-31 09:24 Clausecker Note Added: 0003820
2017-09-14 07:41 geoffclare File Added: sigwinch_example.2.c
2017-09-14 07:42 geoffclare Note Added: 0003854


Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker