Reputation: 1746
Say I have a program, abc
in Linux, with a method:
char *currentPath(){
char *path=NULL;
path = getcwd(path, MAXPATHLEN);
return path;
}
When calling abc
directly, this path returns the path that abc
is in.
If I make a symbolic link to abc
, and call the symbolic link, currentPath()
returns the path of the symbolic link.
Is there a way to get make this method return the path of abc
? I am interested in accessing files relative to the location of abc
.
Upvotes: 0
Views: 2538
Reputation: 4446
Try this code (modify it to meet your need):
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#define MAXPATHLEN 256
char buffer[1024];
char *currentPath(char *bin_path){
char *path = NULL;
ssize_t len;
struct stat file_stat;
if (lstat(bin_path, &file_stat) != 0)
{
/* handle error */
fprintf(stderr, "ERROR\n");
}
if (!S_ISREG(file_stat.st_mode))
{
/* file is a symlink */
fprintf(stdout, "Is a symlink\n");
if ((len = readlink(bin_path, buffer, sizeof(buffer)-1)) != -1)
buffer[len] = '\0';
/* In this case we return the name of the link */
return buffer;
}
else
{
fprintf(stdout, "Is a regular file\n");
path = getcwd(bin_path, MAXPATHLEN);
return path;
}
}
int main(int argc, char **argv)
{
fprintf(stdout, "My path is : %s\n", currentPath(argv[0]));
return 0;
}
Upvotes: 0
Reputation: 36061
Use realpath(const char *path, char *resolved_path)
realpath() expands all symbolic links and resolves references to /./, /../ and extra '/' characters in the null-terminated string named by path to produce a canonicalized absolute pathname.
In your case:
char *currentPath() {
char *path, *canon_path;
path = getcwd(NULL, MAXPATHLEN);
canon_path = realpath(path, NULL);
free(path);
return canon_path;
}
Note that this does not get the path of the executable program (it is unclear what you're trying to do). To do that portably is trickier. You'll need to use the value of argv[0]
to get it:
char *bindir(char *argv0) {
char *canon_path = realpath(argv0, NULL);
char *canon_dir = strdup(dirname(canon_path));
free(canon_path);
return canon_dir;
}
The strdup
call is required because dirname
may modify its argument and return a pointer into that or return a pointer to a statically allocated buffer.
Upvotes: 2
Reputation: 754590
You can't use getcwd()
to help get the executable name; it is not a sensible way to go about finding the pathname of the executable.
On Linux, there is a symlink /proc/self/exe
that gives you the name of the executable if you read it with the readlink()
system call. Beware, the readlink()
system call does not null terminate the value it returns (and I have no idea why not; it is singularly weird behaviour in my book, and an instant cause of bugs for the unwary).
There are a number of problems with your scheme.
/bin/ls
without having to be in the /bin
directory.If you're worried about security, be aware that the value of argv[0]
is under the control of the program launching the target program. The shell behaves nicely; other programs may be more malicious:
#include <unistd.h>
int main(void)
{
char *argv[] = { "/opt/you/bin/bogus", "300", 0 };
execvp("sleep", argv);
return(-1);
}
This passes the program name as /opt/you/bin/bogus
even though it invokes the program sleep
.
If you search the web, you will find plenty of examples of 'how to get the executable name' that assume that argv[0]
is the way to go; it is not. Other platforms have other techniques for getting to the executable name. Using /proc/self/exe
is not portable; neither are the other techniques.
Upvotes: 4