Finding the path to a executable?

H. S. Teoh hsteoh at quickfur.ath.cx
Wed Aug 7 10:06:19 PDT 2013


On Wed, Aug 07, 2013 at 12:55:10PM -0400, Nick Sabalausky wrote:
> On Wed, 07 Aug 2013 09:13:03 +0200
> "Tommi" <tommitissari at hotmail.com> wrote:
> 
> > On Wednesday, 7 August 2013 at 05:31:24 UTC, Alan wrote:
> > > Hello!  This may seem like a simple question, maybe an 
> > > embarassing question but how would I fetch the absolute path to 
> > > the directory where my executable is located?  My wording is 
> > > known to be confusing so I will give an example:
> > >
> > > cd ~/projects/program
> > > dmd Program.d -ofProgram
> > >
> > > That executable would be located in /home/alan/projects/program 
> > > for example.  SO my question is how would I fetch the absolute 
> > > path to that directory?
> > >
> > > Thanks for any help!
> > 
> > This should work on at least couple of systems, but I haven't 
> > tested this on other than Mac. Also, it's not completely robust, 
> > because paths could be longer than 4096 chars.
> > 
> > version(Windows) {
> >      import std.c.windows.windows;
> > }
> > else version(OSX) {
> >      private extern(C) int _NSGetExecutablePath(char* buf, uint* 
> > bufsize);
> > }
> > else version(linux) {
> >      import std.c.linux.linux;
> > }
> > else {
> >      static assert(0);
> > }
> > import std.conv;
> > 
> > // Returns the full path to the currently running executable
> > string executablePath()
> > {
> >      static string cachedExecutablePath;
> > 
> >      if (!cachedExecutablePath) {
> >          char[4096] buf;
> >          uint filePathLength;
> > 
> >          version(Windows) {
> >              filePathLength = GetModuleFileNameA(null, buf.ptr, 
> > buf.length - 1);
> >              assert(filePathLength != 0);
> >          }
> >          else version(OSX) {
> >              filePathLength = cast(uint) (buf.length - 1);
> >              int res = _NSGetExecutablePath(buf.ptr, 
> > &filePathLength);
> >              assert(res == 0);
> >          }
> >          else version(linux) {
> >              filePathLength = readlink(toStringz(selfExeLink), 
> > buf.ptr, buf.length - 1);
> >          }
> >          else {
> >              static assert(0);
> >          }
> >          cachedExecutablePath = to!string(buf[0 .. 
> > filePathLength]);
> >      }
> >      return cachedExecutablePath;
> > }
> > 
> > // Returns the file name of the currently running executable
> > string executableName()
> > {
> >      return executablePath().baseName();
> > }
> > 
> > // Returns the path to the directory of the currently running 
> > executable
> > string executableDirPath()
> > {
> >      return executablePath().dirName();
> > }
> 
> Yes, this is the way to do it. Never use args[0]: it's useless as it
> doesn't follow symlinks (might not even follow aliases, though I'm
> not certain), and strictly-speaking can't even be guaranteed to be
> correct at all anyway.

+1. If you invoke your program from the shell, it will generally be
correct (though unhelpful if the program was found through $PATH,
because the shell only passes the bare program name in argv[0], not the
full path, leaving you having to search through $PATH all over again --
and even then, there's no guarantee the shell wasn't configured NOT to
pass $PATH along: some security models recommend not doing so).

But if your program was invoked from another program, there's no
guarantee at all what args[0] contains. For all you know, it could be
"/path/to/rootkit/maliciousProgram.exe".


> If it were up to me, args[0] would be eliminated outright.

Naw, there are some valid use cases for it. Take a look at busybox, for
example. :)


T

-- 
Не дорог подарок, дорога любовь.


More information about the Digitalmars-d mailing list