1 /* GKrellM
2 |  Copyright (C) 1999-2019 Bill Wilson
3 |
4 |  Author:  Bill Wilson    billw@gkrellm.net
5 |  Latest versions might be found at:  http://gkrellm.net
6 |
7 |  netbsd.c code is Copyright (C):
8 |             Anthony Mallet <anthony.mallet@useless-ficus.net>
9 |
10 |
11 |  GKrellM is free software: you can redistribute it and/or modify it
12 |  under the terms of the GNU General Public License as published by
13 |  the Free Software Foundation, either version 3 of the License, or
14 |  (at your option) any later version.
15 |
16 |  GKrellM is distributed in the hope that it will be useful, but WITHOUT
new(entry_types: &::wasm_bindgen::JsValue) -> Self17 |  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 |  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
19 |  License for more details.
20 |
21 |  You should have received a copy of the GNU General Public License
22 |  along with this program. If not, see http://www.gnu.org/licenses/
23 |
24 |
25 |  Additional permission under GNU GPL version 3 section 7
26 |
27 |  If you modify this program, or any covered work, by linking or
28 |  combining it with the OpenSSL project's OpenSSL library (or a
29 |  modified version of that library), containing parts covered by
30 |  the terms of the OpenSSL or SSLeay licenses, you are granted
31 |  additional permission to convey the resulting work.
32 |  Corresponding Source for a non-source form of such a combination
33 |  shall include the source code for the parts of OpenSSL used as well
34 |  as that of the covered work.
35 */
36 
37 #include <kvm.h>
38 
39 kvm_t	*kvmd = NULL;
40 char	errbuf[_POSIX2_LINE_MAX];
41 
42 
entry_types(&mut self, val: &::wasm_bindgen::JsValue) -> &mut Self43 void
44 gkrellm_sys_main_init(void)
45 	{
46 	/* We just ignore error, here.  Even if GKrellM doesn't have
47 	|  kmem privilege, it runs with available information.
48 	*/
49 	kvmd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
50 	if (setgid(getgid()) != 0)
51 		{
52 		fprintf(stderr, "Can't drop setgid privileges.");
53 		exit(1);
54 		}
55 	}
56 
57 void
58 gkrellm_sys_main_cleanup(void)
59 	{
60 	}
61 
62 
63 /* ===================================================================== */
64 /* CPU monitor interface */
65 
66 #include <sys/param.h>
67 #include <sys/sysctl.h>
68 #include <sys/sched.h>
69 
70 static gint ncpus;
71 
72 static gint get_ncpus(void);
73 
74 void
75 gkrellm_sys_cpu_read_data(void)
76 {
77    static int mib[] = { CTL_KERN, KERN_CP_TIME };
78    u_int64_t cp_time[ncpus][CPUSTATES];
79    int n;
80    size_t len;
81 
82    if (ncpus > 1) {
83        len = sizeof(cp_time[0]);
84        /* The sysctl() is magic -- it returns the aggregate if
85 	  there's not enough room for all CPU's. */
86        if (sysctl(mib, 2, cp_time, &len, NULL, 0) == 0)
87 	   gkrellm_cpu_assign_composite_data(cp_time[0][CP_USER],
88 	       cp_time[0][CP_NICE], cp_time[0][CP_SYS], cp_time[0][CP_IDLE]);
89    }
90 
91    len = sizeof(cp_time);
92    if (sysctl(mib, 2, cp_time, &len, NULL, 0) < 0) return;
93    for (n = 0; n < ncpus; n++)
94 	gkrellm_cpu_assign_data(n, cp_time[n][CP_USER],
95 	   cp_time[n][CP_NICE], cp_time[n][CP_SYS], cp_time[n][CP_IDLE]);
96 }
97 
98 gboolean
99 gkrellm_sys_cpu_init(void)
100     {
101 	ncpus = get_ncpus();
102 	gkrellm_cpu_set_number_of_cpus(ncpus);
103 	return TRUE;
104 	}
105 
106 static gint
107 get_ncpus(void)
108 {
109 	static int mib[] = { CTL_HW, HW_NCPU };
110 	int ncpus;
111 	size_t len = sizeof(int);
112 
113 	if (sysctl(mib, 2, &ncpus, &len, NULL, 0) < 0)
114 		return 1;
115 	else
116 		return ncpus;
117 }
118 
119 
120 /* ===================================================================== */
121 /* Proc monitor interface */
122 
123 #include <sys/proc.h>
124 #include <sys/sysctl.h>
125 #include <uvm/uvm_extern.h>
126 
127 #include <utmp.h>
128 
129 void
130 gkrellm_sys_proc_read_data(void)
131 {
132    int mib[6];
133    double avenrun;
134 	guint	n_forks = 0, n_processes = 0;
135    struct uvmexp_sysctl uvmexp;
136    size_t size;
137 
138    mib[0] = CTL_KERN;
139    mib[1] = KERN_PROC2;
140    mib[2] = KERN_PROC_ALL;
141    mib[3] = 0;
142    mib[4] = sizeof(struct kinfo_proc2);
143    mib[5] = 0;
144    if (sysctl(mib, 6, NULL, &size, NULL, 0) >= 0) {
145       n_processes = size / sizeof(struct kinfo_proc2);
146    }
147 
148    mib[0] = CTL_VM;
149    mib[1] = VM_UVMEXP2;
150    size = sizeof(uvmexp);
151    if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) >= 0) {
152       n_forks = uvmexp.forks;
153    }
154 
155    if (getloadavg(&avenrun, 1) <= 0)
156 		avenrun = 0;
157 	gkrellm_proc_assign_data(n_processes, 0, n_forks, avenrun);
158 }
159 
160 void
161 gkrellm_sys_proc_read_users(void)
162 	{
163 	gint	n_users;
164    static time_t utmp_mtime;
165    struct utmp utmp;
166    struct stat s;
167    FILE *ut;
168 
169 	if (stat(_PATH_UTMP, &s) == 0 && s.st_mtime != utmp_mtime)
170 		{
171 		if ((ut = fopen(_PATH_UTMP, "r")) != NULL)
172 			{
173 			n_users = 0;
174 			while (fread(&utmp, sizeof(utmp), 1, ut))
175 				{
176 				if (utmp.ut_name[0] == '\0') continue;
177 					++n_users;
178 				}
179 			(void)fclose(ut);
180 			gkrellm_proc_assign_users(n_users);
181 			}
182 		utmp_mtime = s.st_mtime;
183 		}
184 	}
185 
186 gboolean
187 gkrellm_sys_proc_init(void)
188 	{
189 	return TRUE;
190 	}
191 
192 
193 /* ===================================================================== */
194 /* Memory/Swap monitor interface */
195 
196 #include <sys/vmmeter.h>
197 #include <sys/sysctl.h>
198 #include <uvm/uvm_extern.h>
199 
200 
201 void
202 gkrellm_sys_mem_read_data(void)
203 {
204    int mib[2];
205    guint64 total, used, free, shared, buffers, cached;
206    struct vmtotal vmt;
207    struct uvmexp_sysctl uvmexp;
208    size_t len;
209 
210    mib[0] = CTL_VM;
211    mib[1] = VM_METER;
212    len = sizeof(vmt);
213    if (sysctl(mib, 2, &vmt, &len, NULL, 0) < 0)
214       memset(&vmt, 0, sizeof(vmt));
215 
216    mib[0] = CTL_VM;
217    mib[1] = VM_UVMEXP2;
218    len = sizeof(uvmexp);
219    if (sysctl(mib, 2, &uvmexp, &len, NULL, 0) < 0)
220       memset(&uvmexp, 0, sizeof(uvmexp));
221 
222    total = uvmexp.npages << uvmexp.pageshift;
223 
224    /* not sure of what must be computed */
225    free = (uvmexp.inactive + uvmexp.free) << uvmexp.pageshift;
226    shared = vmt.t_rmshr << uvmexp.pageshift;
227 
228    /* can't use "uvmexp.active << uvmexp.pageshift" here because the
229     * display for "free" uses "total - used" which is very wrong. */
230    used = total - free;
231 
232    /* don't know how to get those values */
233    buffers = 0;
234    cached = 0;
235 
236    gkrellm_mem_assign_data(total, used, free, shared, buffers, cached);
237 
238 }
239 
240 void
241 gkrellm_sys_swap_read_data(void)
242 {
243    static int pgout, pgin;
244    int mib[2];
245    struct uvmexp_sysctl uvmexp;
246    size_t len;
247    static gulong swapin = 0, swapout = 0;
248    guint64 swap_total, swap_used;
249 
250    mib[0] = CTL_VM;
251    mib[1] = VM_UVMEXP2;
252    len = sizeof(uvmexp);
253    if (sysctl(mib, 2, &uvmexp, &len, NULL, 0) < 0)
254       memset(&uvmexp, 0, sizeof(uvmexp));
255 
256    /* show only the pages located on the disk and not in memory */
257    swap_total = (guint64) (uvmexp.swpages << uvmexp.pageshift);
258    swap_used = (guint64) (uvmexp.swpgonly << uvmexp.pageshift);
259 
260    /* For page in/out operations, uvmexp struct doesn't seem to be reliable */
261 
262    /* if the number of swapped pages that are in memory (inuse - only) is
263     * greater that the previous value (pgin), we count this a "page in" */
264    if (uvmexp.swpginuse - uvmexp.swpgonly > pgin)
265       swapin += uvmexp.swpginuse - uvmexp.swpgonly - pgin;
266    pgin = uvmexp.swpginuse - uvmexp.swpgonly;
267 
268    /* same for page out */
269    if (uvmexp.swpgonly > pgout)
270       swapout += uvmexp.swpgonly - pgout;
271    pgout = uvmexp.swpgonly;
272 
273    gkrellm_swap_assign_data(swap_total, swap_used, swapin, swapout);
274 }
275 
276 gboolean
277 gkrellm_sys_mem_init(void)
278 	{
279 	return TRUE;
280 	}
281 
282 
283 /* ===================================================================== */
284 /* Sensor monitor interface */
285 
286   /* Tables of voltage correction factors and offsets derived from the
287   |  compute lines in sensors.conf.  See the README file.
288   */
289 	/* "lm78-*" "lm78-j-*" "lm79-*" "w83781d-*" "sis5595-*" "as99127f-*" */
290 	/* Values from LM78/LM79 data sheets	*/
291 #if 0
292 static VoltDefault	voltdefault0[] =
293 	{
294 	{ "Vcor1",	1.0,    0, NULL },
295 	{ "Vcor2",	1.0,    0, NULL },
296 	{ "+3.3V",	1.0,    0, NULL },
297 	{ "+5V",	1.68,   0, NULL },		/* in3 ((6.8/10)+1)*@	*/
298 	{ "+12V",	4.0,    0, NULL },		/* in4 ((30/10)+1)*@	*/
299 	{ "-12V",	-4.0,   0, NULL },		/* in5 -(240/60)*@		*/
300 	{ "-5V",	-1.667, 0, NULL }		/* in6 -(100/60)*@		*/
301 	};
302 #endif
303 
304 /* The SENSORS_DIR is not defined as a directory, but directly points on
305  * the "sysmon" device, which implements envsys(4) API. This #define is
306  * not really useful for NetBSD since every sensor will use that device,
307  * but it still provides the location of the device inside the GUI. */
308 #define SENSORS_DIR	"/dev/sysmon"
309 
310 #include <sys/envsys.h>
311 
312 
313 /*
314  * get_netbsd_sensor ----------------------------------------------------
315  *
316  * Perform sensor reading
317  */
318 #include <sys/ioctl.h>
319 
320 gboolean
321 gkrellm_sys_sensors_get_temperature(gchar *path, gint id,
322         gint iodev, gint interface, gfloat *temp)
323 {
324    envsys_tre_data_t data;	/* sensor data */
325 
326    data.sensor = interface;
327    if (ioctl(iodev, ENVSYS_GTREDATA, &data) < 0) return FALSE;
328    if (!(data.validflags & (ENVSYS_FVALID|ENVSYS_FCURVALID))) return FALSE;
329 
330    if (data.units == ENVSYS_STEMP) {
331       if (temp)	/* values in uK */
332 	     *temp = (data.cur.data_us / 1.0e6) - 273.15/*0K*/ ;
333 	 return TRUE;
334    }
335 
336    return FALSE;
337 }
338 
339 gboolean
340 gkrellm_sys_sensors_get_fan(gchar *path, gint id,
341         gint iodev, gint interface, gfloat *fan)
342 {
343    envsys_tre_data_t data;	/* sensor data */
344 
345    data.sensor = interface;
346    if (ioctl(iodev, ENVSYS_GTREDATA, &data) < 0) return FALSE;
347    if (!(data.validflags & (ENVSYS_FVALID|ENVSYS_FCURVALID))) return FALSE;
348 
349    if (data.units == ENVSYS_SFANRPM) {
350       if (fan)	/* values in RPM */
351 	    *fan = data.cur.data_us;
352 	 return TRUE;
353    }
354    return FALSE;
355 }
356 
357 gboolean
358 gkrellm_sys_sensors_get_voltage(gchar *path, gint id,
359         gint iodev, gint interface, gfloat *volt)
360 {
361    envsys_tre_data_t data;	/* sensor data */
362 
363    data.sensor = interface;
364    if (ioctl(iodev, ENVSYS_GTREDATA, &data) < 0) return FALSE;
365    if (!(data.validflags & (ENVSYS_FVALID|ENVSYS_FCURVALID))) return FALSE;
366 
367    if (data.units == ENVSYS_SVOLTS_DC) {
368       if (volt)		/* values in uV */
369 	    *volt = data.cur.data_s / 1.0e6;
370 	 return TRUE;
371    }
372 
373    return FALSE;
374 }
375 
376 /*
377  *
378  * At the moment, only two chips are supported: lm78 and alike (see
379  * lm(4)), and VT82C68A South Bridge for VIA chipsets (see viaenv(4)).
380  * Both support the envsys(4) API.
381  *
382  * XXX /dev/sysmon is opened but never closed. This is a problem since
383  * the driver wants an exclusive lock (e.g. envstat won't work when
384  * GKrellM will be running). But, at this time, I don't want to
385  * open/close sysmon each time a reading is needed. See README for
386  * details.
387  */
388 
389 gboolean
390 gkrellm_sys_sensors_init(void)
391 {
392    envsys_basic_info_t info;	/* sensor misc. info */
393    int fd;			/* file desc. for /dev/sysmon */
394    int id = 0;			/* incremented for each sensor */
395    int type;
396    char *s, base_name[33];
397    gboolean	found_sensors = FALSE;
398 
399    /* check if some sensor is configured */
400    fd = open(SENSORS_DIR, O_RDONLY); /* never closed */
401    if (fd < 0) return FALSE;
402 
403    /* iterate through available sensors, until the first invalid */
404    for(info.sensor=0; ; info.sensor++) {
405 
406       /* stop if we can't ioctl() */
407       if (ioctl(fd, ENVSYS_GTREINFO, &info) < 0) break;
408       /* stop if that sensor is not valid */
409       if (!(info.validflags & ENVSYS_FVALID)) break;
410 
411       switch(info.units) {
412 	 case ENVSYS_STEMP:
413 	    type = SENSOR_TEMPERATURE;	break;
414 	 case ENVSYS_SFANRPM:
415 	    type = SENSOR_FAN;		break;
416 	 case ENVSYS_SVOLTS_DC:
417 	    type = SENSOR_VOLTAGE;		break;
418 	 default:
419 	    /* unwanted sensor type: continue */
420 	    continue;
421       }
422 
423       /* ok, we've got one working sensor */
424       sprintf(base_name, "%32s", info.desc);
425       /* must map spaces into something else (for config file items) */
426       for(s=strchr(base_name, ' '); s != NULL; s=strchr(s, ' '))
427 	 *s++ = '_';
428 
429       gkrellm_sensors_add_sensor(type, SENSORS_DIR, base_name,
430            id, fd, info.sensor, 1.0,
431            0.0, NULL, NULL);
432       found_sensors = TRUE;
433    }
434    return found_sensors;
435 }
436 
437 
438 
439 /* ===================================================================== */
440 /* Battery monitor interface */
441 
442 #if defined(__i386__) || defined(__powerpc__)
443 # include <sys/ioctl.h>
444 # include <machine/apmvar.h>
445 
446 # define	APMDEV		"/dev/apm"
447 #endif
448 
449 static int battery_use_apm = 1;
450 
451 /* battery data, index by [battery number] */
452 static struct battery_acpi_data {
453   gboolean available;	int available_index;
454   gboolean on_line;	int on_line_index;
455   gboolean charging;	int charging_index;
456   gint full_cap;	int full_cap_index;
457   gint cap;		int cap_index;
458   gint discharge_rate;	int discharge_rate_index;
459   gint charge_rate;	int charge_rate_index;
460 } *battery_acpi_data;
461 static int battery_acpi_data_items;
462 
463 static int
464 gkrellm_battery_data_alloc(int bat)
465 {
466   if (bat + 1 > battery_acpi_data_items)
467     battery_acpi_data_items = bat + 1;
468 
469   battery_acpi_data = realloc(battery_acpi_data,
470 			      battery_acpi_data_items*
471 			      sizeof(*battery_acpi_data));
472   return battery_acpi_data?1:0;
473 }
474 
475 void
476 gkrellm_sys_battery_read_data(void)
477 {
478   int i;
479   int fd;			/* file desc. for /dev/sysmon or /dev/apm */
480   envsys_tre_data_t data;	/* sensor data */
481   int time_left;
482 
483   if (battery_use_apm) {
484 #if defined(__i386__) || defined(__powerpc__)
485     int			r;
486     struct apm_power_info apminfo;
487     gboolean available, on_line, charging;
488     gint percent, time_left;
489 
490     if ((fd = open(APMDEV, O_RDONLY)) == -1) return;
491     memset(&apminfo, 0, sizeof(apminfo));
492     r = ioctl(fd, APM_IOC_GETPOWER, &apminfo);
493     close(fd);
494     if (r == -1) return;
495 
496     available = (apminfo.battery_state != APM_BATT_UNKNOWN);
497     on_line = (apminfo.ac_state == APM_AC_ON) ? TRUE : FALSE;
498     charging = (apminfo.battery_state == APM_BATT_CHARGING) ? TRUE : FALSE;
499     percent = apminfo.battery_life;
500     time_left = apminfo.minutes_left;
501     gkrellm_battery_assign_data(0, available, on_line, charging,
502 				percent, time_left);
503 #else
504     return;
505 #endif
506   }
507 
508    fd = open(SENSORS_DIR, O_RDONLY);
509    if (fd < 0) return;
510 
511    data.sensor = battery_acpi_data[0].on_line_index;
512    if (ioctl(fd, ENVSYS_GTREDATA, &data) < 0) return;
513    if (!(data.validflags & ENVSYS_FVALID)) return;
514    battery_acpi_data[0].on_line = data.cur.data_us ? TRUE:FALSE;
515 
516    /* iterate through available batteries */
517    for(i=0; i<battery_acpi_data_items; i++) {
518 #define read_sensor(x)							\
519      do {								\
520        data.sensor = battery_acpi_data[i].x ## _index;			\
521        if (ioctl(fd, ENVSYS_GTREDATA, &data) < 0) continue;		\
522        if (!(data.validflags & ENVSYS_FCURVALID))			\
523 	 battery_acpi_data[i].x = -1;					\
524        else								\
525 	 battery_acpi_data[i].x = data.cur.data_s;			\
526      } while(0)
527 
528      read_sensor(available);
529      read_sensor(charging);
530      read_sensor(full_cap);
531      read_sensor(cap);
532      read_sensor(discharge_rate);
533      read_sensor(charge_rate);
534 #undef read_sensor
535 
536      if (battery_acpi_data[i].discharge_rate > 0)
537        time_left =
538 	 battery_acpi_data[i].cap * 60 / battery_acpi_data[i].discharge_rate;
539      else if (battery_acpi_data[i].charge_rate > 0)
540        time_left =
541 	 (battery_acpi_data[i].full_cap - battery_acpi_data[i].cap) * 60 /
542 	 battery_acpi_data[i].charge_rate;
543      else
544        time_left = -1;
545 
546      if (battery_acpi_data[i].available) {
547        gkrellm_battery_assign_data(i,
548 				   battery_acpi_data[i].available,
549 				   battery_acpi_data[0].on_line,
550 				   battery_acpi_data[i].charging,
551 
552 				   /* percent */
553 				   battery_acpi_data[i].cap * 100 /
554 				   battery_acpi_data[i].full_cap,
555 
556 				   /* time left (minutes) */
557 				   time_left);
558      } else
559        gkrellm_battery_assign_data(i, 0, 0, 0, -1, -1);
560    }
561 
562    close(fd);
563 }
564 
565 gboolean
566 gkrellm_sys_battery_init()
567 {
568    int fd;			/* file desc. for /dev/sysmon or /dev/apm */
569    envsys_basic_info_t info;	/* sensor misc. info */
570    gboolean found_sensors = FALSE;
571    char fake[2];
572    int r, bat;
573 
574    /* --- check APM first --- */
575 
576 #if defined(__i386__) || defined(__powerpc__)
577    do {
578      struct apm_power_info info;
579 
580      if ((fd = open(APMDEV, O_RDONLY)) == -1) break;
581      r = ioctl(fd, APM_IOC_GETPOWER, &info);
582      close(fd);
583      if (r != -1) {
584        battery_use_apm = 1;
585        return TRUE;
586      }
587    } while(0);
588 #endif
589 
590    /* --- check for some envsys(4) acpi battery --- */
591 
592    battery_use_apm = 0;
593    battery_acpi_data_items = 0;
594    battery_acpi_data = NULL; /* this is never freed */
595 
596    fd = open(SENSORS_DIR, O_RDONLY);
597    if (fd < 0) return FALSE;
598 
599    /* iterate through available sensors */
600    for(info.sensor=0; ; info.sensor++) {
601       /* stop if we can't ioctl() */
602       if (ioctl(fd, ENVSYS_GTREINFO, &info) < 0) break;
603       /* stop if that sensor is not valid */
604       if (!(info.validflags & ENVSYS_FVALID)) break;
605 
606       do {
607 	if (info.units == ENVSYS_INDICATOR &&
608 	    sscanf(info.desc, "acpibat%d presen%1[t]", &bat, fake) == 2) {
609 	  if (!gkrellm_battery_data_alloc(bat)) {
610 	    close(fd);
611 	    return FALSE;
612 	  }
613 	  battery_acpi_data[bat].available_index = info.sensor;
614 	  found_sensors = TRUE;
615 
616 	} else if (info.units == ENVSYS_INDICATOR &&
617 		   sscanf(info.desc, "acpiacad%*d connecte%1[d]", fake) == 1) {
618 	  if (!gkrellm_battery_data_alloc(0)) {
619 	    close(fd);
620 	    return FALSE;
621 	  }
622 	  battery_acpi_data[0].on_line_index = info.sensor;
623 
624 	} else if (info.units == ENVSYS_INDICATOR &&
625 		   sscanf(info.desc,
626 			  "acpibat%d chargin%1[g]", &bat, fake) == 2) {
627 	  if (!gkrellm_battery_data_alloc(bat)) {
628 	    close(fd);
629 	    return FALSE;
630 	  }
631 	  battery_acpi_data[bat].charging_index = info.sensor;
632 	  found_sensors = TRUE;
633 
634 	} else if (info.units == ENVSYS_SAMPHOUR &&
635 		   sscanf(info.desc,
636 			  "acpibat%d design ca%1[p]", &bat, fake) == 2) {
637 	  if (!gkrellm_battery_data_alloc(bat)) {
638 	    close(fd);
639 	    return FALSE;
640 	  }
641 	  battery_acpi_data[bat].full_cap_index = info.sensor;
642 	  found_sensors = TRUE;
643 
644 	} else if (info.units == ENVSYS_SAMPHOUR &&
645 		   sscanf(info.desc,
646 			  "acpibat%d charg%1[e]", &bat, fake) == 2) {
647 	  if (!gkrellm_battery_data_alloc(bat)) {
648 	    close(fd);
649 	    return FALSE;
650 	  }
651 	  battery_acpi_data[bat].cap_index = info.sensor;
652 	  found_sensors = TRUE;
653 
654 	} else if (info.units == ENVSYS_SAMPS &&
655 		   sscanf(info.desc,
656 			  "acpibat%d discharge rat%1[e]", &bat, fake) == 2) {
657 	  if (!gkrellm_battery_data_alloc(bat)) {
658 	    close(fd);
659 	    return FALSE;
660 	  }
661 	  battery_acpi_data[bat].discharge_rate_index = info.sensor;
662 	  found_sensors = TRUE;
663 
664 	} else if (info.units == ENVSYS_SAMPS &&
665 		   sscanf(info.desc,
666 			  "acpibat%d charge rat%1[e]", &bat, fake) == 2) {
667 	  if (!gkrellm_battery_data_alloc(bat)) {
668 	    close(fd);
669 	    return FALSE;
670 	  }
671 	  battery_acpi_data[bat].charge_rate_index = info.sensor;
672 	  found_sensors = TRUE;
673 	}
674       } while(0);
675    }
676 
677    close(fd);
678 
679    return found_sensors;
680 }
681 
682 
683 /* ===================================================================== */
684 /* Disk monitor interface */
685 
686 #include <sys/dkstat.h>
687 #include <sys/disk.h>
688 #include <sys/sysctl.h>
689 
690 #ifdef HW_IOSTATS
691 #define HW_DISKSTATS	HW_IOSTATS
692 #define disk_sysctl	io_sysctl
693 #define dk_rbytes	rbytes
694 #define dk_wbytes	wbytes
695 #define dk_name		name
696 #endif
697 
698 gboolean
699 gkrellm_sys_disk_init(void)
700 {
701 	int mib[3] = { CTL_HW, HW_DISKSTATS, sizeof(struct disk_sysctl) };
702 	size_t size;
703 
704 	/* Just test if the sysctl call works */
705 	if (sysctl(mib, 3, NULL, &size, NULL, 0) == -1)
706 		return (FALSE);
707 
708 	return (TRUE);
709 }
710 
711 void
712 gkrellm_sys_disk_read_data(void)
713 {
714 	int i, n_disks, mib[3] = { CTL_HW, HW_DISKSTATS, sizeof(struct disk_sysctl) };
715 	size_t size;
716 	guint64 rbytes, wbytes;
717 	struct disk_sysctl *dk_drives;
718 
719 	if (sysctl(mib, 3, NULL, &size, NULL, 0) == -1)
720 		return;
721 	dk_drives = malloc(size);
722 	if (dk_drives == NULL)
723 		return;
724 	n_disks = size / sizeof(struct disk_sysctl);
725 
726 	if (sysctl(mib, 3, dk_drives, &size, NULL, 0) == -1)
727 		return;
728 
729 	for (i = 0; i < n_disks; i++) {
730 #if __NetBSD_Version__ >= 106110000
731 		rbytes = dk_drives[i].dk_rbytes;
732 		wbytes = dk_drives[i].dk_wbytes;
733 #else
734 		rbytes = dk_drives[i].dk_bytes;
735 		wbytes = 0;
736 #endif
737 
738 		gkrellm_disk_assign_data_by_name(dk_drives[i].dk_name, rbytes, wbytes, FALSE);
739 	}
740 
741 	free(dk_drives);
742 }
743 
744 gchar *
745 gkrellm_sys_disk_name_from_device(gint device_number, gint unit_number,
746 			gint *order)
747 	{
748 	return NULL;	/* disk data by device not implemented */
749 	}
750 
751 gint
752 gkrellm_sys_disk_order_from_name(const gchar *name)
753 	{
754 	return -1;  /* append disk charts as added */
755 	}
756 
757 #if __NetBSD_Version__ >= 399000100
758 
759 #include "../inet.h"
760 
761 #include <errno.h>
762 #include <sys/socket.h>
763 #include <netinet/in.h>
764 #include <netinet/tcp_fsm.h>
765 
766 static const struct gkrellm_inet_fam {
767 	sa_family_t family;
768 	const char *mib;
769 } families[] = { {AF_INET, "net.inet.tcp.pcblist"},
770 #ifdef INET6
771     {AF_INET6, "net.inet6.tcp6.pcblist"},
772 #endif
773     {0, NULL} };
774 
775 void
776 gkrellm_sys_inet_read_tcp_data()
777 {
778 	ActiveTCP tcp;
779 	int mib[CTL_MAXNAME], i;
780 	size_t sz;
781 	u_int namelen;
782 	struct kinfo_pcb *pcbt = NULL;
783 	const struct gkrellm_inet_fam *pf = families;
784 
785 	while (pf->mib != NULL) {
786 		sz = CTL_MAXNAME;
787 		if (sysctlnametomib(pf->mib, mib, &sz) == -1)
788 			return;
789 		namelen = sz;
790 
791 		mib[namelen++] = PCB_ALL;
792 		mib[namelen++] = 0;
793 		mib[namelen++] = sizeof(struct kinfo_pcb);
794 		mib[namelen++] = INT_MAX;
795 
796 		sz = 0;
797 		pcbt = NULL;
798 		if (sysctl(&mib[0], namelen, pcbt, &sz, NULL, 0) == -1)
799 			return;
800 		pcbt = malloc(sz);
801 		if (pcbt == NULL)
802 			return;
803 		if (sysctl(&mib[0], namelen, pcbt, &sz, NULL, 0) == -1)
804 			return;
805 
806 		sz /= sizeof(struct kinfo_pcb);
807 		for (i = 0; i < sz; i++) {
808 			tcp.family = pf->family;
809 			if (pf->family == AF_INET) {
810 				struct sockaddr_in *sin =
811 				    (struct sockaddr_in *)&pcbt[i].ki_dst;
812 				tcp.remote_addr.s_addr = sin->sin_addr.s_addr;
813 				tcp.remote_port = sin->sin_port;
814 
815 				sin = (struct sockaddr_in *)&pcbt[i].ki_src;
816 				tcp.local_port = sin->sin_port;
817 #ifdef INET6
818 			} else { /* AF_INET6 */
819 				struct sockaddr_in6 *sin =
820 				    (struct sockaddr_in6 *)&pcbt[i].ki_dst;
821 				memcpy(&tcp.remote_addr6, &sin->sin6_addr,
822 				    sizeof(struct in6_addr));
823 				tcp.remote_port = sin->sin6_port;
824 
825 				sin = (struct sockaddr_in6 *)&pcbt[i].ki_src;
826 				tcp.local_port = sin->sin6_port;
827 #endif
828 			}
829 			if (pcbt[i].ki_tstate == TCPS_ESTABLISHED)
830 				gkrellm_inet_log_tcp_port_data(&tcp);
831 		}
832 		free(pcbt);
833 		pf++;
834 	}
835 }
836 #endif
837