Ç - LSTAT上的/ proc / PID / EXE(C - Lstat on /proc/

2019-10-20 09:49发布

我试图让大小在/ proc /进程/ EXE与LSTAT文件的字节。 这里是我的代码:

int     main(int argc, char *argv[]) 
{   
 struct stat    sb;
 char       *linkname;
 ssize_t    r;

  if (argc != 2) 
  {
    fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  if (lstat(argv[1], &sb) == -1) 
  {
    perror("lstat");
    exit(EXIT_FAILURE);
  }

  printf("sb.st_size %d\n", sb.st_size);   

  exit(EXIT_SUCCESS);
}

好像sb.st_size总是等于0,我不明白为什么。 此外,该样品是从的readlink(2)手册页中提取。

编辑:我试图得到它在openSUSE工作。

在此先感谢乌拉圭回合的帮助的人。

Answer 1:

在该文件中的/ proc不是普通的文件。 对大部分孩子来说, stat()等。 返回.st_size == 0

特别是, /proc/PID/exe是不是真的符号链接或硬链接,而是一个特殊的伪文件,其行为大多喜欢一个符号链接。

(如果你需要,你可以检测procfs的文件检查.st_dev领域。相较于.st_dev从获得lstat("/proc/self/exe",..)例如。)

要获取的路径,基于其PID特定execubtable,我建议的方法依靠的返回值readlink()代替:

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>

/* Creative Commons CC0: Public Domain dedication
 * (In jurisdictions without public domain, this example program
 *  is licensed under the Creative Commons CC0 license.)
 *
 * To the extent possible under law, Nominal Animal has waived all
 * copyright and related or neighboring rights to this example program.
 *
 * In other words, you are free to use it in any way you wish,
 * but if it breaks something, you get to keep all the pieces.
*/

/** exe_of() - Obtain the executable path a process is running
 * @pid: Process ID
 * @sizeptr: If specified, the allocated size is saved here
 * @lenptr: If specified, the path length is saved here
 * Returns the dynamically allocated pointer to the path,
 * or NULL with errno set if an error occurs.
*/
char *exe_of(const pid_t pid, size_t *const sizeptr, size_t *const lenptr)
{
    char   *exe_path = NULL;
    size_t  exe_size = 1024;
    ssize_t exe_used;
    char    path_buf[64];
    int     path_len;

    path_len = snprintf(path_buf, sizeof path_buf, "/proc/%ld/exe", (long)pid);
    if (path_len < 1 || path_len >= sizeof path_buf) {
        errno = ENOMEM;
        return NULL;
    }

    while (1) {

        exe_path = malloc(exe_size);
        if (!exe_path) {
            errno = ENOMEM;
            return NULL;
        }

        exe_used = readlink(path_buf, exe_path, exe_size - 1);
        if (exe_used == (ssize_t)-1)
            return NULL;

        if (exe_used < (ssize_t)1) {
            /* Race condition? */
            errno = ENOENT;
            return NULL;
        }

        if (exe_used < (ssize_t)(exe_size - 1))
            break;

        free(exe_path);
        exe_size += 1024;
    }

    /* Try reallocating the exe_path to minimum size.
     * This is optional, and can even fail without
     * any bad effects. */
    {
        char *temp;

        temp = realloc(exe_path, exe_used + 1);
        if (temp) {
            exe_path = temp;
            exe_size = exe_used + 1;
        }
    }

    if (sizeptr)
        *sizeptr = exe_size;

    if (lenptr)
        *lenptr = exe_used;

    exe_path[exe_used] = '\0';
    return exe_path;
}

int main(int argc, char *argv[])
{
    int   arg;
    char *exe;
    long  pid;
    char  dummy;

    if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
        printf("\n");
        printf("Usage: %s [ -h | --help ]\n", argv[0]);
        printf("       %s PID [ PID ... ]\n", argv[0]);
        printf("\n");
        return 0;
    }

    for (arg = 1; arg < argc; arg++)
        if (sscanf(argv[arg], " %ld %c", &pid, &dummy) == 1 && pid > 0L) {
            exe = exe_of((pid_t)pid, NULL, NULL);
            if (exe) {
                printf("Process %ld runs '%s'.\n", pid, exe);
                free(exe);
            } else
                printf("Process %ld: %s.\n", pid, strerror(errno));
        } else {
            printf("%s: Invalid PID.\n", argv[arg]);
            return 1;
        }

    return 0;
}

如上所述, exe_of()函数返回,其中所述伪符号链接的动态分配的拷贝/proc/PID/exe点,任选地存储所述分配的大小和/或路径长度太。 (示例程序上面并不​​需要他们,所以他们是NULL。)

这个想法很简单:分配初始动态指针是大多数情况下足够大,但不是大得离谱。 保留最后一个字节的结束串NUL字节。 如果返回的大小readlink()是一样的给它的缓冲区长度-它不添加终结结束串NUL字节本身- ,则缓冲区可能已经过短; 丢弃它,分配更大的缓冲器,和重试。

同样,如果你想读一个伪文件下的全部内容/proc/ ,您不能使用lstat() / stat()首先要搞清楚,你可能会缓冲多大需要; 你需要分配一个缓冲区,多读就可以了,并在必要时,只是重新分配一个更大的缓冲区。 (我可以显示该示例代码了。)

有问题吗?



Answer 2:

无法在我要回复很抱歉后发表评论!

Valgrind的将报告exe_path = malloc(exe_size); 在标称动物的职位为“块肯定已失去”。 所以,如果你正在使用的功能,那么你的记忆力会上升得非常快。

即使释放内存当您返回NULL会解决这个问题。 还应该增加从调用的malloc(字符*)的显式转换,使您使用-Wall GCC停止抱怨

char* exe_of(const pid_t pid, size_t *const sizeptr, size_t *const lenptr)
{
    char   *exe_path = NULL;
    size_t  exe_size = 1024;
    ssize_t exe_used;
    char    path_buf[64];
    unsigned int path_len;

    path_len = snprintf(path_buf, sizeof path_buf, "/proc/%ld/exe", (long)pid);
    if (path_len < 1 || path_len >= sizeof path_buf) {
        errno = ENOMEM;
        return NULL;
    }

    while (1) {

        exe_path = (char*)malloc(exe_size);
        if (!exe_path) {
            errno = ENOMEM;
            return NULL;
        }

        exe_used = readlink(path_buf, exe_path, exe_size - 1);
        if (exe_used == (ssize_t)-1) {
            free(exe_path);
            return NULL;
        }

        if (exe_used < (ssize_t)1) {
            /* Race condition? */
            errno = ENOENT;
            free(exe_path);
            return NULL;
        }

        if (exe_used < (ssize_t)(exe_size - 1))
            break;

        free(exe_path);
        exe_size += 1024;
    }

    /* Try reallocating the exe_path to minimum size.
     * This is optional, and can even fail without
     * any bad effects. */
    {
        char *temp;

        temp = (char*)realloc(exe_path, exe_used + 1);
        if (temp) {
            exe_path = temp;
            exe_size = exe_used + 1;
        }
    }

    if (sizeptr)
        *sizeptr = exe_size;

    if (lenptr)
        *lenptr = exe_used;

    exe_path[exe_used] = '\0';
    return exe_path;
}


Answer 3:

一般来说,你不必担心这一点,但名义动物评论后,似乎从/ proc / PID / EXE Linux的限制文件路径由PAGE_SIZE。 因此,即使文件系统支持长于路径,有没有办法让的readlink()给你这条道路,因为这是作为一个硬限制来实现。 我已经找到了另一种方式,所以如果执行的readlink失败ENAMETOOLONG,你可以阅读的/ proc / PID /地图,虽然这可能是碰碰运气,我发现它击中每个进程都在4个不同的发行版除非不具有系统进程实际文件名(ENOENT)

int getExecutableFromMaps(char *buf, size_t bufsize) {
  FILE *fp;
  char *mylinebuf = NULL;
  size_t mylinebufsize = 0;
  size_t counter = 0;
  size_t start = 0;
  size_t column = 0;
  int result = -1;
  fp = fopen("/proc/self/maps", "r");
  if( fp != NULL ) {
    if( getline(&mylinebuf, &mylinebufsize, fp) >= 0 ) {
      if( mylinebuf != NULL ) {
        while( column < 5 && counter < mylinebufsize ) {
          while( counter < mylinebufsize && mylinebuf[counter] != ' ') {
            counter++;
          }
          while( counter < mylinebufsize && mylinebuf[counter] == ' ') {
            counter++;
          }
          column++;
        }
        int start = counter;
        while( counter < mylinebufsize && (mylinebuf[counter] != '\n' && mylinebuf[counter] != '\r') ) {
          counter++;
        }
        if( counter <= mylinebufsize && start < counter && (counter-start+1)<=bufsize ) {
          memcpy(buf, &mylinebuf[start], counter-start);
          buf[counter-start+1] = 0;
          result = counter-start+1;
        }
      }
    }
    if( mylinebuf != NULL ) {
      free(mylinebuf);
    }
    fclose(fp);
  }
  return result;
}

注:这是补充代码只应被调用后的readlink失败,因为这是昂贵的。



文章来源: C - Lstat on /proc/pid/exe