Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 11 Jun 2025 15:32:51 +0000
From:      bugzilla-noreply@freebsd.org
To:        bugs@FreeBSD.org
Subject:   [Bug 287451] [/bin/ls] readdir() errors delivered via fts_children() are silently discarded
Message-ID:  <bug-287451-227@https.bugs.freebsd.org/bugzilla/>

index | next in thread | raw e-mail

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=287451

            Bug ID: 287451
           Summary: [/bin/ls] readdir() errors delivered via
                    fts_children() are silently discarded
           Product: Base System
           Version: 15.0-CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: bin
          Assignee: bugs@FreeBSD.org
          Reporter: no.spam.c@mail.ru

Hello.

# Problem

When running the 'ls' command against an unreadable directory, its exit code is
zero, and no read error is printed.

Example:

root@testhost:~ # mount | grep -F /mnt
/dev/da1p1.eli on /mnt (ufs, local, soft-updates)
root@testhost:~ # ls /mnt
.snap   test    test2
root@testhost:~ # ls /mnt/test2
1.txt
root@testhost:~ # ls /mnt/test
root@testhost:~ # echo $?
0
root@testhost:~ # truss ls -l /mnt/test/ 2>&1 | tail
fstat(4,{ mode=drwxr-xr-x ,inode=98304,size=26624,blksize=32768 }) = 0 (0x0)
fchdir(0x4)                                      = 0 (0x0)
getdirentries(4,0x5743bd843000,4096,0x5743bd840028) ERR#97 'Integrity check
failed'
close(4)                                         = 0 (0x0)
fchdir(0x3)                                      = 0 (0x0)
fstat(1,{ mode=p--------- ,inode=708,size=0,blksize=4096 }) = 0 (0x0)
total 0
write(1,"total 0\n",8)                           = 8 (0x8)
exit(0x0)                                       
process exit, rval = 0
root@testhost:~ # 

Compare this to the 'find' command (which reports the error properly):

root@testhost:~ # find /mnt/
/mnt/
/mnt/.snap
/mnt/test
find: /mnt/test: Integrity check failed
/mnt/test2
/mnt/test2/1.txt
root@testhost:~ # echo $?
1
root@testhost:~ # 

# Root cause

The bug is in 'bin/ls/ls.c':

static void
traverse(int argc, char *argv[], int options)
{
        FTS *ftsp;
        FTSENT *p, *chp;
        int ch_options;

        if ((ftsp =
            fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL)
                err(1, "fts_open");

        [...]

        chp = fts_children(ftsp, 0);
        if (chp != NULL)
                display(NULL, chp, options);
        if (f_listdir) {
                fts_close(ftsp);
                return;
        }

        [...]

        while (errno = 0, (p = fts_read(ftsp)) != NULL)
                switch (p->fts_info) {
                case FTS_DC:
                        [...]
                        break;
                case FTS_DNR:
                case FTS_ERR:
                        [...]
                        break;
                case FTS_D:
                        if (p->fts_level != FTS_ROOTLEVEL &&
                            p->fts_name[0] == '.' && !f_listdot)
                                break;

                        [...]

                        chp = fts_children(ftsp, ch_options); // BUG!
                        display(p, chp, options);

                        [...]
                        break;
                default:
                        break;
                }
        if (errno) // 'errno' is 0 after the loop!
                err(1, "fts_read");
        fts_close(ftsp);
}

The second call to 'fts_children()' returns NULL and 'errno' is set to a
non-zero value, but it's not checked in the code.

Subsequent calls (i.e., to 'fts_read()' in the while loop) reset the 'errno'
value, so it becomes zero after the loop.

-- 
You are receiving this mail because:
You are the assignee for the bug.

home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-287451-227>