procps/proc/readproc.c

713 lines
20 KiB
C
Raw Normal View History

2002-02-02 04:17:29 +05:30
/*
* New Interface to Process Table -- PROCTAB Stream (a la Directory streams)
* Copyright (C) 1996 Charles L. Blake.
* Copyright (C) 1998 Michael K. Johnson
* Copyright 1998-2002 Albert Cahalan
2002-02-02 04:17:29 +05:30
* May be distributed under the conditions of the
* GNU Library General Public License; a copy is in COPYING
*/
2002-09-27 19:18:00 +05:30
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "version.h"
#include "readproc.h"
2002-12-09 12:30:07 +05:30
#include "alloc.h"
#include "pwcache.h"
#include "devname.h"
#include "procps.h"
2002-02-02 04:17:29 +05:30
#include <stdio.h>
#include <stdlib.h>
2002-12-03 14:37:59 +05:30
#include <errno.h>
2002-02-02 04:17:29 +05:30
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/dir.h>
#include <sys/types.h>
#include <sys/stat.h>
2002-09-27 19:18:00 +05:30
#ifdef FLASK_LINUX
#include <fs_secure.h>
#endif
2003-09-18 03:28:32 +05:30
// sometimes it's easier to do this manually, w/o gcc helping
2003-02-17 06:27:15 +05:30
#ifdef PROF
extern void __cyg_profile_func_enter(void*,void*);
#define ENTER(x) __cyg_profile_func_enter((void*)x,(void*)x)
#define LEAVE(x) __cyg_profile_func_exit((void*)x,(void*)x)
#else
#define ENTER(x)
#define LEAVE(x)
#endif
///////////////////////////////////////////////////////////////////////////
2002-02-02 04:17:29 +05:30
2003-02-17 06:27:15 +05:30
typedef struct status_table_struct {
unsigned char name[6]; // /proc/*/status field name
short len; // name length
#ifdef LABEL_OFFSET
long offset; // jump address offset
#else
void *addr;
#endif
} status_table_struct;
#ifdef LABEL_OFFSET
2003-05-30 08:43:32 +05:30
#define F(x) {#x, sizeof(#x)-1, (long)(&&case_##x-&&base)},
2003-02-17 06:27:15 +05:30
#else
#define F(x) {#x, sizeof(#x)-1, &&case_##x},
#endif
#define NUL {"", 0, 0},
2002-12-03 14:37:59 +05:30
2003-02-17 06:27:15 +05:30
// Derived from:
// gperf -7 --language=ANSI-C --key-positions=1,3,4 -C -n -c sml.gperf
2002-02-02 04:17:29 +05:30
2003-02-17 06:27:15 +05:30
static void status2proc(char *S, proc_t *restrict P){
static const unsigned char asso[] = {
56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 15, 56, 56, 56, 56, 56,
56, 56, 25, 30, 15, 3, 56, 5, 56, 3, 56, 56, 3, 56, 10, 56,
18, 56, 13, 0, 30, 25, 0, 56, 56, 56, 56, 56, 56, 56, 56, 56,
56, 30, 56, 8, 0, 0, 56, 25, 56, 5, 56, 56, 56, 0, 56, 56,
56, 56, 56, 56, 0, 56, 56, 56, 0, 56, 56, 56, 56, 56, 56, 56
};
static const status_table_struct table[] = {
F(VmStk)
NUL
NUL
F(VmExe)
NUL
F(VmSize)
NUL
NUL
F(VmLib)
NUL
F(Name)
F(VmLck)
NUL
F(VmRSS)
NUL
NUL
NUL
NUL
F(ShdPnd)
NUL
F(Gid)
NUL
NUL
F(PPid)
NUL
NUL
NUL
NUL
F(SigIgn)
NUL
F(State)
NUL
NUL
F(Pid)
NUL
F(Tgid)
NUL
NUL
NUL
NUL
F(Uid)
NUL
NUL
F(SigPnd)
NUL
F(VmData)
NUL
NUL
NUL
NUL
F(SigBlk)
NUL
NUL
NUL
NUL
F(SigCgt)
NUL
NUL
NUL
NUL
NUL
NUL
NUL
NUL
};
2002-02-02 04:17:29 +05:30
2003-02-17 06:27:15 +05:30
#undef F
#undef NUL
2002-02-02 04:17:29 +05:30
2003-02-17 06:27:15 +05:30
ENTER(0x220);
P->vm_size = 0;
P->vm_lock = 0;
P->vm_rss = 0;
P->vm_data = 0;
P->vm_stack= 0;
P->vm_exe = 0;
P->vm_lib = 0;
2002-02-02 04:17:29 +05:30
2003-02-17 06:27:15 +05:30
goto base;
2003-02-12 13:45:53 +05:30
2003-02-17 06:27:15 +05:30
for(;;){
char *colon;
status_table_struct entry;
// advance to next line
S = strchr(S, '\n');
if(unlikely(!S)) break; // if no newline
S++;
// examine a field name (hash and compare)
base:
if(unlikely(!*S)) break;
entry = table[63 & (asso[S[3]] + asso[S[2]] + asso[S[0]])];
colon = strchr(S, ':');
if(unlikely(!colon)) break;
if(unlikely(colon[1]!='\t')) break;
if(unlikely(colon-S != entry.len)) continue;
if(unlikely(memcmp(entry.name,S,colon-S))) continue;
S = colon+2; // past the '\t'
#ifdef LABEL_OFFSET
goto *(&&base + entry.offset);
2002-02-02 04:17:29 +05:30
#else
2003-02-17 06:27:15 +05:30
goto *entry.addr;
2002-02-02 04:17:29 +05:30
#endif
2003-02-17 06:27:15 +05:30
case_Gid:
P->rgid = strtol(S,&S,10);
P->egid = strtol(S,&S,10);
P->sgid = strtol(S,&S,10);
P->fgid = strtol(S,&S,10);
continue;
case_Name:{
2003-02-18 09:21:03 +05:30
unsigned u = 0;
while(u < sizeof P->cmd - 1u){
2003-02-17 06:27:15 +05:30
int c = *S++;
if(unlikely(c=='\n')) break;
2003-02-18 09:21:03 +05:30
if(unlikely(c=='\0')) break; // should never happen
2003-02-17 06:27:15 +05:30
if(unlikely(c=='\\')){
c = *S++;
if(c=='\n') break; // should never happen
if(!c) break; // should never happen
if(c=='n') c='\n'; // else we assume it is '\\'
}
2003-02-18 09:21:03 +05:30
P->cmd[u++] = c;
2003-02-17 06:27:15 +05:30
}
2003-02-18 09:21:03 +05:30
P->cmd[u] = '\0';
S--; // put back the '\n' or '\0'
2003-02-17 06:27:15 +05:30
continue;
}
case_PPid:
P->ppid = strtol(S,&S,10);
continue;
case_Pid:
P->pid = strtol(S,&S,10);
continue;
case_ShdPnd:
memcpy(P->signal, S, 16);
P->signal[16] = '\0';
continue;
case_SigBlk:
memcpy(P->blocked, S, 16);
P->blocked[16] = '\0';
continue;
case_SigCgt:
memcpy(P->sigcatch, S, 16);
P->sigcatch[16] = '\0';
continue;
case_SigIgn:
memcpy(P->sigignore, S, 16);
P->sigignore[16] = '\0';
continue;
case_SigPnd:
memcpy(P->signal, S, 16);
P->signal[16] = '\0';
continue;
2002-02-02 04:17:29 +05:30
2003-02-17 06:27:15 +05:30
case_State:
P->state = *S;
continue;
case_Tgid:
P->tgid = strtol(S,&S,10);
continue;
case_Uid:
P->ruid = strtol(S,&S,10);
P->euid = strtol(S,&S,10);
P->suid = strtol(S,&S,10);
P->fuid = strtol(S,&S,10);
continue;
case_VmData:
P->vm_data = strtol(S,&S,10);
continue;
case_VmExe:
P->vm_exe = strtol(S,&S,10);
continue;
case_VmLck:
P->vm_lock = strtol(S,&S,10);
continue;
case_VmLib:
P->vm_lib = strtol(S,&S,10);
continue;
case_VmRSS:
P->vm_rss = strtol(S,&S,10);
continue;
case_VmSize:
P->vm_size = strtol(S,&S,10);
continue;
case_VmStk:
P->vm_stack = strtol(S,&S,10);
continue;
}
LEAVE(0x220);
}
///////////////////////////////////////////////////////////////////////
2002-02-02 04:17:29 +05:30
2002-12-21 16:04:50 +05:30
// Reads /proc/*/stat files, being careful not to trip over processes with
// names like ":-) 1 2 3 4 5 6".
2002-11-25 15:46:33 +05:30
static void stat2proc(const char* S, proc_t *restrict P) {
2002-12-03 14:48:27 +05:30
unsigned num;
2002-12-03 14:37:59 +05:30
char* tmp;
2003-02-17 06:27:15 +05:30
ENTER(0x160);
2002-02-02 04:17:29 +05:30
/* fill in default values for older kernels */
P->exit_signal = SIGCHLD;
P->processor = 0;
2002-10-03 15:11:57 +05:30
P->rtprio = -1;
P->sched = -1;
2002-12-03 14:37:59 +05:30
2002-12-21 11:52:00 +05:30
S = strchr(S, '(') + 1;
tmp = strrchr(S, ')');
2002-12-03 14:37:59 +05:30
num = tmp - S;
2002-12-07 14:04:03 +05:30
if(unlikely(num >= sizeof P->cmd)) num = sizeof P->cmd - 1;
2002-12-03 14:37:59 +05:30
memcpy(P->cmd, S, num);
P->cmd[num] = '\0';
S = tmp + 2; // skip ") "
num = sscanf(S,
2002-02-02 04:17:29 +05:30
"%c "
"%d %d %d %d %d "
2002-05-28 09:48:55 +05:30
"%lu %lu %lu %lu %lu "
"%Lu %Lu %Lu %Lu " /* utime stime cutime cstime */
"%ld %ld %ld %ld "
"%Lu " /* start_time */
"%lu "
2002-02-02 04:17:29 +05:30
"%ld "
2003-01-16 13:33:40 +05:30
"%lu %"KLF"u %"KLF"u %"KLF"u %"KLF"u %"KLF"u "
2002-02-02 04:17:29 +05:30
"%*s %*s %*s %*s " /* discard, no RT signals & Linux 2.1 used hex */
2003-01-16 13:33:40 +05:30
"%"KLF"u %lu %lu "
2002-10-03 15:11:57 +05:30
"%d %d "
"%lu %lu",
2002-02-02 04:17:29 +05:30
&P->state,
&P->ppid, &P->pgrp, &P->session, &P->tty, &P->tpgid,
2002-05-28 09:48:55 +05:30
&P->flags, &P->min_flt, &P->cmin_flt, &P->maj_flt, &P->cmaj_flt,
&P->utime, &P->stime, &P->cutime, &P->cstime,
&P->priority, &P->nice, &P->timeout, &P->it_real_value,
&P->start_time,
&P->vsize,
2002-02-02 04:17:29 +05:30
&P->rss,
&P->rss_rlim, &P->start_code, &P->end_code, &P->start_stack, &P->kstk_esp, &P->kstk_eip,
/* P->signal, P->blocked, P->sigignore, P->sigcatch, */ /* can't use */
&P->wchan, &P->nswap, &P->cnswap,
/* -- Linux 2.0.35 ends here -- */
2002-10-03 15:11:57 +05:30
&P->exit_signal, &P->processor, /* 2.2.1 ends with "exit_signal" */
/* -- Linux 2.2.8 to 2.5.17 end here -- */
&P->rtprio, &P->sched /* both added to 2.5.18 */
2002-02-02 04:17:29 +05:30
);
2003-02-17 06:27:15 +05:30
LEAVE(0x160);
2002-02-02 04:17:29 +05:30
}
2003-02-17 06:27:15 +05:30
/////////////////////////////////////////////////////////////////////////
2002-11-25 15:46:33 +05:30
static void statm2proc(const char* s, proc_t *restrict P) {
2002-02-02 04:17:29 +05:30
int num;
num = sscanf(s, "%ld %ld %ld %ld %ld %ld %ld",
&P->size, &P->resident, &P->share,
&P->trs, &P->lrs, &P->drs, &P->dt);
/* fprintf(stderr, "statm2proc converted %d fields.\n",num); */
}
2002-10-12 09:55:57 +05:30
static int file2str(const char *directory, const char *what, char *ret, int cap) {
2002-02-02 04:17:29 +05:30
static char filename[80];
int fd, num_read;
sprintf(filename, "%s/%s", directory, what);
2002-12-03 14:37:59 +05:30
fd = open(filename, O_RDONLY, 0);
if(unlikely(fd==-1)) return -1;
num_read = read(fd, ret, cap - 1);
2002-02-02 04:17:29 +05:30
close(fd);
2003-02-17 06:27:15 +05:30
if(unlikely(num_read<=0)) return -1;
ret[num_read] = '\0';
2002-02-02 04:17:29 +05:30
return num_read;
}
2002-10-12 09:55:57 +05:30
static char** file2strvec(const char* directory, const char* what) {
2002-02-02 04:17:29 +05:30
char buf[2048]; /* read buf bytes at a time */
char *p, *rbuf = 0, *endbuf, **q, **ret;
int fd, tot = 0, n, c, end_of_file = 0;
int align;
sprintf(buf, "%s/%s", directory, what);
2002-12-03 14:37:59 +05:30
fd = open(buf, O_RDONLY, 0);
if(fd==-1) return NULL;
2002-02-02 04:17:29 +05:30
/* read whole file into a memory buffer, allocating as we go */
while ((n = read(fd, buf, sizeof buf - 1)) > 0) {
2002-10-14 02:02:09 +05:30
if (n < (int)(sizeof buf - 1))
2002-02-02 04:17:29 +05:30
end_of_file = 1;
if (n == 0 && rbuf == 0)
return NULL; /* process died between our open and read */
if (n < 0) {
if (rbuf)
free(rbuf);
return NULL; /* read error */
}
if (end_of_file && buf[n-1]) /* last read char not null */
buf[n++] = '\0'; /* so append null-terminator */
rbuf = xrealloc(rbuf, tot + n); /* allocate more memory */
memcpy(rbuf + tot, buf, n); /* copy buffer into it */
tot += n; /* increment total byte ctr */
if (end_of_file)
break;
}
close(fd);
if (n <= 0 && !end_of_file) {
if (rbuf) free(rbuf);
return NULL; /* read error */
}
endbuf = rbuf + tot; /* count space for pointers */
align = (sizeof(char*)-1) - ((tot + sizeof(char*)-1) & (sizeof(char*)-1));
for (c = 0, p = rbuf; p < endbuf; p++)
if (!*p)
c += sizeof(char*);
c += sizeof(char*); /* one extra for NULL term */
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;
}
2002-12-03 14:37:59 +05:30
// warning: interface may change
int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid){
char name[32];
int fd;
2002-12-03 14:48:27 +05:30
unsigned n = 0;
dst[0] = '\0';
2002-12-03 14:37:59 +05:30
snprintf(name, sizeof name, "/proc/%u/cmdline", pid);
fd = open(name, O_RDONLY);
2002-12-03 14:48:27 +05:30
if(fd==-1) return 0;
2002-12-03 14:37:59 +05:30
for(;;){
ssize_t r = read(fd,dst+n,sz-n);
if(r==-1){
if(errno==EINTR) continue;
break;
}
n += r;
if(n==sz) break; // filled the buffer
if(r==0) break; // EOF
}
close(fd);
2002-12-03 14:37:59 +05:30
if(n){
int i;
if(n==sz) n--;
dst[n] = '\0';
i=n;
while(i--){
2003-02-17 06:27:15 +05:30
int c = dst[i];
if(c<' ' || c>'~') dst[i]=' ';
2002-12-03 14:37:59 +05:30
}
}
return n;
}
2002-02-02 04:17:29 +05:30
/* 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; \
} )
2003-09-18 03:28:32 +05:30
//////////////////////////////////////////////////////////////////////////////////
// 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, char *restrict const path) {
static struct stat sb; // stat() buffer
static char sbuf[1024]; // buffer for stat,statm
unsigned flags = PT->flags;
2002-02-02 04:17:29 +05:30
2002-12-09 05:23:05 +05:30
if (unlikely(stat(path, &sb) == -1)) /* no such dirent (anymore) */
2002-02-02 04:17:29 +05:30
goto next_proc;
2002-09-27 19:18:00 +05:30
2002-10-22 11:42:12 +05:30
if ((flags & PROC_UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid))
2002-02-02 04:17:29 +05:30
goto next_proc; /* not one of the requested uids */
2002-12-21 16:57:47 +05:30
p->euid = sb.st_uid; /* need a way to get real uid */
2003-06-30 09:00:35 +05:30
p->egid = sb.st_gid; /* need a way to get real gid */
2002-09-27 19:18:00 +05:30
2002-12-09 00:21:56 +05:30
if (flags & PROC_FILLSTAT) { /* read, parse /proc/#/stat */
2002-12-09 05:23:05 +05:30
if (unlikely( file2str(path, "stat", sbuf, sizeof sbuf) == -1 ))
2002-12-09 00:21:56 +05:30
goto next_proc; /* error reading /proc/#/stat */
stat2proc(sbuf, p); /* parse /proc/#/stat */
}
2002-02-02 04:17:29 +05:30
2003-09-18 03:28:32 +05:30
if (unlikely(flags & PROC_FILLMEM)) { /* read, parse /proc/#/statm */
2002-12-09 05:23:05 +05:30
if (likely( file2str(path, "statm", sbuf, sizeof sbuf) != -1 ))
2002-02-02 04:17:29 +05:30
statm2proc(sbuf, p); /* ignore statm errors here */
} /* statm fields just zero */
2002-10-22 11:42:12 +05:30
if (flags & PROC_FILLSTATUS) { /* read, parse /proc/#/status */
2002-12-09 05:23:05 +05:30
if (likely( file2str(path, "status", sbuf, sizeof sbuf) != -1 )){
2002-12-03 14:37:59 +05:30
status2proc(sbuf, p);
2002-02-02 04:17:29 +05:30
}
}
/* some number->text resolving which is time consuming */
2002-10-22 11:42:12 +05:30
if (flags & PROC_FILLUSR){
2002-02-02 04:17:29 +05:30
strncpy(p->euser, user_from_uid(p->euid), sizeof p->euser);
2002-10-22 11:42:12 +05:30
if(flags & PROC_FILLSTATUS) {
2002-02-02 04:17:29 +05:30
strncpy(p->ruser, user_from_uid(p->ruid), sizeof p->ruser);
strncpy(p->suser, user_from_uid(p->suid), sizeof p->suser);
strncpy(p->fuser, user_from_uid(p->fuid), sizeof p->fuser);
}
}
/* some number->text resolving which is time consuming */
2002-10-22 11:42:12 +05:30
if (flags & PROC_FILLGRP){
strncpy(p->egroup, group_from_gid(p->egid), sizeof p->egroup);
2002-10-22 11:42:12 +05:30
if(flags & PROC_FILLSTATUS) {
strncpy(p->rgroup, group_from_gid(p->rgid), sizeof p->rgroup);
strncpy(p->sgroup, group_from_gid(p->sgid), sizeof p->sgroup);
2002-02-02 04:17:29 +05:30
strncpy(p->fgroup, group_from_gid(p->fgid), sizeof p->fgroup);
}
}
2002-10-22 11:42:12 +05:30
if ((flags & PROC_FILLCOM) || (flags & PROC_FILLARG)) /* read+parse /proc/#/cmdline */
2002-02-02 04:17:29 +05:30
p->cmdline = file2strvec(path, "cmdline");
else
p->cmdline = NULL;
2002-12-09 05:23:05 +05:30
if (unlikely(flags & PROC_FILLENV)) /* read+parse /proc/#/environ */
2002-02-02 04:17:29 +05:30
p->environ = file2strvec(path, "environ");
else
p->environ = NULL;
2002-02-02 04:17:29 +05:30
return p;
2003-09-18 03:28:32 +05:30
next_proc:
return NULL;
}
//////////////////////////////////////////////////////////////////////////////////
// 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, char *restrict const path) {
static struct direct *ent; /* dirent handle */
for (;;) {
ent = readdir(PT->procfs);
if(unlikely(unlikely(!ent) || unlikely(!ent->d_name))) return 0;
if(likely( likely(*ent->d_name > '0') && likely(*ent->d_name <= '9') )) break;
}
p->pid = strtoul(ent->d_name, NULL, 10);
memcpy(path, "/proc/", 6);
strcpy(path+6, ent->d_name); // trust /proc to not contain evil top-level entries
return 1;
2002-02-02 04:17:29 +05:30
}
2003-09-18 03:28:32 +05:30
#define PROCPATHLEN 64 // must hold /proc/2000222000/task/2000222000/cmdline
//////////////////////////////////////////////////////////////////////////////////
// This "finds" processes in a list that was given to openproc().
// Return non-zero on success. (pid was handy)
static int listed_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p, char *restrict const path) {
pid_t pid = *(PT->pids)++;
if(likely( pid )){
snprintf(path, PROCPATHLEN, "/proc/%d", pid);
p->pid = pid;
}
return pid;
}
//////////////////////////////////////////////////////////////////////////////////
// This "finds" processes by guessing every possible one of them.
// Return non-zero on success. (pid was handy)
static int stupid_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p, char *restrict const path) {
pid_t pid = --PT->u;
if(likely( pid )){
snprintf(path, PROCPATHLEN, "/proc/%d", pid);
p->pid = pid;
}
return pid;
}
//////////////////////////////////////////////////////////////////////////////////
/* readproc: return a pointer to a proc_t filled with requested info about the
2002-02-02 04:17:29 +05:30
* 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.
*/
2003-09-18 03:28:32 +05:30
proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict p) {
static char path[PROCPATHLEN]; // must hold /proc/2000222000/task/2000222000/cmdline
proc_t *ret;
proc_t *saved_p;
saved_p = p;
if(!p) p = xcalloc(p, sizeof *p); /* passed buf or alloced mem */
for(;;){
// fills in the path and the p->pid
if (unlikely(! PT->finder(PT,p,path) )) goto out;
// go read the process data
ret = PT->reader(PT,p,path);
if(ret) return ret;
}
out:
if(!saved_p) free(p);
return NULL;
}
2002-02-02 04:17:29 +05:30
2003-09-18 03:28:32 +05:30
//////////////////////////////////////////////////////////////////////////////////
2002-02-02 04:17:29 +05:30
2003-09-18 03:28:32 +05:30
// initiate a process table scan
PROCTAB* openproc(int flags, ...) {
va_list ap;
PROCTAB* PT = xmalloc(sizeof(PROCTAB));
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;
2002-12-21 11:52:00 +05:30
}
2003-09-18 03:28:32 +05:30
PT->flags = flags;
2002-02-02 04:17:29 +05:30
2003-09-18 03:28:32 +05:30
if(getenv("EVIL_PROC_HACK")){
PT->finder = stupid_nextpid;
PT->u = 10000;
}
2003-09-18 03:28:32 +05:30
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);
}
2003-09-18 03:28:32 +05:30
va_end(ap); /* Clean up args list */
2002-02-02 04:17:29 +05:30
2003-09-18 03:28:32 +05:30
return PT;
}
2003-09-18 03:28:32 +05:30
// terminate a process table scan
void closeproc(PROCTAB* PT) {
if (PT){
if (PT->procfs) closedir(PT->procfs);
free(PT);
}
}
// deallocate the space allocated by readproc if the passed rbuf was NULL
void 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);
2002-02-02 04:17:29 +05:30
}
2003-09-18 03:28:32 +05:30
//////////////////////////////////////////////////////////////////////////////////
2002-02-02 04:17:29 +05:30
void look_up_our_self(proc_t *p) {
2003-05-31 20:48:13 +05:30
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
2002-02-02 04:17:29 +05:30
}
2003-01-15 16:22:39 +05:30
HIDDEN_ALIAS(readproc);
2002-02-02 04:17:29 +05:30
/* Convenient wrapper around openproc and readproc to slurp in the whole process
* table subset satisfying the constraints of flags and the optional PID list.
2003-07-03 10:50:19 +05:30
* Free allocated memory with exit(). Access via tab[N]->member. The pointer
* list is NULL terminated.
2002-02-02 04:17:29 +05:30
*/
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 */
2002-10-22 11:42:12 +05:30
if (flags & PROC_UID) {
2002-02-02 04:17:29 +05:30
/* 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);
}
2002-10-22 11:42:12 +05:30
else if (flags & PROC_PID)
2002-02-02 04:17:29 +05:30
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 */
2003-01-15 16:22:39 +05:30
tab[n] = readproc_direct(PT, NULL); /* final null to terminate */
2002-02-02 04:17:29 +05:30
} while (tab[n++]); /* stop when NULL reached */
closeproc(PT);
return tab;
}