1 /*
2 *
3 * Conky, a system monitor, based on torsmo
4 *
5 * Any original torsmo code is licensed under the BSD license
6 *
7 * All code written since the fork of torsmo is licensed under the GPL
8 *
9 * Please see COPYING for details
10 *
11 * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12 * Copyright (c) 2005-2021 Brenden Matthews, Philip Kovacs, et. al.
13 * (see AUTHORS)
14 * All rights reserved.
15 *
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 *
28 */
29
30 #include "netbsd.h"
31 #include "net_stat.h"
32
33 static kvm_t *kd = nullptr;
34 int kd_init = 0, nkd_init = 0;
35 u_int32_t sensvalue;
36 char errbuf[_POSIX2_LINE_MAX];
37
init_kvm(void)38 static int init_kvm(void) {
39 if (kd_init) { return 0; }
40
41 kd = kvm_openfiles(nullptr, NULL, NULL, KVM_NO_FILES, errbuf);
42 if (kd == nullptr) {
43 warnx("cannot kvm_openfiles: %s", errbuf);
44 return -1;
45 }
46 kd_init = 1;
47 return 0;
48 }
49
swapmode(int * retavail,int * retfree)50 static int swapmode(int *retavail, int *retfree) {
51 int n;
52 struct swapent *sep;
53
54 *retavail = 0;
55 *retfree = 0;
56
57 n = swapctl(SWAP_NSWAP, 0, 0);
58
59 if (n < 1) {
60 warn("could not get swap information");
61 return 0;
62 }
63
64 sep = (struct swapent *)malloc(n * (sizeof(*sep)));
65
66 if (sep == nullptr) {
67 warn("memory allocation failed");
68 return 0;
69 }
70
71 if (swapctl(SWAP_STATS, (void *)sep, n) < n) {
72 warn("could not get swap stats");
73 return 0;
74 }
75 for (; n > 0; n--) {
76 *retavail += (int)dbtob(sep[n - 1].se_nblks);
77 *retfree += (int)dbtob(sep[n - 1].se_nblks - sep[n - 1].se_inuse);
78 }
79 *retavail = (int)(*retavail / 1024);
80 *retfree = (int)(*retfree / 1024);
81
82 return 1;
83 }
84
prepare_update()85 void prepare_update() {}
86
update_uptime()87 void update_uptime() {
88 int mib[2] = {CTL_KERN, KERN_BOOTTIME};
89 struct timeval boottime;
90 time_t now;
91 int size = sizeof(boottime);
92
93 if ((sysctl(mib, 2, &boottime, &size, nullptr, 0) != -1) &&
94 (boottime.tv_sec != 0)) {
95 time(&now);
96 info.uptime = now - boottime.tv_sec;
97 } else {
98 warn("could not get uptime");
99 info.uptime = 0;
100 }
101 }
102
check_mount(struct text_object * obj)103 int check_mount(struct text_object *obj) {
104 /* stub */
105 (void)obj;
106 return 0;
107 }
108
update_meminfo()109 void update_meminfo() {
110 int mib[] = {CTL_VM, VM_UVMEXP2};
111 int total_pages, inactive_pages, free_pages;
112 int swap_avail, swap_free;
113 const int pagesize = getpagesize();
114 struct uvmexp_sysctl uvmexp;
115 size_t size = sizeof(uvmexp);
116
117 if (sysctl(mib, 2, &uvmexp, &size, nullptr, 0) < 0) {
118 warn("could not get memory info");
119 return;
120 }
121
122 total_pages = uvmexp.npages;
123 free_pages = uvmexp.free;
124 inactive_pages = uvmexp.inactive;
125
126 info.memmax = (total_pages * pagesize) >> 10;
127 info.mem = ((total_pages - free_pages - inactive_pages) * pagesize) >> 10;
128 info.memwithbuffers = info.mem;
129 info.memeasyfree = info.memfree = info.memmax - info.mem;
130 info.legacymem = info.mem;
131
132 if (swapmode(&swap_avail, &swap_free) >= 0) {
133 info.swapmax = swap_avail;
134 info.swap = (swap_avail - swap_free);
135 info.swapfree = swap_free;
136 }
137 }
138
update_net_stats()139 void update_net_stats() {
140 int i;
141 double delta;
142 struct ifnet ifnet;
143 struct ifnet_head ifhead; /* interfaces are in a tail queue */
144 u_long ifnetaddr;
145 static struct nlist namelist[] = {{"_ifnet"}, {nullptr}};
146 static kvm_t *nkd;
147
148 if (!nkd_init) {
149 nkd = kvm_openfiles(nullptr, NULL, NULL, O_RDONLY, errbuf);
150 if (nkd == nullptr) {
151 warnx("cannot kvm_openfiles: %s", errbuf);
152 warnx("maybe you need to setgid kmem this program?");
153 return;
154 } else if (kvm_nlist(nkd, namelist) != 0) {
155 warn("cannot kvm_nlist");
156 return;
157 } else {
158 nkd_init = 1;
159 }
160 }
161
162 if (kvm_read(nkd, (u_long)namelist[0].n_value, (void *)&ifhead,
163 sizeof(ifhead)) < 0) {
164 warn("cannot kvm_read");
165 return;
166 }
167
168 /* get delta */
169 delta = current_update_time - last_update_time;
170 if (delta <= 0.0001) { return; }
171
172 for (i = 0, ifnetaddr = (u_long)ifhead.tqh_first;
173 ifnet.if_list.tqe_next && i < 16;
174 ifnetaddr = (u_long)ifnet.if_list.tqe_next, i++) {
175 struct net_stat *ns;
176 long long last_recv, last_trans;
177
178 kvm_read(nkd, (u_long)ifnetaddr, (void *)&ifnet, sizeof(ifnet));
179 ns = get_net_stat(ifnet.if_xname, nullptr, NULL);
180 ns->up = 1;
181 last_recv = ns->recv;
182 last_trans = ns->trans;
183
184 if (ifnet.if_ibytes < ns->last_read_recv) {
185 ns->recv +=
186 ((long long)4294967295U - ns->last_read_recv) + ifnet.if_ibytes;
187 } else {
188 ns->recv += (ifnet.if_ibytes - ns->last_read_recv);
189 }
190
191 ns->last_read_recv = ifnet.if_ibytes;
192
193 if (ifnet.if_obytes < ns->last_read_trans) {
194 ns->trans +=
195 ((long long)4294967295U - ns->last_read_trans) + ifnet.if_obytes;
196 } else {
197 ns->trans += (ifnet.if_obytes - ns->last_read_trans);
198 }
199
200 ns->last_read_trans = ifnet.if_obytes;
201
202 ns->recv += (ifnet.if_ibytes - ns->last_read_recv);
203 ns->last_read_recv = ifnet.if_ibytes;
204 ns->trans += (ifnet.if_obytes - ns->last_read_trans);
205 ns->last_read_trans = ifnet.if_obytes;
206
207 ns->recv_speed = (ns->recv - last_recv) / delta;
208 ns->trans_speed = (ns->trans - last_trans) / delta;
209 }
210 }
211
update_total_processes()212 int update_total_processes() {
213 /* It's easier to use kvm here than sysctl */
214
215 int n_processes;
216
217 info.procs = 0;
218
219 if (init_kvm() < 0) {
220 return;
221 } else {
222 kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2),
223 &n_processes);
224 }
225
226 info.procs = n_processes;
227
228 return 0;
229 }
230
update_running_processes()231 void update_running_processes() {
232 struct kinfo_proc2 *p;
233 int n_processes;
234 int i, cnt = 0;
235
236 info.run_procs = 0;
237
238 if (init_kvm() < 0) {
239 return;
240 } else {
241 p = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2),
242 &n_processes);
243 for (i = 0; i < n_processes; i++) {
244 if (p[i].p_stat == LSRUN || p[i].p_stat == LSIDL ||
245 p[i].p_stat == LSONPROC) {
246 cnt++;
247 }
248 }
249 }
250
251 info.run_procs = cnt;
252 }
253
254 struct cpu_load_struct {
255 unsigned long load[5];
256 };
257
258 struct cpu_load_struct fresh = {{0, 0, 0, 0, 0}};
259
260 long cpu_used, oldtotal, oldused;
261
update_cpu_usage()262 void update_cpu_usage() {
263 long used, total;
264 static u_int64_t cp_time[CPUSTATES];
265 size_t len = sizeof(cp_time);
266
267 info.cpu_usage = 0;
268
269 if (sysctlbyname("kern.cp_time", &cp_time, &len, nullptr, 0) < 0) {
270 warn("cannot get kern.cp_time");
271 }
272
273 fresh.load[0] = cp_time[CP_USER];
274 fresh.load[1] = cp_time[CP_NICE];
275 fresh.load[2] = cp_time[CP_SYS];
276 fresh.load[3] = cp_time[CP_IDLE];
277 fresh.load[4] = cp_time[CP_IDLE];
278
279 used = fresh.load[0] + fresh.load[1] + fresh.load[2];
280 total = fresh.load[0] + fresh.load[1] + fresh.load[2] + fresh.load[3];
281
282 if ((total - oldtotal) != 0) {
283 info.cpu_usage = ((double)(used - oldused)) / (double)(total - oldtotal);
284 } else {
285 info.cpu_usage = 0;
286 }
287
288 oldused = used;
289 oldtotal = total;
290 }
291
free_cpu(struct text_object *)292 void free_cpu(struct text_object *) { /* no-op */
293 }
294
update_load_average()295 void update_load_average() {
296 double v[3];
297
298 getloadavg(v, 3);
299
300 info.loadavg[0] = (float)v[0];
301 info.loadavg[1] = (float)v[1];
302 info.loadavg[2] = (float)v[2];
303 }
304
get_acpi_temperature(int fd)305 double get_acpi_temperature(int fd) { return -1; }
306
get_battery_stuff(char * buf,unsigned int n,const char * bat,int item)307 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item) {}
308
open_acpi_temperature(const char * name)309 int open_acpi_temperature(const char *name) { return -1; }
310
get_acpi_ac_adapter(char * p_client_buffer,size_t client_buffer_size,const char * adapter)311 void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size,
312 const char *adapter) {
313 (void)adapter; // only linux uses this
314
315 if (!p_client_buffer || client_buffer_size <= 0) { return; }
316
317 /* not implemented */
318 memset(p_client_buffer, 0, client_buffer_size);
319 }
320
321 /* char *get_acpi_fan() */
get_acpi_fan(char * p_client_buffer,size_t client_buffer_size)322 void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size) {
323 if (!p_client_buffer || client_buffer_size <= 0) { return; }
324
325 /* not implemented */
326 memset(p_client_buffer, 0, client_buffer_size);
327 }
328
get_entropy_avail(unsigned int * val)329 int get_entropy_avail(unsigned int *val) { return 1; }
330
get_entropy_poolsize(unsigned int * val)331 int get_entropy_poolsize(unsigned int *val) { return 1; }
332