How to get the pathname of the current executable?
Jonathan I. Kamens
jik at athena.mit.edu
Thu Feb 8 07:56:10 AEST 1990
The subject of finding the full path name of the currently running
process was discussed in comp.unix.wizards fairly recently (in September
of last year, to be precise), and pretty much beaten until dead.
The best posting on the subject was the one I've tacked onto the end
of this article; it is a routine to do what you want whenever it's
possible, with a whole bunch of comments explaining when (and why) it's not.
I hope it helps.
BTW, I didn't write it, I'm just reposting it.
Jonathan Kamens USnail:
MIT Project Athena 11 Ashford Terrace
jik at Athena.MIT.EDU Allston, MA 02134
Office: 617-253-8495 Home: 617-782-0710
------------------------------
Article 19066 of comp.unix.wizards:
Path: bloom-beacon!usc!apple!sun-barr!newstop!sun!limes
From: limes at sun.com (Greg Limes)
Newsgroups: comp.unix.wizards
Subject: Re: Reading the symbol table of the currently running executable
Date: 7 Sep 89 22:31:03 GMT
References: <9104 at june.cs.washington.edu> <6131 at lynx.UUCP>
Sender: news at sun.Eng.Sun.COM
Organization: Sun Microsystems, Inc.
Lines: 243
In-reply-to: mitch at lynx.uucp's message of 5 Sep 89 17:17:36 GMT
In article <6131 at lynx.UUCP> mitch at lynx.uucp (Mitch Bunnell) writes:
> In article <9104 at june.cs.washington.edu> bcn at cs.washington.edu
(Clifford Neuman) writes:
> > 2) Obtaining the full path name of the presently running executable.
> 2 - Not possible.
Back before I knew this was impossible, I wrote the following piece of
support code. It has been doing the impossible for me for quite some
time (geez, has it been that long?) with limitations as stated.
/*
* findx package 25may88 limes at sun.com
*
* Over the last few days (weeks?) there has been some traffic about how to
* tell where a running program came from. Well, there is a way to find
* out without changing the shell, the kernel, C language startup
* conventions, or whatever.
*
* Anyway, here is the basic idea, presented as a package that should compile
* and run without too many problems.
*
* WHAT IT DOES First, it locates the path to the executable that was used by
* the exec() that started this process. If the command name starts with a
* "/", it must be taken literally; if it contains a "/", then it is
* always relative to the current working directory at the start of the
* program; otherwise, we have to chase across the PATH value in the
* environment. If there is no PATH, or the PATH is empty, check the
* current working directory.
*
* On systems with symbolic links, we are not through yet. The purpose is to
* locate the directory it is in, so we can get at any related data files.
* So, we chase symbolic links until we have the real path name of the
* final resolution file.
*
* SECURITY This can be spoofed easily by making a hard link to, or a copy
* of, the executable. If you want your program to be sure that it has
* found the one true installation location, you will have to verify that
* for yourself. findx() just locates the most likely candidate.
*
* PORTABILITY This was developed on a Sun3 running SunOS 4.0, but I think I
* at least made the algorithm portable. You may need to mess with include
* files and such. Symbolic link searching is turned on if your errno.h
* supplies ELOOP, and off otherwise; I assume that all systems with
* symlinks have a readlink() call.
*
* HOW TO USE IT Here is the definition of the various parameters. Further
* down you will find an example main, so fear not ...
*
* findx (cmd, cwd, dir, pgm, run, path)
*
* cmd pass the command name (argv[0]) here. findx() knows how to handle
* just about anything. If it starts with /, then we use the absolute
* name, and ignore the path. If it contains a /, then use the relative
* name and ignore the path. Otherwise, look for the file in each
* directory named in the path for the file; if there is no path, pretend
* its "." like the execvp does.
*
* cwd pass a big buffer here. if this begins with a slash, I will assume
* it is filled in with the current working directory; otherwise, I will
* fill it in using getcwd(). Should be at least MAXPATHLEN bytes, if you
* do not fill it in yourself.
*
* dir pass a big buffer here. this gets the full path name of the
* directory that the executable was read from. Should be at least
* MAXPATHLEN bytes.
*
* pgm pass THE ADDRESS of a pointer variable here. findx() will fill the
* pointer variable with a pointer to the final component of the string
* passed as cmd above. Send a (char **)0 if you don't care about this.
*
* run pass THE ADDRESS of a pointer variable here. findx() will fill the
* pointer variable with a pointer to the final component of the name of
* the runnning program. Send a (char **)0 if you don't care about this.
*
* path pass the user's PATH variable here. I made it a parameter so you
* can fiddle with the path first. If you do not want to fiddle, pass
* getenv("PATH").
*
* RETURN VALUES: Normally, findx() will return zero if all is well. If
* something goes wrong, it will return -1 with the global variable
* "errno" set to a corresponding error number.
*/
#include <strings.h>
#include <errno.h>
#include <sys/param.h>
#define X_OK 1
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
#ifndef ENAMETOOLONG
#define ENAMETOOLONG EINVAL
#endif
int findx (); /* get location of directory */
int resolve (); /* get link resolution name */
#ifdef TESTMAIN
extern char *getenv (); /* read value from environment */
char *pn = (char *) 0;/* program name */
char *rn = (char *) 0;/* run name */
char rd[MAXPATHLEN]; /* run directory */
char wd[MAXPATHLEN] = "."; /* working directory */
int
main (argc, argv)
int argc;
char **argv;
{
findx (*argv, wd, rd, &pn, &rn, getenv ("PATH"));
printf ("%s: %s running in %s from %s\n", pn, rn, wd, rd);
return 0;
}
#endif
/*-
* findx - find executable file in PATH
* PARAMETERS:
* cmd filename as typed by user
* cwd where to return working directory
* dir where to return program's directory
* pgm where to return what user called it
* run where to return final resolution name
* path user's path from environment
* RETURNS: returns zero for success, -1 for error (with errno set properly).
*/
int
findx (cmd, cwd, dir, pgm, run, path)
char *cmd;
char *cwd;
char *dir;
char **pgm;
char **run;
char *path;
{
int rv = 0;
char *f, *s;
if (!cmd || !*cmd || !cwd || !dir) {
errno = EINVAL; /* stupid arguments! */
return -1;
}
if (!path || !*path) /* missing or null path */
path = "."; /* assume sanity */
if (*cwd != '/')
if (!(getcwd (cwd, MAXPATHLEN)))
return -1; /* cant get working directory */
f = rindex (cmd, '/');
if (pgm) /* user wants program name */
*pgm = f ? f + 1 : cmd;
if (dir) { /* user wants program directory */
rv = -1;
if (*cmd == '/') /* absname given */
rv = resolve ("", cmd + 1, dir, run);
else if (f) /* relname given */
rv = resolve (cwd, cmd, dir, run);
else if (f = path) { /* from searchpath */
rv = -1;
errno = ENOENT; /* errno gets this if path empty */
while (*f && (rv < 0)) {
s = f;
while (*f && (*f != ':'))
++f;
if (*f)
*f++ = 0;
if (*s == '/')
rv = resolve (s, cmd, dir, run);
else {
char abuf[MAXPATHLEN];
sprintf (abuf, "%s/%s", cwd, s);
rv = resolve (abuf, cmd, dir, run);
}
}
}
}
return rv;
}
/*
* resolve - check for specified file in specified directory sets up
* dir, following symlinks. returns zero for success, or -1 for error
* (with errno set properly)
*/
int
resolve (indir, cmd, dir, run)
char *indir; /* search directory */
char *cmd; /* search for name */
char *dir; /* directory buffer */
char **run; /* resultion name ptr ptr */
{
char *p;
int rv = -1;
#ifdef ELOOP
int lcc = 0;
int sll;
char symlink[MAXPATHLEN + 1];
#endif
do {
errno = ENAMETOOLONG;
if (strlen (indir) + strlen (cmd) + 2 > MAXPATHLEN)
break;
sprintf (dir, "%s/%s", indir, cmd);
if (access (dir, X_OK) < 0)
break; /* not an executable program */
#ifdef ELOOP
while ((sll = readlink (dir, symlink, MAXPATHLEN)) >= 0) {
symlink[sll] = 0;
if (*symlink == '/')
strcpy (dir, symlink);
else
sprintf (rindex (dir, '/'), "/%s", symlink);
}
if (errno != EINVAL)
break;
#endif
p = rindex (dir, '/');
*p++ = 0;
if (run) /* user wants resolution name */
*run = p;
rv = 0; /* complete, with success! */
} while (0);
return rv;
}
--
-- Greg Limes limes at sun.com ...!sun!limes 73327,2473 [choose one]
More information about the Comp.unix.questions
mailing list