📄 readproc.c
字号:
rbuf = xrealloc(rbuf, tot + c + align); /* make room for ptrs AT END */ endbuf = rbuf + tot; /* addr just past data buf */ q = ret = (char**) (endbuf+align); /* ==> free(*ret) to dealloc */ *q++ = p = rbuf; /* point ptrs to the strings */ endbuf--; /* do not traverse final NUL */ while (++p < endbuf) if (!*p) /* NUL char implies that */ *q++ = p+1; /* next string -> next char */ *q = 0; /* null ptr list terminator */ return ret;}/* These are some nice GNU C expression subscope "inline" functions. The can be used with arbitrary types and evaluate their arguments exactly once.*//* 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; \ } )/* readproc: return a pointer to a proc_t filled with requested info about the * next process available matching the restriction set. If no more such * processes are available, return a null pointer (boolean false). Use the * passed buffer instead of allocating space if it is non-NULL. *//* This is optimized so that if a PID list is given, only those files are * searched for in /proc. If other lists are given in addition to the PID list, * the same logic can follow through as for the no-PID list case. This is * fairly complex, but it does try to not to do any unnecessary work. * Unfortunately, the reverse filtering option in which any PID *except* the * ones listed is pursued. */#define flags (PT->flags)proc_t* readproc(PROCTAB* PT, proc_t* rbuf) { static struct direct *ent; /* dirent handle */ static struct stat sb; /* stat buffer */ static char path[32], sbuf[256]; /* bufs for stat,statm */ int allocated = 0, matched = 0; /* flags */ proc_t *p = NULL; /* loop until a proc matching restrictions is found or no more processes */ /* I know this could be a while loop -- this way is easier to indent ;-) */next_proc: /* get next PID for consideration */ if (Do(PID)) { if (!*PT->pids) /* set to next item in pids */ return NULL; sprintf(path, "/proc/%d", *(PT->pids)++); matched = 1; } else { /* get next numeric /proc ent */ while ((ent = readdir(PT->procfs)) && (*ent->d_name < '0' || *ent->d_name > '9')) ; if (!ent || !ent->d_name) return NULL; sprintf(path, "/proc/%s", ent->d_name); } if (stat(path, &sb) == -1) /* no such dirent (anymore) */ goto next_proc; if (Do(UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid)) goto next_proc; /* not one of the requested uids */ if (!allocated) { /* assign mem for return buf */ p = rbuf ? rbuf : xcalloc(p, sizeof *p); /* passed buf or alloced mem */ allocated = 1; /* remember space is set up */ } p->uid = sb.st_uid; /* need a way to get real uid */ if ((file2str(path, "stat", sbuf, sizeof sbuf)) == -1) goto next_proc; /* error reading /proc/#/stat */ stat2proc(sbuf, p); /* parse /proc/#/stat *//* OMINFO { */ p->where = readint( path , "where" ); /* parse /proc/#/where */ p->nmigs = readint( path , "nmigs" ); /* parse /proc/#/nmigs */ if ( oMout ) /* useless stuff for mtop, only mps set oMout to CL_fmt */ { p->lock = readint( path , "lock" ); /* parse /proc/#/lock */ /* ** !!! dynamic allocation of readcantmove() is a memory leak if used by mtop !!! ** (ininfluent if used by mps since its output is page buffered) */ p->cantmove = readcantmove( path , p->lock ); /* parse /proc/#/cantmove */ } else { /* ** if mps && !oMout, avoid segfault on compare (--sort) of empty fields ** if mtop, nop nop (assigment but don't waste time and resources) */ p->lock = 0; p->cantmove = ""; }/* } OMINFO */ if (!matched && Do(TTY) && !XinL(dev_t, p->tty, PT->ttys)) goto next_proc; /* not one of the requested ttys */ if (!matched && Do(ANYTTY) && p->tty == -1) goto next_proc; /* no controlling terminal */ if (!matched && Do(STAT) && !strchr(PT->stats,p->state)) goto next_proc; /* not one of the requested states */ if (Do(FILLMEM)) { /* read, parse /proc/#/statm */ if ((file2str(path, "statm", sbuf, sizeof sbuf)) != -1 ) statm2proc(sbuf, p); /* ignore statm errors here */ } /* statm fields just zero */ /* some number->text resolving which is time consuming */ if (Do(FILLTTY)) dev_to_tty(p->ttyc, p->tty); if (Do(FILLUSR)) strncpy(p->user, user_from_uid(p->uid), sizeof p->user); if (Do(FILLCMD)) /* read+parse /proc/#/cmdline */ p->cmdline = file2strvec(path, "cmdline"); if (Do(FILLENV)) /* read+parse /proc/#/environ */ p->environ = file2strvec(path, "environ"); if (p->state == 'Z') /* fixup cmd for zombies */ strncat(p->cmd," <zombie>", sizeof p->cmd); return p;}#undef flags/* Convenient wrapper around openproc and readproc to slurp in the whole process * tree subset satisfying the constraints of flags and the optional PID list. * Free allocated memory with freeproctree(). The tree structure is a classic * left-list children + right-list siblings. The algorithm is a two-pass of the * process table. Since most process trees will have children with strictly * increasing PIDs, most of the structure will be picked up in the first pass. * The second loop then cleans up any nodes which turn out to have preceeded * their parent in /proc order. *//* Traverse tree 't' breadth-first looking for a process with pid p */proc_t* LookupPID(proc_t* t, pid_t p) { proc_t* tmp = NULL; if (!t) return NULL; if (t->pid == p) /* look here/terminate recursion */ return t; if ((tmp = LookupPID(t->l, p))) /* recurse over children */ return tmp; for (; t; t=t->r) /* recurse over siblings */ if ((tmp = LookupPID(tmp, p))) return tmp; return NULL;}proc_t* readproctree(int flags, ...) { static proc_t tree; PROCTAB* PT = NULL; proc_t *node, *tmp=NULL, *tmp2=NULL; va_list ap; /* pass through apropriate arguments to openproc */ va_start(ap, flags); if (Do(UID)) { /* temporary variables to ensure that va_arg() instances * are called in the right order */ uid_t* u; int i; u = va_arg(ap, uid_t*); i = va_arg(ap, int); PT = openproc(flags, u, i); } else if (Do(PID) || Do(TTY) || Do(STAT)) PT = openproc(flags, va_arg(ap, void*)); else PT = openproc(flags); va_end(ap); /* first pass: build tree, putting orphans on the first level */ tree.l = tree.r = NULL; while ((node = readproc(PT,0))) if ((tmp = LookupPID(&tree, node->ppid))) { node->r = tmp->l->r; /* node --> left list of parent */ tmp->l->r = node; } else { node->r = tree.r; /* node --> right list of 'tree' */ tree.r = node; } /* second pass: scan tree for PPIDs of level-1 nodes moving links as necessary */ for (node = &tree; node; node = node->r) if ((tmp = LookupPID(&tree, node->r->ppid))) { tmp2 = node->r; /* unlink from right list of 'tree' */ node->r = node->r->r; tmp2->r = tmp->l->r; /* insert as child of found node */ tmp->l->r = node; } closeproc(PT); return &tree;}/* Convenient wrapper around openproc and readproc to slurp in the whole process * table subset satisfying the constraints of flags and the optional PID list. * Free allocated memory with freeproctab(). Access via tab[N]->member. The * pointer list is NULL terminated. */proc_t** readproctab(int flags, ...) { PROCTAB* PT = NULL; proc_t** tab = NULL; int n = 0; va_list ap; va_start(ap, flags); /* pass through args to openproc */ if (Do(UID)) { /* temporary variables to ensure that va_arg() instances * are called in the right order */ uid_t* u; int i; u = va_arg(ap, uid_t*); i = va_arg(ap, int); PT = openproc(flags, u, i); } else if (Do(PID) || Do(TTY) || Do(STAT)) PT = openproc(flags, va_arg(ap, void*)); /* assume ptr sizes same */ else PT = openproc(flags); va_end(ap); do { /* read table: */ tab = xrealloc(tab, (n+1)*sizeof(proc_t*));/* realloc as we go, using */ tab[n] = readproc(PT, NULL); /* final null to terminate */ } while (tab[n++]); /* stop when NULL reached */ closeproc(PT); return tab;}/* deallocate a table of pointers to proc structures */void freeproctab(proc_t** tab) { proc_t** p; for(p = tab; *p; p++) freeproc(*p); free(tab);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -