web-dev-qa-db-ja.com

パスを見つけるためにreadlinkを実装する方法

Cで実行可能ファイルの場所を見つける方法は? の解決策として使用されるreadlink関数を使用して、char配列へのパスを取得するにはどうすればよいですか?また、変数bufおよびbufsizeは何を表し、それらをどのように初期化するのですか?

編集:上記の質問のように、現在実行中のプログラムのパスを取得しようとしています。その質問への答えはreadlink("proc/self/exe")を使用すると述べました。それを自分のプログラムに実装する方法がわかりません。私は試した:

char buf[1024];  
string var = readlink("/proc/self/exe", buf, bufsize);  

これは明らかに正しくありません。

24
a sandwhich

これ readlink()関数を適切に使用readlink関数の正しい使用法。

std::stringにパスがある場合、次のようなことができます:

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

std::string do_readlink(std::string const& path) {
    char buff[PATH_MAX];
    ssize_t len = ::readlink(path.c_str(), buff, sizeof(buff)-1);
    if (len != -1) {
      buff[len] = '\0';
      return std::string(buff);
    }
    /* handle error condition */
}

固定パスの後だけの場合:

std::string get_selfpath() {
    char buff[PATH_MAX];
    ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1);
    if (len != -1) {
      buff[len] = '\0';
      return std::string(buff);
    }
    /* handle error condition */
}

それを使用するには:

int main()
{
  std::string selfpath = get_selfpath();
  std::cout << selfpath << std::endl;
  return 0;
}
38
Mat

manpage の内容を見てみましょう。

 readlink() places the contents of the symbolic link path in the buffer
 buf, which has size bufsiz.  readlink does not append a NUL character to
 buf.

OK。十分にシンプルでなければなりません。 1024文字のバッファがあるとします。

 char buf[1024];

 /* The manpage says it won't null terminate.  Let's zero the buffer. */
 memset(buf, 0, sizeof(buf));

 /* Note we use sizeof(buf)-1 since we may need an extra char for NUL. */
 if (readlink("/proc/self/exe", buf, sizeof(buf)-1) < 0)
 {
    /* There was an error...  Perhaps the path does not exist
     * or the buffer is not big enough.  errno has the details. */
    perror("readlink");
    return -1;
 }
4
asveikau

受け入れられた答えはほぼ正しいです。ただし、PATH_MAXは信頼できないためです。

システムにそのような制限がない場合、POSIXごとに定義される保証はありません。

(readlink(2)マンページから)

また、定義されている場合、必ずしも「真の」制限を表すとは限りません。 ( http://insanecoding.blogspot.fr/2007/11/pathmax-simply-isnt.html を参照)

Readlinkのマンページもsymlinkでそれを行う方法を提供します:

静的なサイズのバッファを使用すると、シンボリックリンクのコンテンツに十分なスペースが提供されない場合があります。バッファーに必要なサイズは、リンク上のlstat(2)の呼び出しによって返されるstat.st_size値から取得できます。ただし、readlink()およびread- linkat()によって書き込まれたバイト数をチェックして、シンボリックリンクのサイズが呼び出し間で増加していないことを確認する必要があります。

ただし、/ proc/self/exe /の場合、ほとんどの/ procファイルの場合、stat.st_sizeは0になります。残っている唯一の解決策は、バッファが収まらないときにバッファのサイズを変更することです。

この目的のために、次のようにvector<char>を使用することをお勧めします。

std::string get_selfpath()
{
    std::vector<char> buf(400);
    ssize_t len;

    do
    {
        buf.resize(buf.size() + 100);
        len = ::readlink("/proc/self/exe", &(buf[0]), buf.size());
    } while (buf.size() == len);

    if (len > 0)
    {
        buf[len] = '\0';
        return (std::string(&(buf[0])));
    }
    /* handle error */
    return "";
}
3
Wddysr
char *
readlink_malloc (const char *filename)
{
  int size = 100;
  char *buffer = NULL;

  while (1)
    {
      buffer = (char *) xrealloc (buffer, size);
      int nchars = readlink (filename, buffer, size);
      if (nchars < 0)
        {
          free (buffer);
          return NULL;
        }
      if (nchars < size)
        return buffer;
      size *= 2;
    }
}

取得元: http://www.delorie.com/gnu/docs/glibc/libc_279.html

2
onelineproof
_#include <stdlib.h>
#include <unistd.h>

static char *exename(void)
{
    char *buf;
    char *newbuf;
    size_t cap;
    ssize_t len;

    buf = NULL;
    for (cap = 64; cap <= 16384; cap *= 2) {
        newbuf = realloc(buf, cap);
        if (newbuf == NULL) {
            break;
        }
        buf = newbuf;
        len = readlink("/proc/self/exe", buf, cap);
        if (len < 0) {
            break;
        }
        if ((size_t)len < cap) {
            buf[len] = 0;
            return buf;
        }
    }
    free(buf);
    return NULL;
}

#include <stdio.h>

int main(void)
{
    char *e = exename();
    printf("%s\n", e ? e : "unknown");
    free(e);
    return 0;
}
_

これは、伝統的な「適切なバッファーサイズがわからない場合は、2の累乗で再割り当てする」というトリックを使用しています。パス名に64バイト未満を割り当てることは、努力する価値がないと想定します。また、16384(2 ** 14)バイトの実行可能パス名は、プログラムのインストール方法になんらかの異常があることを示している必要があると想定しています。パス名を知っておくと、すぐに大きな問題が発生するため、心配する必要はありません。約。

_PATH_MAX_のような定数を気にする必要はありません。非常に多くのメモリを予約することは、ほとんどすべてのパス名にとって過剰であり、別の回答で述べられているように、いずれにしても実際の上限であるとは限りません。このアプリケーションでは、16384などの常識的な上限を選択できます。常識的な上限がないアプリケーションでも、2の累乗の増加を再割り当てすることは良いアプローチです。 nバイトの結果には_log n_呼び出しのみが必要であり、浪費するメモリ容量は結果の長さに比例します。また、文字列の長さがrealloc()readlink()の間で変化する競合状態も回避します。

0
Lassi