Getting path to executed program file
Jonathan I. Kamens
jik at athena.mit.edu
Wed Jul 25 16:49:56 AEST 1990
In article <9995 at pt.cs.cmu.edu>, tgl at zog.cs.cmu.edu (Tom Lane) writes:
|> Is there any way for a program to discover the path name of the file
|> from which it was executed?
Appended to this message is a message posted to comp.unix.wizards by
Greg Limes the nth time this was asked (your message was the mth time,
where m is about three or four more than n if I recall correctly, and
n is nonnegligable :-). It says just about all there is to say about
this question. I haven't had occasion to use his source code yet, so
I don't know whether or not it has bugs, but I doubt 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
Message-ID: <LIMES.89Sep7153103 at ouroborous.wseng.sun.com>
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.wizards
mailing list