20

Possible Duplicate:
how to find the location of the executable in C

I would like an executable to be able to discover its own path; I have a feeling that the answer is "you can't do this", but I would like this to be confirmed!

I don't think I can use getcwd(), because I might not be executing it from the same directory. I don't think I can use argv[0], because that is based on the string that's used to execute it. Are there any other options?

Rationale

The real problem is that I'd like to place an executable somewhere on a filesystem, and place a default config file alongside it. I want the executable to be able to read its config file at runtime, but I don't want to hardcode this location into the executable, nor do I want the user to have to set environment variables. If there's a better solution to this situation, I'm all ears...

Community
  • 1
  • 1
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680

5 Answers5

33

The file /proc/self/exe is a simlink to the currently running executable.

Cercerilla
  • 1,353
  • 12
  • 13
17

Edit: It was pointed out that using /proc/self/exe is more straightforward. That is entirely true, but I didn't see any benefit in editing the code. Since I still get comments about it, I've edited it.

#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>

int main()
{
  char dest[PATH_MAX];
  memset(dest,0,sizeof(dest)); // readlink does not null terminate!
  if (readlink("/proc/self/exe", dest, PATH_MAX) == -1) {
    perror("readlink");
  } else {
    printf("%s\n", dest);
  }
  return 0;
}

Initial answer: You can use getpid() to find the pid of the current process, then read /proc/<pid>/cmdline (for a human reader) or /proc/<pid>/exe which is a symlink to the actual program. Then, using readlink(), you can find the full path of the program.

Here is an implementation in C:

#include <sys/types.h>
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>

int main()
{
  char path[PATH_MAX];
  char dest[PATH_MAX];
  memset(dest,0,sizeof(dest)); // readlink does not null terminate!
  pid_t pid = getpid();
  sprintf(path, "/proc/%d/exe", pid);
  if (readlink(path, dest, PATH_MAX) == -1) {
    perror("readlink");
  } else {
    printf("%s\n", dest);
  }
  return 0;
}

If you want to try, you can then compile this, make a symlink from the executable to an other path, and call the link:

$ gcc -o mybin source.c
$ ln -s ./mybin /tmp/otherplace
$ /tmp/otherplace
/home/fser/mybin
Aif
  • 11,015
  • 1
  • 30
  • 44
  • 5
    As noted in @Cercerilla's answer, `/proc/self/exe` works just like `/proc//exe`, and you don't have to futz with finding out your own pid. – Tim Ruddick Sep 19 '14 at 17:30
  • 4
    that's right, I've been using `self` recently! – Aif Sep 21 '14 at 00:50
  • Your strategy of `/proc/.../exe` is the right one. Use `snprintf` (note the `n`) instead of `sprintf`. Use `%ld` instead of `%d` and cast the pid to `long`. Using `/proc/self/exe` avoids both of those concerns. Store the `readlink()` result in `ssize_t n;` and check that `(size_t)n < sizeof(dest)`. – Lassi Mar 19 '20 at 10:02
  • @Lassi thanks for your comment! The assumption with the sprintf (as opposed to snprintf) was that we're copying and existing path into a statically allocated one of `PATH_MAX`. Implicitly assuming that the existing path couldn't be any larger. Do you see a practical scenario where that couldn't be the case? – Aif Mar 19 '20 at 11:38
  • 1
    Nope - you're right that there is no practical scenario in this case. The reason is simply `sprintf` and `strcpy` are so often used unsafely that experienced C programmers no longer recommend them for any purpose, and compilers/linters may warn about them. Using `snprintf` instead is an "I know what I'm doing" signal that at least ensures bugs in the code do not turn into buffer overflows. It's possible to verify that individual uses of `sprintf` and `strcpy` are correct, but it's error-prone and is a lot of effort in a big codebase. – Lassi Mar 19 '20 at 12:12
  • In this case, we could use `char path[32]; snprintf(path, sizeof(path), "/proc/%ld/exe", (long)pid);` Assuming that `pid_t` fits in `long`, and that `long` is at most 64 bits wide, we get 10 chars for `/proc//exe` + 20 chars for printing 2^64 in decimal + 1 char for the null terminator. That's 31 chars; rounding up to the next power-of-two, we get 32. `snprintf(path, sizeof(path), ...)` ensures we don't cause a buffer overflow if we counted wrong. – Lassi Mar 19 '20 at 12:17
  • Although readlink doesn't nul-terminate, using memset is highly inefficient. Instead, after having checked the function didn't failed and the buffer wasn't full, simply put a zero at the returned value offset : ssize_t n = readlink(...); ; dest[n] = '\0'; – Hurricane Nov 24 '21 at 07:22
6

Use the proc filesystem

Your flow would be:

  • Get pid of executable
  • look at /proc/PID/exe for a symlink
NG.
  • 22,560
  • 5
  • 55
  • 61
  • why the downvote? and why only downvote mine when CodeninjaTim basically says the same thing? – NG. Oct 26 '10 at 15:55
  • 5
    There's no need to get the pid and dynamically manipulate strings. The hard-coded string `"/proc/self/exe"` is simpler and better. – R.. GitHub STOP HELPING ICE May 26 '11 at 19:08
  • This is a correct solution for Linux and does not deserve a downvote. `/proc/self/exe` is a simpler way to do the same thing but manually inserting the PID still works fine. – Lassi Mar 19 '20 at 09:49
1

Well, you have to use getcwd() in conjuction with argv[0]. The first one gives you the working directory, the second one gives you the relative location of the binary from the working directory (or an absolute path).

Šimon Tóth
  • 35,456
  • 20
  • 106
  • 151
  • and why downvote this one too? someone's being lame.. – NG. Oct 26 '10 at 15:56
  • 3
    I didn't downvote, but I don't think this works. `argv[0]` is not necessarily relative (consider running executable from command-line as `/blah/my_app`). – Oliver Charlesworth Oct 26 '10 at 16:01
  • 1
    Programs to run not searched in cwd, but in $PATH, until you specify path to executable. – Vovanium Oct 26 '10 at 16:03
  • 1
    `argv[0]` might not even be a real executable name. – Hedede Nov 29 '16 at 12:07
  • Unfortunately this will only work by accident. An arbitrary string can be passed as `argv[0]` to `execve()`. Even in the case where `argv[0]` is only a basename without a directory part, and actually refers to the executable, that name is often not in CWD; it can be in any directory in `PATH`. There is no portable solution. For Linux, the `readlink("/proc/self/exe")` solution is correct, and is much easier to code than a `PATH ` search. – Lassi Mar 19 '20 at 09:44
1

Get your name from argv[0] then call out to the which command. This will obv only work if your executable is in $PATH.

Gaius
  • 2,556
  • 1
  • 24
  • 43
  • Unfortunately `argv[0]` based solutions will only work by accident. It is also advisable to avoid calling out to an external command such as `which` for simple tasks, as that adds many more factors which can break. While there is no portable and reliable solution, for Linux `readlink("/proc/self/exe")` is simple and correct. – Lassi Mar 19 '20 at 09:54