Better error message if dynamic linking fails

197 Views Asked by At

I get this error if dynamic linking fails:

/ # /manager
/bin/sh: /manager: not found

For the average user this is very confusing, because /manager exists.

Now, after searching for some hours, I found that I can debug it like this to get a better error message:

> / # ldd /manager
        /lib64/ld-linux-x86-64.so.2 (0x7f6f93f09000)
Error loading shared library libresolv.so.2: No such file or directory (needed by /manager)
        libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7f6f93f09000)
        libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7f6f93f09000)

I would like to have a better error message.

Something like:

/ # /manager
/bin/sh: /manager: Error loading shared library libresolv.so.2: No such file or directory (needed by /manager)

If this is not possible, then a generic error message would be nice:

/ # /manager
/bin/sh: /manager: loading a shared library failed.

This would help a lot of people on this planet.

Now my question to the kernel experts:

Is it possible to get a patch into the related source code, so that in future users get a better error message?

This is a container image based on alpine.

Sub-question: Where is the related source code?

3

There are 3 best solutions below

0
Emilio Silva On

The error code ENOENT, corresponding to the message not found, is coming directly from the kernel, via the execve(2) syscall. From the man page:

ENOENT

The file filename or a script or ELF interpreter does not exist, or a shared library needed for file or interpreter cannot be found.

It cannot be "fixed" at the kernel level, or at the libc level, because that would break a well-known interface.

If the shell is Bash, it is giving you this message after calling execve(2) from a function called shell_execve(), in file execute_cmd.c. Some relevant code:

execve (command, args, env);
i = errno; /* this would be ENOENT */

if (executable_file (command) == 0)
    {
      errno = i;
      file_error (command); /* No such file or directory */
    }
else if (i == ENOENT)
  {
    errno = i;
    internal_error (_("%s: cannot execute: required file not found"), command);
  }

The best place to patch and include a better message is right there.

Bash already tries to improve the message. If the file did not exist, the message would be "No such file or directory". When the file exists and is executable, the message changes to "required file not found", which is closer to what you want. If the required file were the interpreter, the message would change to "bad interpreter".

So, you could add "check whether all dynamic libraries exist using ldd" to the existing message. To know which library, you would need to bring some code from ldd(1).

I do not know what is your shell, but older versions of Bash would just return "No such file or directory", as you are getting.

0
Krab On

You can always work around it with a shell script. You can test for file existence and then check if the libraries can be loaded.

Here's an explanation how to find out. https://unix.stackexchange.com/questions/481250/ldd-equivalent-which-fail-when-library-not-found

I understand you deploy just a single file, but adding a script may be simpler than patching kernel.

1
user2679290 On

You could try to run it, if it fails, then run ldd and print the error. Something along the lines of:

/manager
if [ $? -eq 2 ]; then

err= $(ldd /manager 2>&1 | grep "Error loading shared library")

if [ -z $err ]; 
then echo "ENOENT error, unspecified reason"; 
else echo $err;   
fi 
 
fi