游戲廳游戲大全-mattslinks.com

google seo -> telegram: @ehseo6

">Newsnet 2022-10-02 07:20
  • home  >   /让互联网发展成果更好地造福社会   >   游戲廳游戲大全
  • 最賺錢的區塊鏈手游 鏈游手機游戲打金排行榜
    怎么治療失眠鏈 清風幫您 無限內購破解游戲大全
    imtoken錢包不需要手機號注冊嗎 how about 游戲廳游戲大全?
    What's the 游戲廳游戲大全 phone number? What is 游戲廳游戲大全 contact information ?
    Online consultation 游戲廳游戲大全 The picture of the 游戲廳游戲大全
    游戲廳游戲大全of the video Is 游戲廳游戲大全 for real ?
    游戲廳游戲大全's website A map of 游戲廳游戲大全
    游戲廳游戲大全 of tiktok 游戲廳游戲大全music
    游戲廳游戲大全 of news 游戲廳游戲大全app
    游戲廳游戲大全company Customer service of 游戲廳游戲大全 company

    皇冠体育招商『0886.tv』b3c1v2I-20221002

    皇冠体育招商『0886.tv』b3c1v2I-20221002

    皇冠体育招商『0886.tv』b3c1v2I-20221002

    回到main中,还剩最后一点点代码:

        lists_and_needs(); 
        finalize_stacks(); //<===
    
        if(forest_type || sort_list) fancy_spew(); 
        else simple_spew(); /* no sort, no forest */
        show_one_proc((proc_t *)-1,format_list); /* no output yet? */
    
        procps_pids_unref(&Pids_info);
        return 0;
    }
    

    finalize_stacks是一个……基本由宏组成的函数。中间重复的宏太多了我就删掉了。

    static void finalize_stacks (void)
    {
        format_node *f_node;
        sort_node *s_node;
    
    #if (PIDSITEMS < 60)
    # error PIDSITEMS (common.h) should be at least 60!
    #endif
    
        /* first, ensure minimum result structures for items
           which may or may not actually be displayable ... */
        Pids_index = 0;
    
        // needed by for selections
        chkREL(CMD)
        chkREL(ID_EGID)
        ………………
        chkREL(extra)
        chkREL(noop)
    
        // now accommodate any results not yet satisfied
        f_node = format_list;
        while (f_node) {
            (*f_node->pr)(NULL, NULL);
            f_node = f_node->next;
        }
        s_node = sort_list;
        while (s_node) {
            if (s_node->xe) (*s_node->xe)(NULL, NULL);
            s_node = s_node->next;
        }
    
        procps_pids_reset(Pids_info, Pids_items, Pids_index);
    }
    

    其中,chkREL的定义如下:

    #define namREL(e) rel_ ## e
    #define makEXT(e) extern int namREL(e);
    #define makREL(e) int namREL(e) = -1;
    #define chkREL(e) if (namREL(e) < 0) { \
          Pids_items[Pids_index] = PIDS_ ## e; \
          namREL(e) = (Pids_index < PIDSITEMS) ? Pids_index++ : rel_noop; }
    

    展开一下就是:

       if(rel_XX < 0) {
         Pids_items[Pids_index] = PIDS_XX;
         rel_XX = (Pids_index < PIDSITEMS) ? Pids_index++ : rel_noop;
       }
    

    chkREL实际做的事情就是初始化Pids_items中各不同的rel_XXX项。然后,对format_list中的每一项,都调用其pr()来处理。pr其实就是print函数,调用snprintf向其outbuf来输出内容。然后,对sort_list中的每一项,调用其xe()来处理。最后,调用procps_pids_reset。之前看过一次就不再重复了。

    回到main中,下一个函数是fancy_spew,当然仅当开启forest_type / sort_list后才调用。

        if(forest_type || sort_list) fancy_spew();  //<---
        else simple_spew(); /* no sort, no forest */
        show_one_proc((proc_t *)-1,format_list); /* no output yet? */
    
        procps_pids_unref(&Pids_info);
        return 0;
    }
    

    fancy_spew定义如下:

    /***** sorted or forest */
    static void fancy_spew(void) {
        struct pids_fetch *pidread;
        enum pids_fetch_type which;
        proc_t *buf;
        int i, n = 0;
    
        which = (thread_flags & TF_loose_tasks)
                ? PIDS_FETCH_THREADS_TOO : PIDS_FETCH_TASKS_ONLY;
    
        pidread = procps_pids_reap(Pids_info, which);
        if (!pidread || !pidread->counts->total) {
            fprintf(stderr, _("fatal library error, reap\n"));
            exit(EXIT_FAILURE);
        }
        processes = xcalloc(pidread->counts->total, sizeof(void*));
        for (i = 0; i < pidread->counts->total; i++) {
            buf = pidread->stacks[i];
            value_this_proc_pcpu(buf);
            if (want_this_proc(buf))
                processes[n++] = buf;
        }
        if (n) {
            if(forest_type) prep_forest_sort();
            while(sort_list) {
                procps_pids_sort(Pids_info, processes, n, sort_list->sr, sort_list->reverse);
                sort_list = sort_list->next;
            }
            if(forest_type) show_forest(n);
            else show_proc_array(n);
        }
        free(processes);
    }
    

    调用的第一个函数是procps_pids_reap。这个函数是一个重要的信息处理函数。它调用pids_oldproc_open。

    /* procps_pids_reap():
     *
     * Harvest all the available tasks/threads and provide the result
     * stacks along with a summary of the information gathered.
     *
     * Returns: pointer to a pids_fetch struct on success, NULL on error.
     */
    PROCPS_EXPORT struct pids_fetch *procps_pids_reap (
        struct pids_info *info,
        enum pids_fetch_type which)
    {
        int rc;
    
        errno = EINVAL;
        if (info == NULL)
            return NULL;
        if (which != PIDS_FETCH_TASKS_ONLY && which != PIDS_FETCH_THREADS_TOO)
            return NULL;
        /* with items & numitems technically optional at 'new' time, it's
           expected 'reset' will have been called -- but just in case ... */
        if (!info->curitems)
            return NULL;
        errno = 0;
    
        if (!pids_oldproc_open(&info->fetch_PT, info->oldflags))
            return NULL;
        info->read_something = which ? readeither : readproc;
    
        rc = pids_stacks_fetch(info);
    
        pids_oldproc_close(&info->fetch_PT);
        // we better have found at least 1 pid
        return (rc > 0) ? &info->fetch.results : NULL;
    } // end: procps_pids_reap
    

    pids_oldproc_open定义如下,重要的一眼就可以看出来,openproc函数。

    static inline int pids_oldproc_open (
        PROCTAB **this,
        unsigned flags,
        ...)
    {
        va_list vl;
        int *ids;
        int num = 0;
    
        if (*this == NULL) {
            va_start(vl, flags);
            ids = va_arg(vl, int*);
            if (flags & PROC_UID) num = va_arg(vl, int);
            va_end(vl);
            if (NULL == (*this = openproc(flags, ids, num)))
                return 0;
        }
        return 1;
    } // end: pids_oldproc_open
    

    openproc的定义如下,函数比较长,重要的内容我们分段切入阅读。

    // initiate a process table scan
    PROCTAB *openproc(unsigned flags, ...) {
        va_list ap;
        struct stat sbuf;
        static __thread int did_stat;
        PROCTAB *PT = calloc(1, sizeof(PROCTAB));
    
        if (!PT)
            return NULL;
        if (!did_stat) {
            task_dir_missing = stat("/proc/self/task", &sbuf);
            did_stat = 1;
        }
    

    这里注册一些处理函数。

        PT->taskdir = NULL;
        PT->taskdir_user = -1;
        PT->taskfinder = simple_nexttid;
        PT->taskreader = simple_readtask;
    
        PT->reader = simple_readproc;
        if (flags & PROC_PID) {
            PT->procfs = NULL;
            PT->finder = listed_nextpid;
        } else {
            PT->procfs = opendir("/proc");
            if (!PT->procfs) {
                free(PT);
                return NULL;
            }
            PT->finder = simple_nextpid;
        }
        PT->flags = flags;
    

    如果传入的内容包含一组pid/uid则这里读取它们。我们现在还没遇到这个情况,暂且不理。

        va_start(ap, flags);
        if (flags & PROC_PID)
            PT->pids = va_arg(ap, pid_t*);
        else if (flags & PROC_UID) {
            PT->uids = va_arg(ap, uid_t*);
            PT->nuid = va_arg(ap, int);
        }
        va_end(ap);
    

    MAX_BUFSZ为1024 * 64 * 2字节。这里初始化src_buffer和dst_buffer(都是全局变量)。

        if (!src_buffer
                && !(src_buffer = malloc(MAX_BUFSZ))) {
            closedir(PT->procfs);
            free(PT);
            return NULL;
        }
        if (!dst_buffer
                && !(dst_buffer = malloc(MAX_BUFSZ))) {
            closedir(PT->procfs);
            free(src_buffer);
            free(PT);
            return NULL;
        }
    
        return PT;
    }
    

    两个buffer已经申请完成,回到上上一层的procps_pids_reap中。下一个调用的函数是pids_stacks_fetch。其代码如下:

    static int pids_stacks_fetch (
        struct pids_info *info)
    {
    #define n_alloc  info->fetch.n_alloc
    #define n_inuse  info->fetch.n_inuse
    #define n_saved  info->fetch.n_alloc_save
        struct stacks_extent *ext;
    

    最前方是一堆初始化的,这里先懒得看了,有需要后面再返回来阅读。STACKS_INIT的值是1024。

        // initialize stuff -----------------------------------
        if (!info->fetch.anchor) {
            if (!(info->fetch.anchor = calloc(STACKS_INIT, sizeof(void *))))
                return -1;
            if (!(ext = pids_stacks_alloc(info, STACKS_INIT)))
                return -1;       // here, errno was set to ENOMEM
            memcpy(info->fetch.anchor, ext->stacks, sizeof(void *) * STACKS_INIT);
            n_alloc = STACKS_INIT;
        }
        pids_toggle_history(info);
        memset(&info->fetch.counts, 0, sizeof(struct pids_counts));
    

    之后就到具体的处理函数了。info->read_something由procps_pids_reap设置,如果fetch的是PIDS_FETCH_TASKS_ONLY则read_something是readeither,否则是readproc。这个标志由thread_flags决定(fancy_spew中设置)。

        // iterate stuff --------------------------------------
        n_inuse = 0;
        while (info->read_something(info->fetch_PT, &info->fetch_proc)) {
    

    readeither,其代码如下。调用的函数也如注释中描述的那样,是一堆simple_函数。

    //////////////////////////////////////////////////////////////////////////////////
    // readeither: return a pointer to a proc_t filled with requested info about
    // the next unique process or task available.  If no more are available,
    // return a null pointer (boolean false).
    proc_t *readeither (PROCTAB *restrict const PT, proc_t *restrict x) {
        static __thread proc_t skel_p;    // skeleton proc_t, only uses tid + tgid
        static __thread proc_t *new_p;    // for process/task transitions
        static __thread int canary, leader;
        char path[PROCPATHLEN];
        proc_t *ret;
    
        free_acquired(x);
    
        if (new_p) {
            if (new_p->tid != canary) new_p = NULL;
            goto next_task;
        }
    
    next_proc:
        new_p = NULL;
        for (;;) {
            if (errno == ENOMEM) goto end_procs;
            // fills in the PT->path, plus skel_p.tid and skel_p.tgid
            if (!PT->finder(PT,&skel_p)) goto end_procs;       // simple_nextpid
            leader = skel_p.tid;
            if (!task_dir_missing) break;
            if ((ret = PT->reader(PT,x))) return ret;          // simple_readproc
        }
    
    next_task:
        // fills in our path, plus x->tid and x->tgid
        if (!(PT->taskfinder(PT,&skel_p,x,path)))              // simple_nexttid
            goto next_proc;
        /* to avoid loss of some thread group leader data,
           we must check its base dir, not its 'task' dir! */
        if (x->tid == leader) ret = PT->reader(PT,x);          // simple_readproc
        else ret = PT->taskreader(PT,x,path);                  // simple_readtask
        if (!ret) goto next_proc;
        if (!new_p) {
            new_p = ret;
            canary = new_p->tid;
        }
        return ret;
    
    end_procs:
        return NULL;
    }
    

    我们随便抽几个例子看一下。首先是simple_nextpid。它在/proc下读取下一个文件夹。

    //////////////////////////////////////////////////////////////////////////////////
    // This finds processes in /proc in the traditional way.
    // Return non-zero on success.
    static int simple_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p) {
    static __thread struct dirent *ent; /* dirent handle */
    char *restrict const path = PT->path;
    for (;;) {
    ent = readdir(PT->procfs);
    if(!ent || !ent->d_name[0]) return 0;
    if(*ent->d_name > '0' && *ent->d_name <= '9') break;
    }
    p->tgid = strtoul(ent->d_name, NULL, 10);
    p->tid = p->tgid;
    snprintf(path, PROCPATHLEN, "/proc/%s", ent->d_name);
    return 1;
    }

    而具体处理/proc信息的是simple_readproc,我们依旧分解着来读。

    //////////////////////////////////////////////////////////////////////////////////
    // This reads process info from /proc in the traditional way, for one process.
    // The pid (tgid? tid?) is already in p, and a path to it in path, with some
    // room to spare.
    static proc_t *simple_readproc(PROCTAB *restrict const PT, proc_t *restrict const p) {
        static __thread struct utlbuf_s ub = { NULL, 0 };    // buf for stat,statm,status
        static __thread struct stat sb;     // stat() buffer
        char *restrict const path = PT->path;
        unsigned flags = PT->flags;
        int rc = 0;
    
        if (stat(path, &sb) == -1)                  /* no such dirent (anymore) */
            goto next_proc;
    
        if ((flags & PROC_UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid))
            goto next_proc;                      /* not one of the requested uids */
    

    这里遇到一个XinLN宏,用于测试列表的前N个项目中有没有某个类型的值。这里列表是PT->uids。

    /* Test if item X of type T is present in the 0 terminated list L */
    #   define XinL(T, X, L) ( {                    \
                T  x = (X), *l = (L);               \
                while (*l && *l != x) l++;          \
                *l == x;                            \
            } )
    
    /* Test if item X of type T is present in the list L of length N */
    #   define XinLN(T, X, L, N) ( {                \
                T x = (X), *l = (L);                \
                int i = 0, n = (N);                 \
                while (i < n && l[i] != x) i++;     \
                i < n && l[i] == x;                 \
            } )
    

    回到原来的代码里。很快可以看到一个名为file2str的函数,用于从文件中读取数据,放到ub->buf里。

    static int file2str(const char *directory, const char *what, struct utlbuf_s *ub) {
    #define buffGRW 1024
        char path[PROCPATHLEN];
        int fd, num, tot_read = 0, len;
    
        /* on first use we preallocate a buffer of minimum size to emulate
           former 'local static' behavior -- even if this read fails, that
           buffer will likely soon be used for another subdirectory anyway
           ( besides, with the calloc call we will never need use memcpy ) */
        if (ub->buf) ub->buf[0] = '\0';
        else {
            ub->buf = calloc(1, (ub->siz = buffGRW));
            if (!ub->buf) return -1;
        }
        len = snprintf(path, sizeof path, "%s/%s", directory, what);
        if (len <= 0 || (size_t)len >= sizeof path) return -1;
        if (-1 == (fd = open(path, O_RDONLY, 0))) return -1;
        while (0 < (num = read(fd, ub->buf + tot_read, ub->siz - tot_read))) {
            tot_read += num;
            if (tot_read < ub->siz) break;
            if (ub->siz >= INT_MAX - buffGRW) {
                tot_read--;
                break;
            }
            if (!(ub->buf = realloc(ub->buf, (ub->siz += buffGRW)))) {
                close(fd);
                return -1;
            }
        };
        ub->buf[tot_read] = '\0';
        close(fd);
        if (tot_read < 1) return -1;
        return tot_read;
    #undef buffGRW
    }
    

    回到外层函数,可以看到它读取stat,然后调用stat2proc(其他同)对读取到的数据进行处理。这里的处理都是psproc的核心功能,因此我们会挨个跟踪进去。

        p->euid = sb.st_uid;                        /* need a way to get real uid */
        p->egid = sb.st_gid;                        /* need a way to get real gid */
    

    首先是stat2proc。stat文件形式类似:

    $ cat /proc/13/stat
    13 (bash) S 12 13 12 1025 0 0 0 0 0 0 21 59 120 489 20 0 1 0 34 213183188992 1011 18446744073709551615 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    

    stat2proc(是的我没贴代码……不然太多了)会去查找( ) 括号中的内容,这个是来自task_struct结构的进程名,最长只有15字节。为了处理进程名中的特殊字符,它还会对其进行简单替换,然后对剩余内容进行扫描(sscanf)并保存到结构体中。

        if (flags & PROC_FILLSTAT) {                // read /proc/#/stat
            if (file2str(path, "stat", &ub) == -1)
                goto next_proc;
            rc += stat2proc(ub.buf, p);
        }
    

    接下来是io的内容,一个sscanf解决。

        if (flags & PROC_FILLIO) {                  // read /proc/#/io
            if (file2str(path, "io", &ub) != -1)
                io2proc(ub.buf, p);
        }
    

    然后是读取smaps,不过是从smaps_rollup读取。这个文件在哪个系统里有我目前还不清楚。它解析该文件,然后把每一项都创建一个object存起来。

        if (flags & PROC_FILLSMAPS) {               // read /proc/#/smaps_rollup
            if (file2str(path, "smaps_rollup", &ub) != -1)
                smaps2proc(ub.buf, p);
        }
    

    statm,一样是sscanf读取。

        if (flags & PROC_FILLMEM) {                 // read /proc/#/statm
            if (file2str(path, "statm", &ub) != -1)
                statm2proc(ub.buf, p);
        }
    

    status,一样。pwcache_get_user调用getpwuid来获取信息。如果用户名过长,则只复制uid部分。

        if (flags & PROC_FILLSTATUS) {              // read /proc/#/status
            if (file2str(path, "status", &ub) != -1) {
                rc += status2proc(ub.buf, p, 1);
                if (flags & (PROC_FILL_SUPGRP & ~PROC_FILLSTATUS))
                    rc += supgrps_from_supgids(p);
                if (flags & (PROC_FILL_OUSERS & ~PROC_FILLSTATUS)) {
                    p->ruser = pwcache_get_user(p->ruid);
                    p->suser = pwcache_get_user(p->suid);
                    p->fuser = pwcache_get_user(p->fuid);
                }
                if (flags & (PROC_FILL_OGROUPS & ~PROC_FILLSTATUS)) {
                    p->rgroup = pwcache_get_group(p->rgid);
                    p->sgroup = pwcache_get_group(p->sgid);
                    p->fgroup = pwcache_get_group(p->fgid);
                }
            }
        }
    
        // if multithreaded, some values are crap
        if(p->nlwp > 1)
            p->wchan = ~0ul;
    
        /* some number->text resolving which is time consuming */
        /* ( names are cached, so memcpy to arrays was silly ) */
        if (flags & PROC_FILLUSR)
            p->euser = pwcache_get_user(p->euid);
        if (flags & PROC_FILLGRP)
            p->egroup = pwcache_get_group(p->egid);
    

    继续,environ部分。首先仍然是读取environ文件,但是如果失败了,则调用vectorize_dash_rc解析p->environ_v。

        if (flags & PROC_FILLENV)                   // read /proc/#/environ
            if (!(p->environ_v = file2strvec(path, "environ")))
                rc += vectorize_dash_rc(&p->environ_v);
        if (flags & PROC_EDITENVRCVT)
            rc += fill_environ_cvt(path, p);
    

    这里出现了一个新函数,vectorize_dash_rc,把"-"转为一个“vector元素”保存在*vec中。

    // This littl' guy just serves those true vectorized fields
    // ( when a /proc source field didn't exist )
    static int vectorize_dash_rc (char ***vec) {
        if (!(*vec = vectorize_this_str("-")))
            return 1;
        return 0;
    }
    char **vectorize_this_str (const char *src) {
    #define pSZ  (sizeof(char*))
        char *cpy, **vec;
        size_t adj, tot;
    
        tot = strlen(src) + 1;                       // prep for our vectors
        if (tot < 1 || tot >= INT_MAX) tot = INT_MAX-1; // integer overflow?
        adj = (pSZ-1) - ((tot + pSZ-1) & (pSZ-1));   // calc alignment bytes
        cpy = calloc(1, tot + adj + (2 * pSZ));      // get new larger buffer
        if (!cpy) return NULL;                       // oops, looks like ENOMEM
        snprintf(cpy, tot, "%s", src);               // duplicate their string
        vec = (char**)(cpy + tot + adj);             // prep pointer to pointers
        *vec = cpy;                                  // point 1st vector to string
        *(vec+1) = NULL;                             // null ptr 'list' delimit
        return vec;                                  // ==> free(*vec) to dealloc
    #undef pSZ
    }
    

    最后回来调用fill_environ_cvt。

    // This routine reads an 'environ' for the designated proc_t and
    // guarantees the caller a valid proc_t.environ pointer.
    static int fill_environ_cvt (const char *directory, proc_t *restrict p) {
        dst_buffer[0] = '\0';
        if (read_unvectored(src_buffer, MAX_BUFSZ, directory, "environ", ' '))
            escape_str(dst_buffer, src_buffer, MAX_BUFSZ);
        p->environ = strdup(dst_buffer[0] ? dst_buffer : "-");
        if (!p->environ)
            return 1;
        return 0;
    }
    

    它调用read_unvectored来解析数据。它的前半部分从文件中读取数据(这个单独封装成一个函数不好吗……重复看到好多次了)。如果出现“\n”或者“\0”,则改为“sep”(最后一个参数)。

    // this is the former under utilized 'read_cmdline', which has been
    // generalized in support of these new libproc flags:
    //     PROC_EDITCGRPCVT, PROC_EDITCMDLCVT and PROC_EDITENVRCVT
    static int read_unvectored(char *restrict const dst, unsigned sz, const char *whom, const char *what, char sep) {
        char path[PROCPATHLEN];
        int fd, len;
        unsigned n = 0;
    
        if(sz <= 0) return 0;
        if(sz >= INT_MAX) sz = INT_MAX-1;
        dst[0] = '\0';
    
        len = snprintf(path, sizeof(path), "%s/%s", whom, what);
        if(len <= 0 || (size_t)len >= sizeof(path)) return 0;
        fd = open(path, O_RDONLY);
        if(fd==-1) return 0;
    
        for(;;) {
            ssize_t r = read(fd,dst+n,sz-n);
            if(r==-1) {
                if(errno==EINTR) continue;
                break;
            }
            if(r<=0) break;  // EOF
            n += r;
            if(n==sz) {      // filled the buffer
                --n;         // make room for '\0'
                break;
            }
        }
        close(fd);
        if(n) {
            unsigned i = n;
            while(i && dst[i-1]=='\0') --i; // skip trailing zeroes
            while(i--)
                if(dst[i]=='\n' || dst[i]=='\0') dst[i]=sep;
            if(dst[n-1]==' ') dst[n-1]='\0';
        }
        dst[n] = '\0';
        return n;
    }
    

    处理结束后调用escape_str。MAX_BUFSZ是1024642。escape_str定义如下,用于标准化字符串。

    static inline void esc_all (unsigned char *str) {
        unsigned char c;
    
        // if bad locale/corrupt str, replace non-printing stuff
        while (*str) {
            if ((c = ESC_tab[*str]) != '|')
                *str = c;
            ++str;
        }
    }
    
    static inline void esc_ctl (unsigned char *str, int len) {
        int i, n;
    
        for (i = 0; i < len; ) {
            // even with a proper locale, strings might be corrupt
            if ((n = UTF_tab[*str]) < 0 || i + n > len) {
                esc_all(str);
                return;
            }
            // and eliminate those non-printing control characters
            if (*str < 0x20 || *str == 0x7f)
                *str = '?';
            str += n;
            i += n;
        }
    }
    
    int escape_str (unsigned char *dst, const unsigned char *src, int bufsize) {
        static __thread int utf_sw = 0;
        int n;
    
        if (utf_sw == 0) {
            char *enc = nl_langinfo(CODESET);
            utf_sw = enc && strcasecmp(enc, "UTF-8") == 0 ? 1 : -1;
        }
        SECURE_ESCAPE_ARGS(dst, bufsize);
        n = snprintf(dst, bufsize, "%s", src);
        if (n < 0) {
            *dst = '\0';
            return 0;
        }
        if (n >= bufsize) n = bufsize-1;
        if (utf_sw < 0)
            esc_all(dst);
        else
            esc_ctl(dst, n);
        return n;
    }
    

    下一行,类似的做法,只不过处理cmdline。

        if (flags & PROC_FILLARG)                   // read /proc/#/cmdline
            if (!(p->cmdline_v = file2strvec(path, "cmdline")))
                rc += vectorize_dash_rc(&p->cmdline_v);
        if (flags & PROC_EDITCMDLCVT)
            rc += fill_cmdline_cvt(path, p);
    

    fill_cmdline_cvt稍有不同。

    // This routine reads a 'cmdline' for the designated proc_t, "escapes"
    // the result into a single string while guaranteeing the caller a
    // valid proc_t.cmdline pointer.
    static int fill_cmdline_cvt (const char *directory, proc_t *restrict p) {
    #define uFLG ( ESC_BRACKETS | ESC_DEFUNCT )
        if (read_unvectored(src_buffer, MAX_BUFSZ, directory, "cmdline", ' '))
            escape_str(dst_buffer, src_buffer, MAX_BUFSZ);
        else
            escape_command(dst_buffer, p, MAX_BUFSZ, uFLG);
        p->cmdline = strdup(dst_buffer[0] ? dst_buffer : "?");
        if (!p->cmdline)
            return 1;
        return 0;
    #undef uFLG
    }
    

    其中escape_command定义如下。这里将数据解析到pp->cmd中。pp是上一层的“p”,最早在stat中被设置。

    // Reads /proc/*/stat files, being careful not to trip over processes with
    // names like ":-) 1 2 3 4 5 6".
    static int stat2proc (const char *S, proc_t *restrict P) {
        char buf[64], raw[64];
        //...............
            if (!P->cmd) {
                num = tmp - S;
                memcpy(raw, S, num);
                raw[num] = '\0';
                escape_str(buf, raw, sizeof(buf));
                if (!(P->cmd = strdup(buf))) return 1;    //<------------
            }
    
    
    
    int escape_command (unsigned char *outbuf, const proc_t *pp, int bytes, unsigned flags) {
        int overhead = 0;
        int end = 0;
    
        if (flags & ESC_BRACKETS)
            overhead += 2;
        if (flags & ESC_DEFUNCT) {
            if (pp->state == 'Z') overhead += 10;    // chars in " <defunct>"
            else flags &= ~ESC_DEFUNCT;
        }
        if (overhead + 1 >= bytes) {
            // if no room for even one byte of the command name
            outbuf[0] = '\0';
            return 0;
        }
        if (flags & ESC_BRACKETS)
            outbuf[end++] = '['; 
        end += escape_str(outbuf+end, pp->cmd, bytes-overhead);  //<----从cmd拷贝到outbuf+end。
        // we want "[foo] <defunct>", not "[foo <defunct>]"
        if (flags & ESC_BRACKETS)
            outbuf[end++] = ']'; 
        if (flags & ESC_DEFUNCT) {
            memcpy(outbuf+end, " <defunct>", 10);  
            end += 10;
        }
        outbuf[end] = '\0';
        return end;  // bytes, not including the NUL
    }
    

    接下来是读取cgroup、oom_score/oom_score_adj/ns/sdlogin

        if ((flags & PROC_FILLCGROUP))              // read /proc/#/cgroup
            if (!(p->cgroup_v = file2strvec(path, "cgroup")))
                rc += vectorize_dash_rc(&p->cgroup_v);
        if (flags & PROC_EDITCGRPCVT)
            rc += fill_cgroup_cvt(path, p);
    
        if (flags & PROC_FILLOOM) {
            if (file2str(path, "oom_score", &ub) != -1)
                oomscore2proc(ub.buf, p);
            if (file2str(path, "oom_score_adj", &ub) != -1)
                oomadj2proc(ub.buf, p);
        }
    
        if (flags & PROC_FILLNS)                    // read /proc/#/ns/*
            procps_ns_read_pid(p->tid, &(p->ns));
    
    
        if (flags & PROC_FILLSYSTEMD)               // get sd-login.h stuff
            rc += sd2proc(p);
    

    这里读取lxc container相关的内容。

        if (flags & PROC_FILL_LXC)                  // value the lxc name
            p->lxcname = lxc_containers(path);
    
        if (flags & PROC_FILL_LUID)                 // value the login user id
            p->luid = login_uid(path);
    

    解析exe指向的路径。

        if (flags & PROC_FILL_EXE) {
            if (!(p->exe = readlink_exe(path)))
                rc += 1;
        }
    

    以及最后一小部分内容。

        if (flags & PROC_FILLAUTOGRP)               // value the 2 autogroup fields
            autogroup_fill(path, p);
    
        if (rc == 0) return p;
        errno = ENOMEM;
    next_proc:
        return NULL;
    }
    

    读取完成后回到readeither里,另一个重要的是simple_readtask。但它读取的基本一样,不同的是它从/proc/#/task/#下面读。最后重复这一步骤直到所有的被读完。

    另一个函数是readproc,是一个简化版readeither它的定义如下

    proc_t *readproc(PROCTAB *restrict const PT, proc_t *restrict p) {
        proc_t *ret;
    
        free_acquired(p);
    
        for(;;) {
            if (errno == ENOMEM) goto out;
            // fills in the path, plus p->tid and p->tgid
            if (!PT->finder(PT,p)) goto out;
    
            // go read the process data
            ret = PT->reader(PT,p);
            if(ret) return ret;
        }
    
    out:
        return NULL;
    }
    

    回到外侧pids_stacks_fetch中,剩余的基本就是在整理数据,并做展示前的准备工作。

            if (!(n_inuse < n_alloc)) {
                n_alloc += STACKS_GROW;
                if (!(info->fetch.anchor = realloc(info->fetch.anchor, sizeof(void *) * n_alloc))
                        || (!(ext = pids_stacks_alloc(info, STACKS_GROW))))
                    return -1;   // here, errno was set to ENOMEM
                memcpy(info->fetch.anchor + n_inuse, ext->stacks, sizeof(void *) * STACKS_GROW);
            }
            if (!pids_proc_tally(info, &info->fetch.counts, &info->fetch_proc))
                return -1;       // here, errno was set to ENOMEM
            if (!pids_assign_results(info, info->fetch.anchor[n_inuse++], &info->fetch_proc))
                return -1;       // here, errno was set to ENOMEM
        }
        /* while the possibility is extremely remote, the readproc.c (read_something) |
           simple_readproc and simple_readtask guys could have encountered this error |
           in which case they would have returned a NULL, thus ending our while loop. | */
        if (errno == ENOMEM)
            return -1;
    
        // finalize stuff -------------------------------------
        /* note: we go to this trouble of maintaining a duplicate of the consolidated |
                 extent stacks addresses represented as our 'anchor' since these ptrs |
                 are exposed to a user (um, not that we don't trust 'em or anything). |
                 plus, we can NULL delimit these ptrs which we couldn't do otherwise. | */
        if (n_saved < n_inuse + 1) {
            n_saved = n_inuse + 1;
            if (!(info->fetch.results.stacks = realloc(info->fetch.results.stacks, sizeof(void *) * n_saved)))
                return -1;
        }
        memcpy(info->fetch.results.stacks, info->fetch.anchor, sizeof(void *) * n_inuse);
        info->fetch.results.stacks[n_inuse] = NULL;
    
        return n_inuse;     // callers beware, this might be zero !
    #undef n_alloc
    #undef n_inuse
    #undef n_saved
    } // end: pids_stacks_fetch
    

    标签:none

    添加新评论


    请输入验证码

    体彩17190期七位数 河北快三近50 排列三吧贴 风吹雪pc蛋蛋预测软件手机版 湖北福彩3q开奖
    不即不离大乐透 体彩 福彩正版藏机诗 11选5直组任最快 山东 福建十一选五遗漏数据查询 看49期快三开奖结果 百度
    程远大乐透最新预测 排列五和值200期走势图 河南福彩官网首页 大乐透浙江走势1 500万彩票下载
    山东十一选五推荐号码预测 超级大乐透7加3中3加2 我要找福彩3d字谜 排列三012路 图文 排列三振幅走势