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 "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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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++;
|
||||||
|
|
Loading…
Reference in New Issue