解析/ proc psinfo和argv返回:对于定义的数据类型错误,值太大

时间:2015-06-24 11:07:45

标签: solaris ps solaris-10

我有一个相当简单的代码,用于处理solaris中的/ proc / *文件以获取进程信息和参数。在大多数情况下它工作(意味着它确实在某些进程上正确地显示了参数),但是在一些进程参数(特别是它们很长的地方)上,它失败并产生错误Value too large for defined data type

有没有人知道为什么会失败?

第108行失败的arguments数组的pread()行。

实际上它是一些带有许多参数的java进程,如果有帮助就会失败。

有趣的是:

  1. 检查二进制/proc/<pid>/psinfo文件,它非常小 - 显然不足以包含我在某些进程中查看的那种长参数。对psinfo文件的内容执行十六进制转储确认它们不存在。

  2. 当有长参数时,pr_argv的值为零。

  3. 在进一步挖掘时,看起来这些参数都在/proc/(pid)/object/tmpfs.394.2.71404854中。我想知道为什么。

  4. 代码:

    #include <dirent.h>
    #include <ctype.h>
    #include <assert.h>
    #include <malloc.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/processor.h>
    #include <sys/sysinfo.h>
    #include <sys/param.h>
    
    #include <kstat.h>
    #include <procfs.h>
    
    #define PROC_ERRNO ((errno == ENOENT) ? ESRCH : errno)
    
    #define my_pread(fd, ptr, type, offset) \
        (pread(fd, ptr, sizeof(type), offset) == sizeof(type))
    
    static int proc_psinfo_get(psinfo_t *psinfo, pid_t pid)
    {
        int fd, retval = 0;
        char buffer[BUFSIZ];
    
        sprintf(buffer, "/proc/%d/psinfo", pid);
    
        if ((fd = open(buffer, O_RDONLY)) < 0) {
            return ESRCH;
        }
    
        if (!my_pread(fd, psinfo, psinfo_t, 0)) {
            retval = errno;
        }
    
        close(fd);
    
        return retval;
    }
    
    int main(int argc, char **argv)
    {
        DIR *dirp = opendir("/proc");
        struct dirent *ent;
        char *models[] = {
            "unknown", "32bit", "64bit"
        };
    
        while ((ent = readdir(dirp))) {
            pid_t pid;
            psinfo_t psinfo;
            int retval;
            char buffer[BUFSIZ];
            char *argvb[56];
            char **argvp = argvb;
    
            int n, fd;
            size_t nread = 0;
            unsigned int argv_size;
    
            if (!isdigit(*ent->d_name)) {
                continue;
            }
            psinfo.pr_dmodel = 0;
            pid = strtoul(ent->d_name, NULL, 10);
            retval = proc_psinfo_get(&psinfo, pid);
            printf("---------------------------------\n");
            printf("pid=%d, status=%s, model=%s\n",
                   pid, retval ? strerror(retval) : "OK",
                   models[psinfo.pr_dmodel]);
    
            printf("Parent Pid: %ld\n", psinfo.pr_ppid);
        printf("UID: %ld\n", psinfo.pr_uid);
        printf("size: %ld\n", psinfo.pr_size);
        printf("rss: %ld\n", psinfo.pr_rssize);
    
            printf("pcpu: %d\n", psinfo.pr_pctcpu);
        printf("pctmem: %d\n", psinfo.pr_pctmem);
        printf("zoneid: %d\n", psinfo.pr_zoneid);
    
        printf("pr_sname: %c\n", psinfo.pr_lwp.pr_sname);
    
        printf("Up Start: (%ld, %ld)\n", psinfo.pr_start.tv_sec, psinfo.pr_start.tv_nsec);
            printf("Command: %s\n", psinfo.pr_fname);
    
        // print argc
            argv_size = sizeof(*argvp) * psinfo.pr_argc;
            sprintf(buffer, "/proc/%d/as", pid);
            printf("argc=%d, argv_size=%d\n",
                   psinfo.pr_argc, argv_size);
    
            if ((fd = open(buffer, O_RDONLY)) < 0) {
                printf("open(%s) == %s\n",
                       buffer, strerror(PROC_ERRNO));
                if (argvp != argvb) {
                    free(argvp);
                }
                continue;
            }
    
            if (argv_size > sizeof(argvb)) {
                argvp = malloc(argv_size);
            }
    
            if ((long int)(nread = pread(fd, argvp, argv_size, (off_t)psinfo.pr_argv)) <= 0) {
                close(fd);
            printf("error in reading argvp\n");
                printf("   pread(%d, 0x%lx, %d, 0x%lx) == %d (%s)\n",
                       fd, (unsigned long)argvp, argv_size,
                       (unsigned long)psinfo.pr_argv,
                       nread, strerror(errno));
                continue;
            }
    
        // parse the args here
            for (n = 0; n < psinfo.pr_argc; n++) {
                int alen;
                char *arg;
    
                if ((long int)(nread = pread(fd, buffer, sizeof(buffer), (off_t)argvp[n])) <= 0) {
                    close(fd);
            printf("buffer %d   argvp as ld %ld   argvp as lu %lu ", sizeof(buffer), argvp[n] , argvp[n] );
                    printf("   %-2d) pread(%d, 0x%lx, %d, 0x%lx) == %d (%s)\n",
                           n, fd, (unsigned long)&buffer[0], sizeof(buffer),
                           (unsigned long)argvp[n],
                           nread, strerror(errno));
                    break;
                }
    
                printf("   %-2d) nread=%-4d, ", n, nread);
                fflush(stdout);
                alen = strlen(buffer)+1;
                printf(" alen=%-4d ", alen);
                fflush(stdout);
                arg = malloc(alen);
                memcpy(arg, buffer, alen);
                printf(" {%s}\n", arg);
                fflush(stdout);
            }
    
            if (argvp != argvb) {
                free(argvp);
            }
    
            close(fd);
        }
    
        closedir(dirp);
    
        return 0;
    }
    

1 个答案:

答案 0 :(得分:0)

你试图从文件末尾的起始位置读取。

来自keywords documentation

  

ssize_t pread(int fildes,void * buf,size_t nbyte,off_t offset);

     

...

     

<强> EOVERFLOW

     

该文件是常规文件,nbyte大于0,起始   position位于文件结尾之前,起始位置是   大于或等于在公开场合确定的偏移最大值   与fildes相关的文件描述。