Minutes of the 5th October 2017 Teleconference Austin-839 Page 1 of 1 Submitted by Andrew Josey, The Open Group. 7th October 2017 Attendees: David Clissold, IBM Don Cragun, IEEE PASC OR Nick Stoughton, USENIX, ISO/IEC JTC 1/SC 22 OR Andrew Josey, The Open Group Richard Hansen, Google Mark Ziegast, SHware Systems Dev. Geoff Clare, The Open Group Martin Rehak, Oracle, The Open Group OR Joerg Schilling, FOKUS Fraunhofer Apologies: * General news Andrew noted that the IEEE P1003.1 recirculation ballot had completed on Sunday October 1. Response rate 91%, approval rate 100%, abstention rate 4% Andrew has submitted the draft to IEEE RevCom, and it has been confirmed as on the agenda for December. * Outstanding actions ( Please note that this section has been flushed to shorten the minutes - to locate the previous set of outstanding actions, look to the minutes from 28 Jan 2016) Bug 0000249: Add standard support for $'...' in shell Reopened http://austingroupbugs.net/bug_view_page.php?bug_id=249 We will return to bug 249 on a future call. Bug 0000953: Alias expansion is under-specified Was Accepted as Marked http://austingroupbugs.net/view.php?id=953 Richard has an action to propose new wording to discuss in a future telecon. * Current Business Three items from previous weeks are still open: Bug 1061: Please add memmem() (and maybe wmemmem()) OPEN http://austingroupbugs.net/view.php?id=1061 Bug 1053: Add a "size" mode to stty(1) OPEN http://austingroupbugs.net/view.php?id=1053 This remains open. Bug 1063: missing specification for sh -h OPEN http://austingroupbugs.net/bug_view_page.php?bug_id=1063 We have started on this item and need to continue at a future meeting. Bug 1151: Introduce new signal SIGWINCH and functions tcsetsize(), tcgetsize() to get/set terminal window size Accepted as marked http://austingroupbugs.net/view.php?id=1151 This item is tagged for Issue 8. 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 winsize Structure --------------------- The 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. 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: Terminal window size changed. The section "CHANGE HISTORY" shall be amended appropriately. On P201 L6734 (XBD 11.1.4) add tcsetsize() to the list of functions, after tcsetpgrp(). Change P1410, L46849-46859 in the DESCRIPTION of open() from: O_TTY_INIT If path identifies a terminal device other than a pseudo-terminal, the device is not already open in any process, and either O_TTY_INIT is set in oflag or O_TTY_INIT has the value zero, open() shall set any non-standard termios structure terminal parameters to a state that provides conforming behavior; see XBD Section 11.2 (on page 205). It is unspecified whether O_TTY_INIT has any effect if the device is already open in any process. If path identifies the slave side of a pseudo-terminal that is not already open in any process, open() shall set any non-standard termios structure terminal parameters to a state that provides conforming behavior, regardless of whether O_TTY_INIT is set. If path does not identify a terminal device, O_TTY_INIT shall be ignored. to: O_TTY_INIT If path identifies a terminal device other than a pseudo-terminal, the device is not already open in any process, and either O_TTY_INIT is set in oflag or O_TTY_INIT has the value zero, open() shall set any non-standard termios structure terminal parameters to a state that provides conforming behavior see XBD Section 11.2 (on page 205) and initialize the winsize structure associated with the terminal to appropriate default settings. It is unspecified whether O_TTY_INIT has any effect if the device is already open in any process. If path identifies the slave side of a pseudo-terminal that is not already open in any process, open() shall set any non-standard termios structure terminal parameters to a state that provides conforming behavior and initialize the winsize structure associated with the terminal to appropriate default settings, regardless of whether O_TTY_INIT is set. If path does not identify a terminal device, O_TTY_INIT shall be ignored. 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 size of a terminal window SYNOPSIS #include int tcgetsize(int fildes, struct winsize *winsize_p); DESCRIPTION The tcgetsize() function shall get the terminal window size associated with the terminal referred to by fildes and store it 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. If the terminal referred to by fildes was opened without O_TTY_INIT and is not a pseudo-terminal, and the terminal window size has not been set by a call to tcsetsize(), the terminal window size is unspecified. If the terminal was opened with O_TTY_INIT or is a pseudo-terminal, and the terminal window size has not been set by a call to tcsetsize(), the terminal window size shall be set to an appropriate default (see [xref to open()]). If the terminal window size has been set by a call to tcsetsize(), the values set by that call shall be returned. 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 #include #include #include #include #include #include #include static volatile sig_atomic_t vrow; static volatile sig_atomic_t vcol; static volatile sig_atomic_t newsize; static void winch_handler(int signum) { struct winsize ws; int sav_errno = errno; (void)signum; /* prevent compiler warning that signum is unused */ /* set volatile vars to new winsize, or 0 if unavailable or too large */ if (tcgetsize(STDERR_FILENO, &ws) == -1) { vrow = vcol = 0; } else { if (ws.ws_row <= SIG_ATOMIC_MAX && ws.ws_col <= SIG_ATOMIC_MAX) { vrow = ws.ws_row; vcol = ws.ws_col; } else { vrow = vcol = 0; } } newsize = 1; errno = sav_errno; } int main(void) { struct sigaction sa; struct winsize ws; sigset_t winch_set; char inbuf[512]; sa.sa_handler = winch_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGWINCH, &sa, NULL); sigemptyset(&winch_set); sigaddset(&winch_set, SIGWINCH); raise(SIGWINCH); /* gets the initial winsize */ for (;;) { if (fgets(inbuf, sizeof inbuf, stdin) == NULL) { if (feof(stdin)) exit(0); else if (errno == EINTR) continue; else { perror("Error reading stdin"); exit(1); } } else { if (newsize) { /* prevent updates to volatile vars while we read them */ sigprocmask(SIG_BLOCK, &winch_set, NULL); ws.ws_row = vrow; ws.ws_col = vcol; sigprocmask(SIG_UNBLOCK, &winch_set, NULL); newsize = 0; } printf("row = %3hu, col = %3hu\n", ws.ws_row, ws.ws_col); /* process inbuf ... */ } } } APPLICATION USAGE Applications should take care to avoid race conditions and other undefined behavior when calling tcgetsize() from signal handlers. A common but incorrect idiom is to establish a signal handler for SIGWINCH from which tcgetsize() is called to update a global struct winsize. This usage is incorrect as accessing a struct winsize is not guaranteed to be an atomic operation. Instead, applications should have tcgetsize() write to a local structure and copy each member the application is interested in to a global variable of type volatile sig_atomic_t. Furthermore, SIGWINCH should be blocked from delivery while the terminal size is read from these global variables to further avoid race conditions. A simpler alternative, if the application is structured in a suitable way, is just to set a flag in the signal handler and then call tcgetsize() (and clear the flag) at an appropriate place in the code if the flag has been set. Multi-threaded applications should avoid the signal handler idiom in general. Instead, it is advised to use sigwait() to wait for the delivery of a SIGWINCH signal. If the terminal window size changes while a process is in the background, it is not notified via SIGWINCH (which is sent only to the foreground process group). Applications can handle this case by calling tcgetsize() if the process receives SIGCONT, to check whether the terminal window size changed while the process was stopped. If a background process writes to a terminal and the TOSTOP flag is clear (see [xref to XBD 11.2.5 Local Modes]), the process might not receive SIGTTOU or SIGWINCH signals and thus might not be notified when the terminal window size might have changed. Such processes must periodically poll the current terminal window size if needed. RATIONALE The tcgetsize() function is provided to allow applications to query the current terminal window size. This is necessary for applications intended to be run in terminals whose terminal window size can be changed at runtime. Conventionally, a SIGWINCH signal is delivered to a controlling terminal's foreground process group whenever its terminal window size is changed. By installing a signal handler for SIGWINCH, a process can detect the change to the controlling terminal's window size and take action, e.g. by redrawing its user interface to the new size. FUTURE DIRECTIONS None. SEE ALSO tcsetsize(), 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 size of a terminal window SYNOPSIS #include int tcsetsize(int fildes, const struct winsize *winsize_p); DESCRIPTION The tcsetsize() function shall set the terminal 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. No signal shall be delivered if the terminal size was changed to the same value it had before the tcsetsize() call. A SIGWINCH may also be delivered to an implementation defined set of other processes. The tcsetsize() function shall return successfully if it was able to update all members of the winsize structure associated with the terminal. It is unspecified whether changing the terminal window size causes any changes to the size of the terminal's font. 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 modify only fields defined by this volume of POSIX.1-20xx between the call to tcgetsize() and tcsetsize(), leaving all other fields unmodified. No actions defined by this volume of POSIX.1-20xx, 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 this terminal device (using the O_TTY_INIT flag if it is non-zero and the device is not a pseudo-terminal), shall cause the terminal window size to change. If tcsetsize() is called from a process which is a member of a background process group on a fildes associated with its controlling terminal: If the calling thread is blocking SIGTTOU signals or the process is ignoring SIGTTOU signals, the operation completes normally and no signal is sent. Otherwise, a SIGTTOU signal shall be sent to the process group. RETURN VALUE Upon successful completion, 0 shall be returned. Otherwise, -1 shall be returned, the terminal window size shall not be changed, and errno shall be set to indicate the error. ERRORS The tcsetsize() function shall fail if: [EBADF] The fildes argument is not a valid file descriptor. [EIO] The process group of the writing process is orphaned, the calling thread is not blocking SIGTTOU, and the process is not ignoring SIGTTOU. [ENOTTY] The file associated with fildes is not a terminal. The tcsetsize() function may fail if: [EINVAL] An attempt was made to change an attribute represented in the winsize structure to an unsupported value. EXAMPLES None. APPLICATION USAGE If the terminal window of a pseudo terminal is resized, the attached master process should invoke tcsetsize() to relay the new terminal window size to the foreground process group. If a process attached to the slave of a pseudo-terminal calls tcsetsize(), the attached master process should attempt to change the screen to reflect the new size. RATIONALE This standard does not mention the ws_xpixel and ws_ypixel fields that appear in the winsize structure of some historical implementations. With current hardware, it is not obvious that the unsigned short type used for these fields is sufficient and no uses of these fields in portable code were found. However, since these and other fields may be included in the winsize structure, the standard requires that applications use tcgetsize() to initialize any fields that may be provided by an implementation before setting the ws_cols and ws_rows fields using tcsetsize() to avoid unintentionally destroying data in other fields in this structure. FUTURE DIRECTIONS None. SEE ALSO tcgetsize(), The "CHANGE HISTORY" section shall be filled in appropriately. New reserved prefix ws_ : To the first table in §2.2.2, add ws_ as a reserved prefix for the header (after c_, B[0-9], TC). tcgetsize() and tcsetsize() are async-signal-safe: To the list of async-signal-safe functions in §2.4.3, add tcgetsize() and tcsetsize(). Next Steps ---------- The next call is on October 12th, 2017 (a Thursday) Calls are anchored on US time. (8am Pacific) This call will be for the regular 90 minutes. http://austingroupbugs.net An IRC channel will be available for the meeting irc://irc.freenode.net/austingroupbugs An etherpad is usually up for the meeting, with a URL using the date format as below: https://posix.rhansen.org/p/201x-mm-dd username=posix password=2115756#