1 /*
2 htop - dragonflybsd/Platform.c
3 (C) 2014 Hisham H. Muhammad
4 (C) 2017 Diederik de Groot
5 Released under the GNU GPLv2+, see the COPYING file
6 in the source distribution for its full text.
7 */
8 
9 #include "dragonflybsd/Platform.h"
10 
11 #include <math.h>
12 #include <time.h>
13 #include <sys/resource.h>
14 #include <sys/sysctl.h>
15 #include <sys/time.h>
16 #include <sys/types.h>
17 #include <vm/vm_param.h>
18 
19 #include "ClockMeter.h"
20 #include "CPUMeter.h"
21 #include "DateMeter.h"
22 #include "DateTimeMeter.h"
23 #include "HostnameMeter.h"
24 #include "LoadAverageMeter.h"
25 #include "MemoryMeter.h"
26 #include "MemorySwapMeter.h"
27 #include "ProcessList.h"
28 #include "SwapMeter.h"
29 #include "SysArchMeter.h"
30 #include "TasksMeter.h"
31 #include "UptimeMeter.h"
32 #include "dragonflybsd/DragonFlyBSDProcess.h"
33 #include "dragonflybsd/DragonFlyBSDProcessList.h"
34 
35 
36 const ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
37 
38 const SignalItem Platform_signals[] = {
39    { .name = " 0 Cancel",    .number =  0 },
40    { .name = " 1 SIGHUP",    .number =  1 },
41    { .name = " 2 SIGINT",    .number =  2 },
42    { .name = " 3 SIGQUIT",   .number =  3 },
43    { .name = " 4 SIGILL",    .number =  4 },
44    { .name = " 5 SIGTRAP",   .number =  5 },
45    { .name = " 6 SIGABRT",   .number =  6 },
46    { .name = " 7 SIGEMT",    .number =  7 },
47    { .name = " 8 SIGFPE",    .number =  8 },
48    { .name = " 9 SIGKILL",   .number =  9 },
49    { .name = "10 SIGBUS",    .number = 10 },
50    { .name = "11 SIGSEGV",   .number = 11 },
51    { .name = "12 SIGSYS",    .number = 12 },
52    { .name = "13 SIGPIPE",   .number = 13 },
53    { .name = "14 SIGALRM",   .number = 14 },
54    { .name = "15 SIGTERM",   .number = 15 },
55    { .name = "16 SIGURG",    .number = 16 },
56    { .name = "17 SIGSTOP",   .number = 17 },
57    { .name = "18 SIGTSTP",   .number = 18 },
58    { .name = "19 SIGCONT",   .number = 19 },
59    { .name = "20 SIGCHLD",   .number = 20 },
60    { .name = "21 SIGTTIN",   .number = 21 },
61    { .name = "22 SIGTTOU",   .number = 22 },
62    { .name = "23 SIGIO",     .number = 23 },
63    { .name = "24 SIGXCPU",   .number = 24 },
64    { .name = "25 SIGXFSZ",   .number = 25 },
65    { .name = "26 SIGVTALRM", .number = 26 },
66    { .name = "27 SIGPROF",   .number = 27 },
67    { .name = "28 SIGWINCH",  .number = 28 },
68    { .name = "29 SIGINFO",   .number = 29 },
69    { .name = "30 SIGUSR1",   .number = 30 },
70    { .name = "31 SIGUSR2",   .number = 31 },
71    { .name = "32 SIGTHR",    .number = 32 },
72    { .name = "33 SIGLIBRT",  .number = 33 },
73 };
74 
75 const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals);
76 
77 const MeterClass* const Platform_meterTypes[] = {
78    &CPUMeter_class,
79    &ClockMeter_class,
80    &DateMeter_class,
81    &DateTimeMeter_class,
82    &LoadAverageMeter_class,
83    &LoadMeter_class,
84    &MemoryMeter_class,
85    &MemorySwapMeter_class,
86    &SwapMeter_class,
87    &TasksMeter_class,
88    &UptimeMeter_class,
89    &BatteryMeter_class,
90    &HostnameMeter_class,
91    &SysArchMeter_class,
92    &AllCPUsMeter_class,
93    &AllCPUs2Meter_class,
94    &AllCPUs4Meter_class,
95    &AllCPUs8Meter_class,
96    &LeftCPUsMeter_class,
97    &RightCPUsMeter_class,
98    &LeftCPUs2Meter_class,
99    &RightCPUs2Meter_class,
100    &LeftCPUs4Meter_class,
101    &RightCPUs4Meter_class,
102    &LeftCPUs8Meter_class,
103    &RightCPUs8Meter_class,
104    &BlankMeter_class,
105    NULL
106 };
107 
Platform_init(void)108 bool Platform_init(void) {
109    /* no platform-specific setup needed */
110    return true;
111 }
112 
Platform_done(void)113 void Platform_done(void) {
114    /* no platform-specific cleanup needed */
115 }
116 
Platform_setBindings(Htop_Action * keys)117 void Platform_setBindings(Htop_Action* keys) {
118    /* no platform-specific key bindings */
119    (void) keys;
120 }
121 
Platform_getUptime()122 int Platform_getUptime() {
123    struct timeval bootTime, currTime;
124    int mib[2] = { CTL_KERN, KERN_BOOTTIME };
125    size_t size = sizeof(bootTime);
126 
127    int err = sysctl(mib, 2, &bootTime, &size, NULL, 0);
128    if (err) {
129       return -1;
130    }
131    gettimeofday(&currTime, NULL);
132 
133    return (int) difftime(currTime.tv_sec, bootTime.tv_sec);
134 }
135 
Platform_getLoadAverage(double * one,double * five,double * fifteen)136 void Platform_getLoadAverage(double* one, double* five, double* fifteen) {
137    struct loadavg loadAverage;
138    int mib[2] = { CTL_VM, VM_LOADAVG };
139    size_t size = sizeof(loadAverage);
140 
141    int err = sysctl(mib, 2, &loadAverage, &size, NULL, 0);
142    if (err) {
143       *one = 0;
144       *five = 0;
145       *fifteen = 0;
146       return;
147    }
148    *one     = (double) loadAverage.ldavg[0] / loadAverage.fscale;
149    *five    = (double) loadAverage.ldavg[1] / loadAverage.fscale;
150    *fifteen = (double) loadAverage.ldavg[2] / loadAverage.fscale;
151 }
152 
Platform_getMaxPid()153 int Platform_getMaxPid() {
154    int maxPid;
155    size_t size = sizeof(maxPid);
156    int err = sysctlbyname("kern.pid_max", &maxPid, &size, NULL, 0);
157    if (err) {
158       return 999999;
159    }
160    return maxPid;
161 }
162 
Platform_setCPUValues(Meter * this,unsigned int cpu)163 double Platform_setCPUValues(Meter* this, unsigned int cpu) {
164    const DragonFlyBSDProcessList* fpl = (const DragonFlyBSDProcessList*) this->pl;
165    unsigned int cpus = this->pl->activeCPUs;
166    const CPUData* cpuData;
167 
168    if (cpus == 1) {
169       // single CPU box has everything in fpl->cpus[0]
170       cpuData = &(fpl->cpus[0]);
171    } else {
172       cpuData = &(fpl->cpus[cpu]);
173    }
174 
175    double  percent;
176    double* v = this->values;
177 
178    v[CPU_METER_NICE]   = cpuData->nicePercent;
179    v[CPU_METER_NORMAL] = cpuData->userPercent;
180    if (this->pl->settings->detailedCPUTime) {
181       v[CPU_METER_KERNEL]  = cpuData->systemPercent;
182       v[CPU_METER_IRQ]     = cpuData->irqPercent;
183       this->curItems = 4;
184       percent = v[0] + v[1] + v[2] + v[3];
185    } else {
186       v[2] = cpuData->systemAllPercent;
187       this->curItems = 3;
188       percent = v[0] + v[1] + v[2];
189    }
190 
191    percent = isnan(percent) ? 0.0 : CLAMP(percent, 0.0, 100.0);
192 
193    v[CPU_METER_FREQUENCY] = NAN;
194    v[CPU_METER_TEMPERATURE] = NAN;
195 
196    return percent;
197 }
198 
Platform_setMemoryValues(Meter * this)199 void Platform_setMemoryValues(Meter* this) {
200    // TODO
201    const ProcessList* pl = this->pl;
202 
203    this->total = pl->totalMem;
204    this->values[0] = pl->usedMem;
205    this->values[1] = pl->buffersMem;
206    // this->values[2] = "shared memory, like tmpfs and shm"
207    this->values[3] = pl->cachedMem;
208    // this->values[4] = "available memory"
209 }
210 
Platform_setSwapValues(Meter * this)211 void Platform_setSwapValues(Meter* this) {
212    const ProcessList* pl = this->pl;
213    this->total = pl->totalSwap;
214    this->values[0] = pl->usedSwap;
215    this->values[1] = NAN;
216 }
217 
218 extern char **DragonFlyBSDGet_env(pid_t pid);
219 
Platform_getProcessEnv(pid_t pid)220 char* Platform_getProcessEnv(pid_t pid) {
221    char *env = NULL, **fenv = NULL, *ptr = NULL;
222    size_t size = 0;
223 
224    fenv = DragonFlyBSDGet_env(pid);
225 
226    if (fenv) {
227       ptr = fenv[0];
228       while (ptr && *ptr) {
229          size += strlen(ptr) + 1;
230          ptr += strlen(ptr) + 1;
231       }
232       env = xMalloc(size+2);
233       memcpy(env, fenv[0], size);
234       env[size] = 0;
235       env[size+1] = 0;
236    }
237    return env;
238 }
239 
Platform_getInodeFilename(pid_t pid,ino_t inode)240 char* Platform_getInodeFilename(pid_t pid, ino_t inode) {
241    (void)pid;
242    (void)inode;
243    return NULL;
244 }
245 
Platform_getProcessLocks(pid_t pid)246 FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) {
247    (void)pid;
248    return NULL;
249 }
250 
Platform_getDiskIO(DiskIOData * data)251 bool Platform_getDiskIO(DiskIOData* data) {
252    // TODO
253    (void)data;
254    return false;
255 }
256 
Platform_getNetworkIO(NetworkIOData * data)257 bool Platform_getNetworkIO(NetworkIOData* data) {
258    // TODO
259    (void)data;
260    return false;
261 }
262 
Platform_getBattery(double * percent,ACPresence * isOnAC)263 void Platform_getBattery(double* percent, ACPresence* isOnAC) {
264    int life;
265    size_t life_len = sizeof(life);
266    if (sysctlbyname("hw.acpi.battery.life", &life, &life_len, NULL, 0) == -1)
267       *percent = NAN;
268    else
269       *percent = life;
270 
271    int acline;
272    size_t acline_len = sizeof(acline);
273    if (sysctlbyname("hw.acpi.acline", &acline, &acline_len, NULL, 0) == -1)
274       *isOnAC = AC_ERROR;
275    else
276       *isOnAC = acline == 0 ? AC_ABSENT : AC_PRESENT;
277 }
278