7

I created some hardlinks on an NTFS drive, but because of that, they are all executable and colored as executable instead of as hardlinks (regular file with more than one link).

I did a test on my ext4 drive and it's the same problem: Any file with more than one link gets nicely highlighted when using ls --color, but as soon as it has one executable bit, it gets the "executable" coloring (bold by default, no highlighting).

I tried various LS_COLOR settings, but no change.

My current ~/.dir_colors file is simplified to this:

RESET 0
HARDLINK 44;37
#EXEC 01;32;41

And I test it with this:

eval "$(dircolors ~/.dir_colors)"; ls -l --color

The file seems to work for changing the colors, highlighting, etc, but I can't get executable hardlinks to be colored according to the HARDLINK setting.

Update: After some research, it seems that "exe coloring takes precedence". Looks like it is hardcoded into ls itself:

So the only solution would be a customized "ls", is that correct?

2
  • Yes, if it is hard coded then there is no way around that. You could try a different ls, eg the BSD ls (I looked at the busybox, LS_COLORS isn't implemented). But you will probably have to compile another ls from source anyway, if you already know the change you need to make, why not just do this to the GNU one?
    – Graeme
    Apr 4, 2014 at 15:49
  • 1
    I just did. And it does work. :) Of course, it would be nicer to have a finer color-tuning ability in the official ls.
    – KIAaze
    Apr 4, 2014 at 16:07

3 Answers 3

3

Well, after looking at the source, I had to go all the way. :)

There is currently no way of coloring hardlinked executables differently than non-hardlinked executables, other than creating a custom version of ls.

Here's how I did it on Ubuntu 10.04.4 (The problem also exists on Ubuntu 13.10, but I wasn't on that when I did it. Should be very similar though):

sudo apt-get build-dep coreutils
apt-get source coreutils
cd coreutils-7.4

Modified src/ls.c as follows:

$ diff coreutils-7.4/src/ls.c coreutils-7.4.custom/src/ls.c
4107,4108c4107,4108
<         else if ((mode & S_IXUGO) != 0)
<           type = C_EXEC;
---
> //      else if ((mode & S_IXUGO) != 0)
> //        type = C_EXEC;

Then compile everything:

debuild -us -uc -b

This command ends with an error, but it does compile a new ls in src/ls, which works as desired. :)

Alternative solutions:

  • Create an ls-equivalent script using bash or python.
  • Some aliases I was already using before to locate hard links:

    alias findHardLinkedFiles_SortByInode='find . -type f -links +1 -printf "inode=%i %s=size nlinks=%n file=%p \n" | sort -n'

    alias findHardLinkedFiles_SortBySize='find . -type f -links +1 -printf "%s=size nlinks=%n inode=%i file=%p \n" | sort -n'

How to color the terminal output:

2
  • "There is currently no way of coloring hardlinked executables differently than non-hardlinked executables" That's because every single file is hardlinked. Quoting Wikipedia: "In computing, a hard link is a directory entry that associates a name with a file on a file system.". Note a name, not another name.
    – user
    Apr 7, 2014 at 11:07
  • Thanks for posting this! It would be great if you could take a second and accept it. Accepting you answer is fine and even encouraged, and that way, the question can be shown as solved.
    – terdon
    Jun 21, 2015 at 11:09
3

Based in KIAaze answer, I came up with my custom modification: (Done in Ubuntu 14.04 with coreutils 8.21)

Install: (no change) -- be sure you have deb-src repositories enabled --

sudo apt-get build-dep coreutils
apt-get source coreutils
cd coreutils-8.21

(Keep a note on which packages were installed during the "build-dep coreutils" command, you will need them to clean up at the end).

Code modifications: (patch available here)

Added: "C_EXEC_HARDLINK" and "em":

    enum indicator_no
      {
        C_LEFT, C_RIGHT, C_END, C_RESET, C_NORM, C_FILE, C_DIR, C_LINK,
        C_FIFO, C_SOCK,
        C_BLK, C_CHR, C_MISSING, C_ORPHAN, C_EXEC, C_DOOR, C_SETUID, C_SETGID,
        C_STICKY, C_OTHER_WRITABLE, C_STICKY_OTHER_WRITABLE, C_CAP,
C_MULTIHARDLINK, C_EXEC_HARDLINK, C_CLR_TO_EOL
      };

    static const char *const indicator_name[]=
      {
        "lc", "rc", "ec", "rs", "no", "fi", "di", "ln", "pi", "so",
        "bd", "cd", "mi", "or", "ex", "do", "su", "sg", "st",
        "ow", "tw", "ca", "mh", "em", "cl", NULL
      };

Set default color:

    static struct bin_str color_indicator[] =
      {
        { LEN_STR_PAIR ("\033[") },     /* lc: Left of color sequence */
        { LEN_STR_PAIR ("m") },     /* rc: Right of color sequence */
        { 0, NULL },            /* ec: End color (replaces lc+no+rc) */
        { LEN_STR_PAIR ("0") },     /* rs: Reset to ordinary colors */
        { 0, NULL },            /* no: Normal */
        { 0, NULL },            /* fi: File: default */
        { LEN_STR_PAIR ("01;34") },     /* di: Directory: bright blue */
        { LEN_STR_PAIR ("01;36") },     /* ln: Symlink: bright cyan */
        { LEN_STR_PAIR ("33") },        /* pi: Pipe: yellow/brown */
        { LEN_STR_PAIR ("01;35") },     /* so: Socket: bright magenta */
        { LEN_STR_PAIR ("01;33") },     /* bd: Block device: bright yellow */
        { LEN_STR_PAIR ("01;33") },     /* cd: Char device: bright yellow */
        { 0, NULL },            /* mi: Missing file: undefined */
        { 0, NULL },            /* or: Orphaned symlink: undefined */
        { LEN_STR_PAIR ("01;32") },     /* ex: Executable: bright green */
        { LEN_STR_PAIR ("01;35") },     /* do: Door: bright magenta */
        { LEN_STR_PAIR ("37;41") },     /* su: setuid: white on red */
        { LEN_STR_PAIR ("30;43") },     /* sg: setgid: black on yellow */
        { LEN_STR_PAIR ("37;44") },     /* st: sticky: black on blue */
        { LEN_STR_PAIR ("34;42") },     /* ow: other-writable: blue on green */
        { LEN_STR_PAIR ("30;42") },     /* tw: ow w/ sticky: black on green */
        { LEN_STR_PAIR ("30;41") },     /* ca: black on red */
        { 0, NULL },     /* mh: HardLink: disabled by default */
        { 0, NULL },  /* em: Executable HardLink: disabled by default */
        { LEN_STR_PAIR ("\033[K") },    /* cl: clear to end of line */
      };

You can set your custom colors either above or in your .bashrc script like this:

export LS_COLORS="ln=01;36:mh=01;36:em=01;33";

see: What do the different colors mean in the terminal?

Set the priority rule:

        {
          type = C_FILE;

          if ((mode & S_ISUID) != 0 && is_colored (C_SETUID))
            type = C_SETUID;
          else if ((mode & S_ISGID) != 0 && is_colored (C_SETGID))
            type = C_SETGID;
          else if (is_colored (C_CAP) && f->has_capability)
            type = C_CAP;
          else if ((1 stat.st_nlink) && (mode & S_IXUGO) != 0 && is_colored (C_EXEC_HARDLINK))
            type = C_EXEC_HARDLINK;
          else if ((mode & S_IXUGO) != 0 && is_colored (C_EXEC))
            type = C_EXEC;
          else if ((1 stat.st_nlink) && is_colored (C_MULTIHARDLINK))
            type = C_MULTIHARDLINK;
        }

Then compile: (command must be run as user, not root)

debuild -us -uc -b

You can run the above command several times as it will clean the compilation each time (in case you want to do your own customizations).

(as stated by KIAaze, it may return an error at the end related to a test, but the "ls" command works fine).

Finally, we replace "ls":

sudo mv /bin/ls /bin/ls.orig
sudo mv src/ls /bin/ls

Cleaning up:

cd ..
rm -rf coreutils*
sudo apt-get remove <list of packages installed by 'build-dep coreutils'>
1

Personally I find the coloring of hardlinks arbitrary in the first place. I find it better to highlight the link count in the long listing when it's >= 2. You can see that in my ls wrapper script at:

http://www.pixelbeat.org/scripts/l

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .