mirror of https://github.com/xzeldon/htop.git
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:
commit
68c3270be8
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
|
|
Loading…
Reference in New Issue