November 2008 (using Leopard 10.5.5)

PATH and other evironment issues in Leopard

PATH and path_helper

Leopard introduced this great(?) new way of setting up default PATH and and MANPATH, in /usr/libexec/path_helper. Some people don't like it much, but I think it's not bad, and it's perfectly workable once you understand all of the issues.

The idea is simple. /etc/paths contains the initial PATH values, one path per line, in order. /etc/paths.d contains additional files, with paths to be added to your PATH. They'll be added based on the sort order of the filenames there. This does make me wish they'd called the one default file in there 50_X11, instead of X11, so that they'd created a precedent of numbering things in desired order. But they didn't. You can change it, or you can add other prefixes to anything you add there. It's also worth mentioning that if a path is repeated in more than one place, it is NOT added more than once. The first location wins.

But how does it really work?

First of all, path_helper seem to be run exclusively out of /etc/profile and /etc/csh.login. This means that for things that are not login shells, path_helper is NOT run (for both types of shell). An example would be starting an xterm with +ls, or running a command in ssh (e.g. 'ssh hostname who'). However /etc/bashrc, or /etc/csh.cshrc are still both run for interactive shells, and so ar the user's .bashrc or .cshrc files. So if the user customizes their PATH in these files, these changes will still show up.

Of course a shell which is not interactive (e.g. a script) shouldn't read ANY of these files, and in that case it will simply get the initial default PATH. But sh and csh behave differently. If there is no PATH at all, sh/bash uses a compiled-in PATH of "/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin:." (as of Leopard 10.5.5). csh/tcsh does not use a compiled-in PATH, but it DOES source /etc/csh.cshrc, and $HOME/.cshrc. Yes that's right, these are sourced even when running shell scripts (c.f. "use of csh considered harmful").

Second of all, /etc/paths does not actually contain initial PATH values. You can prove this by removing this file, and noting that you don't get rid of these paths (except for /usr/local/bin). /etc/paths does contain paths that are added first, but they are ADDED to the current PATH, they don't replace it. The initial PATH of "/usr/bin:/bin:/usr/sbin:/sbin" seems to be hardcoded in /sbin/launchd. This means that anything you want to set as a true default initial starting PATH, is best set in /etc/profile and /etc/csh.login, before the call to path_helper. In my case, I wanted to take out the sbin directories (these directories should contain commands for admins, not for general users).

Third, X11 is special. If you just run "xterm" from a Terminal window, Leopard very cooly automatically starts up X11, but it won't be that surprising that the xterm that runs inherits the environment from the Terminal window. But there's still some funky stuff going on. The script /usr/X11/bin/startx adds two things to your path, if they aren't there already; /usr/X11/bin gets added to the beginning of your path, and /usr/X11R6/bin gets added to the end of your path. This is kind of stupid since under Leopard these are both the same directory. But the other weird thing is that startx is started by /System/Library/LaunchAgents/org.x.startx.plist (which isn't the weird part). If you peek in there, you'll notice that it explicitly calls this script by calling bash with the --login option. What this means is that X11 gets started using /etc/profile, and hence path_helper. And what THIS means is that an xterm started with command-N (⌘-N) may have a different environment (inherited from X11) than if you start xterm from the command line in a Terminal window.

(Feb '09) One more thing I've found about X11. When you start X11 by clicking on the X11 icon, it (by default) starts an xterm too. But the xterm started here is not a child of X11, it's started in parallel, and it is started without using the path_helper stuff. So it won't have the same system-supplied environment that any subsequent applications started by X11 will have.

To fully control the user's PATH, I'd suggest setting it to empty in /etc/profile and /etc/csh.login immediately before path_helper is called, and then use the mechanism they provide to give an initial path in /etc/paths, and then provide path packages in /etc/paths.d BUT in light of the weird xterm problem described above, perhaps scrapping the whole thing and doing traditional user dot file setup is the way to go.

Cron jobs are a whole 'nother thing too, and maybe I'll get into that at some point.

MANPATH

MANPATH can be controlled in the same way that PATH can. The parallel files /etc/manpaths and /etc/manpaths.d/* exist, and work just the same. I don't think launchd provides any default values, so whatever is in /etc/manpaths really does work out to be the default.

However, man can also be configured using /etc/man.conf. But much of this file is ignored if MANPATH is set. If you prefer /etc/man.conf, then my suggestion would be to either clear out /etc/manpaths and /etc/manpaths.d/*, or just remove the variable MANPATH after path_helper is called in /etc/profile and /etc/csh.login ("unset MANPATH" for sh/bash, and "unsetenv MANPATH" for csh/tcsh).

X11 environment

You may notice that you can start any X11 command, and that causes X11 itself to start -- one of the cute uses of launchd. But for this to work, the DISPLAY environment variable must be set even though X11 isn't running. This is set by launchd, but not the process ID 1 system launchd that functions like init on other Unix systems. When you log in, the system starts a user-level launchd, and this is what sets your DISPLAY variable, and handles the as-needed launching of X11. This has some important ramifications in configuring X11.

So far the only X11 config I've had to do was for MacPorts and Fink. If you add either or both of these, you'll find that those X11-based applications may not find the app-defaults files that they came with. The problem is that the default search path, which seems to be compiled in to libXt, doesn't look in the new locations. Environment variables XFILESEARCHPATH and XUSERFILESEARCHPATH can be used to tell libXt where to look.

I haven't found an excellent solution here. I add to the user's startup files that if they're on a Darwin system, they get the variable XUSERFILESEARCHPATH set to "/opt/local/lib/X11/app-defaults/%N:/sw/etc/app-defaults/%N". Note that one really strange gotcha here is that other percent-things (like %T) don't work here, so a path that WOULD work in XFILESEARCHPATH will NOT work in XUSERFILESEARCHPATH. Apparently this wierdness is true on all platforms, not just OS X.

You can't really add this to /usr/X11/bin/startx. In a traditional environment this would be ok, because most X11 clients are descendenants of the X server. Because of the launchd tricks, this isn't true on Leopard. You can start X things from anywhere that's a child of the user-level launchd. In practice this will probably just be shells, so you really want your default dot files to set up this environment. It would be great if there was some file where you could configure variables set by launchd, or (specific to this case), if there was a file where you could configure the libXt search paths.

In a more perfect world

It'd be nice if I could put group-readable files into /etc/paths.d, and only members of that group would get that path. This does in fact work if you are willing to live with "Permission denied" error messages for all users not in those groups.

Even cooler would be a subscription-based thing. Default system files would have things like "subscribe core,x11,fink", and this would take care of all variables for those packages in one swoop. Then the user could do things like "unsubscribe fink; subscribe admin,macports" to alter their entire environment from the default. By the way, I'm pretty sure this idea was suggested to me about 20 years ago by J Greely, and who knows where he got it.


Reader Comments (Experimental. Moderated, expect delays. Posts may be edited or ignored. I reserve the right to remove any or all comments, at any time.)

6 comments:

At 2009/02/22 18:48
JosephN wrote:

Just wanted to drop a quick note here about

~/.MacOSX/environment.plist

This file defines the environment variables for normal applications (i.e. not anything executed in a shell or terminal window). You will likely have to create this file and directory yourself. First touch the file, then open it in the property list editor and add key value pairs.

The reason this is interesting is if you put PATH and MANPATH in this plist file then any shell you start will include these environment variables as read in from this file (unless you overwrite them locally by declaring a new PATH variable).

So really the path helper script and organization is a total waste. The PATH and MANPATH variables should be defined in the environment.plist file so your normal apps have access to the same environment as your shell apps do.

At 2009/02/22 19:17
wrote:

Thanks. I'll look into this when I get a chance. I'm worried it might become deprecated.

At 2011/01/21 11:31
SteveL wrote:

If you set the PATH environment variable in ~/.MacOSX/environment.plist some applications, like X11, will fail to launch.

For more information check out the post by David Whetstone at http://discussions.apple.com/thread.jspa?threadID=2149229&tstart=0

At 2011/03/14 12:11
wrote:

FYI, just one typo: /etrc/profile

Thanks for writing this post, it is helping me learn more about PATH.

I'm trying to find out if entering a comment: #whatever into /etc/paths is OK, or if it breaks that (or everything afterwards). When I do $ echo $PATH it shows my comment line.

At 2011/06/30 6:49
Johann Visagie wrote:

I don't know at what point this behaviour changed, but as of right now (OS X 10.6.8), path_helper(8) no longer prints the commands to set $MANPATH, unless $MANPATH is is already defined (even if zero-length).

This means that path_helper's behaviour now differs from that described in its own man page.

I would guess that this change was made to enable the use of man.conf(8) by default. However, it does mean that any changes made to /etc/manpaths or /etc/manpaths.d/* will not take effect unless one manually invokes path_helper from shell startup scripts.

At 2011/07/01 3:58
Johann Visagie wrote:

If I may update my comment of yesterday: It appears that path_helper(8)'s man page does in fact describe its behaviour correctly. It contains the following parenthesised sentence: "(The MANPATH environment variable will not be modified unless it is already set in the environment.)"

It's also very clear from the path_helper.c source file that it only adjusts MANPATH if it's already set:

http://www.opensource.apple.com/source/shell_cmds/shell_cmds-149/path_helper/path_helper.c

End Comments

Add a comment


More Mac OS X Stuff


Tom Fine's Home
Send Me Email