Added preliminary attempt at jails support on FreeBSD - JID and JAIL (name) columns, somewhat more correct kernel "thread" detection.

Seems FreeBSD kernel can spawn both kernel processes (what is what htop currently sees) and kernel threads.
For now let's consider kernel processes kernel "threads".
This commit is contained in:
Martin "eto" Misuth 2015-09-30 22:04:26 +02:00
parent 2d1507ad5a
commit 8c00fa4582
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;
@ -131,6 +137,48 @@ 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;
@ -149,9 +197,15 @@ void ProcessList_goThroughEntries(ProcessList* this) {
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,7 +254,7 @@ void ProcessList_goThroughEntries(ProcessList* this) {
default: proc->state = '?'; default: proc->state = '?';
} }
if (Process_isKernelThread(proc)) { if (Process_isKernelThread(fp)) {
this->kernelThreads++; this->kernelThreads++;
} }