2

我努力了:

char *path = realpath(getenv("_"), NULL);
*(strrchr(path, '/')+1) = '\0';

这可行,但如果我的可执行文件被父进程调用,则会显示父进程的路径。

我用谷歌搜索了很多,但我找不到任何正常工作的解决方案。

/proc是没有选择的。

4

2 回答 2

1

经过一些实验,我想我有一个可行的解决方案......

#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;
}
于 2015-07-18T20:58:11.507 回答
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 中。

他回答说:

对于这么小的需求,相当昂贵。

于 2016-07-07T21:41:16.630 回答