📄 readproc.c
字号:
if(unlikely(unlikely(!ent) || unlikely(!ent->d_name))) return 0; if(likely( likely(*ent->d_name > '0') && likely(*ent->d_name <= '9') )) break; } p->tgid = strtoul(ent->d_name, NULL, 10); p->tid = p->tgid; memcpy(path, "/proc/", 6); strcpy(path+6, ent->d_name); // trust /proc to not contain evil top-level entries return 1;}//////////////////////////////////////////////////////////////////////////////////// This finds tasks in /proc/*/task/ in the traditional way.// Return non-zero on success.static int simple_nexttid(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict const t, char *restrict const path) { static struct direct *ent; /* dirent handle */ if(PT->taskdir_user != p->tgid){ if(PT->taskdir){ closedir(PT->taskdir); } // use "path" as some tmp space snprintf(path, PROCPATHLEN, "/proc/%d/task", p->tgid); PT->taskdir = opendir(path); if(!PT->taskdir) return 0; PT->taskdir_user = p->tgid; } for (;;) { ent = readdir(PT->taskdir); if(unlikely(unlikely(!ent) || unlikely(!ent->d_name))) return 0; if(likely( likely(*ent->d_name > '0') && likely(*ent->d_name <= '9') )) break; } t->tid = strtoul(ent->d_name, NULL, 10); t->tgid = p->tgid; t->ppid = p->ppid; // cover for kernel behavior? we want both actually...? snprintf(path, PROCPATHLEN, "/proc/%d/task/%s", p->tgid, ent->d_name); return 1;}//////////////////////////////////////////////////////////////////////////////////// This "finds" processes in a list that was given to openproc().// Return non-zero on success. (tgid was handy)static int listed_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p) { char *restrict const path = PT->path; pid_t tgid = *(PT->pids)++; if(likely( tgid )){ snprintf(path, PROCPATHLEN, "/proc/%d", tgid); p->tgid = tgid; p->tid = tgid; // they match for leaders } return tgid;}///////////////////////////////////////////////////////////////////////////////////* 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. */proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict p) { proc_t *ret; proc_t *saved_p; PT->did_fake=0;// if (PT->taskdir) {// closedir(PT->taskdir);// PT->taskdir = NULL;// PT->taskdir_user = -1;// } saved_p = p; if(!p) p = xcalloc(p, sizeof *p); /* passed buf or alloced mem */ for(;;){ // fills in the path, plus p->tid and p->tgid if (unlikely(! PT->finder(PT,p) )) goto out; // go read the process data ret = PT->reader(PT,p); if(ret) return ret; }out: if(!saved_p) free(p); // FIXME: maybe set tid to -1 here, for "-" in display? return NULL;}//////////////////////////////////////////////////////////////////////////////////// readtask: return a pointer to a proc_t filled with requested info about the// next task available. If no more such tasks are available, return a null// pointer (boolean false). Use the passed buffer instead of allocating// space if it is non-NULL.proc_t* readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict t) { static char path[PROCPATHLEN]; // must hold /proc/2000222000/task/2000222000/cmdline proc_t *ret; proc_t *saved_t; saved_t = t; if(!t) t = xcalloc(t, sizeof *t); /* passed buf or alloced mem */ // 1. got to fake a thread for old kernels // 2. for single-threaded processes, this is faster (but must patch up stuff that differs!) if(task_dir_missing || p->nlwp < 2){ if(PT->did_fake) goto out; PT->did_fake=1; memcpy(t,p,sizeof(proc_t)); // use the per-task pending, not per-tgid pending#ifdef SIGNAL_STRING memcpy(&t->signal, &t->_sigpnd, sizeof t->signal);#else t->signal = t->_sigpnd;#endif return t; } for(;;){ // fills in the path, plus t->tid and t->tgid if (unlikely(! PT->taskfinder(PT,p,t,path) )) goto out; // simple_nexttid // go read the task data ret = PT->taskreader(PT,p,t,path); // simple_readtask if(ret) return ret; }out: if(!saved_t) free(t); return NULL;}//////////////////////////////////////////////////////////////////////////////////// initiate a process table scanPROCTAB* openproc(int flags, ...) { va_list ap; struct stat sbuf; static int did_stat; PROCTAB* PT = xmalloc(sizeof(PROCTAB)); 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) return NULL; PT->finder = simple_nextpid; } PT->flags = flags; va_start(ap, flags); /* Init args list */ 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); /* Clean up args list */ return PT;}// terminate a process table scanvoid closeproc(PROCTAB* PT) { if (PT){ if (PT->procfs) closedir(PT->procfs); if (PT->taskdir) closedir(PT->taskdir); memset(PT,'#',sizeof(PROCTAB)); free(PT); }}// deallocate the space allocated by readproc if the passed rbuf was NULLvoid freeproc(proc_t* p) { if (!p) /* in case p is NULL */ return; /* ptrs are after strings to avoid copying memory when building them. */ /* so free is called on the address of the address of strvec[0]. */ if (p->cmdline) free((void*)*p->cmdline); if (p->environ) free((void*)*p->environ); free(p);}//////////////////////////////////////////////////////////////////////////////////void look_up_our_self(proc_t *p) { char sbuf[1024]; if(file2str("/proc/self", "stat", sbuf, sizeof sbuf) == -1){ fprintf(stderr, "Error, do this: mount -t proc none /proc\n"); _exit(47); } stat2proc(sbuf, p); // parse /proc/self/stat}HIDDEN_ALIAS(readproc);HIDDEN_ALIAS(readtask);/* 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 exit(). 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 (flags & PROC_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 (flags & PROC_PID) 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_direct(PT, NULL); /* final null to terminate */ } while (tab[n++]); /* stop when NULL reached */ closeproc(PT); return tab;}// Try again, this time with threads and selection.proc_data_t *readproctab2(int(*want_proc)(proc_t *buf), int(*want_task)(proc_t *buf), PROCTAB *restrict const PT) { proc_t** ptab = NULL; unsigned n_proc_alloc = 0; unsigned n_proc = 0; proc_t** ttab = NULL; unsigned n_task_alloc = 0; unsigned n_task = 0; proc_t* data = NULL; unsigned n_alloc = 0; unsigned long n_used = 0; proc_data_t *pd; for(;;){ proc_t *tmp; if(n_alloc == n_used){ //proc_t *old = data; n_alloc = n_alloc*5/4+30; // grow by over 25% data = realloc(data,sizeof(proc_t)*n_alloc); //if(!data) return NULL; } if(n_proc_alloc == n_proc){ //proc_t **old = ptab; n_proc_alloc = n_proc_alloc*5/4+30; // grow by over 25% ptab = realloc(ptab,sizeof(proc_t*)*n_proc_alloc); //if(!ptab) return NULL; } tmp = readproc_direct(PT, data+n_used); if(!tmp) break; if(!want_proc(tmp)) continue; ptab[n_proc++] = (proc_t*)(n_used++); if(!( PT->flags & PROC_LOOSE_TASKS )) continue; for(;;){ proc_t *t; if(n_alloc == n_used){ proc_t *old = data; n_alloc = n_alloc*5/4+30; // grow by over 25% data = realloc(data,sizeof(proc_t)*n_alloc); // have to move tmp too tmp = data+(tmp-old); //if(!data) return NULL; } if(n_task_alloc == n_task){ //proc_t **old = ttab; n_task_alloc = n_task_alloc*5/4+1; // grow by over 25% ttab = realloc(ttab,sizeof(proc_t*)*n_task_alloc); //if(!ttab) return NULL; } t = readtask_direct(PT, tmp, data+n_used); if(!t) break; if(!want_task(t)) continue; ttab[n_task++] = (proc_t*)(n_used++); } } pd = malloc(sizeof(proc_data_t)); pd->proc = ptab; pd->task = ttab; pd->nproc = n_proc; pd->ntask = n_task; if(PT->flags & PROC_LOOSE_TASKS){ pd->tab = ttab; pd->n = n_task; }else{ pd->tab = ptab; pd->n = n_proc; } // change array indexes to pointers while(n_proc--) ptab[n_proc] = data+(long)(ptab[n_proc]); while(n_task--) ttab[n_task] = data+(long)(ttab[n_task]); return pd;}/* * get_proc_stats - lookup a single tasks information and fill out a proc_t * * On failure, returns NULL. On success, returns 'p' and 'p' is a valid * and filled out proc_t structure. */proc_t * get_proc_stats(pid_t pid, proc_t *p) { static char path[PATH_MAX], sbuf[1024]; struct stat statbuf; sprintf(path, "/proc/%d", pid); if (stat(path, &statbuf)) { perror("stat"); return NULL; } if (file2str(path, "stat", sbuf, sizeof sbuf) >= 0) stat2proc(sbuf, p); /* parse /proc/#/stat */ if (file2str(path, "statm", sbuf, sizeof sbuf) >= 0) statm2proc(sbuf, p); /* ignore statm errors here */ if (file2str(path, "status", sbuf, sizeof sbuf) >= 0) status2proc(sbuf, p, 0 /*FIXME*/); return p;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -