How to know the path of current binary file? [duplicate] - c

This question already has answers here:
Finding current executable's path without /proc/self/exe
(14 answers)
Closed 7 years ago.
Is there a way in C/C++ to find the location (full path) of the current executed program?
(The problem with argv[0] is that it does not give the full path.)

To summarize:
On Unixes with /proc really straight and realiable way is to:
readlink("/proc/self/exe", buf, bufsize) (Linux)
readlink("/proc/curproc/file", buf, bufsize) (FreeBSD)
readlink("/proc/self/path/a.out", buf, bufsize) (Solaris)
On Unixes without /proc (i.e. if above fails):
If argv[0] starts with "/" (absolute path) this is the path.
Otherwise if argv[0] contains "/" (relative path) append it to cwd
(assuming it hasn't been changed yet).
Otherwise search directories in $PATH for executable argv[0].
Afterwards it may be reasonable to check whether the executable isn't actually a symlink.
If it is resolve it relative to the symlink directory.
This step is not necessary in /proc method (at least for Linux).
There the proc symlink points directly to executable.
Note that it is up to the calling process to set argv[0] correctly.
It is right most of the times however there are occasions when the calling process cannot be trusted (ex. setuid executable).
On Windows: use GetModuleFileName(NULL, buf, bufsize)

Use GetModuleFileName() function if you are using Windows.

Please note that the following comments are unix-only.
The pedantic answer to this question is that there is no general way to answer this question correctly in all cases. As you've discovered, argv[0] can be set to anything at all by the parent process, and so need have no relation whatsoever to the actual name of the program or its location in the file system.
However, the following heuristic often works:
If argv[0] is an absolute path, assume this is the full path to the executable.
If argv[0] is a relative path, ie, it contains a /, determine the current working directory with getcwd() and then append argv[0] to it.
If argv[0] is a plain word, search $PATH looking for argv[0], and append argv[0] to whatever directory you find it in.
Note that all of these can be circumvented by the process which invoked the program in question. Finally, you can use linux-specific techniques, such as mentioned by emg-2. There are probably equivalent techniques on other operating systems.
Even supposing that the steps above give you a valid path name, you still might not have the path name you actually want (since I suspect that what you actually want to do is find a configuration file somewhere). The presence of hard links means that you can have the following situation:
-- assume /app/bin/foo is the actual program
$ mkdir /some/where/else
$ ln /app/bin/foo /some/where/else/foo # create a hard link to foo
$ /some/where/else/foo
Now, the approach above (including, I suspect, /proc/$pid/exe) will give /some/where/else/foo as the real path to the program. And, in fact, it is a real path to the program, just not the one you wanted. Note that this problem doesn't occur with symbolic links which are much more common in practice than hard links.
In spite of the fact that this approach is in principle unreliable, it works well enough in practice for most purposes.

Not an answer actually, but just a note to keep in mind.
As we could see, the problem of finding the location of running executable is quite tricky and platform-specific in Linux and Unix. One should think twice before doing that.
If you need your executable location for discovering some configuration or resource files, maybe you should follow the Unix way of placing files in the system: put configs to /etc or /usr/local/etc or in current user home directory, and /usr/share is a good place to put your resource files.

In many POSIX systems you could check a simlink located under /proc/PID/exe. Few examples:
# file /proc/*/exe
/proc/1001/exe: symbolic link to /usr/bin/distccd
/proc/1023/exe: symbolic link to /usr/sbin/sendmail.sendmail
/proc/1043/exe: symbolic link to /usr/sbin/crond

Remember that on Unix systems the binary may have been removed since it was started. It's perfectly legal and safe on Unix. Last I checked Windows will not allow you to remove a running binary.
/proc/self/exe will still be readable, but it will not be a working symlink really. It will be... odd.

On Mac OS X, use _NSGetExecutablePath.
See man 3 dyld and this answer to a similar question.

For Linux you can find the /proc/self/exe way of doing things bundled up in a nice library called binreloc, you can find the library at:
http://autopackage.org/docs/binreloc/

I would
1) Use the basename() function: http://linux.die.net/man/3/basename
2) chdir() to that directory
3) Use getpwd() to get the current directory
That way you'll get the directory in a neat, full form, instead of ./ or ../bin/.
Maybe you'll want to save and restore the current directory, if that is important for your program.

Related

Can a C header file only specify a name of another header file

I found a pacman project in github where a file conf.c includes a header file #include "ini.h" where ini.h contains only a single line (i.e no #include statement):
//ini.h
../common/ini.c
I have never seen anyone doing this before! It seems a bit hackish/rough around the edges. My questions are:
Is this legal C?
Is it portable?
Is it recommended?
I would have assumed the answer should be no for all these questions, but I may be learning something new...
edit
From the answers, I see its a Linux symlink. I guess that this means it is not portable to Windows, and would also make it more difficult to read outside a unix environment. I would also imagine that using relative paths (or include directories) instead of symlinks would be a better practice in cases like this for reasons mentioned above...
src/pacman/ini.h is a symbolic link according to the site.
Symbolic link has an information of where the target file is (path name), and I guess it is what is displayed on the site.
The OS will redirect access to that ini.h to ../common/ini.h, which is a normal C code.
I don't see any reason why not. The include statement indicates the compiler to replace that line with the whatever is in the included file

How to find execute files in Linux?

I wants to get the names of execute files in some directory in Linux.
How can I do it?
I tried to use opendir like this:
dir = opendir(directoryName);
I need to get only the names of the execute files.
I programming in C.
thanks :)
You should define what you mean by executable files.
That could be any file with its execute bit (it is the owner, group, or other) set. Then test with access(2) & X_OK and/or use stat(2).
That could also be only ELF executables. See elf(5); then the issue might be to check that a file could indeed be executed, which might be difficult (what about missing library dependencies? or ill-formed ELF files?). Maybe use libelf (and/or libmagic to do the equivalent of file(1) command).
To scan recursively a file tree, use nftw(3); to scan just a directory use opendir(3) & readdir(3) (don't forget the closedir!), then you'll probably need to build the complete file path from each directory entry (perhaps using snprintf(3) or asprintf(3))
See also Advanced Linux Programming

how to find source file name from executable?

IN LINUX:
Not sure if it is possible. I have 100 source file, and 100 respective executable files.
Now, given the executable file, is it possible to determine, respective source file.
I guess you can give this a try.
readelf -s a.out | grep FILE
I think you can add some grep and sed magic to the above command and get the source file name.
No, since your assumption, that a single binary comes from exactly one source file, is very false.
Most real applications consist of hundreds, if not thousands, of individual source files that are all compiled separately, with the results liked together to form the binary.
If you have non-stripped binaries, or (even better) binaries compiled with debugging information present, then there might (or will, for the case of debugging info) be information left in the file to allow you to figure out the names of the source files, but in general you won't have such binaries unless you build them yourself.
If source filenames are present in an executable, you can find them with:
strings executable | grep '\.c'
But filenames may or may not be present in the executable and they may or may not represent the source filenames.
Change .c to whatever extension you assume the program has been written in.
Your question only makes sense if we presume that it is a given fact that every single one of these 100 executables comes from a single source file, and that you have all those source files and are capable of compiling them all.
What you can do is to declare within each source file a string that looks like "HERE!HERE!>>>" + __FILE__ and then write a utility which searches for "HERE!HERE!>>>" inside the executable and parses the string which follows it. __FILE__ is a preprocessor directive which expands to the full pathname of the source file being compiled.
This kind of help falls in the 'close the barn door after the horse has run away' kind of thing, but it might help future posters.
This is an old problem. UNIX and Linux support the what command which was invented by Mark Rochkind (if I remember correctly), for his version of SCCS. Handles exactly this type of problem. It is only 100% reliable for one source file -> one exectuable (or object file ) kind of thing. There are other more important uses.
char unique_id[] = "#(#)identification information";
The #(#) is called a "what string" and does not occur as a by-product of compiling source into an executable image. Use what from the command line. Inside code use maybe something like this (assumes you get only one file name as an answer, therefore choose your what strings carefully):
char *foo(char *whoami, size_t len_whoami)
{
char tmp[80]={0x0};
FILE *cmd;
sprintf(tmp, "/usr/bin/grep -F -l '%s' /path/to/*.c", unique_id);
cmd=popen(tmp, "r");
fgets(whoami, len_whoami, cmd);
pclose(cmd);
return whoami;
}
will return the source code file name with the same what string from which your executable was built. In other words, exactly what you asked, except I'm sure you never heard of what strings, so they do not exist in your current code base.

How can a currently running C program find out what directory it is located in?

Say I have a command line C program which is currently executing, and I want to read a file or execute another binary in the same directory - how can I find out what directory that is?
Note that I'm not looking for the current working directory. The user may have invoked my original program in any of the following ways (and possibly others I don't know about).
../../program
/home/matt/program
PATH=$PATH:/home/matt program
Ideally I'm looking for something which will work on a unix system and windows via MinGW.
http://c-faq.com/osdep/exepath.html
According to the C FAQ it can't be done reliably
Finding current executable's path without /proc/self/exe
Concat getcwd() and dirname(argv[0])

Beginner Doing K&R

I'm just starting programming and going through K&R to try and learn C. I've gotten to the section on command line arguments (5.10) but now I'm stumped. Every time I try and open a program I've written with command line arguments I'm told that file X, X being the argument, doesn't exist.
`gcc -o find find.c
open find test
The file /Documents/Learning_C/test does not exist.`
Any suggestions? Thanks
What system are you on? In Unix/Linux you compile & run your executable via:
gcc -o find find.c
./find test
As others have noted, when you prefix your binary with "./", there wont be any naming conflicts. However, if you made find accessible in your $PATH, you might have some conflicts with find and test--standard programs with most *nix distributions... Maybe you could choose more specific names (i.e. ./myFind testArg)
Try giving your output executable a different name.
I suspect your executing the system find command which is looking for a directory called 'test'.
Or try forcing it by executing
./find toto
Edit: Prepending the ./ to the command is important because it tells the shell to execute the find in the current directory as opposed to the first 'find' that exists in your PATH. It is normally recommended that you don't have . (the current directory) in your PATH for security reasons.
HTH
P.S. Forgot to say good one for working through K&R. I just finished doing the same after working in C for thirty years and it was good to get back and refresh the mind!
Instead of making us all individually guess what exactly you're doing wrong, perhaps you should paste the program you're using for the illustration mentioned ?

Resources