* written by Nicolai Haehnle <email@example.com>
* I hereby release this trivial piece of code to the public domain.
* The function getexename() returns the filename of the currently loaded
* Intended use of this function is to facilitate easier packaging of
* third-party software for the Linux operating system. The FHS mandates
* that files that belong to one package are scattered throughout the
* file system. This works as long as packages are maintained by a
* package management program. However, it is impossible for application
* developers to provide packages for every Linux distribution out there.
* Finding the file locations is also difficult when an application is
* installed locally by a user inside her own home directory.
* The simplest and most straight-forward solution to this problem is to
* put all files belonging to a package into the same directory. The program
* executable can then reference the necessary data files by using paths
* relative to the executable location.
* To give an example:
* A simple game, consisting of an executable and a number of data files
* (e.g. images), resides entirely in one directory, with absolute filenames
* like this:
* The game executable can use getexename() to find its own location, strip
* off the last component to get the directory the executable is located in,
* and append the relative paths "images/hero.png" and "images/badass.png"
* to reference the data files.
* The game will be completely position independent. The user is free to
* move it somewhere else in the filesystem, and it will just work; it will
* no longer be necessary to change configuration files or even recompile the
* If you are concerned about executables showing up in a user's PATH, you
* should somehow arrange for symlinks to be made. For example, if
* /usr/games/foogame is a symlink to /the/path/foogame, the user can run the
* game simply by typing "foogame" in the shell (provided that /usr/games is in
* the user's PATH); since symlinks cannot fool getexename(), the game will
* still work. (Do note that a hard link will defeat getexename()).
* Note that while it is possible to reference data files based on the current
* working directory, this technique only works if the user explicitly sets
* the CWD to the application's base directory. Therefore, using the executable
* name as a base is more robust.
* Also note that while argv can be used as the executable name in many
* cases as well, it is easily fooled by symlinks and may not contain an
* absolute filename. argv can also be set to something entirely different
* from the executable filename by the executing process, either delibaretly
* or by invoking scripts.
* Note that this function relies on the layout of the /proc file system, so
* portability is an issue. While I assume that this part of /proc is fairly
* stable, I have no documentation whatsoever about potential differences
* between Linux kernel versions in this area.
* getexename - Get the filename of the currently running executable
* The getexename() function copies an absolute filename of the currently
* running executable to the array pointed to by buf, which is of length size.
* If the filename would require a buffer longer than size elements, NULL is
* returned, and errno is set to ERANGE; an application should check for this
* error, and allocate a larger buffer if necessary.
* Return value:
* NULL on failure, with errno set accordingly, and buf on success. The
* contents of the array pointed to by buf is undefined on error.
* This function is tested on Linux only. It relies on information supplied by
* the /proc file system.
* The returned filename points to the final executable loaded by the execve()
* system call. In the case of scripts, the filename points to the script
* handler, not to the script.
* The filename returned points to the actual exectuable and not a symlink.
char* getexename(char* buf, size_t size)
char linkname; /* /proc/<pid>/exe */
/* Get our PID and build the name of the link in /proc */
pid = getpid();
if (snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid) < 0)
/* This should only happen on large word systems. I'm not sure
what the proper response is here.
Since it really is an assert-like condition, aborting the
program seems to be in order. */
/* Now read the symbolic link */
ret = readlink(linkname, buf, size);
/* In case of an error, leave the handling up to the caller */
if (ret == -1)
/* Report insufficient buffer size */
if (ret >= size)
errno = ERANGE;
/* Ensure proper NUL termination */
buf[ret] = 0;
#if 1 /* testing */
* Trivial test and sample use of getexename().
buf = NULL;
size = 32; /* Set an initial size estimate */
/* Allocate and fill the buffer */
buf = (char*)malloc(size);
res = getexename(buf, size);
/* Get out of the loop on success */
/* Anything but ERANGE indicates a real error */
if (errno != ERANGE)
buf = NULL;
/* ERANGE means the buffer was too small. Free the current
buffer and retry with a bigger one. */
size *= 2;
/* Exit on failure */
if (buf == NULL)
/* Now print the executable name. */
printf("getexename(): %s\n", buf);
return 0; /* Indicate success */
#endif /* testing */