coreutils icon indicating copy to clipboard operation
coreutils copied to clipboard

ls: -l renders additional +

Open AleksaBajat opened this issue 6 months ago • 1 comments

On Fedora (on Arch tests work as intended) native ll doesn't print + in the end, coreutils ls -l does. It seems that . is replaced with + on Fedora.

thread 'test_ls::test_ls_long_format' panicked at tests/by-util/test_ls.rs:1148:62:
Stdout does not match regex:
total 0
drwxr-xr-x+ 3 1000 1000 80 Jun 28 17:58 .
drwxr-xr-x+ 3 1000 1000 60 Jun 28 17:58 ..
drwxr-xr-x+ 2 1000 1000 40 Jun 28 17:58 test-long-dir
-rw-r--r-- 1 1000 1000  0 Jun 28 17:58 test-long-file

failures:
    test_ls::test_ls_color_norm
    test_ls::test_ls_inode
    test_ls::test_ls_long_format
    test_ls::test_ls_long_formats

Native ll output:

~/Documents/projects/coreutils (main) » ll                                                                                                                                                            abajat@fedora
total 248K
-rw-r--r--. 1 abajat abajat 4.6K Jun 28 18:11 build.rs
-rw-r--r--. 1 abajat abajat 102K Jun 27 05:52 Cargo.lock
-rw-r--r--. 1 abajat abajat  26K Jun 28 16:25 Cargo.toml
-rw-r--r--. 1 abajat abajat 5.2K Jun 24 14:51 CODE_OF_CONDUCT.md
-rw-r--r--. 1 abajat abajat  14K Jun 24 14:51 CONTRIBUTING.md
-rw-r--r--. 1 abajat abajat  229 Jun 24 14:51 Cross.toml
-rw-r--r--. 1 abajat abajat 4.4K Jun 24 14:51 deny.toml
-rw-r--r--. 1 abajat abajat  12K Jun 24 14:51 DEVELOPMENT.md
drwxr-xr-x. 1 abajat abajat  140 Jun 24 14:51 docs
-rw-r--r--. 1 abajat abajat  980 Jun 24 14:51 flake.lock
-rw-r--r--. 1 abajat abajat 2.0K Jun 24 14:51 flake.nix
drwxr-xr-x. 1 abajat abajat   96 Jun 28 16:25 fuzz
-rw-r--r--. 1 abajat abajat  11K Jun 24 14:51 GNUmakefile
-rw-r--r--. 1 abajat abajat 1.1K Jun 24 14:51 LICENSE
-rw-r--r--. 1 abajat abajat   55 Jun 24 14:51 Makefile
-rw-r--r--. 1 abajat abajat  11K Jun 24 14:51 Makefile.toml
-rw-r--r--. 1 abajat abajat  306 Jun 24 14:51 oranda.json
-rw-r--r--. 1 abajat abajat 7.9K Jun 24 14:51 README.md
-rw-r--r--. 1 abajat abajat 1.2K Jun 24 14:51 README.package.md
-rw-r--r--. 1 abajat abajat   44 Jun 24 14:51 renovate.json
drwxr-xr-x. 1 abajat abajat   72 Jun 24 14:51 src
drwxr-xr-x. 1 abajat abajat  112 Jun 27 07:37 target
drwxr-xr-x. 1 abajat abajat  108 Jun 24 14:51 tests
drwxr-xr-x. 1 abajat abajat  834 Jun 24 14:51 util

Coreutils ls -l output:

~/Documents/projects/coreutils (main) » ./target/debug/coreutils ls -l                                                                                                                                 abajat@fedora
total 248
-rw-r--r--+ 1 abajat abajat   5227 Jun 24 14:51 CODE_OF_CONDUCT.md
-rw-r--r--+ 1 abajat abajat  14064 Jun 24 14:51 CONTRIBUTING.md
-rw-r--r--+ 1 abajat abajat 103770 Jun 27 05:52 Cargo.lock
-rw-r--r--+ 1 abajat abajat  26301 Jun 28 16:25 Cargo.toml
-rw-r--r--+ 1 abajat abajat    229 Jun 24 14:51 Cross.toml
-rw-r--r--+ 1 abajat abajat  11565 Jun 24 14:51 DEVELOPMENT.md
-rw-r--r--+ 1 abajat abajat  10886 Jun 24 14:51 GNUmakefile
-rw-r--r--+ 1 abajat abajat   1056 Jun 24 14:51 LICENSE
-rw-r--r--+ 1 abajat abajat     55 Jun 24 14:51 Makefile
-rw-r--r--+ 1 abajat abajat  10264 Jun 24 14:51 Makefile.toml
-rw-r--r--+ 1 abajat abajat   8081 Jun 24 14:51 README.md
-rw-r--r--+ 1 abajat abajat   1222 Jun 24 14:51 README.package.md
-rw-r--r--+ 1 abajat abajat   4670 Jun 28 18:11 build.rs
-rw-r--r--+ 1 abajat abajat   4503 Jun 24 14:51 deny.toml
drwxr-xr-x+ 1 abajat abajat    140 Jun 24 14:51 docs
-rw-r--r--+ 1 abajat abajat    980 Jun 24 14:51 flake.lock
-rw-r--r--+ 1 abajat abajat   2033 Jun 24 14:51 flake.nix
drwxr-xr-x+ 1 abajat abajat     96 Jun 28 16:25 fuzz
-rw-r--r--+ 1 abajat abajat    306 Jun 24 14:51 oranda.json
-rw-r--r--+ 1 abajat abajat     44 Jun 24 14:51 renovate.json
drwxr-xr-x+ 1 abajat abajat     72 Jun 24 14:51 src
drwxr-xr-x+ 1 abajat abajat    112 Jun 27 07:37 target
drwxr-xr-x+ 1 abajat abajat    108 Jun 24 14:51 tests
drwxr-xr-x+ 1 abajat abajat    834 Jun 24 14:51 util

AleksaBajat avatar Jun 28 '25 18:06 AleksaBajat

I think this is the behavior if

  • selinux is active
  • uutils is built without selinux support

Could you please rebuild with cargo build --features feat_selinux and try again?

Log from my PC

ubuntu@ubuntu-qemu:~/coreutils$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             default
Current mode:                   permissive
Mode from config file:          permissive
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     actual (secure)
Max kernel policy version:      33
ubuntu@ubuntu-qemu:~/coreutils$ cargo build && ./target/debug/coreutils ls -laZ README.md
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.26s
-rw-rw-r--+ 1 ubuntu ubuntu ? 8081 Aug 17 09:09 README.md
ubuntu@ubuntu-qemu:~/coreutils$ cargo build --features feat_selinux && ./target/debug/coreutils ls -laZ README.md
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.22s
-rw-rw-r--. 1 ubuntu ubuntu unconfined_u:object_r:user_home_t:s0 8081 Aug 17 09:09 README.md

martinkunkel2 avatar Aug 17 '25 12:08 martinkunkel2

I think this may be resolved by: https://github.com/uutils/coreutils/pull/8660 and https://github.com/uutils/coreutils/pull/8663

On Fedora (on Arch tests work as intended) native ll doesn't print + in the end, coreutils ls -l does. It seems that . is replaced with + on Fedora.

'+' is the symbol for ACLs. ls has correctness issues with ACLs and Capabilities. For instance, simply having xattrs present does not imply we have ACLs. But here is the current code:

pub fn has_acl<P: AsRef<Path>>(file: P) -> bool {
    // don't use exacl here, it is doing more getxattr call then needed
    xattr::list_deref(file).is_ok_and(|acl| {
        // if we have extra attributes, we have an acl
        acl.count() > 0
    })
}

These should be methods on PathData and we should store all xattrs like so:

pub static POSIX_ACL_ACCESS_KEY: LazyLock<OsString> =
    LazyLock::new(|| "system.posix_acl_access".into());
pub static POSIX_ACL_DEFAULT_KEY: LazyLock<OsString> =
    LazyLock::new(|| "system.posix_acl_default".into());
pub static SET_CAPABILITY_KEY: LazyLock<OsString> = LazyLock::new(|| "security.capability".into());
...

    #[cfg(all(unix, not(any(target_os = "android", target_os = "macos"))))]
    fn xattrs(&self) -> &Option<HashMap<OsString, Vec<u8>>> {
        self.xattrs
            .get_or_init(|| retrieve_xattrs(&self.p_buf, self.must_dereference).ok())
    }

    #[cfg(all(unix, not(any(target_os = "android", target_os = "macos"))))]
    fn has_acl(&self, out: &mut BufWriter<Stdout>) -> bool {
        self.xattrs()
            .as_ref()
            .and_then(|map| {
                map.get(&*POSIX_ACL_ACCESS_KEY).or_else(|| {
                    // Default ACL only applies to directories - avoid 2nd syscall here
                    // See: https://www.usenix.org/legacy/publications/library/proceedings/usenix03/tech/freenix03/full_papers/gruenbacher/gruenbacher_html/main.html
                    if self.file_type(out).map(|ft| !ft.is_dir()).unwrap_or(false) {
                        return None;
                    }

                    map.get(&*POSIX_ACL_DEFAULT_KEY)
                })
            })
            .map(|vec| !vec.is_empty())
            .unwrap_or(false)
    }

    #[cfg(all(unix, not(any(target_os = "android", target_os = "macos"))))]
    fn has_capability(&self) -> bool {
        // don't use exacl here, it is doing more getxattr call then needed
        self.xattrs()
            .as_ref()
            .and_then(|map| map.get(&*SET_CAPABILITY_KEY))
            .map(|vec| !vec.is_empty())
            .unwrap_or(false)
    }

kimono-koans avatar Sep 21 '25 18:09 kimono-koans

When one file has selinux context and another does not, the column alignment in ls -l is off. The GNU coreutils correctly aligns columns, replacing the . with a space for files with no selinux context.

$ /usr/bin/ls -l .cargo/bin/hrep tmp/earbuds
-rwxr-xr-x. 1 mng mng 3758704 Sep 25 22:44 .cargo/bin/hrep
-rw-r--r--  1 mng mng    1003 May 22 18:21 tmp/earbuds

$ coreutils ls -l .cargo/bin/hrep tmp/earbuds
-rwxr-xr-x+ 1 mng mng 3758704 Sep 25 22:44 .cargo/bin/hrep
-rw-r--r-- 1 mng mng    1003 May 22 18:21 tmp/earbuds

mousefad avatar Sep 26 '25 14:09 mousefad

When one file has selinux context and another does not, the column alignment in ls -l is off. The GNU coreutils correctly aligns columns, replacing the . with a space for files with no selinux context.

$ /usr/bin/ls -l .cargo/bin/hrep tmp/earbuds
-rwxr-xr-x. 1 mng mng 3758704 Sep 25 22:44 .cargo/bin/hrep
-rw-r--r--  1 mng mng    1003 May 22 18:21 tmp/earbuds

$ coreutils ls -l .cargo/bin/hrep tmp/earbuds
-rwxr-xr-x+ 1 mng mng 3758704 Sep 25 22:44 .cargo/bin/hrep
-rw-r--r-- 1 mng mng    1003 May 22 18:21 tmp/earbuds

I have a fix for this in one of my trees. See: https://github.com/kimono-koans/coreutils/tree/refinements

kimono-koans avatar Oct 02 '25 15:10 kimono-koans

On Fedora (on Arch tests work as intended) native ll doesn't print + in the end, coreutils ls -l does. It seems that . is replaced with + on Fedora.

@AleksaBajat would you try your luck with my PR to see if it fixes your issue?: https://github.com/uutils/coreutils/pull/8660

kimono-koans avatar Oct 02 '25 22:10 kimono-koans