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 <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
@ -19,15 +20,22 @@ in the source distribution for its full text.
typedef enum FreeBSDProcessFields {
// Add platform-specific fields here, with ids >= 100
LAST_PROCESSFIELD = 100,
JID = 100,
JAIL = 101,
LAST_PROCESSFIELD = 102,
} FreeBSDProcessField;
typedef struct FreeBSDProcess_ {
Process super;
int kernel;
int jid;
char* jname;
} FreeBSDProcess;
#ifndef Process_isKernelThread
#define Process_isKernelThread(_process) (_process->pgrp == 0)
#define Process_isKernelThread(_process) (_process->kernel == 1)
#endif
#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, },
[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, },
[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, },
};
ProcessPidColumn Process_pidColumns[] = {
{ .id = JID, .label = "JID" },
{ .id = PID, .label = "PID" },
{ .id = PPID, .label = "PPID" },
{ .id = TPGID, .label = "TPGID" },
@ -95,16 +106,26 @@ FreeBSDProcess* FreeBSDProcess_new(Settings* settings) {
void Process_delete(Object* cast) {
FreeBSDProcess* this = (FreeBSDProcess*) cast;
Process_done((Process*)cast);
free(this->jname);
free(this);
}
void FreeBSDProcess_writeField(Process* this, RichString* str, ProcessField field) {
//FreeBSDProcess* fp = (FreeBSDProcess*) this;
FreeBSDProcess* fp = (FreeBSDProcess*) this;
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
//int n = sizeof(buffer) - 1;
int n = sizeof(buffer) - 1;
switch (field) {
// 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:
Process_writeField(this, str, field);
return;
@ -124,11 +145,20 @@ long FreeBSDProcess_compare(const void* v1, const void* v2) {
}
switch (settings->sortKey) {
// 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:
return Process_compare(v1, v2);
}
}
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 <sys/param.h>
#include <sys/jail.h>
#include <sys/uio.h>
#define JAIL_ERRMSGLEN 1024
char jail_errmsg[JAIL_ERRMSGLEN];
typedef struct CPUData_ {
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].totalPeriod = 1;
}
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_cache_count", MIB_vm_stats_vm_v_cache_count, &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);
assert(fpl->kd);
@ -74,14 +80,14 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
void ProcessList_delete(ProcessList* this) {
const FreeBSDProcessList* fpl = (FreeBSDProcessList*) this;
if (fpl->kd) kvm_close(fpl->kd);
ProcessList_done(this);
free(this);
}
static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) {
const FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl;
size_t len = sizeof(pl->totalMem);
sysctl(MIB_hw_physmem, 2, &(pl->totalMem), &len, NULL, 0);
pl->totalMem /= 1024;
@ -90,7 +96,7 @@ static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) {
pl->freeMem = pl->totalMem - pl->usedMem;
sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(pl->cachedMem), &len, NULL, 0);
pl->cachedMem *= pageSizeKb;
struct kvm_swap swap[16];
int nswap = kvm_getswapinfo(fpl->kd, swap, sizeof(swap)/sizeof(swap[0]), 0);
pl->totalSwap = 0;
@ -101,7 +107,7 @@ static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) {
}
pl->totalSwap *= pageSizeKb;
pl->usedSwap *= pageSizeKb;
pl->sharedMem = 0; // currently unused
pl->buffersMem = 0; // not exposed to userspace
}
@ -131,27 +137,75 @@ char* FreeBSDProcessList_readProcessName(kvm_t* kd, struct kinfo_proc* kproc, in
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) {
FreeBSDProcessList* fpl = (FreeBSDProcessList*) this;
Settings* settings = this->settings;
bool hideKernelThreads = settings->hideKernelThreads;
bool hideUserlandThreads = settings->hideUserlandThreads;
FreeBSDProcessList_scanMemoryInfo(this);
int count = 0;
struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_ALL, 0, &count);
for (int i = 0; i < count; i++) {
struct kinfo_proc* kproc = &kprocs[i];
bool preExisting = false;
Process* proc = ProcessList_getProcess(this, kproc->ki_pid, &preExisting, (Process_New) FreeBSDProcess_new);
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) {
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->tpgid = kproc->ki_tpgid;
proc->tgid = kproc->ki_pid;
@ -163,6 +217,7 @@ void ProcessList_goThroughEntries(ProcessList* this) {
proc->user = UsersTable_getRef(this->usersTable, proc->st_uid);
ProcessList_add((ProcessList*)this, proc);
proc->comm = FreeBSDProcessList_readProcessName(fpl->kd, kproc, &proc->basenameOffset);
fp->jname = FreeBSDProcessList_readJailName(kproc);
} else {
if (settings->updateProcessNames) {
free(proc->comm);
@ -174,8 +229,12 @@ void ProcessList_goThroughEntries(ProcessList* this) {
proc->m_resident = kproc->ki_rssize; // * pageSizeKb;
proc->nlwp = kproc->ki_numthreads;
proc->time = (kproc->ki_runtime + 5000) / 10000;
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;
} else if (PRI_IS_REALTIME(kproc->ki_pri.pri_class)) {
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;
}
switch (kproc->ki_stat) {
case SIDL: proc->state = 'I'; break;
case SRUN: proc->state = 'R'; break;
@ -194,10 +254,10 @@ void ProcessList_goThroughEntries(ProcessList* this) {
default: proc->state = '?';
}
if (Process_isKernelThread(proc)) {
if (Process_isKernelThread(fp)) {
this->kernelThreads++;
}
this->totalTasks++;
if (proc->state == 'R')
this->runningTasks++;