Merge pull request #281 from etosan/master

Added preliminary attempt at jails support on FreeBSD - JID and JAIL (name) columns
This commit is contained in:
Hisham Muhammad 2015-09-30 22:28:40 -03:00
commit 68c3270be8
2 changed files with 111 additions and 21 deletions

View File

@ -12,6 +12,7 @@ in the source distribution for its full text.
#include "CRT.h" #include "CRT.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/syscall.h> #include <sys/syscall.h>
@ -19,15 +20,22 @@ in the source distribution for its full text.
typedef enum FreeBSDProcessFields { typedef enum FreeBSDProcessFields {
// Add platform-specific fields here, with ids >= 100 // Add platform-specific fields here, with ids >= 100
LAST_PROCESSFIELD = 100, JID = 100,
JAIL = 101,
LAST_PROCESSFIELD = 102,
} FreeBSDProcessField; } FreeBSDProcessField;
typedef struct FreeBSDProcess_ { typedef struct FreeBSDProcess_ {
Process super; Process super;
int kernel;
int jid;
char* jname;
} FreeBSDProcess; } FreeBSDProcess;
#ifndef Process_isKernelThread #ifndef Process_isKernelThread
#define Process_isKernelThread(_process) (_process->pgrp == 0) #define Process_isKernelThread(_process) (_process->kernel == 1)
#endif #endif
#ifndef Process_isUserlandThread #ifndef Process_isUserlandThread
@ -72,10 +80,13 @@ ProcessFieldData Process_fields[] = {
[TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, }, [TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, },
[NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, }, [NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, },
[TGID] = { .name = "TGID", .title = " TGID ", .description = "Thread group ID (i.e. process ID)", .flags = 0, }, [TGID] = { .name = "TGID", .title = " TGID ", .description = "Thread group ID (i.e. process ID)", .flags = 0, },
[JID] = { .name = "JID", .title = " JID ", .description = "Jail prison ID", .flags = 0, },
[JAIL] = { .name = "JAIL", .title = "JAIL ", .description = "Jail prison name", .flags = 0, },
[LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, }, [LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
}; };
ProcessPidColumn Process_pidColumns[] = { ProcessPidColumn Process_pidColumns[] = {
{ .id = JID, .label = "JID" },
{ .id = PID, .label = "PID" }, { .id = PID, .label = "PID" },
{ .id = PPID, .label = "PPID" }, { .id = PPID, .label = "PPID" },
{ .id = TPGID, .label = "TPGID" }, { .id = TPGID, .label = "TPGID" },
@ -95,16 +106,26 @@ FreeBSDProcess* FreeBSDProcess_new(Settings* settings) {
void Process_delete(Object* cast) { void Process_delete(Object* cast) {
FreeBSDProcess* this = (FreeBSDProcess*) cast; FreeBSDProcess* this = (FreeBSDProcess*) cast;
Process_done((Process*)cast); Process_done((Process*)cast);
free(this->jname);
free(this); free(this);
} }
void FreeBSDProcess_writeField(Process* this, RichString* str, ProcessField field) { void FreeBSDProcess_writeField(Process* this, RichString* str, ProcessField field) {
//FreeBSDProcess* fp = (FreeBSDProcess*) this; FreeBSDProcess* fp = (FreeBSDProcess*) this;
char buffer[256]; buffer[255] = '\0'; char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR]; int attr = CRT_colors[DEFAULT_COLOR];
//int n = sizeof(buffer) - 1; int n = sizeof(buffer) - 1;
switch (field) { switch (field) {
// add FreeBSD-specific fields here // add FreeBSD-specific fields here
case JID: snprintf(buffer, n, Process_pidFormat, fp->jid); break;
case JAIL:{
snprintf(buffer, n, "%-11s ", fp->jname); break;
if (buffer[11] != '\0') {
buffer[11] = ' ';
buffer[12] = '\0';
}
break;
}
default: default:
Process_writeField(this, str, field); Process_writeField(this, str, field);
return; return;
@ -124,11 +145,20 @@ long FreeBSDProcess_compare(const void* v1, const void* v2) {
} }
switch (settings->sortKey) { switch (settings->sortKey) {
// add FreeBSD-specific fields here // add FreeBSD-specific fields here
case JID:
return (p1->jid - p2->jid);
case JAIL:
return strcmp(p1->jname ? p1->jname : "", p2->jname ? p2->jname : "");
default: default:
return Process_compare(v1, v2); return Process_compare(v1, v2);
} }
} }
bool Process_isThread(Process* this) { bool Process_isThread(Process* this) {
return (Process_isKernelThread(this)); FreeBSDProcess* fp = (FreeBSDProcess*) this;
if (fp->kernel == 1 )
return 1;
else
return (Process_isUserlandThread(this));
} }

View File

@ -20,6 +20,12 @@ in the source distribution for its full text.
/*{ /*{
#include <kvm.h> #include <kvm.h>
#include <sys/param.h>
#include <sys/jail.h>
#include <sys/uio.h>
#define JAIL_ERRMSGLEN 1024
char jail_errmsg[JAIL_ERRMSGLEN];
typedef struct CPUData_ { typedef struct CPUData_ {
unsigned long long int totalTime; unsigned long long int totalTime;
@ -58,13 +64,13 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
fpl->cpus[i].totalTime = 1; fpl->cpus[i].totalTime = 1;
fpl->cpus[i].totalPeriod = 1; fpl->cpus[i].totalPeriod = 1;
} }
size_t len; size_t len;
len = 4; sysctlnametomib("vm.stats.vm.v_wire_count", MIB_vm_stats_vm_v_wire_count, &len); len = 4; sysctlnametomib("vm.stats.vm.v_wire_count", MIB_vm_stats_vm_v_wire_count, &len);
len = 4; sysctlnametomib("vm.stats.vm.v_cache_count", MIB_vm_stats_vm_v_cache_count, &len); len = 4; sysctlnametomib("vm.stats.vm.v_cache_count", MIB_vm_stats_vm_v_cache_count, &len);
len = 2; sysctlnametomib("hw.physmem", MIB_hw_physmem, &len); len = 2; sysctlnametomib("hw.physmem", MIB_hw_physmem, &len);
pageSizeKb = PAGE_SIZE_KB; pageSizeKb = PAGE_SIZE_KB;
fpl->kd = kvm_open(NULL, "/dev/null", NULL, 0, NULL); fpl->kd = kvm_open(NULL, "/dev/null", NULL, 0, NULL);
assert(fpl->kd); assert(fpl->kd);
@ -74,14 +80,14 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
void ProcessList_delete(ProcessList* this) { void ProcessList_delete(ProcessList* this) {
const FreeBSDProcessList* fpl = (FreeBSDProcessList*) this; const FreeBSDProcessList* fpl = (FreeBSDProcessList*) this;
if (fpl->kd) kvm_close(fpl->kd); if (fpl->kd) kvm_close(fpl->kd);
ProcessList_done(this); ProcessList_done(this);
free(this); free(this);
} }
static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) { static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) {
const FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl; const FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl;
size_t len = sizeof(pl->totalMem); size_t len = sizeof(pl->totalMem);
sysctl(MIB_hw_physmem, 2, &(pl->totalMem), &len, NULL, 0); sysctl(MIB_hw_physmem, 2, &(pl->totalMem), &len, NULL, 0);
pl->totalMem /= 1024; pl->totalMem /= 1024;
@ -90,7 +96,7 @@ static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) {
pl->freeMem = pl->totalMem - pl->usedMem; pl->freeMem = pl->totalMem - pl->usedMem;
sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(pl->cachedMem), &len, NULL, 0); sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(pl->cachedMem), &len, NULL, 0);
pl->cachedMem *= pageSizeKb; pl->cachedMem *= pageSizeKb;
struct kvm_swap swap[16]; struct kvm_swap swap[16];
int nswap = kvm_getswapinfo(fpl->kd, swap, sizeof(swap)/sizeof(swap[0]), 0); int nswap = kvm_getswapinfo(fpl->kd, swap, sizeof(swap)/sizeof(swap[0]), 0);
pl->totalSwap = 0; pl->totalSwap = 0;
@ -101,7 +107,7 @@ static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) {
} }
pl->totalSwap *= pageSizeKb; pl->totalSwap *= pageSizeKb;
pl->usedSwap *= pageSizeKb; pl->usedSwap *= pageSizeKb;
pl->sharedMem = 0; // currently unused pl->sharedMem = 0; // currently unused
pl->buffersMem = 0; // not exposed to userspace pl->buffersMem = 0; // not exposed to userspace
} }
@ -131,27 +137,75 @@ char* FreeBSDProcessList_readProcessName(kvm_t* kd, struct kinfo_proc* kproc, in
return comm; return comm;
} }
char* FreeBSDProcessList_readJailName(struct kinfo_proc* kproc) {
int jid;
struct iovec jiov[6];
char* jname;
char jnamebuf[MAXHOSTNAMELEN];
if (kproc->ki_jid != 0 ){
memset(jnamebuf, 0, sizeof(jnamebuf));
*(const void **)&jiov[0].iov_base = "jid";
jiov[0].iov_len = sizeof("jid");
jiov[1].iov_base = &kproc->ki_jid;
jiov[1].iov_len = sizeof(kproc->ki_jid);
*(const void **)&jiov[2].iov_base = "name";
jiov[2].iov_len = sizeof("name");
jiov[3].iov_base = jnamebuf;
jiov[3].iov_len = sizeof(jnamebuf);
*(const void **)&jiov[4].iov_base = "errmsg";
jiov[4].iov_len = sizeof("errmsg");
jiov[5].iov_base = jail_errmsg;
jiov[5].iov_len = JAIL_ERRMSGLEN;
jail_errmsg[0] = 0;
jid = jail_get(jiov, 6, 0);
if (jid < 0) {
if (!jail_errmsg[0])
snprintf(jail_errmsg, JAIL_ERRMSGLEN, "jail_get: %s", strerror(errno));
return NULL;
} else if (jid == kproc->ki_jid) {
jname = strdup(jnamebuf);
if (jname == NULL)
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
return jname;
} else {
return NULL;
}
} else {
jnamebuf[0]='-';
jnamebuf[1]='\0';
jname = strdup(jnamebuf);
}
return jname;
}
void ProcessList_goThroughEntries(ProcessList* this) { void ProcessList_goThroughEntries(ProcessList* this) {
FreeBSDProcessList* fpl = (FreeBSDProcessList*) this; FreeBSDProcessList* fpl = (FreeBSDProcessList*) this;
Settings* settings = this->settings; Settings* settings = this->settings;
bool hideKernelThreads = settings->hideKernelThreads; bool hideKernelThreads = settings->hideKernelThreads;
bool hideUserlandThreads = settings->hideUserlandThreads; bool hideUserlandThreads = settings->hideUserlandThreads;
FreeBSDProcessList_scanMemoryInfo(this); FreeBSDProcessList_scanMemoryInfo(this);
int count = 0; int count = 0;
struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_ALL, 0, &count); struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_ALL, 0, &count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
struct kinfo_proc* kproc = &kprocs[i]; struct kinfo_proc* kproc = &kprocs[i];
bool preExisting = false; bool preExisting = false;
Process* proc = ProcessList_getProcess(this, kproc->ki_pid, &preExisting, (Process_New) FreeBSDProcess_new); Process* proc = ProcessList_getProcess(this, kproc->ki_pid, &preExisting, (Process_New) FreeBSDProcess_new);
FreeBSDProcess* fp = (FreeBSDProcess*) proc; FreeBSDProcess* fp = (FreeBSDProcess*) proc;
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc))); proc->show = ! ((hideKernelThreads && Process_isKernelThread(fp)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
if (!preExisting) { if (!preExisting) {
fp->jid = kproc->ki_jid;
proc->pid = kproc->ki_pid;
if ( ! ((kproc->ki_pid == 0) || (kproc->ki_pid == 1) ) && kproc->ki_flag & P_SYSTEM)
fp->kernel = 1;
else
fp->kernel = 0;
proc->ppid = kproc->ki_ppid; proc->ppid = kproc->ki_ppid;
proc->tpgid = kproc->ki_tpgid; proc->tpgid = kproc->ki_tpgid;
proc->tgid = kproc->ki_pid; proc->tgid = kproc->ki_pid;
@ -163,6 +217,7 @@ void ProcessList_goThroughEntries(ProcessList* this) {
proc->user = UsersTable_getRef(this->usersTable, proc->st_uid); proc->user = UsersTable_getRef(this->usersTable, proc->st_uid);
ProcessList_add((ProcessList*)this, proc); ProcessList_add((ProcessList*)this, proc);
proc->comm = FreeBSDProcessList_readProcessName(fpl->kd, kproc, &proc->basenameOffset); proc->comm = FreeBSDProcessList_readProcessName(fpl->kd, kproc, &proc->basenameOffset);
fp->jname = FreeBSDProcessList_readJailName(kproc);
} else { } else {
if (settings->updateProcessNames) { if (settings->updateProcessNames) {
free(proc->comm); free(proc->comm);
@ -174,8 +229,12 @@ void ProcessList_goThroughEntries(ProcessList* this) {
proc->m_resident = kproc->ki_rssize; // * pageSizeKb; proc->m_resident = kproc->ki_rssize; // * pageSizeKb;
proc->nlwp = kproc->ki_numthreads; proc->nlwp = kproc->ki_numthreads;
proc->time = (kproc->ki_runtime + 5000) / 10000; proc->time = (kproc->ki_runtime + 5000) / 10000;
proc->priority = kproc->ki_pri.pri_level - PZERO; proc->priority = kproc->ki_pri.pri_level - PZERO;
if (kproc->ki_pri.pri_class == PRI_TIMESHARE) {
if (strcmp("intr", kproc->ki_comm) == 0 && kproc->ki_flag & P_SYSTEM) {
proc->nice = 0; //@etosan: freebsd intr kernel process (not thread) has weird nice value
} else if (kproc->ki_pri.pri_class == PRI_TIMESHARE) {
proc->nice = kproc->ki_nice - NZERO; proc->nice = kproc->ki_nice - NZERO;
} else if (PRI_IS_REALTIME(kproc->ki_pri.pri_class)) { } else if (PRI_IS_REALTIME(kproc->ki_pri.pri_class)) {
proc->nice = PRIO_MIN - 1 - (PRI_MAX_REALTIME - kproc->ki_pri.pri_level); proc->nice = PRIO_MIN - 1 - (PRI_MAX_REALTIME - kproc->ki_pri.pri_level);
@ -183,6 +242,7 @@ void ProcessList_goThroughEntries(ProcessList* this) {
proc->nice = PRIO_MAX + 1 + kproc->ki_pri.pri_level - PRI_MIN_IDLE; proc->nice = PRIO_MAX + 1 + kproc->ki_pri.pri_level - PRI_MIN_IDLE;
} }
switch (kproc->ki_stat) { switch (kproc->ki_stat) {
case SIDL: proc->state = 'I'; break; case SIDL: proc->state = 'I'; break;
case SRUN: proc->state = 'R'; break; case SRUN: proc->state = 'R'; break;
@ -194,10 +254,10 @@ void ProcessList_goThroughEntries(ProcessList* this) {
default: proc->state = '?'; default: proc->state = '?';
} }
if (Process_isKernelThread(proc)) { if (Process_isKernelThread(fp)) {
this->kernelThreads++; this->kernelThreads++;
} }
this->totalTasks++; this->totalTasks++;
if (proc->state == 'R') if (proc->state == 'R')
this->runningTasks++; this->runningTasks++;