xosview  1.23
About: xosview is an X Windows based system monitor (cpu, memory, swap and network usage; interrupt and serial activities; load average).
  Fossies Dox: xosview-1.23.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

kernel.cc
Go to the documentation of this file.
1 //
2 // NetBSD port:
3 // Copyright (c) 1995, 1996, 1997-2002 by Brian Grayson (bgrayson@netbsd.org)
4 //
5 // This file was written by Brian Grayson for the NetBSD and xosview
6 // projects.
7 // This file contains code from the NetBSD project, which is covered
8 // by the standard BSD license.
9 // Dummy device ignore code by : David Cuka (dcuka@intgp1.ih.att.com)
10 // The OpenBSD interrupt meter code was written by Oleg Safiullin
11 // (form@vs.itam.nsc.ru).
12 // This file may be distributed under terms of the GPL or of the BSD
13 // license, whichever you choose. The full license notices are
14 // contained in the files COPYING.GPL and COPYING.BSD, which you
15 // should have received. If not, contact one of the xosview
16 // authors for a copy.
17 //
18 
19 #include "kernel.h"
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <kvm.h>
26 #include <nlist.h>
27 #include <limits.h>
28 #include <string.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <ifaddrs.h>
32 #include <sysexits.h>
33 #include <sys/types.h>
34 #include <sys/queue.h>
35 #include <sys/socket.h>
36 #include <sys/sysctl.h>
37 #include <net/if.h>
38 
39 #if defined(XOSVIEW_DFBSD)
40 #define _KERNEL_STRUCTURES
41 #include <kinfo.h>
42 #endif
43 
44 #if defined(XOSVIEW_FREEBSD) || defined(XOSVIEW_DFBSD)
45 static const char ACPIDEV[] = "/dev/acpi";
46 static const char APMDEV[] = "/dev/apm";
47 static int maxcpus = 1;
48 #include <sys/ioctl.h>
49 #include <sys/resource.h>
50 #include <dev/acpica/acpiio.h>
51 #include <machine/apm_bios.h>
52 #endif
53 
54 #if defined(XOSVIEW_NETBSD)
55 #include <sys/sched.h>
56 #include <sys/iostat.h>
57 #include <sys/envsys.h>
58 #include <prop/proplib.h>
59 #include <paths.h>
60 static int mib_cpt[2] = { CTL_KERN, KERN_CP_TIME };
61 static int mib_dsk[3] = { CTL_HW, HW_IOSTATS, sizeof(struct io_sysctl) };
62 #endif
63 
64 #if defined(XOSVIEW_OPENBSD)
65 #include <sys/sched.h>
66 #include <sys/disk.h>
67 #include <sys/mount.h>
68 #include <net/route.h>
69 #include <net/if_dl.h>
70 static int mib_spd[2] = { CTL_HW, HW_CPUSPEED };
71 static int mib_cpt[2] = { CTL_KERN, KERN_CPTIME };
72 static int mib_cpt2[3] = { CTL_KERN, KERN_CPTIME2, 0 };
73 static int mib_ifl[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
74 #endif
75 
76 #if defined(XOSVIEW_OPENBSD) || defined(XOSVIEW_DFBSD)
77 #include <sys/sensors.h>
78 static int mib_sen[5] = { CTL_HW, HW_SENSORS };
79 #endif
80 
81 #if defined(HAVE_DEVSTAT)
82 #include <devstat.h>
83 #endif
84 
85 #if defined(HAVE_UVM)
86 #include <string.h>
87 #include <sys/malloc.h>
88 #include <sys/device.h>
89 #include <uvm/uvm_extern.h>
90 #ifdef VM_UVMEXP2
91 static int mib_uvm[2] = { CTL_VM, VM_UVMEXP2 };
92 #else
93 static int mib_uvm[2] = { CTL_VM, VM_UVMEXP };
94 #endif
95 #else
96 #if defined(XOSVIEW_FREEBSD)
97 #define _WANT_VMMETER
98 #endif
99 #include <sys/vmmeter.h>
100 #endif
101 
102 #if defined(HAVE_SWAPCTL)
103 #include <sys/swap.h>
104 #endif
105 
106 
107 // ------------------------ local variables ----------------------------------
108 
109 // This single kvm_t is shared by all of the kvm routines.
110 kvm_t* kd = NULL;
111 
112 // This struct has the list of all the symbols we want from the kernel.
113 static struct nlist nlst[] =
114 {
115 // We put a dummy symbol for a don't care, and ignore warnings about
116 // this later on. This keeps the indices within the nlist constant.
117 #define DUMMY_SYM "dummy_sym"
118 
119 #if defined(XOSVIEW_OPENBSD)
120 { "_disklist" },
121 #define DISKLIST_SYM_INDEX 0
122 #else
123 { DUMMY_SYM },
124 #define DUMMY_0
125 #endif
126 #if defined(XOSVIEW_NETBSD)
127 { "_allevents" },
128 #define ALLEVENTS_SYM_INDEX 1
129 { "_bufmem" },
130 #define BUFMEM_SYM_INDEX 2
131 #else
132 { DUMMY_SYM },
133 #define DUMMY_1
134 { DUMMY_SYM },
135 #define DUMMY_2
136 #endif
137 #if defined(XOSVIEW_FREEBSD)
138 { "_intrnames" },
139 #define INTRNAMES_SYM_INDEX 3
140 # if __FreeBSD_version >= 900040
141 { "_sintrnames" },
142 # else
143 { "_eintrnames" },
144 # endif
145 #define EINTRNAMES_SYM_INDEX 4
146 { "_intrcnt" },
147 #define INTRCNT_SYM_INDEX 5
148 # if __FreeBSD_version >= 900040
149 { "_sintrcnt" },
150 # else
151 { "_eintrcnt" },
152 # endif
153 #define EINTRCNT_SYM_INDEX 6
154 #endif
155 { NULL }
156 };
157 
158 static char kernelFileName[_POSIX2_LINE_MAX];
159 
160 
161 // ------------------------ utility functions --------------------------------
162 // The following is an error-checking form of kvm_read. In addition
163 // it uses kd as the implicit kernel-file to read. Saves typing.
164 // Since this is C++, it's an inline function rather than a macro.
165 
166 static inline void
167 safe_kvm_read(unsigned long kernel_addr, void* user_addr, size_t nbytes) {
168  /* Check for obvious bad symbols (i.e., from /netbsd when we
169  * booted off of /netbsd.old), such as symbols that reference
170  * 0x00000000 (or anywhere in the first 256 bytes of memory). */
171  int retval = 0;
172  if ( (kernel_addr & 0xffffff00) == 0 )
173  errx(EX_SOFTWARE, "safe_kvm_read() was attempted on EA %#lx.", kernel_addr);
174  if ( (retval = kvm_read(kd, kernel_addr, user_addr, nbytes)) == -1 )
175  err(EX_SOFTWARE, "kvm_read() of kernel address %#lx", kernel_addr);
176  if (retval != (int)nbytes)
177  warn("safe_kvm_read(%#lx) returned %d bytes, not %d", kernel_addr, retval, (int)nbytes);
178 }
179 
180 // This version uses the symbol offset in the nlst variable, to make it
181 // a little more convenient. BCG
182 static inline void
183 safe_kvm_read_symbol(int nlstOffset, void* user_addr, size_t nbytes) {
184  safe_kvm_read(nlst[nlstOffset].n_value, user_addr, nbytes);
185 }
186 
187 int
188 ValidSymbol(int index) {
189  return ( (nlst[index].n_value & 0xffffff00) != 0 );
190 }
191 
192 int
193 SymbolValue(int index) {
194  return nlst[index].n_value;
195 }
196 
197 void
199  kernelFileName[0] = '\0';
200 }
201 
202 void
203 SetKernelName(const char* kernelName) {
204  if (strlen(kernelName) >= _POSIX2_LINE_MAX)
205  errx(EX_OSFILE, "Kernel file name of '%s' is too long.", kernelName);
206 
207  strncpy(kernelFileName, kernelName, _POSIX2_LINE_MAX);
208 }
209 
210 void
212  char errstring[_POSIX2_LINE_MAX];
213 
214  if (kd)
215  return; // kd is non-NULL, so it has been initialized. BCG
216 
217  /* Open it read-only, for a little added safety. */
218  /* If the first character of kernelFileName is not '\0', then use
219  * that kernel file. Otherwise, use the default kernel, by
220  * specifying NULL. */
221  if ((kd = kvm_openfiles((kernelFileName[0] ? kernelFileName : NULL),
222  NULL, NULL, O_RDONLY, errstring)) == NULL) {
223  warn("OpenKDIfNeeded(): %s", errstring);
224  return;
225  }
226 
227  // Parenthetical note: FreeBSD kvm_openfiles() uses getbootfile() to get
228  // the correct kernel file if the 1st arg is NULL. As far as I can see,
229  // one should always use NULL in FreeBSD, but I suppose control is never a
230  // bad thing... (pavel 21-Jan-1998)
231 
232  /* Now grab the symbol offsets for the symbols that we want. */
233  if (kvm_nlist(kd, nlst) < 0)
234  err(EX_OSERR, "Could not get kvm symbols");
235 
236  // Look at all of the returned symbols, and check for bad lookups.
237  // (This may be unnecessary, but better to check than not to... )
238  struct nlist *nlp = nlst;
239  while (nlp && nlp->n_name) {
240  if ( strncmp(nlp->n_name, DUMMY_SYM, strlen(DUMMY_SYM))) {
241  if ( nlp->n_type == 0 || nlp->n_value == 0 )
242 #if defined(XOSVIEW_FREEBSD) && defined(__alpha__)
243  /* XXX: this should be properly fixed. */
244  ;
245 #else
246  warnx("kvm_nlist() lookup failed for symbol '%s'.", nlp->n_name);
247 #endif
248  }
249  nlp++;
250  }
251 }
252 
253 int
255  size_t size;
256  int cpu_speed = 0;
257 
258 #if defined(XOSVIEW_FREEBSD)
259  char name[25];
260  int speed = 0, cpus = BSDCountCpus(), avail_cpus = 0;
261  size = sizeof(speed);
262  for (int i = 0; i < cpus; i++) {
263  snprintf(name, 25, "dev.cpu.%d.freq", i);
264  if ( sysctlbyname(name, &speed, &size, NULL, 0) == 0 ) {
265  // count only cpus with individual freq available
266  cpu_speed += speed;
267  avail_cpus++;
268  }
269  }
270  if (avail_cpus > 1)
271  cpu_speed /= avail_cpus;
272 #elif defined(XOSVIEW_OPENBSD)
273  size = sizeof(cpu_speed);
274  if ( sysctl(mib_spd, 2, &cpu_speed, &size, NULL, 0) < 0 )
275  err(EX_OSERR, "syscl hw.cpuspeed failed");
276 #else /* XOSVIEW_NETBSD || XOSVIEW_DFBSD */
277  uint64_t speed = 0;
278  size = sizeof(speed);
279 #if defined(XOSVIEW_NETBSD)
280  if ( sysctlbyname("machdep.tsc_freq", &speed, &size, NULL, 0) < 0 )
281  warn("sysctl machdep.tsc_freq failed");
282 #else /* XOSVIEW_DFBSD */
283  if ( sysctlbyname("hw.tsc_frequency", &speed, &size, NULL, 0) < 0 )
284  err(EX_OSERR, "sysctl hw.tsc_frequency failed");
285 #endif
286  cpu_speed = speed / 1000000;
287 #endif
288  return cpu_speed;
289 }
290 
291 
292 // -------------------- PageMeter & MemMeter functions -----------------------
293 void
295  OpenKDIfNeeded();
296 }
297 
298 /* meminfo[5] = { active, inactive, wired, cached, free } */
299 /* pageinfo[2] = { pages_in, pages_out } */
300 void
301 BSDGetPageStats(uint64_t *meminfo, uint64_t *pageinfo) {
302 #if defined(HAVE_UVM)
303 #ifdef VM_UVMEXP2
304  struct uvmexp_sysctl uvm;
305 #else
306  struct uvmexp uvm;
307 #endif
308  size_t size = sizeof(uvm);
309  if ( sysctl(mib_uvm, 2, &uvm, &size, NULL, 0) < 0 )
310  err(EX_OSERR, "sysctl vm.uvmexp failed");
311 
312  if (meminfo) {
313  // UVM excludes kernel memory -> assume it is active mem
314  meminfo[0] = (uint64_t)(uvm.npages - uvm.inactive - uvm.wired - uvm.free) * uvm.pagesize;
315  meminfo[1] = (uint64_t)uvm.inactive * uvm.pagesize;
316  meminfo[2] = (uint64_t)uvm.wired * uvm.pagesize;
317 
318  // cache is already included in active and inactive memory and
319  // there's no way to know how much is in which -> disable cache
320  meminfo[3] = 0;
321  meminfo[4] = (uint64_t)uvm.free * uvm.pagesize;
322  }
323  if (pageinfo) {
324  pageinfo[0] = (uint64_t)uvm.pgswapin;
325  pageinfo[1] = (uint64_t)uvm.pgswapout;
326  }
327 #else /* HAVE_UVM */
328  struct vmmeter_fbsd {
329  u_int v_active_count;
330  u_int v_inactive_count;
331  u_int v_wire_count;
332  u_int v_cache_count;
333  u_int v_free_count;
334  u_int v_page_size;
335  u_int v_vnodepgsin;
336  u_int v_vnodepgsout;
337  u_int v_swappgsin;
338  u_int v_swappgsout;
339  } vm;
340 #if defined(XOSVIEW_FREEBSD)
341  size_t size = sizeof(unsigned int);
342 #define GET_VM_STATS(name) \
343  sysctlbyname("vm.stats.vm." #name, &vm.name, &size, NULL, 0)
344  GET_VM_STATS(v_active_count);
345  GET_VM_STATS(v_inactive_count);
346  GET_VM_STATS(v_wire_count);
347 #if __FreeBSD_version < 1200017
348  GET_VM_STATS(v_cache_count);
349 #endif
350  GET_VM_STATS(v_free_count);
351  GET_VM_STATS(v_page_size);
352  GET_VM_STATS(v_vnodepgsin);
353  GET_VM_STATS(v_vnodepgsout);
354  GET_VM_STATS(v_swappgsin);
355  GET_VM_STATS(v_swappgsout);
356 #undef GET_VM_STATS
357 #else /* XOSVIEW_DFBSD */
358  struct vmstats vms;
359  size_t size = sizeof(vms);
360  if ( sysctlbyname("vm.vmstats", &vms, &size, NULL, 0) < 0 )
361  err(EX_OSERR, "sysctl vm.vmstats failed");
362  size = sizeof(vm);
363  if ( sysctlbyname("vm.vmmeter", &vm, &size, NULL, 0) < 0 )
364  err(EX_OSERR, "sysctl vm.vmmeter failed");
365 #endif
366  if (meminfo) {
367 #if defined(XOSVIEW_FREEBSD)
368  meminfo[0] = (uint64_t)vm.v_active_count * vm.v_page_size;
369  meminfo[1] = (uint64_t)vm.v_inactive_count * vm.v_page_size;
370  meminfo[2] = (uint64_t)vm.v_wire_count * vm.v_page_size;
371 #if __FreeBSD_version < 1200017
372  meminfo[3] = (uint64_t)vm.v_cache_count * vm.v_page_size;
373 #endif
374  meminfo[4] = (uint64_t)vm.v_free_count * vm.v_page_size;
375 #else /* XOSVIEW_DFBSD */
376  meminfo[0] = (uint64_t)vms.v_active_count * vms.v_page_size;
377  meminfo[1] = (uint64_t)vms.v_inactive_count * vms.v_page_size;
378  meminfo[2] = (uint64_t)vms.v_wire_count * vms.v_page_size;
379  meminfo[3] = (uint64_t)vms.v_cache_count * vms.v_page_size;
380  meminfo[4] = (uint64_t)vms.v_free_count * vms.v_page_size;
381 #endif
382  }
383  if (pageinfo) {
384  pageinfo[0] = (uint64_t)vm.v_vnodepgsin + (uint64_t)vm.v_swappgsin;
385  pageinfo[1] = (uint64_t)vm.v_vnodepgsout + (uint64_t)vm.v_swappgsout;
386  }
387 #endif
388 }
389 
390 
391 // ------------------------ CPUMeter functions -------------------------------
392 
393 void
395  OpenKDIfNeeded();
396 #if defined(XOSVIEW_FREEBSD)
397  size_t size = sizeof(maxcpus);
398  if ( sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0 )
399  err(EX_OSERR, "sysctl kern.smp.maxcpus failed");
400 #elif defined(XOSVIEW_DFBSD)
401  if ( kinfo_get_cpus(&maxcpus) )
402  err(EX_OSERR, "kinfo_get_cpus() failed");
403 #endif
404 }
405 
406 void
407 BSDGetCPUTimes(uint64_t *timeArray, unsigned int cpu) {
408  // timeArray is CPUSTATES long.
409  // cpu is the number of CPU to return, starting from 1. If cpu == 0,
410  // return aggregate times for all CPUs.
411  // All BSDs have separate calls for aggregate and separate times. Only
412  // OpenBSD returns one CPU per call, others return all at once.
413  if (!timeArray)
414  err(EX_SOFTWARE, "BSDGetCPUTimes(): passed pointer was null.");
415  size_t size;
416 #if defined(XOSVIEW_DFBSD)
417  size = sizeof(struct kinfo_cputime);
418  struct kinfo_cputime *times = (struct kinfo_cputime *)calloc(maxcpus + 1, size);
419 #elif defined(XOSVIEW_NETBSD)
420  size = CPUSTATES * sizeof(uint64_t);
421  uint64_t *times = (uint64_t*)calloc(BSDCountCpus() + 1, size);
422 #elif defined(XOSVIEW_FREEBSD)
423  size = CPUSTATES * sizeof(long);
424  long *times = (long*)calloc(maxcpus + 1, size);
425 #else // XOSVIEW_OPENBSD
426  uint64_t *times = (uint64_t*)calloc(CPUSTATES, sizeof(uint64_t));
427 #endif
428  // this array will have aggregate values at 0, then each CPU (except on
429  // OpenBSD), so that cpu can be used as index
430  if (!times)
431  err(EX_OSERR, "BSDGetCPUTimes(): malloc failed");
432 
433 #if defined(XOSVIEW_DFBSD)
434  if (cpu == 0) {
435  if (kinfo_get_sched_cputime(times))
436  err(EX_OSERR, "kinfo_get_sched_cputime() failed");
437  }
438  else {
439  size = maxcpus * sizeof(times[0]);
440  if ( sysctlbyname("kern.cputime", times + 1, &size, NULL, 0) < 0 )
441  err(EX_OSERR, "sysctl kern.cputime failed");
442  }
443  timeArray[0] = times[cpu].cp_user;
444  timeArray[1] = times[cpu].cp_nice;
445  timeArray[2] = times[cpu].cp_sys;
446  timeArray[3] = times[cpu].cp_intr;
447  timeArray[4] = times[cpu].cp_idle;
448 #else // !XOSVIEW_DFBSD
449  size = CPUSTATES * sizeof(times[0]);
450  if (cpu == 0) { // aggregate times
451 #if defined(XOSVIEW_FREEBSD)
452  if ( sysctlbyname("kern.cp_time", times, &size, NULL, 0) < 0 )
453 #else // XOSVIEW_NETBSD || XOSVIEW_OPENBSD
454  if ( sysctl(mib_cpt, 2, times, &size, NULL, 0) < 0 )
455 #endif
456  err(EX_OSERR, "sysctl kern.cp_time failed");
457  }
458  else { // separate times
459 #if defined(XOSVIEW_FREEBSD)
460  size *= maxcpus;
461  if ( sysctlbyname("kern.cp_times", times + CPUSTATES, &size, NULL, 0) < 0 )
462  err(EX_OSERR, "sysctl kern.cp_times failed");
463 #elif defined(XOSVIEW_NETBSD)
464  size *= BSDCountCpus();
465  if ( sysctl(mib_cpt, 2, times + CPUSTATES, &size, NULL, 0) < 0 )
466  err(EX_OSERR, "sysctl kern.cp_time failed");
467 #else // XOSVIEW_OPENBSD
468  mib_cpt2[2] = cpu - 1;
469  if ( sysctl(mib_cpt2, 3, times, &size, NULL, 0) < 0 )
470  err(EX_OSERR, "sysctl kern.cp_time2 failed");
471 #endif
472  }
473  for (int i = 0; i < CPUSTATES; i++)
474 #if defined(XOSVIEW_OPENBSD) // aggregates are long, singles uint64_t
475  timeArray[i] = ( cpu ? times[i] : ((long*)(times))[i] );
476 #else // XOSVIEW_FREEBSD || XOSVIEW_NETBSD
477  timeArray[i] = times[cpu * CPUSTATES + i];
478 #endif
479 #endif
480  free(times);
481 }
482 
483 
484 // ------------------------ NetMeter functions -------------------------------
485 int
487  OpenKDIfNeeded();
488  return 1;
489 }
490 
491 void
492 BSDGetNetInOut(uint64_t *inbytes, uint64_t *outbytes, const char *netIface, bool ignored) {
493  struct ifaddrs *ifap, *ifa;
494  *inbytes = 0;
495  *outbytes = 0;
496 
497  if (getifaddrs(&ifap) != 0)
498  return;
499 
500  for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
501  bool skipif = false;
502 
503  if (ifa->ifa_addr->sa_family != AF_LINK)
504  continue;
505 
506  if ( strncmp(netIface, "False", 5) != 0 ) {
507  if ( (!ignored && strncmp(ifa->ifa_name, netIface, 256) != 0) ||
508  ( ignored && strncmp(ifa->ifa_name, netIface, 256) == 0) )
509  skipif = true;
510  }
511 #define IFA_STAT(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
512  if (!skipif) {
513  *inbytes += IFA_STAT(ibytes);
514  *outbytes += IFA_STAT(obytes);
515  }
516 #undef IFA_STAT
517  }
518  freeifaddrs(ifap);
519 }
520 
521 
522 // ---------------------- Swap Meter stuff -----------------------------------
523 
524 int
526  OpenKDIfNeeded();
527  return 1;
528 }
529 
530 void
531 BSDGetSwapInfo(uint64_t *total, uint64_t *used) {
532 #if defined(HAVE_SWAPCTL)
533  // This code is based on a patch sent in by Scott Stevens
534  // (s.k.stevens@ic.ac.uk, at the time).
535  struct swapent *sep, *swapiter;
536  int bsize, rnswap, nswap = swapctl(SWAP_NSWAP, 0, 0);
537  *total = *used = 0;
538 
539  if (nswap < 1) // no swap devices on
540  return;
541 
542  if ( (sep = (struct swapent *)malloc(nswap* sizeof(struct swapent))) == NULL )
543  err(EX_OSERR, "BSDGetSwapInfo(): malloc failed");
544  rnswap = swapctl(SWAP_STATS, (void *)sep, nswap);
545  if (rnswap < 0)
546  err(EX_OSERR, "BSDGetSwapInfo(): getting SWAP_STATS failed");
547  if (nswap != rnswap)
548  warnx("SWAP_STATS gave different value than SWAP_NSWAP "
549  "(nswap=%d versus rnswap=%d).", nswap, rnswap);
550 
551  swapiter = sep;
552  bsize = 512; // block size is that of underlying device, *usually* 512 bytes
553  for ( ; rnswap-- > 0; swapiter++) {
554  *total += (uint64_t)swapiter->se_nblks * bsize;
555  *used += (uint64_t)swapiter->se_inuse * bsize;
556  }
557  free(sep);
558 #else
559  struct kvm_swap kswap;
560  OpenKDIfNeeded();
561  int pgsize = getpagesize();
562  if ( kvm_getswapinfo(kd, &kswap, 1, 0) )
563  err(EX_OSERR, "BSDGetSwapInfo(): kvm_getswapinfo failed");
564 
565  *total = (uint64_t)kswap.ksw_total * pgsize;
566  *used = (uint64_t)kswap.ksw_used * pgsize;
567 #endif
568 }
569 
570 
571 // ----------------------- Disk Meter stuff -----------------------------------
572 
573 #ifdef HAVE_DEVSTAT
574 /*
575  * Make use of the new FreeBSD kernel device statistics library using
576  * code shamelessly borrowed from xsysinfo, which borrowed shamelessly
577  * from FreeBSD's iostat(8).
578  */
579 long generation;
580 devstat_select_mode select_mode;
581 struct devstat_match *matches;
582 int num_matches = 0;
583 int num_selected, num_selections;
584 long select_generation;
585 static struct statinfo cur, last;
586 int num_devices;
587 struct device_selection *dev_select;
588 int nodisk = 0;
589 
590 void
591 DevStat_Init(void) {
592  /*
593  * Make sure that the userland devstat version matches the kernel
594  * devstat version.
595  */
596 #if defined(XOSVIEW_FREEBSD)
597  if (devstat_checkversion(NULL) < 0) {
598 #else
599  if (checkversion() < 0) {
600 #endif
601  nodisk++;
602  warn("%s\n", devstat_errbuf);
603  return;
604  }
605 
606  /* find out how many devices we have */
607 #if defined(XOSVIEW_FREEBSD)
608  if ( (num_devices = devstat_getnumdevs(NULL)) < 0 ) {
609 #else
610  if ( (num_devices = getnumdevs()) < 0 ) {
611 #endif
612  nodisk++;
613  warn("%s\n", devstat_errbuf);
614  return;
615  }
616 
617  cur.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo));
618  last.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo));
619 
620  /*
621  * Grab all the devices. We don't look to see if the list has
622  * changed here, since it almost certainly has. We only look for
623  * errors.
624  */
625 #if defined(XOSVIEW_FREEBSD)
626  if (devstat_getdevs(NULL, &cur) == -1) {
627 #else
628  if (getdevs(&cur) == -1) {
629 #endif
630  nodisk++;
631  warn("%s\n", devstat_errbuf);
632  return;
633  }
634 
635  num_devices = cur.dinfo->numdevs;
636  generation = cur.dinfo->generation;
637  dev_select = NULL;
638 
639  /* only interested in disks */
640  matches = NULL;
641  char da[3] = "da";
642 #if defined(XOSVIEW_FREEBSD)
643  if (devstat_buildmatch(da, &matches, &num_matches) != 0) {
644 #else
645  if (buildmatch(da, &matches, &num_matches) != 0) {
646 #endif
647  nodisk++;
648  warn("%s\n", devstat_errbuf);
649  return;
650  }
651 
652  if (num_matches == 0)
653  select_mode = DS_SELECT_ADD;
654  else
655  select_mode = DS_SELECT_ONLY;
656 
657  /*
658  * At this point, selectdevs will almost surely indicate that the
659  * device list has changed, so we don't look for return values of 0
660  * or 1. If we get back -1, though, there is an error.
661  */
662 #if defined(XOSVIEW_FREEBSD)
663  if (devstat_selectdevs(&dev_select, &num_selected,
664 #else
665  if (selectdevs(&dev_select, &num_selected,
666 #endif
667  &num_selections, &select_generation,
668  generation, cur.dinfo->devices, num_devices,
669  matches, num_matches, NULL, 0, select_mode, 10, 0) == -1) {
670  nodisk++;
671  warn("%s\n", devstat_errbuf);
672  }
673 }
674 
675 uint64_t
676 DevStat_Get(uint64_t *read_bytes, uint64_t *write_bytes) {
677  int dn;
678  long double busy_seconds;
679  uint64_t reads, writes, total_bytes = 0;
680  struct devinfo *tmp_dinfo;
681 
682  if (nodisk > 0)
683  /* Diskless system or some error happened. */
684  return 0;
685 
686  /*
687  * Here what we want to do is refresh our device stats.
688  * getdevs() returns 1 when the device list has changed.
689  * If the device list has changed, we want to go through
690  * the selection process again, in case a device that we
691  * were previously displaying has gone away.
692  */
693 #if defined(XOSVIEW_FREEBSD)
694  switch (devstat_getdevs(NULL, &cur)) {
695 #else
696  switch (getdevs(&cur)) {
697 #endif
698  case -1:
699  return (0);
700  case 1:
701  int retval;
702  num_devices = cur.dinfo->numdevs;
703  generation = cur.dinfo->generation;
704 #if defined(XOSVIEW_FREEBSD)
705  retval = devstat_selectdevs(&dev_select, &num_selected,
706 #else
707  retval = selectdevs(&dev_select, &num_selected,
708 #endif
709  &num_selections, &select_generation,
710  generation, cur.dinfo->devices,
711  num_devices, matches, num_matches,
712  NULL, 0, select_mode, 10, 0);
713  switch(retval) {
714  case -1:
715  return (0);
716  case 1:
717  break;
718  default:
719  break;
720  break;
721  }
722  default:
723  break;
724  }
725 
726  /*
727  * Calculate elapsed time up front, since it's the same for all
728  * devices.
729  */
730 #if defined(XOSVIEW_FREEBSD)
731  busy_seconds = cur.snap_time - last.snap_time;
732 #else
733  busy_seconds = compute_etime(cur.busy_time, last.busy_time);
734 #endif
735  /* this is the first time thru so just copy cur to last */
736  if (last.dinfo->numdevs == 0) {
737  tmp_dinfo = last.dinfo;
738  last.dinfo = cur.dinfo;
739  cur.dinfo = tmp_dinfo;
740 #if defined(XOSVIEW_FREEBSD)
741  last.snap_time = cur.snap_time;
742 #else
743  last.busy_time = cur.busy_time;
744 #endif
745  return (0);
746  }
747 
748  for (dn = 0; dn < num_devices; dn++) {
749  int di;
750  if ( (dev_select[dn].selected == 0) || (dev_select[dn].selected > 10) )
751  continue;
752 
753  di = dev_select[dn].position;
754 #if defined(XOSVIEW_FREEBSD)
755  if (devstat_compute_statistics(&cur.dinfo->devices[di],
756  &last.dinfo->devices[di], busy_seconds,
757  DSM_TOTAL_BYTES_READ, &reads,
758  DSM_TOTAL_BYTES_WRITE, &writes,
759  DSM_NONE) != 0) {
760 #else
761  if (compute_stats_read(&cur.dinfo->devices[di],
762  &last.dinfo->devices[di], busy_seconds,
763  &reads, NULL,
764  NULL, NULL, NULL, NULL, NULL, NULL) != 0) {
765  warn("%s\n", devstat_errbuf);
766  break;
767  }
768  if (compute_stats_write(&cur.dinfo->devices[di],
769  &last.dinfo->devices[di], busy_seconds,
770  &writes, NULL,
771  NULL, NULL, NULL, NULL, NULL, NULL) != 0) {
772 #endif
773  warn("%s\n", devstat_errbuf);
774  break;
775  }
776  *read_bytes += reads;
777  *write_bytes += writes;
778  total_bytes += reads + writes;
779  }
780 
781  tmp_dinfo = last.dinfo;
782  last.dinfo = cur.dinfo;
783  cur.dinfo = tmp_dinfo;
784 #if defined(XOSVIEW_FREEBSD)
785  last.snap_time = cur.snap_time;
786 #else
787  last.busy_time = cur.busy_time;
788 #endif
789 
790  return total_bytes;
791 }
792 #endif
793 
794 int
796  OpenKDIfNeeded();
797 #if defined(HAVE_DEVSTAT)
798  DevStat_Init();
799 #endif
800  return 1;
801 }
802 
803 uint64_t
804 BSDGetDiskXFerBytes(uint64_t *read_bytes, uint64_t *write_bytes) {
805 #if defined(HAVE_DEVSTAT)
806  return DevStat_Get(read_bytes, write_bytes);
807 #else
808  *read_bytes = *write_bytes = 0;
809 # if defined(XOSVIEW_NETBSD)
810  size_t size;
811  // Do a sysctl with a NULL data pointer to get the size that would
812  // have been returned, and use that to figure out # drives.
813  if ( sysctl(mib_dsk, 3, NULL, &size, NULL, 0) < 0 )
814  err(EX_OSERR, "BSDGetDiskXFerBytes(): sysctl hw.iostats #1 failed");
815  unsigned int ndrives = size / mib_dsk[2];
816  struct io_sysctl drive_stats[ndrives];
817 
818  // Get the stats.
819  if ( sysctl(mib_dsk, 3, drive_stats, &size, NULL, 0) < 0 )
820  err(EX_OSERR, "BSDGetDiskXFerBytes(): sysctl hw.iostats #2 failed");
821 
822  // Now accumulate the total.
823  for (uint i = 0; i < ndrives; i++) {
824  *read_bytes += drive_stats[i].rbytes;
825  *write_bytes += drive_stats[i].wbytes;
826  }
827 # else /* XOSVIEW_OPENBSD */
828  /* This function is a little tricky -- we have to iterate over a
829  * list in kernel land. To make things simpler, data structures
830  * and pointers for objects in kernel-land have kvm tacked on front
831  * of their names. Thus, kvmdiskptr points to a disk struct in
832  * kernel memory. kvmcurrdisk is a copy of the kernel's struct,
833  * and it has pointers in it to other structs, so it also is
834  * prefixed with kvm. */
835  struct disklist_head kvmdisklist;
836  struct disk *kvmdiskptr;
837  struct disk kvmcurrdisk;
838  safe_kvm_read_symbol(DISKLIST_SYM_INDEX, &kvmdisklist, sizeof(kvmdisklist));
839  kvmdiskptr = TAILQ_FIRST(&kvmdisklist);
840  while (kvmdiskptr != NULL) {
841  safe_kvm_read((unsigned long)kvmdiskptr, &kvmcurrdisk, sizeof(kvmcurrdisk));
842  *read_bytes += kvmcurrdisk.dk_rbytes;
843  *write_bytes += kvmcurrdisk.dk_wbytes;
844  kvmdiskptr = TAILQ_NEXT(&kvmcurrdisk, dk_link);
845  }
846 # endif
847 #endif
848  return (*read_bytes + *write_bytes);
849 }
850 
851 
852 // ---------------------- Interrupt Meter stuff ------------------------------
853 
854 int
856  OpenKDIfNeeded();
857  // Make sure the intr counter array is nonzero in size.
858 #if defined(XOSVIEW_FREEBSD)
859 # if __FreeBSD_version >= 900040
860  size_t nintr;
861  safe_kvm_read(nlst[EINTRCNT_SYM_INDEX].n_value, &nintr, sizeof(nintr));
862  return ValidSymbol(INTRCNT_SYM_INDEX) && ValidSymbol(EINTRCNT_SYM_INDEX) && (nintr > 0);
863 # else
864  return ValidSymbol(INTRCNT_SYM_INDEX) && ValidSymbol(EINTRCNT_SYM_INDEX) && ((SymbolValue(EINTRCNT_SYM_INDEX) - SymbolValue(INTRCNT_SYM_INDEX)) > 0);
865 # endif
866 #elif defined(XOSVIEW_NETBSD)
867  return ValidSymbol(ALLEVENTS_SYM_INDEX);
868 #endif
869  return 1;
870 }
871 
872 int
874  /* This code is stolen from vmstat. */
875  int count = 0, nbr = 0;
876 #if defined(XOSVIEW_FREEBSD)
877  size_t inamlen, nintr;
878  char *intrnames, *intrs;
879 
880 # if __FreeBSD_version >= 900040
881  safe_kvm_read(nlst[EINTRCNT_SYM_INDEX].n_value, &nintr, sizeof(nintr));
882  safe_kvm_read(nlst[EINTRNAMES_SYM_INDEX].n_value, &inamlen, sizeof(inamlen));
883 # else
884  nintr = nlst[EINTRCNT_SYM_INDEX].n_value - nlst[INTRCNT_SYM_INDEX].n_value;
885  inamlen = nlst[EINTRNAMES_SYM_INDEX].n_value - nlst[INTRNAMES_SYM_INDEX].n_value;
886 # endif
887  if (nintr == 0 || inamlen == 0) {
888  warnx("Could not get interrupt numbers.");
889  return 0;
890  }
891 
892  intrnames = intrs = (char *)malloc(inamlen);
893  if (!intrs)
894  err(EX_OSERR, "BSDNumInts(): malloc failed");
895  safe_kvm_read(nlst[INTRNAMES_SYM_INDEX].n_value, intrs, inamlen);
896  nintr /= sizeof(long);
897  for (uint i = 0; i < nintr; i++) {
898  if ( intrnames[0] && sscanf(intrnames, "irq%d", &nbr) == 1 && nbr > count )
899  count = nbr;
900  intrnames += strlen(intrnames) + 1;
901  }
902  free(intrs);
903 #elif defined(XOSVIEW_NETBSD)
904  struct evcntlist events;
905  struct evcnt evcnt, *evptr;
906  char dummy[30];
907  char *name;
908 
909  safe_kvm_read(nlst[ALLEVENTS_SYM_INDEX].n_value, &events, sizeof(events));
910  evptr = TAILQ_FIRST(&events);
911  while (evptr) {
912  safe_kvm_read((unsigned long)evptr, &evcnt, sizeof(evcnt));
913  if (evcnt.ev_type == EVCNT_TYPE_INTR) {
914  if ( !(name = (char *)malloc(evcnt.ev_namelen + 1)) )
915  err(EX_OSERR, "BSDNumInts(): malloc failed");
916  safe_kvm_read((unsigned long)evcnt.ev_name, name, evcnt.ev_namelen + 1);
917  if ( sscanf(name, "%s%d", dummy, &nbr) == 2 && nbr > count )
918  count = nbr;
919  free(name);
920  }
921  evptr = TAILQ_NEXT(&evcnt, ev_list);
922  }
923 #elif defined(XOSVIEW_OPENBSD)
924  int nintr = 0;
925  int mib_int[4] = { CTL_KERN, KERN_INTRCNT, KERN_INTRCNT_NUM };
926  size_t size = sizeof(nintr);
927  if ( sysctl(mib_int, 3, &nintr, &size, NULL, 0) < 0 ) {
928  warn("Could not get interrupt count");
929  return 0;
930  }
931  for (int i = 0; i < nintr; i++) {
932  mib_int[2] = KERN_INTRCNT_VECTOR;
933  mib_int[3] = i;
934  size = sizeof(nbr);
935  if ( sysctl(mib_int, 4, &nbr, &size, NULL, 0) < 0 )
936  warn("Could not get name of interrupt %d", i);
937  else
938  if ( nbr > count )
939  count = nbr;
940  }
941 #else // XOSVIEW_DFBSD
942  int nintr = 0;
943  size_t inamlen;
944  char *intrnames, *intrs;
945 
946  if ( sysctlbyname("hw.intrnames", NULL, &inamlen, NULL, 0) != 0 ) {
947  warn("sysctl hw.intrnames failed");
948  return 0;
949  }
950  intrnames = intrs = (char *)malloc(inamlen);
951  if (!intrs)
952  err(EX_OSERR, "BSDNumInts(): malloc failed");
953 
954  if ( sysctlbyname("hw.intrnames", intrs, &inamlen, NULL, 0) < 0 ) {
955  warn("sysctl hw.intrnames failed");
956  free(intrs);
957  return 0;
958  }
959  for (uint i = 0; i < inamlen; i++) {
960  if (intrs[i] == '\0') // count end-of-strings
961  nintr++;
962  }
963  for (int i = 0; i < nintr; i++) {
964  if ( sscanf(intrnames, "irq%d", &nbr) == 0 ) {
965  if ( ++nbr > count ) // unused ints are named irqn where
966  count = nbr; // 0<=n<=255, used ones have device name
967  }
968  intrnames += strlen(intrnames) + 1;
969  }
970  free(intrs);
971 #endif
972  return count; // this is the highest numbered interrupt
973 }
974 
975 void
976 BSDGetIntrStats(uint64_t *intrCount, unsigned int *intrNbrs) {
977  /* This code is stolen from vmstat */
978  int nbr = 0;
979 #if defined(XOSVIEW_FREEBSD)
980  unsigned long *kvm_intrcnt, *intrcnt;
981  char *kvm_intrnames, *intrnames;
982  size_t inamlen, nintr;
983 
984 # if __FreeBSD_version >= 900040
985  safe_kvm_read(nlst[EINTRCNT_SYM_INDEX].n_value, &nintr, sizeof(nintr));
986  safe_kvm_read(nlst[EINTRNAMES_SYM_INDEX].n_value, &inamlen, sizeof(inamlen));
987 # else
988  nintr = nlst[EINTRCNT_SYM_INDEX].n_value - nlst[INTRCNT_SYM_INDEX].n_value;
989  inamlen = nlst[EINTRNAMES_SYM_INDEX].n_value - nlst[INTRNAMES_SYM_INDEX].n_value;
990 # endif
991  if (nintr == 0 || inamlen == 0) {
992  warnx("Could not get interrupt numbers.");
993  return;
994  }
995  if ( ((kvm_intrcnt = (unsigned long *)malloc(nintr)) == NULL) ||
996  ((kvm_intrnames = (char *)malloc(inamlen)) == NULL) )
997  err(EX_OSERR, "BSDGetIntrStats(): malloc failed");
998 
999  // keep track of the mem we're given:
1000  intrcnt = kvm_intrcnt;
1001  intrnames = kvm_intrnames;
1002 
1003  safe_kvm_read(nlst[INTRCNT_SYM_INDEX].n_value, kvm_intrcnt, nintr);
1004  safe_kvm_read(nlst[INTRNAMES_SYM_INDEX].n_value, kvm_intrnames, inamlen);
1005 
1006  nintr /= sizeof(long);
1007  /* kvm_intrname has the ASCII names of the IRQs, every null-terminated
1008  * string corresponds to a value in the kvm_intrcnt array
1009  * e.g. irq1: atkbd0 */
1010  for (uint i = 0; i < nintr; i++) {
1011  /* Figure out which irq we have here */
1012  if ( kvm_intrnames[0] && sscanf(kvm_intrnames, "irq%d", &nbr) == 1 ) {
1013  intrCount[nbr] = *kvm_intrcnt;
1014  if (intrNbrs)
1015  intrNbrs[nbr] = 1;
1016  }
1017  kvm_intrcnt++;
1018  kvm_intrnames += strlen(kvm_intrnames) + 1;
1019  }
1020  free(intrcnt);
1021  free(intrnames);
1022 #elif defined(XOSVIEW_NETBSD)
1023  struct evcntlist events;
1024  struct evcnt evcnt, *evptr;
1025  char dummy[30];
1026  char *name;
1027 
1028  safe_kvm_read(nlst[ALLEVENTS_SYM_INDEX].n_value, &events, sizeof(events));
1029  evptr = TAILQ_FIRST(&events);
1030  while (evptr) {
1031  safe_kvm_read((unsigned long)evptr, &evcnt, sizeof(evcnt));
1032  if (evcnt.ev_type == EVCNT_TYPE_INTR) {
1033  if ( !(name = (char *)malloc(evcnt.ev_namelen + 1)) )
1034  err(EX_OSERR, "BSDGetIntrStats(): malloc failed");
1035  safe_kvm_read((unsigned long)evcnt.ev_name, name, evcnt.ev_namelen + 1);
1036  if ( sscanf(name, "%s%d", dummy, &nbr) == 2 ) {
1037  intrCount[nbr] = evcnt.ev_count;
1038  if (intrNbrs)
1039  intrNbrs[nbr] = 1;
1040  }
1041  free(name);
1042  }
1043  evptr = TAILQ_NEXT(&evcnt, ev_list);
1044  }
1045 #elif defined(XOSVIEW_OPENBSD)
1046  int nintr = 0;
1047  uint64_t count = 0;
1048  size_t size = sizeof(nintr);
1049  int mib_int[4] = { CTL_KERN, KERN_INTRCNT, KERN_INTRCNT_NUM };
1050  if ( sysctl(mib_int, 3, &nintr, &size, NULL, 0) < 0 ) {
1051  warn("Could not get interrupt count");
1052  return;
1053  }
1054  for (int i = 0; i < nintr; i++) {
1055  mib_int[2] = KERN_INTRCNT_VECTOR;
1056  mib_int[3] = i;
1057  size = sizeof(nbr);
1058  if ( sysctl(mib_int, 4, &nbr, &size, NULL, 0) < 0 )
1059  continue; // not active
1060  mib_int[2] = KERN_INTRCNT_CNT;
1061  size = sizeof(count);
1062  if ( sysctl(mib_int, 4, &count, &size, NULL, 0) < 0 ) {
1063  warn("sysctl kern.intrcnt.cnt.%d failed", i);
1064  count = 0;
1065  }
1066  intrCount[nbr] += count; // += because ints can share number
1067  if (intrNbrs)
1068  intrNbrs[nbr] = 1;
1069  }
1070 #else // XOSVIEW_DFBSD
1071  int nintr = 0;
1072  size_t inamlen;
1073  unsigned long *intrcnt;
1074  char *dummy, *intrs, **intrnames;
1075 
1076  if ( sysctlbyname("hw.intrnames", NULL, &inamlen, NULL, 0) != 0 ) {
1077  warn("sysctl hw.intrnames failed");
1078  return;
1079  }
1080 
1081  dummy = intrs = (char *)malloc(inamlen);
1082  if (!intrs)
1083  err(EX_OSERR, "BSDGetIntrStats(): malloc failed");
1084  if ( sysctlbyname("hw.intrnames", intrs, &inamlen, NULL, 0) < 0 ) {
1085  warn("sysctl hw.intrnames failed");
1086  free(intrs);
1087  return;
1088  }
1089  for (uint i = 0; i < inamlen; i++) {
1090  if (intrs[i] == '\0') // count end-of-strings
1091  nintr++;
1092  }
1093  if ( !(intrnames = (char **)malloc(nintr * sizeof(char *))) )
1094  err(EX_OSERR, "BSDGetIntrStats(): malloc failed");
1095 
1096  for (int i = 0; i < nintr; i++) {
1097  intrnames[i] = intrs;
1098  intrs += strlen(intrs) + 1;
1099  }
1100  if ( !(intrcnt = (unsigned long *)calloc(nintr, sizeof(long))) )
1101  err(EX_OSERR, "BSDGetIntrStats(): malloc failed");
1102 
1103  inamlen = nintr * sizeof(long);
1104  if ( sysctlbyname("hw.intrcnt", intrcnt, &inamlen, NULL, 0) < 0 )
1105  err(EX_OSERR, "sysctl hw.intrcnt failed");
1106 
1107  for (int i = 0; i < nintr; i++) {
1108  if ( sscanf(intrnames[i], "irq%d", &nbr) == 0 ) {
1109  nbr++;
1110  intrCount[nbr] += intrcnt[i];
1111  if (intrNbrs)
1112  intrNbrs[nbr] = 1;
1113  }
1114  }
1115  free(dummy);
1116  free(intrnames);
1117  free(intrcnt);
1118 #endif
1119 }
1120 
1121 
1122 // ---------------------- Sensor Meter stuff ---------------------------------
1123 
1124 static int mib_cpu[2] = { CTL_HW, HW_NCPU };
1125 
1126 int
1128  int cpus = 0;
1129  size_t size = sizeof(cpus);
1130  if ( sysctl(mib_cpu, 2, &cpus, &size, NULL, 0) < 0 )
1131  warn("sysctl hw.ncpu failed.");
1132  return cpus;
1133 }
1134 
1135 #if defined(__i386__) || defined(__x86_64__)
1136 unsigned int
1137 BSDGetCPUTemperature(float *temps, float *tjmax) {
1138  unsigned int nbr = 0;
1139 #if defined(XOSVIEW_NETBSD)
1140  // All kinds of sensors are read with libprop. We have to go through them
1141  // to find either Intel Core 2 or AMD ones. Actual temperature is in
1142  // cur-value and TjMax, if present, in critical-max.
1143  // Values are in microdegrees Kelvin.
1144  int fd;
1145  const char *name = NULL;
1146  char dummy[20];
1147  prop_dictionary_t pdict;
1148  prop_object_t pobj, pobj1, pobj2;
1149  prop_object_iterator_t piter, piter2;
1150  prop_array_t parray;
1151 
1152  if ( (fd = open(_PATH_SYSMON, O_RDONLY)) == -1 ) {
1153  warn("Could not open %s", _PATH_SYSMON);
1154  return 0; // this seems to happen occasionally, so only warn
1155  }
1156  if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &pdict))
1157  err(EX_OSERR, "Could not get sensor dictionary");
1158  if (close(fd) == -1)
1159  err(EX_OSERR, "Could not close %s", _PATH_SYSMON);
1160 
1161  if (prop_dictionary_count(pdict) == 0) {
1162  warn("No sensors found");
1163  return 0;
1164  }
1165  if ( !(piter = prop_dictionary_iterator(pdict)) )
1166  err(EX_OSERR, "Could not get sensor iterator");
1167 
1168  while ( (pobj = prop_object_iterator_next(piter)) ) {
1169  parray = (prop_array_t)prop_dictionary_get_keysym(pdict, (prop_dictionary_keysym_t)pobj);
1170  if (prop_object_type(parray) != PROP_TYPE_ARRAY)
1171  continue;
1172  name = prop_dictionary_keysym_cstring_nocopy((prop_dictionary_keysym_t)pobj);
1173  if ( strncmp(name, "coretemp", 8) && strncmp(name, "amdtemp", 7) )
1174  continue;
1175  if ( !(piter2 = prop_array_iterator(parray)) )
1176  err(EX_OSERR, "Could not get sensor iterator");
1177 
1178  int i = 0;
1179  sscanf(name, "%[^0-9]%d", dummy, &i);
1180  while ( (pobj = prop_object_iterator_next(piter2)) ) {
1181  if ( !(pobj1 = prop_dictionary_get((prop_dictionary_t)pobj, "type")) )
1182  continue;
1183  if ( (pobj1 = prop_dictionary_get((prop_dictionary_t)pobj, "cur-value")) ) {
1184  if (temps)
1185  temps[i] = (prop_number_integer_value((prop_number_t)pobj1) / 1000000.0) - 273.15;
1186  nbr++;
1187  }
1188  if ( (pobj2 = prop_dictionary_get((prop_dictionary_t)pobj, "critical-max")) && tjmax )
1189  tjmax[i] = (prop_number_integer_value((prop_number_t)pobj2) / 1000000.0) - 273.15;
1190  }
1191  prop_object_iterator_release(piter2);
1192  }
1193  prop_object_iterator_release(piter);
1194  prop_object_release(pdict);
1195 #else /* XOSVIEW_NETBSD */
1196  int val = 0;
1197  size_t size = sizeof(val);
1198 
1199 #if defined(XOSVIEW_OPENBSD) || defined(XOSVIEW_DFBSD)
1200  // All kinds of sensors are read with sysctl. We have to go through them
1201  // to find either Intel Core 2 or AMD ones.
1202  // Values are in microdegrees Kelvin.
1203  struct sensordev sd;
1204  struct sensor s;
1205  int cpu = 0;
1206  char dummy[10];
1207 
1208  for (int dev = 0; dev < 1024; dev++) { // go through all sensor devices
1209  mib_sen[2] = dev;
1210  size = sizeof(sd);
1211  if ( sysctl(mib_sen, 3, &sd, &size, NULL, 0) < 0 ) {
1212  if (errno == ENOENT)
1213  break; // no more sensors
1214  if (errno == ENXIO)
1215  continue; // no sensor with this mib
1216  err(EX_OSERR, "sysctl hw.sensors.%d failed", dev);
1217  }
1218  if ( strncmp(sd.xname, "cpu", 3) )
1219  continue; // not CPU sensor
1220  sscanf(sd.xname, "%[^0-9]%d", dummy, &cpu);
1221 
1222  mib_sen[3] = SENSOR_TEMP; // for each device, get temperature sensors
1223  for (int i = 0; i < sd.maxnumt[SENSOR_TEMP]; i++) {
1224  mib_sen[4] = i;
1225  size = sizeof(s);
1226  if ( sysctl(mib_sen, 5, &s, &size, NULL, 0) < 0 )
1227  continue; // no sensor on this core?
1228  if (s.flags & SENSOR_FINVALID)
1229  continue;
1230  if (temps)
1231  temps[cpu] = (float)(s.value - 273150000) / 1000000.0;
1232  nbr++;
1233  }
1234  }
1235 #else /* XOSVIEW_FREEBSD */
1236  // Temperatures can be read with sysctl dev.cpu.%d.temperature on both
1237  // Intel Core 2 and AMD K8+ processors.
1238  // Values are in degrees Celsius (FreeBSD < 7.2) or in
1239  // 10*degrees Kelvin (FreeBSD >= 7.3).
1240  char name[25];
1241  int cpus = BSDCountCpus();
1242  for (int i = 0; i < cpus; i++) {
1243  snprintf(name, 25, "dev.cpu.%d.temperature", i);
1244  if ( sysctlbyname(name, &val, &size, NULL, 0) == 0) {
1245  nbr++;
1246  if (temps)
1247 #if __FreeBSD_version >= 702106
1248  temps[i] = ((float)val - 2732.0) / 10.0;
1249 #else
1250  temps[i] = (float)val;
1251 #endif
1252  }
1253  else
1254  warn("sysctl %s failed", name);
1255 
1256  if (tjmax) {
1257  snprintf(name, 25, "dev.cpu.%d.coretemp.tjmax", i);
1258  if ( sysctlbyname(name, &val, &size, NULL, 0) == 0 )
1259 #if __FreeBSD_version >= 702106
1260  tjmax[i] = ((float)val - 2732.0) / 10.0;
1261 #else
1262  tjmax[i] = (float)val;
1263 #endif
1264  else
1265  warn("sysctl %s failed", name);
1266  }
1267  }
1268 #endif
1269 #endif
1270  return nbr;
1271 }
1272 #endif
1273 
1274 void
1275 BSDGetSensor(const char *name, const char *valname, float *value, char *unit) {
1276  if (!name || !valname || !value)
1277  errx(EX_SOFTWARE, "NULL pointer passed to BSDGetSensor().");
1278 #if defined(XOSVIEW_NETBSD)
1279  /* Adapted from envstat. */
1280  // All kinds of sensors are read with libprop. Specific device and value
1281  // can be asked for. Values are transformed to suitable units.
1282  int fd, val = 0;
1283  char type[20];
1284  prop_dictionary_t pdict;
1285  prop_object_t pobj, pobj1;
1286  prop_object_iterator_t piter;
1287 
1288  if ( (fd = open(_PATH_SYSMON, O_RDONLY)) == -1 ) {
1289  warn("Could not open %s", _PATH_SYSMON);
1290  return; // this seems to happen occasionally, so only warn
1291  }
1292  if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &pdict))
1293  err(EX_OSERR, "Could not get sensor dictionary");
1294  if (close(fd) == -1)
1295  err(EX_OSERR, "Could not close %s", _PATH_SYSMON);
1296 
1297  if (prop_dictionary_count(pdict) == 0) {
1298  warn("No sensors found");
1299  return;
1300  }
1301  pobj = prop_dictionary_get(pdict, name);
1302  if (prop_object_type(pobj) != PROP_TYPE_ARRAY)
1303  err(EX_USAGE, "Device %s does not exist", name);
1304 
1305  if ( !(piter = prop_array_iterator((prop_array_t)pobj)) )
1306  err(EX_OSERR, "Could not get sensor iterator");
1307 
1308  while ( (pobj = prop_object_iterator_next(piter)) ) {
1309  if ( !(pobj1 = prop_dictionary_get((prop_dictionary_t)pobj, "type")) )
1310  continue;
1311  strlcpy(type, prop_string_cstring_nocopy((prop_string_t)pobj1), 20);
1312  if ( strncmp(type, "Indicator", 3) == 0 ||
1313  strncmp(type, "Battery", 3) == 0 ||
1314  strncmp(type, "Drive", 3) == 0 )
1315  continue; // these are string values
1316  if ( (pobj1 = prop_dictionary_get((prop_dictionary_t)pobj, valname)) )
1317  val = prop_number_integer_value((prop_number_t)pobj1);
1318  else
1319  err(EX_USAGE, "Value %s does not exist", valname);
1320  if ( strncmp(type, "Temperature", 4) == 0 ) {
1321  *value = (val / 1000000.0) - 273.15; // temperatures are in microkelvins
1322  if (unit)
1323  strcpy(unit, "\260C");
1324  }
1325  else if ( strncmp(type, "Fan", 3) == 0 ) {
1326  *value = (float)val; // plain integer value
1327  if (unit)
1328  strcpy(unit, "RPM");
1329  }
1330  else if ( strncmp(type, "Integer", 3) == 0 )
1331  *value = (float)val; // plain integer value
1332  else if ( strncmp(type, "Voltage", 4) == 0 ) {
1333  *value = (float)val / 1000000.0; // electrical units are in micro{V,A,W,Ohm}
1334  if (unit)
1335  strcpy(unit, "V");
1336  }
1337  else if ( strncmp(type, "Ampere hour", 7) == 0 ) {
1338  *value = (float)val / 1000000.0; // electrical units are in micro{V,A,W,Ohm}
1339  if (unit)
1340  strcpy(unit, "Ah");
1341  }
1342  else if ( strncmp(type, "Ampere", 7) == 0 ) {
1343  *value = (float)val / 1000000.0; // electrical units are in micro{V,A,W,Ohm}
1344  if (unit)
1345  strcpy(unit, "A");
1346  }
1347  else if ( strncmp(type, "Watt hour", 5) == 0 ) {
1348  *value = (float)val / 1000000.0; // electrical units are in micro{V,A,W,Ohm}
1349  if (unit)
1350  strcpy(unit, "Wh");
1351  }
1352  else if ( strncmp(type, "Watts", 5) == 0 ) {
1353  *value = (float)val / 1000000.0; // electrical units are in micro{V,A,W,Ohm}
1354  if (unit)
1355  strcpy(unit, "W");
1356  }
1357  else if ( strncmp(type, "Ohms", 4) == 0 ) {
1358  *value = (float)val / 1000000.0; // electrical units are in micro{V,A,W,Ohm}
1359  if (unit)
1360  strcpy(unit, "Ohm");
1361  }
1362  }
1363  prop_object_iterator_release(piter);
1364  prop_object_release(pdict);
1365 #else /* XOSVIEW_NETBSD */
1366  size_t size;
1367  char dummy[50];
1368 #if defined(XOSVIEW_FREEBSD) || defined(XOSVIEW_DFBSD)
1369  // FreeBSD has no sensor framework, but ACPI thermal zones might work.
1370  // They are readable through sysctl (also works in Dragonfly).
1371  // Values are in 10 * degrees Kelvin.
1372  if ( strncmp(name, "tz", 2) == 0 ) {
1373  int val = 0;
1374  size = sizeof(val);
1375  snprintf(dummy, 50, "hw.acpi.thermal.%s.%s", name, valname);
1376  if ( sysctlbyname(dummy, &val, &size, NULL, 0) < 0 )
1377  err(EX_OSERR, "sysctl %s failed", dummy);
1378  *value = ((float)val - 2732.0) / 10.0;
1379  if (unit)
1380  strcpy(unit, "\260C");
1381  return;
1382  }
1383  // If Dragonfly and tzN specified, return. Otherwise, fall through.
1384 #endif
1385 #if defined(XOSVIEW_OPENBSD) || defined(XOSVIEW_DFBSD)
1386  /* Adapted from systat. */
1387  // All kinds of sensors are read with sysctl. We have to go through them
1388  // to find the required device and value. Parameter 'name' is the device
1389  // name and 'valname' consists of type and sensor index (e.g. it0.temp1).
1390  // Values are transformed to suitable units.
1391  int index = -1;
1392  struct sensordev sd;
1393  struct sensor s;
1394 
1395  for (int dev = 0; dev < 1024; dev++) { // go through all sensor devices
1396  mib_sen[2] = dev;
1397  size = sizeof(sd);
1398  if ( sysctl(mib_sen, 3, &sd, &size, NULL, 0) < 0 ) {
1399  if (errno == ENOENT)
1400  break; // no more devices
1401  if (errno == ENXIO)
1402  continue; // no device with this mib
1403  err(EX_OSERR, "sysctl hw.sensors.%d failed", dev);
1404  }
1405  if ( strncmp(sd.xname, name, sizeof(name)) )
1406  continue; // sensor name does not match
1407 
1408  for (int t = 0; t < SENSOR_MAX_TYPES; t++) {
1409  if ( strncmp(sensor_type_s[t], valname, strlen(sensor_type_s[t])) )
1410  continue; // wrong type
1411  mib_sen[3] = t;
1412  sscanf(valname, "%[^0-9]%d", dummy, &index);
1413  if (index < sd.maxnumt[t]) {
1414  mib_sen[4] = index;
1415  size = sizeof(s);
1416  if ( sysctl(mib_sen, 5, &s, &size, NULL, 0) < 0 ) {
1417  if (errno != ENOENT)
1418  err(EX_OSERR, "sysctl hw.sensors.%d.%d.%d failed", dev, t, index);
1419  continue; // no more sensors
1420  }
1421  if (s.flags & SENSOR_FINVALID)
1422  continue;
1423  switch (t) {
1424  case SENSOR_TEMP:
1425  *value = (float)(s.value - 273150000) / 1000000.0;
1426  if (unit)
1427  strcpy(unit, "\260C");
1428  break;
1429  case SENSOR_FANRPM:
1430  *value = (float)s.value;
1431  if (unit)
1432  strcpy(unit, "RPM");
1433  break;
1434  case SENSOR_VOLTS_DC:
1435  case SENSOR_VOLTS_AC:
1436  *value = (float)s.value / 1000000.0;
1437  if (unit)
1438  strcpy(unit, "V");
1439  break;
1440  case SENSOR_OHMS:
1441  *value = (float)s.value;
1442  if (unit)
1443  strcpy(unit, "Ohm");
1444  break;
1445  case SENSOR_WATTS:
1446  *value = (float)s.value / 1000000.0;
1447  if (unit)
1448  strcpy(unit, "W");
1449  break;
1450  case SENSOR_AMPS:
1451  *value = (float)s.value / 1000000.0;
1452  if (unit)
1453  strcpy(unit, "A");
1454  break;
1455  case SENSOR_WATTHOUR:
1456  *value = (float)s.value / 1000000.0;
1457  if (unit)
1458  strcpy(unit, "Wh");
1459  break;
1460  case SENSOR_AMPHOUR:
1461  *value = (float)s.value / 1000000.0;
1462  if (unit)
1463  strcpy(unit, "Ah");
1464  break;
1465  case SENSOR_PERCENT:
1466  *value = (float)s.value / 1000.0;
1467  if (unit)
1468  strcpy(unit, "%");
1469  break;
1470  case SENSOR_LUX:
1471  *value = (float)s.value / 1000000.0;
1472  if (unit)
1473  strcpy(unit, "lx");
1474  break;
1475  case SENSOR_TIMEDELTA:
1476  *value = (float)s.value / 1000000000.0;
1477  if (unit)
1478  strcpy(unit, "s");
1479  break;
1480 #if defined(XOSVIEW_OPENBSD)
1481  case SENSOR_HUMIDITY:
1482  *value = (float)s.value / 1000.0;
1483  if (unit)
1484  strcpy(unit, "%");
1485  break;
1486  case SENSOR_FREQ:
1487  *value = (float)s.value / 1000000.0;
1488  if (unit)
1489  strcpy(unit, "Hz");
1490  break;
1491  case SENSOR_ANGLE:
1492  *value = (float)s.value / 1000000.0;
1493  if (unit)
1494  strcpy(unit, "\260");
1495  break;
1496 #if OpenBSD > 201211
1497  case SENSOR_DISTANCE:
1498  *value = (float)s.value / 1000000.0;
1499  if (unit)
1500  strcpy(unit, "m");
1501  break;
1502  case SENSOR_PRESSURE:
1503  *value = (float)s.value / 1000.0;
1504  if (unit)
1505  strcpy(unit, "Pa");
1506  break;
1507  case SENSOR_ACCEL:
1508  *value = (float)s.value / 1000000.0;
1509  if (unit)
1510  strcpy(unit, "m\\/s\262"); // m/s²
1511  break;
1512 #endif
1513 #endif
1514  case SENSOR_INDICATOR:
1515  case SENSOR_INTEGER:
1516  case SENSOR_DRIVE:
1517  default:
1518  *value = (float)s.value;
1519  break;
1520  }
1521  }
1522  }
1523  }
1524 #endif
1525 #endif
1526 }
1527 
1528 
1529 // ---------------------- Battery Meter stuff ---------------------------------
1530 
1531 bool
1533 #if defined(XOSVIEW_NETBSD)
1534  int fd;
1535  prop_dictionary_t pdict;
1536  prop_object_t pobj;
1537 
1538  if ( (fd = open(_PATH_SYSMON, O_RDONLY)) == -1 )
1539  return false;
1540  if ( prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &pdict) )
1541  err(EX_OSERR, "Could not get sensor dictionary");
1542  if ( close(fd) == -1 )
1543  err(EX_OSERR, "Could not close %s", _PATH_SYSMON);
1544 
1545  if ( prop_dictionary_count(pdict) == 0 )
1546  return false;
1547  pobj = prop_dictionary_get(pdict, "acpibat0"); // just check for 1st battery
1548  if ( prop_object_type(pobj) != PROP_TYPE_ARRAY )
1549  return false;
1550  return true;
1551 #elif defined(XOSVIEW_OPENBSD)
1552  // check if we can get full capacity of the 1st battery
1553  float val = -1.0;
1554  BSDGetSensor("acpibat0", "amphour0", &val);
1555  if (val < 0)
1556  return false;
1557  return true;
1558 #else // XOSVIEW_FREEBSD || XOSVIEW_DFBSD
1559  int fd;
1560  if ( (fd = open(ACPIDEV, O_RDONLY)) == -1 ) {
1561  // No ACPI -> try APM
1562  if ( (fd = open(APMDEV, O_RDONLY)) == -1 )
1563  return false;
1564  struct apm_info aip;
1565  if ( ioctl(fd, APMIO_GETINFO, &aip) == -1 )
1566  return false;
1567  if ( close(fd) == -1 )
1568  err(EX_OSERR, "Could not close %s", APMDEV);
1569  if (aip.ai_batt_stat == 0xff || aip.ai_batt_life == 0xff)
1570  return false;
1571  return true;
1572  }
1573 
1574  union acpi_battery_ioctl_arg battio;
1575  battio.unit = ACPI_BATTERY_ALL_UNITS;
1576  if ( ioctl(fd, ACPIIO_BATT_GET_BATTINFO, &battio) == -1 )
1577  return false;
1578  if ( close(fd) == -1 )
1579  err(EX_OSERR, "Could not close %s", ACPIDEV);
1580  return ( battio.battinfo.state != ACPI_BATT_STAT_NOT_PRESENT );
1581 #endif
1582 }
1583 
1584 void
1585 BSDGetBatteryInfo(int *remaining, unsigned int *state) {
1586  *state = XOSVIEW_BATT_NONE;
1587 #if defined(XOSVIEW_NETBSD) || defined(XOSVIEW_OPENBSD)
1588  int batteries = 0;
1589 #if defined(XOSVIEW_NETBSD)
1590  /* Again adapted from envstat. */
1591  // All kinds of sensors are read with libprop. We have to go through them
1592  // to find the batteries. We need capacity, charge, presence, charging
1593  // status and discharge rate for each battery for the calculations.
1594  // For simplicity, assume all batteries have the same
1595  // charge/discharge status.
1596  int fd;
1597  int total_capacity = 0, total_charge = 0, total_low = 0, total_crit = 0;
1598  const char *name = NULL;
1599  prop_dictionary_t pdict;
1600  prop_object_t pobj, pobj1;
1601  prop_object_iterator_t piter, piter2;
1602  prop_array_t parray;
1603 
1604  if ( (fd = open(_PATH_SYSMON, O_RDONLY)) == -1 ) {
1605  warn("Could not open %s", _PATH_SYSMON);
1606  return; // this seems to happen occasionally, so only warn
1607  }
1608  if ( prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &pdict) )
1609  err(EX_OSERR, "Could not get sensor dictionary");
1610  if ( close(fd) == -1 )
1611  err(EX_OSERR, "Could not close %s", _PATH_SYSMON);
1612 
1613  if ( prop_dictionary_count(pdict) == 0 ) {
1614  warn("No sensors found");
1615  return;
1616  }
1617  if ( !(piter = prop_dictionary_iterator(pdict)) )
1618  err(EX_OSERR, "Could not get sensor iterator");
1619 
1620  while ( (pobj = prop_object_iterator_next(piter)) ) {
1621  int present = 0, capacity = 0, charge = 0, low = 0, crit = 0;
1622  name = prop_dictionary_keysym_cstring_nocopy((prop_dictionary_keysym_t)pobj);
1623  if ( strncmp(name, "acpibat", 7) )
1624  continue;
1625  parray = (prop_array_t)prop_dictionary_get_keysym(pdict, (prop_dictionary_keysym_t)pobj);
1626  if ( prop_object_type(parray) != PROP_TYPE_ARRAY )
1627  continue;
1628  if ( !(piter2 = prop_array_iterator(parray)) )
1629  err(EX_OSERR, "Could not get sensor iterator");
1630 
1631  while ( (pobj = prop_object_iterator_next(piter2)) ) {
1632  if ( !(pobj1 = prop_dictionary_get((prop_dictionary_t)pobj, "state")) )
1633  continue;
1634  if ( prop_string_equals_cstring((prop_string_t)pobj1, "invalid") ||
1635  prop_string_equals_cstring((prop_string_t)pobj1, "unknown") )
1636  continue; // skip sensors without valid data
1637  if ( !(pobj1 = prop_dictionary_get((prop_dictionary_t)pobj, "description")) )
1638  continue;
1639  name = prop_string_cstring_nocopy((prop_string_t)pobj1);
1640  if ( strncmp(name, "present", 7) == 0 ) { // is battery present
1641  if ( (pobj1 = prop_dictionary_get((prop_dictionary_t)pobj, "cur-value")) )
1642  present = prop_number_integer_value((prop_number_t)pobj1);
1643  }
1644  else if ( strncmp(name, "design cap", 10) == 0 ) { // get full capacity
1645  if ( (pobj1 = prop_dictionary_get((prop_dictionary_t)pobj, "cur-value")) )
1646  capacity = prop_number_integer_value((prop_number_t)pobj1);
1647  }
1648  else if ( strncmp(name, "charge", 7) == 0 ) { // get present charge, low and critical levels
1649  if ( (pobj1 = prop_dictionary_get((prop_dictionary_t)pobj, "cur-value")) )
1650  charge = prop_number_integer_value((prop_number_t)pobj1);
1651  if ( (pobj1 = prop_dictionary_get((prop_dictionary_t)pobj, "warning-capacity")) )
1652  low = prop_number_integer_value((prop_number_t)pobj1);
1653  if ( (pobj1 = prop_dictionary_get((prop_dictionary_t)pobj, "critical-capacity")) )
1654  crit = prop_number_integer_value((prop_number_t)pobj1);
1655  }
1656  else if ( strncmp(name, "charging", 8) == 0 ) { // charging or not?
1657  if ( (pobj1 = prop_dictionary_get((prop_dictionary_t)pobj, "cur-value")) )
1658  if ( prop_number_integer_value((prop_number_t)pobj1) )
1659  *state |= XOSVIEW_BATT_CHARGING;
1660  }
1661  else if ( strncmp(name, "discharge rate", 14) == 0 ) { // discharging or not?
1662  if ( (pobj1 = prop_dictionary_get((prop_dictionary_t)pobj, "cur-value")) )
1663  if ( prop_number_integer_value((prop_number_t)pobj1) )
1664  *state |= XOSVIEW_BATT_DISCHARGING;
1665  }
1666  }
1667  if (present) {
1668  total_capacity += capacity;
1669  total_charge += charge;
1670  total_low += low;
1671  total_crit += crit;
1672  batteries++;
1673  }
1674  prop_object_iterator_release(piter2);
1675  }
1676  prop_object_iterator_release(piter);
1677  prop_object_release(pdict);
1678 #else // XOSVIEW_OPENBSD
1679  float total_capacity = 0, total_charge = 0, total_low = 0, total_crit = 0;
1680  char battery[16];
1681  while (batteries < 1024) {
1682  float val = -1.0;
1683  snprintf(battery, 15, "acpibat%d", batteries);
1684  BSDGetSensor(battery, "amphour0", &val); // full capacity
1685  if (val < 0) // no more batteries
1686  break;
1687  batteries++;
1688  total_capacity += val;
1689  BSDGetSensor(battery, "amphour1", &val); // warning capacity
1690  total_low += val;
1691  BSDGetSensor(battery, "amphour2", &val); // low capacity
1692  total_crit += val;
1693  BSDGetSensor(battery, "amphour3", &val); // remaining
1694  total_charge += val;
1695  BSDGetSensor(battery, "raw0", &val); // state
1696  if ((int)val == 1)
1697  *state |= XOSVIEW_BATT_DISCHARGING;
1698  else if ((int)val == 2)
1699  *state |= XOSVIEW_BATT_CHARGING;
1700  // there's also 0 state for idle/full
1701  }
1702 #endif
1703  if (batteries == 0) { // all batteries are off
1704  *state = XOSVIEW_BATT_NONE;
1705  *remaining = 0;
1706  return;
1707  }
1708  *remaining = 100 * total_charge / total_capacity;
1709  if ( !(*state & XOSVIEW_BATT_CHARGING) &&
1710  !(*state & XOSVIEW_BATT_DISCHARGING) )
1711  *state |= XOSVIEW_BATT_FULL; // it's full when not charging nor discharging
1712  if (total_capacity < total_low)
1713  *state |= XOSVIEW_BATT_LOW;
1714  if (total_capacity < total_crit)
1715  *state |= XOSVIEW_BATT_CRITICAL;
1716 #else // XOSVIEW_FREEBSD || XOSVIEW_DFBSD
1717  /* Adapted from acpiconf and apm. */
1718  int fd;
1719  if ( (fd = open(ACPIDEV, O_RDONLY)) == -1 ) {
1720  // No ACPI -> try APM
1721  if ( (fd = open(APMDEV, O_RDONLY)) == -1 )
1722  err(EX_OSFILE, "could not open %s or %s", ACPIDEV, APMDEV);
1723  struct apm_info aip;
1724  if ( ioctl(fd, APMIO_GETINFO, &aip) == -1 )
1725  err(EX_IOERR, "failed to get APM battery info");
1726  if ( close(fd) == -1 )
1727  err(EX_OSERR, "Could not close %s", APMDEV);
1728  if (aip.ai_batt_life <= 100)
1729  *remaining = aip.ai_batt_life; // only 0-100 are valid values
1730  else
1731  *remaining = 0;
1732  if (aip.ai_batt_stat == 0)
1733  *state |= XOSVIEW_BATT_FULL;
1734  else if (aip.ai_batt_stat == 1)
1735  *state |= XOSVIEW_BATT_LOW;
1736  else if (aip.ai_batt_stat == 2)
1737  *state |= XOSVIEW_BATT_CRITICAL;
1738  else if (aip.ai_batt_stat == 3)
1739  *state |= XOSVIEW_BATT_CHARGING;
1740  else
1741  *state = XOSVIEW_BATT_NONE;
1742  return;
1743  }
1744  // ACPI
1745  union acpi_battery_ioctl_arg battio;
1746  battio.unit = ACPI_BATTERY_ALL_UNITS;
1747  if ( ioctl(fd, ACPIIO_BATT_GET_BATTINFO, &battio) == -1 )
1748  err(EX_IOERR, "failed to get ACPI battery info");
1749  if ( close(fd) == -1 )
1750  err(EX_OSERR, "Could not close %s", ACPIDEV);
1751  *remaining = battio.battinfo.cap;
1752  if (battio.battinfo.state != ACPI_BATT_STAT_NOT_PRESENT) {
1753  if (battio.battinfo.state == 0)
1754  *state |= XOSVIEW_BATT_FULL;
1755  if (battio.battinfo.state & ACPI_BATT_STAT_CRITICAL)
1756  *state |= XOSVIEW_BATT_CRITICAL;
1757  if (battio.battinfo.state & ACPI_BATT_STAT_DISCHARG)
1758  *state |= XOSVIEW_BATT_DISCHARGING;
1759  if (battio.battinfo.state & ACPI_BATT_STAT_CHARGING)
1760  *state |= XOSVIEW_BATT_CHARGING;
1761  }
1762 #endif
1763 }
#define XOSVIEW_BATT_CHARGING
Definition: defines.h:50
#define XOSVIEW_BATT_DISCHARGING
Definition: defines.h:51
#define XOSVIEW_BATT_NONE
Definition: defines.h:49
#define XOSVIEW_BATT_LOW
Definition: defines.h:53
#define XOSVIEW_BATT_CRITICAL
Definition: defines.h:54
#define XOSVIEW_BATT_FULL
Definition: defines.h:52
static void safe_kvm_read(unsigned long kernel_addr, void *user_addr, size_t nbytes)
Definition: kernel.cc:167
void BSDGetCPUTimes(uint64_t *timeArray, unsigned int cpu)
Definition: kernel.cc:407
uint64_t BSDGetDiskXFerBytes(uint64_t *read_bytes, uint64_t *write_bytes)
Definition: kernel.cc:804
static struct nlist nlst[]
Definition: kernel.cc:113
bool BSDHasBattery()
Definition: kernel.cc:1532
void BSDGetNetInOut(uint64_t *inbytes, uint64_t *outbytes, const char *netIface, bool ignored)
Definition: kernel.cc:492
void BSDGetSensor(const char *name, const char *valname, float *value, char *unit)
Definition: kernel.cc:1275
void OpenKDIfNeeded()
Definition: kernel.cc:211
int BSDSwapInit()
Definition: kernel.cc:525
kvm_t * kd
Definition: kernel.cc:110
int BSDNumInts()
Definition: kernel.cc:873
void SetKernelName(const char *kernelName)
Definition: kernel.cc:203
void BSDGetBatteryInfo(int *remaining, unsigned int *state)
Definition: kernel.cc:1585
int SymbolValue(int index)
Definition: kernel.cc:193
void BSDGetSwapInfo(uint64_t *total, uint64_t *used)
Definition: kernel.cc:531
void BSDCPUInit()
Definition: kernel.cc:394
void BSDPageInit()
Definition: kernel.cc:294
void BSDGetIntrStats(uint64_t *intrCount, unsigned int *intrNbrs)
Definition: kernel.cc:976
static void safe_kvm_read_symbol(int nlstOffset, void *user_addr, size_t nbytes)
Definition: kernel.cc:183
static char kernelFileName[_POSIX2_LINE_MAX]
Definition: kernel.cc:158
int BSDNetInit()
Definition: kernel.cc:486
int BSDCountCpus(void)
Definition: kernel.cc:1127
int BSDDiskInit()
Definition: kernel.cc:795
void BSDInit()
Definition: kernel.cc:198
void BSDGetPageStats(uint64_t *meminfo, uint64_t *pageinfo)
Definition: kernel.cc:301
int BSDIntrInit()
Definition: kernel.cc:855
static int mib_cpu[2]
Definition: kernel.cc:1124
#define DUMMY_SYM
#define IFA_STAT(s)
int ValidSymbol(int index)
Definition: kernel.cc:188
int BSDGetCPUSpeed()
Definition: kernel.cc:254