我努力了:
char *path = realpath(getenv("_"), NULL);
*(strrchr(path, '/')+1) = '\0';
这可行,但如果我的可执行文件被父进程调用,则会显示父进程的路径。
我用谷歌搜索了很多,但我找不到任何正常工作的解决方案。
/proc
是没有选择的。
经过一些实验,我想我有一个可行的解决方案......
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <sys/sysctl.h>
#include <sys/stat.h>
const char *getExecutablePath(char *epath) {
int mib[4];
char **argv;
size_t len;
const char *comm;
int ok = 0;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
mib[2] = getpid();
mib[3] = KERN_PROC_ARGV;
if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0)
abort();
if (!(argv = malloc(len)))
abort();
if (sysctl(mib, 4, argv, &len, NULL, 0) < 0)
abort();
comm = argv[0];
if (*comm == '/' || *comm == '.') {
if (realpath(comm, epath))
ok = 1;
} else {
char *sp;
char *xpath = strdup(getenv("PATH"));
char *path = strtok_r(xpath, ":", &sp);
struct stat st;
if (!xpath)
abort();
while (path) {
snprintf(epath, PATH_MAX, "%s/%s", path, comm);
if (!stat(epath, &st) && (st.st_mode & S_IXUSR)) {
ok = 1;
break;
}
path = strtok_r(NULL, ":", &sp);
}
free(xpath);
}
if (ok)
*strrchr(epath, '/') = '\0';
free(argv);
return ok ? epath : NULL;
}
int main(void) {
char path[PATH_MAX];
if (getExecutablePath(path))
puts(path);
return 0;
}
遗憾的是,没有办法在 OpenBSD 中获取已执行文件的完整路径。
按照约定,第一个参数指向文件名,而不是完整路径,您不能确定父进程是否会遵循该约定。
以下名为 exe 的命令说明了这一点。
#include <stdio.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/wait.h>
int exe( const char * path, const char * fakepath )
{
pid_t pid = vfork( ) ;
if( pid == 0 )
{
/* Child process */
int fd ;
const int TO = getdtablesize( ) ;
for( fd = 0 ; fd <= TO ; fd++ )
{
close( fd );
}
open( "/dev/tty", O_RDONLY ) ;
open( "/dev/tty", O_WRONLY ) ;
open( "/dev/tty", O_WRONLY ) ;
const char *arguments[2] = { fakepath, NULL } ;
execvp( path, (char**)arguments ) ;
perror( "exe" ) ;
exit( 1 ) ;
}
else if( pid > 0 )
{
/* Parent process */
int status = 0 ;
if( waitpid( pid, &status, 0 ) != -1 )
{
if( WIFEXITED( status ) )
{
return WEXITSTATUS( status ) ;
}
else
{
printf( "exe: child process failed\n" ) ;
return 1 ;
}
}
}
perror( "exe" ) ;
return 1 ;
}
int main( int argc, char * argv[] )
{
if( argc != 3 )
{
printf( "Usage: exe program /fake/first/program/argument\n" ) ;
return 1 ;
}
return exe( argv[1], argv[2] ) ;
}
现在您可以执行一个传递任意第一个参数的程序,如下所示:
exe program /fake/first/program/argument
一位用户要求 Theo de Raadt 实现在该线程中获取已执行文件的完整路径所必需的内容
我想我们可以将“路径”粘贴到辅助向量值中并让 ld.so 如果使用 $ORIGIN 来调用 realpath() 吗?就是这样,或者让内核存储整个过程的整个路径,以便使用 sysctl() 获取。现在它只将(已解析的)原始路径的最后一个组件存储在 p_comm 中。
他回答说:
对于这么小的需求,相当昂贵。