There's a problem with the current +mainBundle code in NSBundle.m.
In attempting to find the executable used to start the process, it
invokes a function called objc_find_executable(). If the executable
path is relative, that function searches $PATH and the current working
directory. If, as is often the case, the executable path is relative
and not in one of the directories in $PATH, it'll find the executable in
the current working directory. But what if the process has changed the
cwd before calling +mainBundle? Well, then it breaks. The best
solution I can see is to find the executable path in NSBundle's
+initialize, i.e. before the program has a chance to change its cwd.
On a related note, the method used by NSBundle has at least one
potential pitfall. If a different version of the program exists in the
path before the one running, it could get the wrong main bundle. Linux
provides a foolproof way to find the process' executable file: look at
/proc/self/exe. It's a symlink to the proper file.
So, this patch updates three files:
* base/configure.in: add a test to see whether a symlink
'/proc/self/exe' exists
* base/Headers/gnustep/base/config.h.in: Add a definition for the test
result
* base/Source/NSBundle.m: Move the discovery of the process' executable
file to +initialize; add code to discover it from /proc, if possible
Index: base/configure
===================================================================
RCS file: /gnustep/gnustep/core/base/configure,v
retrieving revision 1.37
diff -r1.37 configure
4224a4225,4238
> if test $sys_proc_fs = yes; then
> echo $ac_n "checking link to executable in /proc""... $ac_c" 1>&6
> echo "configure:4228: checking link to executable in /proc" >&5
> if test -L /proc/self/exe; then
> cat >> confdefs.h <<\EOF
> #define HAVE_PROC_FS_EXE_LINK 1
> EOF
>
> echo "$ac_t""yes" 1>&6
> else
> echo "$ac_t""no" 1>&6
> fi
> fi
>
Index: base/configure.in
===================================================================
RCS file: /gnustep/gnustep/core/base/configure.in,v
retrieving revision 1.86
diff -r1.86 configure.in
654a655,667
> # Linux (and others?) /proc contains a symlink to the executable
> # file from which the process loaded its code. This can be used
> # by NSBundle.m to locate the main bundle.
> if test $sys_proc_fs = yes; then
> AC_MSG_CHECKING(link to executable in /proc)
> if test -L /proc/self/exe; then
> AC_DEFINE(HAVE_PROC_FS_EXE_LINK)
> AC_MSG_RESULT(yes)
> else
> AC_MSG_RESULT(no)
> fi
> fi
>
Index: base/Headers/gnustep/base/config.h.in
===================================================================
RCS file: /gnustep/gnustep/core/base/Headers/gnustep/base/config.h.in,v
retrieving revision 1.23
diff -r1.23 config.h.in
31a32,34
> /* Define if your system has a /proc/self/exe symlink to the executable */
> #undef HAVE_PROC_FS_EXE_LINK
>
Index: base/Source/NSBundle.m
===================================================================
RCS file: /gnustep/gnustep/core/base/Source/NSBundle.m,v
retrieving revision 1.63
diff -r1.63 NSBundle.m
75a76,78
> /* Keep the path to the executable file for finding the main bundle. */
> static NSString *_executable_path;
>
254a258
> char *output;
277a282,293
> #ifdef HAVE_PROC_FS_EXE_LINK
> _executable_path = [[NSFileManager defaultManager]
> contentsOfSymbolicLinkAtPath: @"/proc/self/exe"];
> #else
> _executable_path =
> [[[NSProcessInfo processInfo] arguments] objectAtIndex: 0];
> output = objc_find_executable([_executable_path cString]);
> NSAssert(output, NSInternalInconsistencyException);
> _executable_path = [NSString stringWithCString: output];
> OBJC_FREE(output);
> #endif
>
312d327
< char *output;
315,320d329
< path = [[[NSProcessInfo processInfo] arguments] objectAtIndex: 0];
< output = objc_find_executable([path cString]);
< NSAssert(output, NSInternalInconsistencyException);
< path = [NSString stringWithCString: output];
< OBJC_FREE(output);
<
322c331
< path = [path stringByDeletingLastPathComponent];
---
> path = [_executable_path stringByDeletingLastPathComponent];