On Sat, 4 Mar 2017, Conrad Meyer wrote:

Author: cem
Date: Sat Mar  4 22:38:10 2017
New Revision: 314685
URL: https://svnweb.freebsd.org/changeset/base/314685

Log:
 ps(1): Only detect terminal width if stdout is a tty

 If stdout isn't a tty, use unlimited width output rather than truncating to
 79 characters.  This is helpful for shell scripts or e.g., 'ps | grep foo'.

This breaks many interactive uses, e.g., 'ps l | less', to work around a
user error.

If the user wants an unlimited width, then they should have asked for it
using -ww (-w only increases the width to 131 if it was smaller).

Shell scripts should be especially careful to use the right options...

 This hardcoded width has some history: In The Beginning of History[0], the
 width of ps was hardcoded as 80 bytes.  In 1985, Bloom@ added detection
 using TIOCGWINSZ on stdin.[1]  In 1986, Kirk merged a change to check
 stdout's window size instead.  In 1990, the fallback checks to stderr and
 stdin's TIOCGWINSZ were added by Marc@, with the commit message "new
 version."[2]

 OS X Darwin has a very similar modification to ps(1), which simply sets
 UNLIMITED for all non-tty outputs.[3]  I've chosen to respect COLUMNS
 instead of behaving identically to Darwin here, but I don't feel strongly
 about that.  We could match OS X for parity if that is desired.

Ignoring COLUMNS would break it completely.  COLUMNS is the only way to
control the width.  Interactive use normally wants the width of the current
terminal, but shell scripts might want to create a file to be read on a
different terminal, or just back on the same terminal where the script
cannout know about the current terminal because it is purely non-interactive
(see comments below about checking all 3 std fd's consistently).

 [0]: https://svnweb.freebsd.org/csrg/bin/ps/ps.c?annotate=1065
 [1]: https://svnweb.freebsd.org/csrg/bin/ps/ps.c?r1=18105&r2=18106
 [2]:
 https://svnweb.freebsd.org/csrg/bin/ps/ps.c?r1=40675&r2=40674&pathrev=40675
 [3]:
 https://opensource.apple.com/source/adv_cmds/adv_cmds-168/ps/ps.c.auto.html

 PR:            217159
 Reported by:   Deepak Nagaraj <n.deepak at gmail.com>

Modified:
 head/bin/ps/ps.c

Modified: head/bin/ps/ps.c
==============================================================================
--- head/bin/ps/ps.c    Sat Mar  4 22:23:59 2017        (r314684)
+++ head/bin/ps/ps.c    Sat Mar  4 22:38:10 2017        (r314685)
@@ -194,6 +194,8 @@ main(int argc, char *argv[])

        if ((cols = getenv("COLUMNS")) != NULL && *cols != '\0')
                termwidth = atoi(cols);
+       else if (!isatty(STDOUT_FILENO))
+               termwidth = UNLIMITED;
        else if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
             ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
             ioctl(STDIN_FILENO,  TIOCGWINSZ, (char *)&ws) == -1) ||

For use in shell scripts, the user should know too much about COLUMNS.
COLUMNS is set automatically by some shells, but not exported, so it
is not normally set here.  But shell scripts should worry about the
effects of environment variables.  Hard-coded -ww would cancel the
setting of termwidth here.  This is the easiest way to blow away the
user's setting  of COLUMNS.  Security-related scripts should do this.
But most scripts should honor the setting.  The use might actually
want the setting to affect ps in the script.

It is probably wrong to check only stdout.  ps is only clearly not
associated with a terminal if all 3 std fd's are not terminals.

If there was a bug in the old version, then it was that the default
is chosen too magically, so no one can remember how to control it.

  (Even simple use of isatty() gives that problem, and causes a
  larger problem in practice -- stdio gives line-buffered output
  which is best for interactive use, but as soon as you pipe the
  output though less it becomes fully buffered and is often delayed
  too long.  Some utilities have an option to give line-buffered
  output (e.g., -l for tcpdump), but most don't, and I can rarely
  remember if they do.)

The problem is not really different for shell scripts.  ps in a shell
script still uses the terminal width if the script outputs to a
terminal.  But if you pipe through less so that you can actually read
the output before it scrolls off, then it magically becomes wide,
unless you remember the COLUMNS variable, and export it, and the script
honors it.  This shows why it is indeed wrong to not check all 3 std
fd's.  Both 'ps | less' and 'script-doing-ps | less' are interactive
uses if they are started on a terminal, since stdin is still a terminal
and so is stderr since you forgot to pipe it to less.  The width should
not change in this case.

  (stdio only does isatty() on the fd of the current stream to set the
  default for line buffering.  It would be too magical for it to check
  other fd's, especially when the current fd is not a std one.  I think
  the unwanted full buffering for most utilities when they are piped
  through less to a terminal results from this.  They just use stdio,
  and it doesn't know the context, so it correctly doesn't adjust the
  magic.  Then most utilities don't know about using setvbuf() to
  adjust the magic to their context, and they really shouldn't know
  if the output is a pipe...)

top(1) has a related non-problem with the default length.  For the non-
interactive use 'top >file', you normally want to see more lines than
fit on the terminal and a probably doing this to see them.  But
the length doesn't change by default.  It is a user error to not use
the option to change it.

Bruce
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to