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