Why does my LD_LIBRARY_PATH get unset launching terminal?

15,479

Solution 1

The terminal binary is most likely setgid to group utmp. Setuid and setgid binaries unset LD_LIBRARY_PATH for security reasons; see ld.so(8):

The necessary shared libraries needed by the program are searched for in the following order

  • Using the environment variable LD_LIBRARY_PATH (LD_AOUT_LIBRARY_PATH for a.out programs). Except if the executable is a setuid/setgid binary, in which case it is ignored.

Solution 2

bash will use different start-up scripts depending on how it is started. There are seven different ways to start it, but the most important are login shells versus non-login interactive shells.

Check out the bash manual for more details. I would suspect the /etc/profile or the ~/.bash_profile is doing something to reset the LD_LIBRARY_PATH variable.


Edit: I think you have done all you reasonably can to show that bash does not have any startup script that unsets LD_LIBRARY_PATH. It is time to bring out the big guns.

The following command will display the entire environment as each process starts up, from bash to xterm, and anything else that happens to be involved -- you will probably get a large amount of output, so saving the output to a file is a good idea.

strace -v -f -e trace=process -o strace_output.txt envrun.sh xterm

Now, the file strace_output.txt will show each system call made by your script and every child process, and you will be able to see which process was the last to have LD_LIBRARY_PATH before it got removed.

Solution 3

In the terminal (xterm, aterm etc), check how the shell was invoked: A login shell will show "-bash" and a non-login shell will show "bash" when you call echo $0.

$ echo $0
-bash
$ bash
$ echo $0
bash

A login bash shell will read the following in order:

  1. /etc/profile
  2. ~/.bash_profile
  3. ~/.bash_login
  4. ~/.profile

Check if any of these files exist, and if they reset the variable. You'll also have to follow any files these files include.

If bash is not invoked as a login shell, it will still read the below files if is determined to be an interactive shell.

  1. /etc/bash.bashrc
  2. ~/.bashrc

A simple way to determine the kind of bash shell being invoked is to define your .bash_profile and .bashrc, and echo "Login shell" and "Interactive shell" respectively.

Once you know the kind of shell being invoked, you have the option of adding your script to the .bashrc or .bash_profile file in your home directory. Alternatively, you can disable the reset of LD_LIBRARY_PATH.

Note that if your .bashrc or .bash_profile is protected by a guard similar to the one below, you might have to call your script outside of it:

if [ "X$BASH_SOURCED" != "XYES" ]; then
        export BASH_SOURCED=YES

fi

Such guards are normally placed to prevent a script being sourced multiple times in a session.

Edit: If it is proving tedius to track down where the variable is being reset, and you have access to /etc/profile or /etc/bash.bashrc for example, you can temporarily add "set -x" near the top of the script to see all the commands that get executed. The output will be pretty verbose, so first do a "set -x" in your shell and run a few commands so you know what to expect.

Solution 4

(This question is very old, but I just encountered the same problem, and am documenting the solution for posteriority:)

I've had this problem with GNU screen (the terminal multiplexer), but it can as well happen with a regular terminal. Teddy was right in my case, screen has setguid set.

$ ls -l /usr/bin/screen
-rwxr-sr-x 1 root 84 361016 Mar 30  2011 /usr/bin/screen
      ^

My solution was to save LD_LIBRARY_PATH before execution, and restoring it afterwards. So I created a wrapper ~/bin/screen (put ~/bin on PATH), with the following contents:

#!/bin/bash

# somehow, screen resets LD_LIBRARY_PATH.
# save it here, and restore it in .bashrc
export PRESERVE_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
/usr/bin/screen "$@"

and then made it executable with chmod +x ~/bin/screen. You might have to open a new shell to get it to pick up the wrapper.

Then I added the following to ~/.bashrc . Remember ~/.bashrc gets sourced every time you start bash, unlike ~/.bash_profile which only gets sourced at login (usually at startup, or when you login over ssh).

if [[ "$PRESERVE_LD_LIBRARY_PATH" != "" ]]; then
    export LD_LIBRARY_PATH="$PRESERVE_LD_LIBRARY_PATH"
    #echo "restored LD_LIBRARY_PATH"
    export -n PRESERVE_LD_LIBRARY_PATH
fi

Now screen (or aterm, xterm, ... just substitute it above) should preserve $LD_LIBRARY_PATH as wanted.

Share:
15,479

Related videos on Youtube

Jack
Author by

Jack

BSc in Computer Programming.

Updated on September 17, 2022

Comments

  • Jack
    Jack over 1 year

    I have a shell script to set up some environment variables and launch whatever program I send in as an argument:

    export PATH=$HOME/local/bin:$PATH
    export LD_LIBRARY_PATH=$HOME/local/lib:$LD_LIBRARY_PATH
    export TESTER="MY TEST VAR"
    
    $@
    

    When I use this to call bash for example it works:

    kjfletch@flatbed:~$ envrun.sh bash
    kjfletch@flatbed:~$ echo $LD_LIBRARY_PATH
    /home/kjfletch/local/lib:
    kjfletch@flatbed:~$ echo $TESTER
    MY TEST VAR
    

    When I use it to call a terminal (xterm, aterm, ...) my LD_LIBRARY_PATH gets unset:

    kjfletch@flatbed:~$ echo $LD_LIBRARY_PATH
    
    kjfletch@flatbed:~$ echo $TESTER
    
    MY TEST VAR
    

    Why does this happen? How can I stop this? (I am running Debian 5.0)

    Update

    My terminal is not calling bash as a login:

    kjfletch@flatbed:~$ echo $0
    bash
    

    My LD_LIBRARY_PATH does not show up in any of the bash startup files (apart from .bash_history and ~/.profile does not exist.):

    kjfletch@flatbed:~$ grep "LD" ~/.bash*
    kjfletch@flatbed:~$ grep "LD" /etc/bash.bashrc 
    kjfletch@flatbed:~$ grep "LD" /etc/profile 
    
    • DrColossos
      DrColossos over 14 years
      Are any of those startup files calling the "source" command or the "." command to bring in other startup scripts? If so, one of those may be the culprit.
    • DevSolar
      DevSolar almost 12 years
      Does not answer your question, but the really good thing would be to get rid of the need for LD_LIBRARY_PATH (reasons: 1 2 3). You could, for example, edit /etc/ld.so.conf, or compile whatever user-defined libs you have in ~/local in a way that they know where to find their libraries (see the links I gave).
  • Jack
    Jack over 14 years
    This was my original thought. After much searching there is nothing to be found. I have the benefit of having a very clean (NEW) $HOME.
  • Jack
    Jack over 14 years
    +1 Thanks for the info. I have updated my OP in response to your answer.
  • Jack
    Jack over 14 years
    I will have to resort to this I think. I will probably source my environment variables in both .xinitrc so my window manager has them, and in .bashrc so that my terminal windows will have them.
  • Admin
    Admin over 14 years
    Do you see the same behaviour if you enter a new bash shell on the same terminal by typing bash? Btw, you'll also need to check files that are called from within /etc/bash.bashrc and /etc/profile - one of those might unset the variable. Alternatively, use the set -x debug option to get a dump of everything that gets done from the time the shell is created.
  • Jack
    Jack over 14 years
    The set -x dump makes no reference to LD_LIBRARY_PATH. Phantom unset.
  • nandhp
    nandhp almost 11 years
    You can also restore LD_LIBRARY_PATH in .screenrc (instead of .bashrc): setenv LD_LIBRARY_PATH "$PRESERVE_LD_LIBRARY_PATH" followed by unsetenv PRESERVE_LD_LIBRARY_PATH