Austin Group Defect Tracker

Aardvark Mark IV


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0001532 [Issue 8 drafts] Shell and Utilities Objection Error 2021-11-03 14:15 2021-11-03 16:04
Reporter stephane View Status public  
Assigned To
Priority normal Resolution Open  
Status New   Product Version Draft 2.1
Name Stephane Chazelas
Organization
User Reference 0001053
Section stty utility
Page Number
Line Number
Final Accepted Text
Summary 0001532: "stty -g" output should not have to be split
Description The resolution of 0001053, about the specification of "stty -g" changes:

-g

    Write to standard output all the current settings in an
    unspecified form that can be used as arguments to another
    invocation of the stty utility on the same system. The form
    used shall not contain any characters that would require
    quoting to avoid word expansion by the shell; see Section
    2.6 (on page 2353).

to:

-g

    Write to standard output all the current settings,
    optionally excluding the terminal window size, in an
    unspecified form that, when used as arguments to another
    invocation of the stty utility on the same system, attempts
    to apply those settings to the terminal. The form used shall
    not contain any sequence that would form an Informational
    Query, nor any characters that would require quoting to
    avoid word expansions, other than field splitting, by the
    shell; see Section 2.6 (on page 2353).

While the 2018 edition had:

-g
    Write to standard output all the current settings in an
    unspecified form that can be used as arguments to another
    invocation of the stty utility on the same system. The form
    used shall not contain any characters that would require
    quoting to avoid word expansion by the shell; see wordexp.

It's one stream of bytes that applications send to standard output.

For that stream of bytes to be "used as argument*S* to another
invocation of the stty utility", it implies that that output should
somehow be split into a list of arguments (and also implies the
result fits in the ARG_MAX limit and doesn't contain NUL bytes).

The reference to 2.6 suggests maybe "sh" should be involved to
perform that splitting. It almost suggests that the output
should be appended to "stty ", or possibly "stty -- " and fed to
sh as in (printf "stty -- "; stty -g) | sh

AFAIK, stty -g was introduced in SysIII circa 1980. It was
outputting on word on one line made of a ":"-separated of alnums
from the portable charset and followed by a newline character.
After it was specified by POSIX, it was also added to BSDs (some
4.3 variant), with "=" in the list of characters that may occur
(not in leading position) in the ":"-delimited list.
GNU stty has used a format similar to SysIII from at least as
far back as 1990.

The way to save and restore it was always to store that output
without the trailing newline characters, which in a shell can be
done with:

saveterm=$(stty -g)

And to restore it:

stty "$saveterm"

The "--" being unnecessary because the output of stty -g never
starts with "-" and with some (including GNU stty) not allowed.

All the documentations of stty I've seen talk of *one* (an)
argument to be passed to stty. They don't say the output may
(let alone should) be split in any way to be passed as several
arguments to stty.

In the unlikely event that there are indeed stty implementations
that require the output of stty -g to be split into arguments
before being fed back to stty, we'd need to specify how those
are meant to be split.
Desired Action Change the description of the -g option to something like:

-g

    Write to standard output all the current settings,
    optionally excluding the terminal window size, in an
    unspecified form that, when stripped of trailing newline
    characters, and used as the one and only argument to another
    invocation of the stty utility on the same system, attempts
    to apply those settings to the terminal. The form used shall
    consist of one line of text consisting of only printable
    characters from the portable character set, excluding
    whitespace characters, NUL, and all characters that are
    special in the syntax of the sh language
    (`"$&*()[]{};'#~?<>\|).

    (alternatively, specify it as the
    ^[[:alnum:]][[:alnum:]=]*:[[:alnum:]=:]*\n
    extended regexp in the C locale.)

A clarifying example would help like:

saveterm=$(stty -g)

and:

[ -n "$saveterm" ] && stty "$saveterm"
[ -n "$saveterm" ] && stty $saveterm
eval "${saveterm:+stty $saveterm}"

Are three ways the settings may be restored, the first one
being the canonical one and the last one assuming none of the
characters allowed in the stty -g output are currently present
in $IFS (and therefore not recommended).

The example should be changed to

saveterm=$(stty −g) # save terminal state
restoresize=$(
  stty size | awk '{printf "stty rows %d cols %d", $1, $2}'
) # save terminal size
stty new settings # set new state
...
[ -n "$saveterm" ] && stty "$saveterm" # restore terminal state
eval "$ttysize" # restore terminal size

Also using awk instead of shell IFS-splitting+globbing as as
discussed on the mailing list, $IFS is not guaranteed to contain
all the blank characters in the locale (and anyway yash is the
only shell that considers multi-byte blanks as
IFS-whitespace-characters wrt IFS-splitting), while awk is
required to split fields on blanks (even though not all
implementations do).
Tags No tags attached.
Attached Files

- Relationships

-  Notes
(0005513)
stephane (reporter)
2021-11-03 14:23

Sorry, a few typos above.

"It was outputting on word on one line made" should be "It was outputting one word on one line made"

The regexp was intended to be

^[[:alnum:]][[:alnum:]=]*:[[:alnum:]=:]*\n$

(starts with an alnum, contains at least 1 ":" and contains only alnums, ":" or "=" characters).

In:

> [ -n "$saveterm" ] && stty "$saveterm"
> [ -n "$saveterm" ] && stty $saveterm
> eval "${saveterm:+stty $saveterm}"

It's the second, not last that is dependant on IFS and should be avoided.
(0005514)
stephane (reporter)
2021-11-03 14:51
edited on: 2021-11-03 14:51

> The reference to 2.6 suggests maybe "sh" should be involved to
> perform that splitting. It almost suggests that the output
> should be appended to "stty ", or possibly "stty -- " and fed to
> sh as in (printf "stty -- "; stty -g) | sh

That however wouldn't work as sh's stdin would then be a pipe and not the terminal . Not to mention the fact that if stty -g fails, the code becomes "stty " or "stty --" which requests tty settings.

Also, in:

> The form used shall
> consist of one line of text consisting of only printable
> characters from the portable character set, excluding
> whitespace characters, NUL, and all characters that are
> special in the syntax of the sh language
> (`"$&*()[]{};'#~?<>\|).

Since I've added "printable" (with the intention of excluding control characters) and "line of text", the "NUL, " is redundant.

(0005515)
stephane (reporter)
2021-11-03 16:01

Also, on a not totally related note, IMO it's undesirable that stty "$saveterm" should restore the cols and rows settings.

In the now most common case of stty being used inside a terminal emulator in some windowing system, the rows and cols are typically being changed on the master side of the pty pair by the terminal emulator when the window of that emulator is resized.

The almost only use cases of "stty rows y cols x" is to fix those tty settings so they match those of the terminal when they are incorrect.

While the general use case for "stty -g" is so one can temporarily disable local echo or icanon while input is taken from the user. And the user could very well resize their terminal whilst they're being prompted for some input, and you don't want stty "$saveterm" to render "rows" and "cols" incorrect afterwards by restoring cols/rows from before the time the terminal window was resized.

If we allow implementations to restore the saved cols/rows upon stty "$saveterm", that means we now have to write:

{
  saveterm=$(stty -g)
  stty -echo
  printf 'Password: '
  IFS= read -r passwd
  printf '\n'

  restoresize=$(
    stty size | awk '{printf "stty rows %d cols %d", $1, $2}'
  )
  if [ -n "$saveterm" ]; then
    stty "$saveterm" # restore terminal state which may break cols/rows
    eval "$restoresize" # restore terminal size potentially broken by stty above
  fi
} 0<> /dev/tty >&0 2>&0


(which does have a race condition) to prompt for a password instead of just:

{
  saveterm=$(stty -g)
  stty -echo
  printf 'Password: '
  IFS= read -r passwd
  printf '\n'
  if [ -n "$saveterm" ]; then
    stty "$saveterm"
  fi
} 0<> /dev/tty >&0 2>&0
(0005516)
stephane (reporter)
2021-11-03 16:04

Sorry again, yet another typo in my initial submission:

> saveterm=$(stty −g) # save terminal state
> restoresize=$(
> stty size | awk '{printf "stty rows %d cols %d", $1, $2}'
> ) # save terminal size
> stty new settings # set new state
> ...
> [ -n "$saveterm" ] && stty "$saveterm" # restore terminal state
> eval "$ttysize" # restore terminal size


Should be eval "$restoresize"

- Issue History
Date Modified Username Field Change
2021-11-03 14:15 stephane New Issue
2021-11-03 14:15 stephane Name => Stephane Chazelas
2021-11-03 14:15 stephane User Reference => 0001053
2021-11-03 14:15 stephane Section => stty utility
2021-11-03 14:23 stephane Note Added: 0005513
2021-11-03 14:51 stephane Note Added: 0005514
2021-11-03 14:51 stephane Note Edited: 0005514
2021-11-03 16:01 stephane Note Added: 0005515
2021-11-03 16:04 stephane Note Added: 0005516


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