Upgraded to Leopard : Making use of /etc/paths.d and path_helper

January 24, 2008 | In: citations

In Leopard, Apple has introduced a new mechanism for managing and maintaining your system path ($PATH).

Previously (and in most current Linux environments) paths were managed by updating the PATH environment variable directly in either the system profile (/etc/profile) or your local profile (~/.bash_profile).

Commonly you had entries like:

  export JAVA_HOME = /usr/lib/j2se/jdk1.5.0_13/
  export PATH=$PATH:$JAVA_HOME/bin
  ...

In Leopard, you no longer have to modify the profile to make adjustments to system paths. Instead, you can put a simple text file containing a path entry (or entries) into /etc/paths.d/.

Each line in this file will be interpreted as a path and added automatically to the system path.

macos-gls000120:~ ajordens$ ls -al /etc/paths.d/
total 40
drwxr-xr-x    7 root  wheel   238 Jan 22 18:51 .
drwxr-xr-x  105 root  wheel  3570 Jan 23 11:59 ..
-rw-r--r--    1 root  wheel    13 Sep 23 20:53 X11
-rw-r--r--    1 root  wheel    16 Jan 22 18:58 groovy
-rw-r--r--    1 root  wheel    15 Jan 22 18:58 maven
-rw-r--r--    1 root  wheel    20 Jan 22 18:58 postgresql
-rw-r--r--    1 root  wheel    15 Jan 22 18:58 scala

macos-gls000120:~ ajordens$ cat /etc/paths.d/scala
$SCALA_HOME/bin

It’s up to you whether you include an environment variable or specify the full path.

Enter Leopard

In order to take advantage of this new feature, your /etc/profile needs to invoke /usr/libexec/path_helper. Depending on your upgrade path to Leopard, your profile may or may not have been automatically updated.

Unfortunately mine wasn’t and I couldn’t find a definitive post telling what changes I had to make to the profile. I decided to write the procedure up so that anyone else wanting to take advantage of paths.d and path_helper could do so.

macos-gls000120:~ ajordens$ cat /etc/profile
# System-wide .profile for sh(1)

if [ "${BASH-no}" != "no" ]; then
        [ -r /etc/bashrc ] && . /etc/bashrc
fi

export ANT_OPTS="-Xmx256M"

export POSTGRESQL_HOME="/opt/local/lib/postgresql82"
export CONFBASE=/usr/local/src/confluence-2.6.2
export HADOOP_HOME=/usr/local/src/hadoop-0.15.2

export GROOVY_HOME=/usr/local/src/groovy-1.5.1
export SCALA_HOME=/usr/local/src/scala-2.6.0-final
export MAVEN_HOME=/usr/local/src/maven-2.0.7

export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/"

if [ -x /usr/libexec/path_helper ]; then
       eval `/usr/libexec/path_helper -s`
fi

That’s basically it. I put the path_helper invocation at the end of the profile because I wanted to be able to substitute environment variables.



12 Responses to Upgraded to Leopard : Making use of /etc/paths.d and path_helper

Avatar

Guillaume Laforge

January 25th, 2008 at 12:54 am

Interesting tip.
I’d be curious to know if there’s a possibility to easily switch some environment variables. Let’s say today I want to use Java 1.4 and Groovy 1.0, and that later one, working on another project, I want to use Java 5 and Groovy 1.5.
How shall I do?

Avatar

jpc

February 28th, 2008 at 3:24 pm

Adam Jordens: The only problem with your solution is that there is little improvement over hardcoded paths in /etc/profile if you hardcode the environment variables instead. ;-) The clean Leopard profile looks like this:
# >>> START
# System-wide .profile for sh(1)

if [ -x /usr/libexec/path_helper ]; then
eval `/usr/libexec/path_helper -s`
fi

if [ "${BASH-no}" != "no" ]; then
[ -r /etc/bashrc ] && . /etc/bashrc
fi
# <<< END

Similar stuff can be found in csh.login and .zprofile (I can post them if anyone is interested.

Guillaume Laforge: I would make a Java symlink pointing to Java-1.5 somewhere and only add Java/bin to the PATH (so when you switch the symlink you will run new binaries).

Avatar

ajordens

March 3rd, 2008 at 12:03 am

I agree that it’s not that much of a difference but you will only be hard-coding the paths in one location.

Personally (and prior to using paths.d in Leopard) I’d just do my all my exports and PATH setup in the /etc/profile or .bash_profile directly.

For a lot of frameworks, you will need to define a FRAMEWORK_HOME environment variable in addition to simply including it on the path. In these situations, I’d argue there’s a slight benefit.

And I agree w/ your suggestion to Guillaume, that’s a pretty standard approach to separating your VMs and is something Apple and the various Linux distros having been doing for awhile (/etc/alternatives/java, etc.).

Avatar

Jürgen

April 7th, 2008 at 11:16 am

Thanks for your post! I helped me a lot.

Avatar

Stephen

April 22nd, 2008 at 4:29 pm

I used a vanilla (unmodified) /etc/profile as it is read only for me, and just added a nice little test file called cdrtools to /etc/paths.d and it worked like a charm! All I had to do was restart my terminal app (opening a new tab would have done the trick as well I assume.

Thanks!

Avatar

Stephen

April 22nd, 2008 at 4:35 pm

Nevermind that previous comment…like a previous poster mentioned path helper is automatically initialized in the /etc/profile

Avatar

Lorin Rivers

June 24th, 2008 at 12:11 pm

What’s wacky about this whole scheme is that you have no control over load order, so if you (for example) use MacPorts, how do make /opt/local/bin be the first part of your $PATH?

Avatar

Kamil Kisiel

July 14th, 2008 at 1:37 pm

Lorin: You can add paths to /etc/paths instead, if you care about the order.

Avatar

Renato

August 2nd, 2008 at 12:35 pm

I had also the problem of wanting /usr/local/bin be first in the path before the defaults. My issue was that I wanted to override a default install of svn and use a newer installed in /usr/local/bin. But the problem is the same as for you.

I played around w/ “/etc/path.d” and edited “/etc/paths” itself adding always “/usr/local/bin/” on top but it would always get listed after the defaults.

I looked at “/etc/paths” and found the following entries:
/usr/bin
/bin
/usr/sbin
/sbin
/usr/local/bin

I had in “/etc/paths.d/” only the file “X11″ which contained one line: “/usr/X11/bin/”
doing a “set” or “echo $PATH” from the command line would return:
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin

So it was clear (also explained in the man page for path_helper) that the content of of the paths.d directory would always be appended to what was found in “paths” itself.

I placed “/usr/local/bin” at top of paths but the order didn’t change. I logged out and back in and even rebooted to make sure there is nothing else causing this behavior but it always remained in the same order.

If I removed “/usr/local/bin” it was gone from the path but the rest stayed as is.
I had the suspicion that the content of “/etc/paths” didn’t really matter for the default entries of “/usr/bin:/bin:/usr/sbin:/sbin” and took them completely out of “/etc/paths” and logged into another shell to prove it. And sure enough, even w/o the entries the path variable was the same.
Therefore here is the order it apparently uses when it calls “path_helper” from /etc/profile at login:
1) System defaults
2) /etc/paths content aside system defaults
3) /etc/paths.d/ content
Apple wanted apparently to play save and not allow users to override system defaults and evtl. cripple the system.

I finally solved the problem by adding
export PATH=/usr/local/bin/:$PATH;

before the path_helper call in /etc/profile:
if [ -x /usr/libexec/path_helper ]; then
eval `/usr/libexec/path_helper -s`
fi

Now “/usr/local/bin” is searched first

Avatar

Reid Ellis

March 12th, 2009 at 8:38 am

Something to note is that the starting path is read from ~/.MacOSX/environment.plist which you can manipulate:

defaults read ~/.MacOSX/environment PATH

defaults write ~/.MacOSX/environment PATH “$PATH”

Avatar

John Bledsoe

January 6th, 2010 at 8:52 pm

In Snow Leopard, moving “/usr/local/bin” to the top in “/etc/paths” now works without modifying “/etc/profile”.

Avatar

Timo Meinen

January 19th, 2010 at 12:14 am

You can just erase the default PATH entry before path_helper is called like this:

if [ -x /usr/libexec/path_helper ]; then
PATH=”"
eval `/usr/libexec/path_helper -s`
fi

Then you have full control in /etc/paths and /etc/paths.d. Do this in

/etc/profile
/etc/csh.login
/etc/zprofile

Comment Form

RSSTwitter Feed

del.icio.us