Home > Archive > Unix Programming > December 2006 > finding the full path of the program which ran.
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
finding the full path of the program which ran.
|
|
| Prasad 2006-12-21, 7:05 pm |
| Hi All,
I m building a library which requires the full path of the program to
which it is linked. How could I do it?
I can't use argv for sure, because this requires user program to be
aware of the library.
The way to find should be portable.
Besides, argv[0] doesn't give the full path. And a program can be ran
using using relative path so, getting the full path is really a hard
process using argv[0].
For eg.
[Pra @pra joshi test]$ cat a_program.c
#include<stdio.h>
void afun ()
{
printf ( "\nIn afun ().\n" );
}
int main ( int argc, char *argv[] )
{
char cwd[100] ;
//intitialize_call_graph ( argv[0] );
getcwd ( cwd, 100 ) ;
printf ( "\ncwd = %s, name = %s \n", cwd, argv[0] ) ;
afun () ;
}
[Pra @pra joshi test]$ ./a.out
cwd = /home/Pra /programs/c/lsp/test, name = ./a.out
In afun ().
[Pra @pra joshi test]$ ../test/a.out
cwd = /home/Pra /programs/c/lsp/test, name = ../test/a.out
In afun ().
[Pra @pra joshi test]$ ../../lsp/test/a.out
cwd = /home/Pra /programs/c/lsp/test, name = ../../lsp/test/a.out
In afun ().
[Pra @pra joshi lsp]$ test/a.out
cwd = /home/Pra /programs/c/lsp, name = test/a.out
In afun ().
There has to be some other way to do it.
Thanks and regards,
Pra .
| |
| Bill Medland 2006-12-21, 7:05 pm |
| Pra wrote:
> Hi All,
>
> I m building a library which requires the full path of the program to
> which it is linked. How could I do it?
Have you tried google?
Search in this group for 'path' in the subject over the past three months
and you should find a couple of discussions.
(But are you sure you really need it?)
--
Bill Medland
| |
| Gordon Burditt 2006-12-22, 4:09 am |
| >I m building a library which requires the full path of the program to
>which it is linked. How could I do it?
How much incentive is there for someone to maliciously make your
program determine the *WRONG* full path, and what happens if it does?
(If this program is going to be setuid, you're really asking for trouble.)
>I can't use argv for sure, because this requires user program to be
>aware of the library.
>
>The way to find should be portable.
>
>Besides, argv[0] doesn't give the full path.
argv[0] does not necessarily give anything remotely related to the
path. argv[0] and the name of the program are passed as separate
arguments to the exec*() family. For example, program = "/bin/ls",
argv[0] = "Copyright 2006 /// Pirates Die in a Fire"
>And a program can be ran
>using using relative path so, getting the full path is really a hard
>process using argv[0].
Prepending the current working directory to the relative path if
it's not absolute isn't "a really hard process", except for the
problem that argv[0] can be entirely fake. The case where the
executable is found with $PATH is more of a problem, especially
when argv[0] and $PATH are both entirely fake.
The value of $PATH passed to your program need not have anything to
do with the path used to search for the program.
>For eg.
>[Pra @pra joshi test]$ cat a_program.c
>#include<stdio.h>
>
>void afun ()
>{
>printf ( "\nIn afun ().\n" );
>}
>
>int main ( int argc, char *argv[] )
>{
>char cwd[100] ;
>//intitialize_call_graph ( argv[0] );
>getcwd ( cwd, 100 ) ;
>printf ( "\ncwd = %s, name = %s \n", cwd, argv[0] ) ;
>afun () ;
>}
>
>[Pra @pra joshi test]$ ./a.out
>cwd = /home/Pra /programs/c/lsp/test, name = ./a.out
>In afun ().
>
>[Pra @pra joshi test]$ ../test/a.out
>cwd = /home/Pra /programs/c/lsp/test, name = ../test/a.out
>In afun ().
>
>[Pra @pra joshi test]$ ../../lsp/test/a.out
>cwd = /home/Pra /programs/c/lsp/test, name = ../../lsp/test/a.out
>In afun ().
>
>[Pra @pra joshi lsp]$ test/a.out
>cwd = /home/Pra /programs/c/lsp, name = test/a.out
>In afun ().
>
>There has to be some other way to do it.
Most of the reasons to do it are bad. Particularly, if you insist
on trying to put executables and writable configuration files in
the same directory, that's a very bad reason.
| |
| Prasad 2006-12-22, 4:09 am |
| Hi All,
Thanks a lot for giving reply.
Let me tell u why I need it...
We have an application on LINUX (developed by us), now we want to
generate the call graphs of it, the call graphs should be dynamic.
So, what I did is, used BFD library to open the executable and used
instrument-functions (functions called automatically whenever any
function is called). To these instrument functions a pointer to
function which will be called is passed). Using this pointer and bfd
library I could map the pointer to it's name. Along with it I am also
loging some other information like current time etc.
Now, BFD library need full path of the executable to open it. So, I
need that full path in my library. This library will just be used for
generating call graphs along with to log more information like time
taken by each funtion etc. So, this library will not be shipped to
customer.
Hence, I need to find the full path of the program to which my library
is linked.
Thanks and regards,
Pra .
Gordon Burditt wrote:
>
> How much incentive is there for someone to maliciously make your
> program determine the *WRONG* full path, and what happens if it does?
> (If this program is going to be setuid, you're really asking for trouble.)
>
>
> argv[0] does not necessarily give anything remotely related to the
> path. argv[0] and the name of the program are passed as separate
> arguments to the exec*() family. For example, program = "/bin/ls",
> argv[0] = "Copyright 2006 /// Pirates Die in a Fire"
>
>
> Prepending the current working directory to the relative path if
> it's not absolute isn't "a really hard process", except for the
> problem that argv[0] can be entirely fake. The case where the
> executable is found with $PATH is more of a problem, especially
> when argv[0] and $PATH are both entirely fake.
>
> The value of $PATH passed to your program need not have anything to
> do with the path used to search for the program.
>
>
> Most of the reasons to do it are bad. Particularly, if you insist
> on trying to put executables and writable configuration files in
> the same directory, that's a very bad reason.
| |
| Stefaan A Eeckels 2006-12-22, 8:04 am |
| On 21 Dec 2006 23:05:28 -0800
"Pra " <pra joshi124@gmail.com> wrote:
> Hence, I need to find the full path of the program to which my library
> is linked.
There is no portable way to do this. On Linux, you can look
at /proc/"pid"/exe which is a symlink to the executable.
--
Stefaan A Eeckels
--
When the need is strong, there are those who will believe anything.
-- Arnold Lobel
| |
|
| "Pra " <pra joshi124@gmail.com> writes:
> Hi All,
> Thanks a lot for giving reply.
>
> Let me tell u why I need it...
> We have an application on LINUX (developed by us), now we want to
> generate the call graphs of it, the call graphs should be dynamic.
>
> So, what I did is, used BFD library to open the executable and used
> instrument-functions (functions called automatically whenever any
> function is called). To these instrument functions a pointer to
> function which will be called is passed). Using this pointer and bfd
> library I could map the pointer to it's name. Along with it I am also
> loging some other information like current time etc.
>
> Now, BFD library need full path of the executable to open it. So, I
> need that full path in my library. This library will just be used for
> generating call graphs along with to log more information like time
> taken by each funtion etc. So, this library will not be shipped to
> customer.
>
> Hence, I need to find the full path of the program to which my library
> is linked.
[..snip..]
On Linux one might use the something like:
<self.c>
#define _GNU_SOURCE
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
int main (void)
{
int ret, len;
pid_t pid;
char path[PATH_MAX + 1];
char proc_path[PATH_MAX + 1];
pid = getpid ();
len = snprintf (proc_path, sizeof (proc_path), "/proc/%d/exe", pid);
if ((size_t) len > sizeof (proc_path)) {
fprintf (stderr, "snprintf failed (length %d, max %d)\n",
len, sizeof (proc_path));
exit (EXIT_FAILURE);
}
ret = readlink (proc_path, path, sizeof (path));
if (ret == -1) {
err (1, "readlink failed");
}
printf ("self path = `%s'\n", path);
exit (EXIT_SUCCESS);
}
</self.c>
--
vale
| |
| Casper H.S. Dik 2006-12-22, 8:04 am |
| Stefaan A Eeckels <hoendech@ecc.lu> writes:
>On 21 Dec 2006 23:05:28 -0800
>"Pra " <pra joshi124@gmail.com> wrote:
[color=darkred]
>There is no portable way to do this. On Linux, you can look
>at /proc/"pid"/exe which is a symlink to the executable.
getexecname() or readlink of /proc/self/path/a.out will find this
information in Solaris.
Casper
--
Expressed in this posting are my opinions. They are in no way related
to opinions held by my employer, Sun Microsystems.
Statements on Sun products included here are not gospel and may
be fiction rather than truth.
| |
| Casper H.S. Dik 2006-12-22, 8:04 am |
| malc <malc@pulsesoft.com> writes:
> char path[PATH_MAX + 1];
> char proc_path[PATH_MAX + 1];
Nit: PATH_MAX is supposed to include the trailing '\0'; why do you think
they made this a manifest constant, other than to use it directly
in your program?
> pid = getpid ();
> len = snprintf (proc_path, sizeof (proc_path), "/proc/%d/exe", pid);
> if ((size_t) len > sizeof (proc_path)) {
> fprintf (stderr, "snprintf failed (length %d, max %d)\n",
> len, sizeof (proc_path));
> exit (EXIT_FAILURE);
> }
> ret = readlink (proc_path, path, sizeof (path));
> if (ret == -1) {
> err (1, "readlink failed");
> }
> printf ("self path = `%s'\n", path);
Error: you are assuming that readlink returns a 0 terminated path;
that is not "a portable assumption".
After checking ret != -1, you need to do this:
proc_path[ret] = '\0';
Casper
--
Expressed in this posting are my opinions. They are in no way related
to opinions held by my employer, Sun Microsystems.
Statements on Sun products included here are not gospel and may
be fiction rather than truth.
| |
|
| Casper H.S. Dik <Casper.Dik@Sun.COM> writes:
> malc <malc@pulsesoft.com> writes:
>
>
> Nit: PATH_MAX is supposed to include the trailing '\0'; why do you think
> they made this a manifest constant, other than to use it directly
> in your program?
I wanted to add a Nit section to the original post to summarize all
the things that were (possibly) wrong with it. Since `info libc'
didn't yield enough information to assume trailing zero is included in
PATH_MAX the decision was made to "play it safe".
Links to the relevant standard that address PATH_MAX situation in
greater detail will be appreciated.
Why no "nit" here? Or pid_t is guaranteed to require no more storage
than int?
[color=darkred]
Cast here is suspicious.
[color=darkred]
>
>
>
> Error: you are assuming that readlink returns a 0 terminated path;
> that is not "a portable assumption".
>
> After checking ret != -1, you need to do this:
>
> proc_path[ret] = '\0';
Indeed. Thank you, this is one the things i keep forgetting.
--
vale
| |
| matevzb 2006-12-22, 8:04 am |
| On Dec 21, 5:41 pm, "Pra " <pra joshi...@gmail.com> wrote:
> Hi All,
>
> I m building a library which requires the full path of the program to
> which it is linked. How could I do it?
>
> I can't use argv for sure, because this requires user program to be
> aware of the library.
>
> The way to find should be portable.
>
> Besides, argv[0] doesn't give the full path. And a program can be ran
> using using relative path so, getting the full path is really a hard
> process using argv[0].
You could try the realpath() function e.g.:
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
int
main (int argc, char **argv)
{
char buf[PATH_MAX+1], buf2[PATH_MAX+1];
char resolved_path[PATH_MAX+1];
if (getcwd (buf, PATH_MAX) == NULL)
{
printf ("ERROR\n");
return EXIT_FAILURE;
}
else
{
printf ("path='%s' argv[0]='%s'\n", buf, argv[0]);
if (argv[0][0] == '/')
{
/* absolute path specified */
strcpy (buf2, argv[0]);
}
else
{
/* relative path specified */
sprintf (buf2, "%s/%s", buf, argv[0]);
}
if (realpath (buf2, resolved_path) != NULL)
{
printf ("resolved path='%s'\n", resolved_path);
}
}
return 0;
}
I _think_ this should be fairly portable, no guarantees though.
--
WYCIWYG - what you C is what you get
| |
| Casper H.S. Dik 2006-12-22, 8:04 am |
| "matevzb" <matevzb@gmail.com> writes:
> char buf[PATH_MAX+1], buf2[PATH_MAX+1];
> char resolved_path[PATH_MAX+1];
Nit: PATH_MAX, not PATH_MAX + 1.
> if (getcwd (buf, PATH_MAX) == NULL)
> {
> printf ("ERROR\n");
> return EXIT_FAILURE;
> }
Note that getcwd could return a value longer than PATH_MAX on some
OSes (but will fail with an error if your buffer is too small)
> else
> {
> printf ("path='%s' argv[0]='%s'\n", buf, argv[0]);
> if (argv[0][0] == '/')
Unfortunately, argv[0] is not at all reliable.
Take the following program and calling it "printarg0":
#include <stdio.h>
int
main(int argc, char **argv)
{
(void) printf("argv[0] is \"%s\"\n", argv[0] ? argv[0] : "(null)");
}
and run it with zsh:
zsh$ ./printarg0
argv[0] is "./printarg0"
zsh$ $PWD/printarg0
argv[0] is "/home/casper/src/printarg0"
zsh$ ARGV0=/bin/sh ./printarg0
argv[0] is "/bin/sh"
zsh$ ARGV0= ./printarg0
argv[0] is ""
Casper
--
Expressed in this posting are my opinions. They are in no way related
to opinions held by my employer, Sun Microsystems.
Statements on Sun products included here are not gospel and may
be fiction rather than truth.
| |
| matevzb 2006-12-22, 8:04 am |
| On Dec 22, 2:06 pm, Casper H.S. Dik <Casper....@Sun.COM> wrote:
> "matevzb" <mate...@gmail.com> writes:
> Nit: PATH_MAX, not PATH_MAX + 1.
Sorry, work habit...
> Note that getcwd could return a value longer than PATH_MAX on some
> OSes (but will fail with an error if your buffer is too small)
True, I'm aware of this , but didn't want to post too much at once. =)
> and run it with zsh:
>
> zsh$ ./printarg0
> argv[0] is "./printarg0"
> zsh$ $PWD/printarg0
> argv[0] is "/home/casper/src/printarg0"
> zsh$ ARGV0=/bin/sh ./printarg0
> argv[0] is "/bin/sh"
> zsh$ ARGV0= ./printarg0
> argv[0] is ""
>
argv!... I mean argh! I wasn't aware of this "feature". Is this
zsh-specific or does it apply to other shells as well? In bash it seems
to work okay.
--
WYCIWYG - what you C is what you get
| |
| Casper H.S. Dik 2006-12-22, 8:04 am |
| "matevzb" <matevzb@gmail.com> writes:
>argv!... I mean argh! I wasn't aware of this "feature". Is this
>zsh-specific or does it apply to other shells as well? In bash it seems
>to work okay.
zsh allows you to specify ARGV0 by setting the ARGV0 variable; it's
just an easy way to demonstrate this.
But in principle, any program is free to put in argv[0] whatever it
likes.
The "path" is used to find the executable; argv[1] .. argv[argc-1] are
the arguments passed to the program and argv[0] is free for the shell to
fill in; the fact that it is generally `basename program` is merely
a convention, though some programs rely on specific values.
Casper
--
Expressed in this posting are my opinions. They are in no way related
to opinions held by my employer, Sun Microsystems.
Statements on Sun products included here are not gospel and may
be fiction rather than truth.
| |
| matevzb 2006-12-22, 7:05 pm |
| On Dec 22, 2:56 pm, Casper H.S. Dik <Casper....@Sun.COM> wrote:
> zsh allows you to specify ARGV0 by setting the ARGV0 variable; it's
> just an easy way to demonstrate this.
>
> But in principle, any program is free to put in argv[0] whatever it
> likes.
>
> The "path" is used to find the executable; argv[1] .. argv[argc-1] are
> the arguments passed to the program and argv[0] is free for the shell to
> fill in; the fact that it is generally `basename program` is merely
> a convention, though some programs rely on specific values.
I'm not sure that this really should be the case. From the C standard:
"If they are defined, the parameters to the main function shall obey
the following constraints:
....
If the value of argc is greater than zero, the string pointed to by
argv[0]
represents the program name; argv[0][0] shall be the null character
if the
program name is not available from the host environment. If the value
of argc is
greater than one, the strings pointed to by argv[1] through
argv[argc-1]
represent the program parameters."
But I suppose unixen can break such rules nonetheless (or, to put it
mildly, "extend" them)
--
WYCIWYG - what you C is what you get
| |
| Rainer Weikusat 2006-12-22, 7:05 pm |
| "matevzb" <matevzb@gmail.com> writes:
> On Dec 22, 2:56 pm, Casper H.S. Dik <Casper....@Sun.COM> wrote:
>
> I'm not sure that this really should be the case.
> From the C standard:
> "If they are defined, the parameters to the main function shall obey
> the following constraints:
> ...
> If the value of argc is greater than zero, the string pointed to by
> argv[0] represents the program name;
For some strange reason, comp.unix.programmer still refers to UNIX(*)
and the relevant standard (single unix specification) says
The value in argv[0] should point to a filename that is
associated with the process being started by one of the exec
functions.
and later on explains that
The requirement on a Strictly Conforming POSIX Application
also states that the value passed as the first argument be a
filename associated with the process being started. Although
some existing applications pass a pathname rather than a
filename in some circumstances, a filename is more generally
useful
[...]
> But I suppose unixen can break such rules nonetheless
The C standard does not specify how a program can execute another
program. Consequently, it does not specify anything about passing
arguments to the main-routine of such a program. The notion of rules
that are 'broken' is therefore somewhat pointless.
| |
| Kohn Emil Dan 2006-12-22, 7:05 pm |
|
On Fri, 22 Dec 2006, matevzb wrote:
<snip>
> I'm not sure that this really should be the case. From the C standard:
> "If they are defined, the parameters to the main function shall obey
> the following constraints:
> ...
> If the value of argc is greater than zero, the string pointed to by
> argv[0]
> represents the program name; argv[0][0] shall be the null character
> if the
> program name is not available from the host environment. If the value
> of argc is
> greater than one, the strings pointed to by argv[1] through
> argv[argc-1]
> represent the program parameters."
> But I suppose unixen can break such rules nonetheless (or, to put it
> mildly, "extend" them)
Hmmm... argv[0] should point to the program name, if available, or to the
empty string if not. Nobody says that the program name should be the same
as the executable file or should resemble it in any way ;-))
Emil
> --
> WYCIWYG - what you C is what you get
>
>
| |
| Gordon Burditt 2006-12-23, 7:02 pm |
| >I'm not sure that this really should be the case. From the C standard:
>"If they are defined, the parameters to the main function shall obey
>the following constraints:
>...
> If the value of argc is greater than zero, the string pointed to by
>argv[0]
> represents the program name; argv[0][0] shall be the null character
>if the
> program name is not available from the host environment. If the value
>of argc is
> greater than one, the strings pointed to by argv[1] through
>argv[argc-1]
> represent the program parameters."
Remember that the "program name" is not necessarily a "program file
name". It might be the name of the program as it is presented in
the catalog of the company selling it, for example, "Adobe Reader
7.0.8 for Linux, Copyright 2006, catalog number 5738-28735937593-38973"
and there's no particular reason to prevent having the entire text
of the license in it as well.
>But I suppose unixen can break such rules nonetheless (or, to put it
>mildly, "extend" them)
| |
| K-mart Cashier 2006-12-24, 7:06 pm |
|
Casper H.S. Dik wrote:
> "matevzb" <matevzb@gmail.com> writes:
>
>
> Nit: PATH_MAX, not PATH_MAX + 1.
>
>
>
> Note that getcwd could return a value longer than PATH_MAX on some
> OSes (but will fail with an error if your buffer is too small)
>
>
> Unfortunately, argv[0] is not at all reliable.
>
> Take the following program and calling it "printarg0":
>
> #include <stdio.h>
>
> int
> main(int argc, char **argv)
> {
> (void) printf("argv[0] is \"%s\"\n", argv[0] ? argv[0] : "(null)");
> }
>
> and run it with zsh:
>
> zsh$ ./printarg0
> argv[0] is "./printarg0"
> zsh$ $PWD/printarg0
> argv[0] is "/home/casper/src/printarg0"
> zsh$ ARGV0=/bin/sh ./printarg0
> argv[0] is "/bin/sh"
> zsh$ ARGV0= ./printarg0
> argv[0] is ""
>
> Casper
> --
perhaps even more perverse...
#include <stdio.h>
int main(int argc, char **argv) {
printf("The string is: %s\n", argv[0]);
return 0;
}
m-net% gcc -g boner.c -o boner
m-net% ./boner
The string is: ./boner
m-net% ARGV0=/bin/sh ./boner
The string is: /bin/sh
m-net% ps waux | grep -v grep | grep cdalten
cdalten 6093 0.0 0.7 2160 1756 pi SN 5:46PM 0:00.03 -zsh
(zsh)
cdalten 6125 0.0 0.2 576 412 pi RN+ 5:47PM 0:00.00 ps waux
cdalten 6126 0.0 0.7 2160 1756 pi RN 5:47PM 0:00.00 -zsh
(zsh)
m-net% ARGV0='Humping your mom' exec sh
$ ps waux | grep -v grep | grep cdalten
cdalten 6093 0.0 0.1 632 304 pi SN 5:46PM 0:00.05 Humping
your mom (sh)
cdalten 6144 0.0 0.2 576 412 pi RN+ 5:47PM 0:00.00 ps waux
cdalten 6145 0.0 0.1 632 304 pi RN+ 5:47PM 0:00.00 Humping
your mom (sh)
cdalten 6146 0.0 0.1 632 304 pi RN+ 5:47PM 0:00.00 Humping
your mom (sh)
$
| |
| K-mart Cashier 2006-12-24, 7:06 pm |
|
Casper H.S. Dik wrote:
> "matevzb" <matevzb@gmail.com> writes:
>
>
> zsh allows you to specify ARGV0 by setting the ARGV0 variable; it's
> just an easy way to demonstrate this.
>
> But in principle, any program is free to put in argv[0] whatever it
> likes.
>
> The "path" is used to find the executable; argv[1] .. argv[argc-1] are
> the arguments passed to the program and argv[0] is free for the shell to
> fill in; the fact that it is generally `basename program` is merely
> a convention, though some programs rely on specific values.
>
> Casper
Or perhaps this might be a bit more closer to reality.
m-net% ARGV0=./boner exec sh
$ ps waux | grep cdalten
cdalten 6327 0.0 0.1 632 304 pi RN+ 5:54PM 0:00.00 ./boner
(sh)
cdalten 6286 0.0 0.1 632 304 pi SN 5:52PM 0:00.04 ./boner
(sh)
cdalten 6326 0.0 0.2 552 388 pi RN+ 5:54PM 0:00.00 ps waux
| |
| pradeep 2006-12-27, 4:10 am |
| Hi prashant,
According to your requirements of application, Better way to do is to
keep log of function addresses in
a file and running a separate program or python script to find out the
corresponding symbol. The above solution will work for the program but
not the shared libraries since shared libraries could be mapped
anywhere.
Anyways,
you could use -pg option and gprof to generate the call graph
HTH
Cheers,
Pradeep
K-mart Cashier wrote:
> Casper H.S. Dik wrote:
>
> Or perhaps this might be a bit more closer to reality.
> m-net% ARGV0=./boner exec sh
> $ ps waux | grep cdalten
> cdalten 6327 0.0 0.1 632 304 pi RN+ 5:54PM 0:00.00 ./boner
> (sh)
> cdalten 6286 0.0 0.1 632 304 pi SN 5:52PM 0:00.04 ./boner
> (sh)
> cdalten 6326 0.0 0.2 552 388 pi RN+ 5:54PM 0:00.00 ps waux
|
|
|
|
|