blob: fb67ef0ab5528a278eda0f27f87617e292795852 [file] [log] [blame] [raw]
/*
htop - solaris/Platform.c
(C) 2014 Hisham H. Muhammad
(C) 2015 David C. Hunt
(C) 2017,2018 Guy M. Broome
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "Platform.h"
#include "Meter.h"
#include "CPUMeter.h"
#include "MemoryMeter.h"
#include "SwapMeter.h"
#include "TasksMeter.h"
#include "LoadAverageMeter.h"
#include "ClockMeter.h"
#include "HostnameMeter.h"
#include "UptimeMeter.h"
#include "SolarisProcess.h"
#include "SolarisProcessList.h"
#include "IOUtils.h"
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/loadavg.h>
#include <string.h>
#include <kstat.h>
#include <math.h>
#include <sys/var.h>
#ifdef HAVE_LIBPROC
#include <libproc.h>
#else
#include <procfs.h>
#include <unistd.h>
#include <fcntl.h>
#endif
/*{
#include "Action.h"
#include "BatteryMeter.h"
#include "SignalsPanel.h"
#include <signal.h>
#include <sys/mkdev.h>
#include <sys/proc.h>
#define MAX_VALUE_OF(T) (((size_t)1 << (sizeof(T) * 8 - ((T)-1 == -1))) - 1)
#ifdef HAVE_LIBPROC
#define kill(pid, signal) kill(pid / 1024, signal)
#endif
extern ProcessFieldData Process_fields[];
typedef struct var kvar_t;
}*/
const SignalItem Platform_signals[] = {
{ .name = " 0 Cancel", .number = 0 },
{ .name = " 1 SIGHUP", .number = 1 },
{ .name = " 2 SIGINT", .number = 2 },
{ .name = " 3 SIGQUIT", .number = 3 },
{ .name = " 4 SIGILL", .number = 4 },
{ .name = " 5 SIGTRAP", .number = 5 },
{ .name = " 6 SIGABRT/IOT", .number = 6 },
{ .name = " 7 SIGEMT", .number = 7 },
{ .name = " 8 SIGFPE", .number = 8 },
{ .name = " 9 SIGKILL", .number = 9 },
{ .name = "10 SIGBUS", .number = 10 },
{ .name = "11 SIGSEGV", .number = 11 },
{ .name = "12 SIGSYS", .number = 12 },
{ .name = "13 SIGPIPE", .number = 13 },
{ .name = "14 SIGALRM", .number = 14 },
{ .name = "15 SIGTERM", .number = 15 },
{ .name = "16 SIGUSR1", .number = 16 },
{ .name = "17 SIGUSR2", .number = 17 },
{ .name = "18 SIGCHLD/CLD", .number = 18 },
{ .name = "19 SIGPWR", .number = 19 },
{ .name = "20 SIGWINCH", .number = 20 },
{ .name = "21 SIGURG", .number = 21 },
{ .name = "22 SIGPOLL/IO", .number = 22 },
{ .name = "23 SIGSTOP", .number = 23 },
{ .name = "24 SIGTSTP", .number = 24 },
{ .name = "25 SIGCONT", .number = 25 },
{ .name = "26 SIGTTIN", .number = 26 },
{ .name = "27 SIGTTOU", .number = 27 },
{ .name = "28 SIGVTALRM", .number = 28 },
{ .name = "29 SIGPROF", .number = 29 },
{ .name = "30 SIGXCPU", .number = 30 },
{ .name = "31 SIGXFSZ", .number = 31 },
{ .name = "32 SIGWAITING", .number = 32 },
{ .name = "33 SIGLWP", .number = 33 },
{ .name = "34 SIGFREEZE", .number = 34 },
{ .name = "35 SIGTHAW", .number = 35 },
{ .name = "36 SIGCANCEL", .number = 36 },
{ .name = "37 SIGLOST", .number = 37 },
{ .name = "38 SIGXRES", .number = 38 },
{ .name = "39 SIGJVM1", .number = 39 },
{ .name = "40 SIGJVM2", .number = 40 },
{ .name = "41 SIGINFO", .number = 41 },
};
const unsigned int Platform_numberOfSignals = sizeof(Platform_signals)/sizeof(SignalItem);
#ifdef HAVE_LIBPROC
ProcessField Platform_defaultFields[] = { PID, LWPID, EFFECTIVE_USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
#else
ProcessField Platform_defaultFields[] = { PID, EFFECTIVE_USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
#endif
MeterClass* Platform_meterTypes[] = {
&CPUMeter_class,
&ClockMeter_class,
&LoadAverageMeter_class,
&LoadMeter_class,
&MemoryMeter_class,
&SwapMeter_class,
&TasksMeter_class,
&BatteryMeter_class,
&HostnameMeter_class,
&UptimeMeter_class,
&AllCPUsMeter_class,
&AllCPUs2Meter_class,
&LeftCPUsMeter_class,
&RightCPUsMeter_class,
&LeftCPUs2Meter_class,
&RightCPUs2Meter_class,
&BlankMeter_class,
NULL
};
void Platform_setBindings(Htop_Action* keys) {
(void) keys;
}
int Platform_numberOfFields = LAST_PROCESSFIELD;
extern char Process_pidFormat[20];
int Platform_getUptime() {
// Fallback to utmpx
return -1;
}
void Platform_getLoadAverage(double* one, double* five, double* fifteen) {
double plat_loadavg[LOADAVG_NSTATS];
if(getloadavg(plat_loadavg, LOADAVG_NSTATS) < 0) return;
*one = plat_loadavg[LOADAVG_1MIN];
*five = plat_loadavg[LOADAVG_5MIN];
*fifteen = plat_loadavg[LOADAVG_15MIN];
}
int Platform_getMaxPid() {
kstat_ctl_t *kc = NULL;
kstat_t *kshandle = NULL;
kvar_t *ksvar = NULL;
int vproc = 32778; // Reasonable Solaris default
kc = kstat_open();
if (kc != NULL) { kshandle = kstat_lookup(kc,"unix",0,"var"); }
if (kshandle != NULL) { kstat_read(kc,kshandle,NULL); }
ksvar = kshandle->ks_data;
if (ksvar->v_proc > 0 ) {
vproc = ksvar->v_proc;
}
if (kc != NULL) { kstat_close(kc); }
return vproc;
}
double Platform_setCPUValues(Meter *meter, int cpu) {
SolarisProcessList* spl = (SolarisProcessList *)meter->pl;
CPUData *cpuData = spl->cpus + (meter->pl->cpuCount > 1 ? cpu : 0);
double* v = meter->values;
double percent;
v[CPU_METER_NICE] = cpuData->nicePercent;
v[CPU_METER_NORMAL] = cpuData->userPercent;
if (meter->pl->settings->detailedCPUTime) {
v[CPU_METER_KERNEL] = cpuData->systemPercent;
v[CPU_METER_IRQ] = cpuData->irqPercent;
Meter_setItems(meter, 4);
percent = v[0]+v[1]+v[2]+v[3];
} else {
v[2] = cpuData->systemAllPercent;
Meter_setItems(meter, 3);
percent = v[0]+v[1]+v[2];
}
percent = CLAMP(percent, 0.0, 100.0);
if (isnan(percent)) percent = 0.0;
return percent;
}
void Platform_setMemoryValues(Meter* this) {
ProcessList* pl = (ProcessList*) this->pl;
this->total = pl->totalMem;
this->values[0] = pl->usedMem;
this->values[1] = pl->buffersMem;
this->values[2] = pl->cachedMem;
}
void Platform_setSwapValues(Meter* this) {
ProcessList* pl = (ProcessList*) this->pl;
this->total = pl->totalSwap;
this->values[0] = pl->usedSwap;
}
#ifdef HAVE_LIBPROC
struct env_accum {
char **env;
unsigned int count;
};
static int append_env(void *arg, struct ps_prochandle *handle, uintptr_t addr, const char *s) {
struct env_accum *accum = arg;
accum->env[accum->count] = xStrdup(s);
accum->env = xRealloc(accum->env, (++accum->count + 1) * sizeof(char *));
return 0;
}
char **Platform_getProcessEnv(Process *proc) {
pid_t pid = ((SolarisProcess *)proc)->realpid;
int graberr;
struct ps_prochandle *handle = Pgrab(pid, PGRAB_RDONLY, &graberr);
if(!handle) return NULL;
struct env_accum accum = { .env = xMalloc(sizeof(char *)) };
Penv_iter(handle, append_env, &accum);
Prelease(handle, 0);
accum.env[accum.count] = NULL;
return accum.env;
}
#else
char **Platform_getProcessEnv(Process *proc) {
bool is_64bit;
SolarisProcess *sol_proc = (SolarisProcess *)proc;
switch(sol_proc->data_model) {
case PR_MODEL_ILP32:
is_64bit = false;
break;
case PR_MODEL_LP64:
is_64bit = true;
break;
default:
return NULL;
}
if(Process_isKernelProcess(proc)) return NULL;
if(sol_proc->env_offset < 0) return NULL;
char path[20];
xSnprintf(path, sizeof path, "/proc/%d/as", (int)proc->pid);
int fd = open(path, O_RDONLY);
if(fd == -1) return NULL;
if(lseek(fd, sol_proc->env_offset, SEEK_SET) < 0) {
close(fd);
return NULL;
}
char **env = xMalloc(sizeof(char *));
unsigned int i = 0;
while(true) {
off_t offset;
if(is_64bit) {
uint64_t buffer;
if(xread(fd, &buffer, 8) < 8) break;
if(buffer > MAX_VALUE_OF(off_t)) continue;
offset = buffer;
} else {
uint32_t buffer;
if(xread(fd, &buffer, 4) < 4) break;
offset = buffer;
}
if(!offset) break;
env[i] = xMalloc(256);
int len = pread(fd, env[i], 256, offset);
if(len < 1) {
free(env[i]);
continue;
}
len = strnlen(env[i], len);
if(len < 255) env[i] = realloc(env[i], len + 1);
else if(len == 256) env[i][255] = 0;
env = xRealloc(env, (++i + 1) * sizeof(char *));
}
close(fd);
env[i] = NULL;
return env;
}
#endif