[comp.unix.wizards] Finding where an executable was run

brian@bucc2.UUCP (05/16/88)

> /* Written  4:25 pm  May 11, 1988 by sun.uucp!limes in bucc2:comp.unix.wiza */
> In article <4527@hoptoad.uucp> gnu@hoptoad.uucp (John Gilmore) writes:
> >If exec() would pass this value to the executed program, say as
> >argv[-1], then a program could reliably know its own name, and apply a
> >simple transformation to it to find its data files (e.g. for program
> >"XXXXXX/foo", its data files are found in "XXXXXX/lib/foo/whatever").
> 
> In Turbo-C, Borland passes the complete path name of the program
> executed as argv[0].  This may be specific to Turbo-C, or may be
> general across MS-DOS.  Are there any programs that this would break?

  I believe this is general to MS-DOS, since Microsoft C does the same
thing. It is annoying when you want to use the program name in error
messages, like:

	fprintf(stderr, "%s: %s\n", argv[0], errmsg);

  Not only do you get the full pathname, but it's probably in uppercase
as well...


...............................................................................

  When the going gets weird, the weird turn pro.

  Brian Michael Wendt       UUCP: {cepu,ihnp4,uiucdcs,noao}!bradley!brian
  Bradley University        ARPA: cepu!bradley!brian@seas.ucla.edu
  (309) 677-2230            ICBM: 40 40' N  89 34' W

gordon@sneaky.UUCP (05/18/88)

> The convention used by ksh-i is to put the full pathname used to exec a file
> in the environment variable "_". This makes a lot of sense to me, and seems
> as good an example of prior art as anything else out there. It is also cleaner
> than most of the suggestions we've seen so far in this discussion, not
> requiring any change to the kernel or the C calling conventions.

Great.  Now all the programs that use one of the forms of "exec" have to
fiddle with the environment (remove the old value of $_, if present, and
add a new one).  Either that, or you change the exec*() family of library
interface routines (you don't really want this in the kernel, do you?) to do
it for you, and relink *EVERYTHING*.  (Does anyone REALLY want exec*()
to call malloc()?  Anyone got a good alternative?)

If you just put the code in the shells (remember, uucico is a commonly
used shell), then I would expect mass confusion when /bin/cc is invoked and 
$_ comes out as "/bin/make".  Or maybe it ends up undefined.  There are 
lots of programs out there that don't use a shell if the command is simple 
enough to parse and exec by itself.

					Gordon L. Burditt
					...!ihnp4!sys1!sneaky!gordon

md@io.UUCP (Mark Dionne) (05/20/88)

I believe system V is different from BSD: argv[0] is always
the full path name of the executable.
-- 
	...!mit-eddie!ileaf!md	  Mark Dionne, Interleaf
	...!sun!sunne!ileaf!md	  Ten Canal Park, Cambridge, MA 02141
					(617) 577-9813 x5551

dg@lakart.UUCP (David Goodenough) (05/20/88)

Net-people:

	I am wrong - I am wrong - I am wrong - I admit it. I have had more
mail telling me this than you can shake a stick at. Two points:

A) Valid objection: with a path == ( . /bin /usr/bin /usr/local )
	I get into trouble. This is a real problem, because it happens
	whenever I fire up something that is not a full path, or not in
	the current directory (i.e. /bin/cat).

B) Less often a problem, but still irritating - things like csh / sh / getty
	whose argv[0] is something real weird (e.g. - -u or whatever). This
	rarely happens for user programs, except when doing a su perhaps.

An interesting notion :-)

On BSD 4.3, most binaries are demand page loaded. This means that the
"text image" is very closely linked to the executable (Let's forget
shell scripts for a moment :-). Does this mean that the kernel's
process tables have some reference to the filesystem and inode number
of the executable, because if so you could do a real neato job with
find - popen("find /filesystem -inum %d", "r");		:-) :-) :-) 
-- 
	dg@lakart.UUCP - David Goodenough		+---+
							| +-+-+
	....... !harvard!adelie!cfisun!lakart!dg	+-+-+ |
						  	  +---+

guy@gorodish.Sun.COM (Guy Harris) (05/21/88)

> I believe system V is different from BSD: argv[0] is always
> the full path name of the executable.

OK, time for some reality:

	argv[0] is always whatever the process that started up the program in
	question passed via the argument list.

This could be the full path name of the executable.  It could be the last
component of that path name.  It could be the first 10 words of the Magna
Carta.  It could be anything the program doing the "exec*" call wanted it to
be.

Thus, it's not a question of which version of the OS you're running.  It's a
question of what program fired up the executable.

I tried it under:

	the "previous" version of the Korn shell (i.e., pre-"ksh-i" - we don't
	have "ksh-i" *sigh*); it does not pass the full path name of the
	executable, but passes the name you typed (assuming no aliases, etc.).

	The SunOS 4.0 Bourne shell, based on the S5R3.1 Bourne shell; it does
	not pass the full path name of the executable, but passes the name you
	typed.

	The SunOS 4.0 C shell, based on the 4.3BSD C shell; it does not pass
	the full path name of the executable, but passes the name you typed.

	The 4.3BSD Bourne shell, based on the V7 Bourne shell; it does not pass
	the full path name of the executable, but passes the name you typed.

	The 4.3BSD C shell; it does not pass the full path name of the
	executable, but passes the name you typed.

	The System V Release 3.1 Bourne shell; it does not pass the full path
	name of the executable, but passes the name you typed.

I think there seems to be a pattern here....

wswietse@eutrc3.UUCP (Wietse Venema) (05/21/88)

In article <611@io.UUCP> md@marvin.UUCP (Mark Dionne) writes:
>I believe system V is different from BSD: argv[0] is always
>the full path name of the executable.

No, with SysV, argv[0] is the command, just as in BSD. You
are confusing MS-DOS with SysV UNIX.
-- 
uucp:	mcvax!eutrc3!wswietse	| Eindhoven University of Technology
bitnet:	wswietse@heithe5	| Dept. of Mathematics and Computer Science
surf:	tuerc5::wswietse	| Eindhoven, The Netherlands.

aglew@urbsdc.Urbana.Gould.COM (05/21/88)

>	"This would make lots of application programs easier to
>	install; you just copy it into somewhere on your PATH and it
>	will run."
>
>If an application uses this scheme to find its associated files, some
>useful Unix idioms cease to work.  For example, say that "rn" lives in
>/usr/news, but I don't want /usr/news in my PATH (too many nasty
>commands are also there).  At present I can put a link to /usr/news/rn
>in a directory that is in my path (e.g., my local bin).  With the
>proposed scheme, that would cause rn to look in my_local_bin/lib/* for
>its data files instead of in /usr/news/lib/*.
>
>  -=- Andrew Klossner   (decvax!tektronix!tekecs!andrew)       [UUCP]

Easy enough to do a readlink(), if you have used a symlink to place
the command on your path.

md@io.UUCP (Mark Dionne) (05/21/88)

I previously wrote:
> I believe system V is different from BSD: argv[0] is always
> the full path name of the executable.

As several people have pointed out, I was either wrong or
overgeneralizing. Sorry. I based this belief on what I was 
told when a "get_exec_name" routine we wrote was ported (by 
others) to AIX on an IBM RT. I don't have access to an RT 
right now, so I can't verify it.

Here's a routine for finding the pathname of an executable.
It might not be perfect, but it illustrates a couple of
twists: watch out for directories, and watch out for
"." and ".."

#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>

#define PATHSIZE 256

GetExecName(argv0, buf)
char*	argv0;
char*	buf;	/* pathname returnes in this buffer */
{
    char    *path;
    char    *getenv(), *getwd(), *getPathElement();

    if (*argv0 == '/') {
	strcpy( buf, argv0 );
	return(0);
    }

    if (*argv0 == '.' && *(argv0+1) == '/') {
	strcpy(buf, argv0 + 2);
	goto found;
    }
    if (*argv0 == '.' && *(argv0+1) == '.' && *(argv0+2) == '/' ) {
	strcpy(buf, argv0);
	goto found;
    }
    path = getenv("PATH");

    while(path != 0) {
	path = getPathElement(path, buf);
	if (*buf == '\0')
	    continue;		/* ignore empty components (::) */
	strcat(buf, "/");
	strcat(buf, argv0);
	if (access(buf, X_OK) == 0) {
	    /* watch out for directories that happen to match */
	    if((get_file_mode(buf) & S_IFMT) == S_IFDIR) continue;
	    /* Got it.  Now if it is not absolute, just prepend cwd */
	    if (*buf != '/') {
		char    tmpbuf[PATHSIZE];

	    found:
		strcpy(tmpbuf, buf);
		if ( getwd(buf) == 0 ) break;
		strcat(buf, "/");
		strcat( buf, tmpbuf );
	    }
	    return(0);
	}
    }

    /* Not found */
    *buf = 0;
    return(-1);
}

long
get_file_mode( path)
char*	path;
{
    struct stat	    stats;

    if ( stat( path, &stats) < 0 ) return ( -1 );
    return ( stats.st_mode );
}

/*  Strip off first element of path into buf.  Returns new path. */
char *getPathElement( path, buf )
register char	*path;
register char	*buf;
{
    while ( (*buf = *path++) != '\0' ) {
	if (*buf == ':') {
	    *buf = '\0';
	    return(path);
	}
	++buf;
    }
    return(0);
}

#include    <stdio.h>

main(argc, argv, envp)
int	argc;
char	**argv;
char	**envp;
{
    char    buf[PATHSIZE];

    printf("Argv[0] : %s\n", argv[0]);
    printf("Return value: %d\n", GetExecName(argv[0], buf));
    printf("Exec name: %s\n", buf);
}
-- 
	...!mit-eddie!ileaf!md	  Mark Dionne, Interleaf
	...!sun!sunne!ileaf!md	  Ten Canal Park, Cambridge, MA 02141
					(617) 577-9813 x5551