sorry for the delay, this is another mail that I meant to take a look
earlier...

On 2023/05/29 16:36:45 +0000, Lucas <lu...@sexy.is> wrote:
> Ping.
> 
> > Hi tech@,
> > 
> > Both test.1 and ksh.1 (under the non-POSIX compatibility flag) state
> > that `test -t` will default to test whether fd 1 is a TTY if the
> > argument is omitted. This isn't the case, and both treat `-t` as the
> > equivalent of `test -n -t`, ie, test if `-t` is a non-empty string,
> > trivially true.
> > 
> > It's easy to see it in `test`: it exits right away in switch(argc).

agreed.  The "(default 1)" in test.1 is completely wrong.

> > `ksh` is a bit more difficult to follow: builtins eventually call c_test
> > in c_test.c. For `test -t`, c_test will be called with wp being "test",
> > "-t". It'll eventually call test_parse, with the test environment set
> > with
> > 
> >     te.pos.wp = wp + 1;
> >     te.wp_end = wp + argc;
> > 
> > For this particular case, argc is 2. Bearing that in mind, test_parse
> > will make a call stack of test_aexpr -> test_oexpr -> test_nexpr ->
> > test_primary. The first 2 ifs are skipped (asuming no TEF_ERROR is set)
> > and the next if, which would handle `test -t` gracefully, isn't entered:
> > one of the && operands, &te->pos.wp[1] < te->wp_end, is false.
> > Afterwards, `-t` is evaled as TO_SNTZE, ie if it's a non-empty string.

Agree on this too.

> > The following diff amends the manpages, removing the "file descriptor
> > is optional" parts, and removes the unused machinery of bin/ksh/c_test.c
> > to deal with an optional argument in `test -t`,

for what is worth I agree with you.  It's a historic behaviour that
has been broken for some time already and noone seems to have noticed,
I think it could go away.

> > together with a small
> > rewrite in test_eval TO_FILTT case, as it was a bit too difficult for me
> > to read: it seems that, for legacy reason (haven't looked at the code
> > history), opnd1 could be NULL for TO_FILTT, the only test with such
> > behaviour. My understanding is that ptest_getopnd avoids that by
> > returning "1". So, opnd1 can't be NULL. bi_getn writes to res, but took
> > me a while to understand that looking only at the conditional call of
> > bi_getn in the if condition. Finally, for some reason, is opnd1 managed
> > to be NULL, isatty(0) is called. I believe that the intention was to do
> > 
> >     res = opnd1 ? isatty(res) : 0;
> > 
> > instead. I think the proposed rewrite is easier to follow.

I think that the rewrite is more complex than needed.  I'm attaching a
slightly revised diff that is closer to the current code.

> > Regress is happy, although nothing in there tests `test -t` or `test -t
> > n`. Existing scripts shouldn't break with this change: `test -t` will
> > keep being true, whether fd 1 is a TTY or not. The diff can be further
> > split on man changes and code changes if needed.
> > 
> > btw, the easy test for `test -t` being wrong, whether under POSIX compat
> > or not, is
> > 
> >     $ test -t 1; echo $? # 1 is TTY in an interactive session
> >     0
> >     $ test -t 1 >&-; echo $? # 1 isn't a TTY because it's closed
> >     1
> >     $ test -t >&-; echo $?
> >     0

bash and ash behave the same out-of-the-box (i.e. without any eventual
posix flag set.)

I'd prefer some more feedback on this before going on.

diff /usr/src
commit - 15eb8637ab039139400e655284e2e2d8ca898a03
path + /usr/src
blob - 7038a52bfa432d515d9683187930407c4d6bd6d5
file + bin/ksh/c_test.c
--- bin/ksh/c_test.c
+++ bin/ksh/c_test.c
@@ -156,12 +156,6 @@ c_test(char **wp)
                        }
                        if (argc == 1) {
                                opnd1 = (*te.getopnd)(&te, TO_NONOP, 1);
-                               /* Historically, -t by itself test if fd 1
-                                * is a file descriptor, but POSIX says its
-                                * a string test...
-                                */
-                               if (!Flag(FPOSIX) && strcmp(opnd1, "-t") == 0)
-                                   break;
                                res = (*te.eval)(&te, TO_STNZE, opnd1,
                                    NULL, 1);
                                if (invert & 1)
@@ -271,14 +265,11 @@ test_eval(Test_env *te, Test_op op, const char *opnd1,
        case TO_FILGZ: /* -s */
                return stat(opnd1, &b1) == 0 && b1.st_size > 0L;
        case TO_FILTT: /* -t */
-               if (opnd1 && !bi_getn(opnd1, &res)) {
+               if (!bi_getn(opnd1, &res)) {
                        te->flags |= TEF_ERROR;
-                       res = 0;
-               } else {
-                       /* generate error if in FPOSIX mode? */
-                       res = isatty(opnd1 ? res : 0);
+                       return 0
                }
-               return res;
+               return isatty(res);
        case TO_FILUID: /* -O */
                return stat(opnd1, &b1) == 0 && b1.st_uid == ksheuid;
        case TO_FILGID: /* -G */
@@ -527,7 +518,7 @@ ptest_getopnd(Test_env *te, Test_op op, int do_eval)
 ptest_getopnd(Test_env *te, Test_op op, int do_eval)
 {
        if (te->pos.wp >= te->wp_end)
-               return op == TO_FILTT ? "1" : NULL;
+               return NULL;
        return *te->pos.wp++;
 }
 
blob - cd3bfc3ebf41217b46c69eaff634cd8e9771c425
file + bin/ksh/ksh.1
--- bin/ksh/ksh.1
+++ bin/ksh/ksh.1
@@ -2569,20 +2569,6 @@ a i in 1 2; do echo i=$i j=$j; done
 alias a='for ' i='j'
 a i in 1 2; do echo i=$i j=$j; done
 .Ed
-.It
-.Ic test .
-In POSIX mode, the expression
-.Sq Fl t
-(preceded by some number of
-.Sq \&!
-arguments) is always true as it is a non-zero length string;
-in non-POSIX mode, it tests if file descriptor 1 is a
-.Xr tty 4
-(i.e. the
-.Ar fd
-argument to the
-.Fl t
-test may be left out and defaults to 1).
 .El
 .Ss Strict Bourne shell mode
 When the
@@ -3857,18 +3843,12 @@ is not empty.
 .It Fl s Ar file
 .Ar file
 is not empty.
-.It Fl t Op Ar fd
+.It Fl t Ar fd
 File descriptor
 .Ar fd
 is a
 .Xr tty 4
 device.
-If the
-.Ic posix
-option is not set,
-.Ar fd
-may be left out, in which case it is taken to be 1 (the behaviour differs due
-to the special POSIX rules described above).
 .It Fl u Ar file
 .Ar file Ns 's
 mode has the setuid bit set.
blob - 6af8fcb71493c1802546069662c36ae7e97b458f
file + bin/test/test.1
--- bin/test/test.1
+++ bin/test/test.1
@@ -153,7 +153,7 @@ is
 True if the file whose file descriptor number
 is
 .Ar file_descriptor
-(default 1) is open and is associated with a terminal.
+is open and is associated with a terminal.
 .It Fl u Ar file
 True if
 .Ar file

Reply via email to