Annotation of src/usr.bin/systat/sensors.c, Revision 1.30
1.30 ! deraadt 1: /* $OpenBSD: sensors.c,v 1.29 2014/10/08 04:10:04 doug Exp $ */
1.8 deanna 2:
1.1 deanna 3: /*
4: * Copyright (c) 2007 Deanna Phillips <deanna@openbsd.org>
5: * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
1.4 deraadt 6: * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
1.1 deanna 7: *
8: * Permission to use, copy, modify, and distribute this software for any
9: * purpose with or without fee is hereby granted, provided that the above
10: * copyright notice and this permission notice appear in all copies.
11: *
12: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19: *
20: */
21:
1.30 ! deraadt 22: #include <sys/types.h>
! 23: #include <sys/signal.h>
1.1 deanna 24: #include <sys/sysctl.h>
25: #include <sys/sensors.h>
26:
27: #include <err.h>
28: #include <errno.h>
29: #include <stdio.h>
30: #include <stdlib.h>
1.13 canacar 31: #include <string.h>
1.1 deanna 32: #include "systat.h"
33:
34: struct sensor sensor;
35: struct sensordev sensordev;
36:
1.13 canacar 37: struct sensinfo {
38: int sn_dev;
39: struct sensor sn_sensor;
40: };
41: #define sn_type sn_sensor.type
42: #define sn_numt sn_sensor.numt
43: #define sn_desc sn_sensor.desc
44: #define sn_status sn_sensor.status
45: #define sn_value sn_sensor.value
46:
1.21 deraadt 47: #define SYSTAT_MAXSENSORDEVICES 1024
48: char *devnames[SYSTAT_MAXSENSORDEVICES];
1.13 canacar 49:
50: #define ADD_ALLOC 100
51: static size_t sensor_cnt = 0;
52: static size_t num_alloc = 0;
53: static struct sensinfo *sensors = NULL;
54:
55: static char *fmttime(double);
56: static void showsensor(struct sensinfo *s);
57:
58: void print_sn(void);
59: int read_sn(void);
60: int select_sn(void);
61:
62: const char *drvstat[] = {
63: NULL,
1.16 okan 64: "empty", "ready", "powering up", "online", "idle", "active",
65: "rebuilding", "powering down", "failed", "degraded"
1.13 canacar 66: };
67:
68:
69: field_def fields_sn[] = {
70: {"SENSOR", 16, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
71: {"VALUE", 16, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
72: {"STATUS", 5, 8, 1, FLD_ALIGN_CENTER, -1, 0, 0, 0},
73: {"DESCRIPTION", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}
74: };
75:
1.24 jasper 76: #define FLD_SN_SENSOR FIELD_ADDR(fields_sn,0)
77: #define FLD_SN_VALUE FIELD_ADDR(fields_sn,1)
78: #define FLD_SN_STATUS FIELD_ADDR(fields_sn,2)
79: #define FLD_SN_DESCR FIELD_ADDR(fields_sn,3)
1.13 canacar 80:
81: /* Define views */
82: field_def *view_sn_0[] = {
83: FLD_SN_SENSOR, FLD_SN_VALUE, FLD_SN_STATUS, FLD_SN_DESCR, NULL
84: };
85:
86:
87: /* Define view managers */
88: struct view_manager sensors_mgr = {
89: "Sensors", select_sn, read_sn, NULL, print_header,
90: print_sn, keyboard_callback, NULL, NULL
91: };
92:
93: field_view views_sn[] = {
94: {view_sn_0, "sensors", '3', &sensors_mgr},
95: {NULL, NULL, 0, NULL}
96: };
97:
98: struct sensinfo *
99: next_sn(void)
1.1 deanna 100: {
1.13 canacar 101: if (num_alloc <= sensor_cnt) {
102: struct sensinfo *s;
103: size_t a = num_alloc + ADD_ALLOC;
104: if (a < num_alloc)
105: return NULL;
1.29 doug 106: s = reallocarray(sensors, a, sizeof(struct sensinfo));
1.13 canacar 107: if (s == NULL)
108: return NULL;
109: sensors = s;
110: num_alloc = a;
111: }
112:
113: return &sensors[sensor_cnt++];
1.1 deanna 114: }
115:
116:
1.13 canacar 117: int
118: select_sn(void)
1.1 deanna 119: {
1.13 canacar 120: num_disp = sensor_cnt;
121: return (0);
1.1 deanna 122: }
123:
1.13 canacar 124: int
125: read_sn(void)
1.1 deanna 126: {
127: enum sensor_type type;
128: size_t slen, sdlen;
129: int mib[5], dev, numt;
1.13 canacar 130: struct sensinfo *s;
1.1 deanna 131:
132: mib[0] = CTL_HW;
133: mib[1] = HW_SENSORS;
134:
135: sensor_cnt = 0;
1.8 deanna 136:
1.21 deraadt 137: for (dev = 0; dev < SYSTAT_MAXSENSORDEVICES; dev++) {
1.1 deanna 138: mib[2] = dev;
1.13 canacar 139: sdlen = sizeof(struct sensordev);
1.1 deanna 140: if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) {
1.21 deraadt 141: if (errno == ENOENT)
142: break;
143: if (errno == ENXIO)
144: continue;
145: error("sysctl: %s", strerror(errno));
1.1 deanna 146: }
1.13 canacar 147:
148: if (devnames[dev] && strcmp(devnames[dev], sensordev.xname)) {
149: free(devnames[dev]);
150: devnames[dev] = NULL;
151: }
152: if (devnames[dev] == NULL)
153: devnames[dev] = strdup(sensordev.xname);
154:
1.1 deanna 155: for (type = 0; type < SENSOR_MAX_TYPES; type++) {
156: mib[3] = type;
157: for (numt = 0; numt < sensordev.maxnumt[type]; numt++) {
158: mib[4] = numt;
1.13 canacar 159: slen = sizeof(struct sensor);
1.2 deraadt 160: if (sysctl(mib, 5, &sensor, &slen, NULL, 0)
1.1 deanna 161: == -1) {
162: if (errno != ENOENT)
1.13 canacar 163: error("sysctl: %s", strerror(errno));
1.1 deanna 164: continue;
165: }
166: if (sensor.flags & SENSOR_FINVALID)
167: continue;
1.13 canacar 168:
169: s = next_sn();
170: s->sn_sensor = sensor;
171: s->sn_dev = dev;
1.1 deanna 172: }
173: }
174: }
1.13 canacar 175:
176: num_disp = sensor_cnt;
177: return 0;
1.1 deanna 178: }
179:
180:
181: void
1.13 canacar 182: print_sn(void)
1.1 deanna 183: {
1.13 canacar 184: int n, count = 0;
185:
186: for (n = dispstart; n < num_disp; n++) {
187: showsensor(sensors + n);
188: count++;
189: if (maxprint > 0 && count >= maxprint)
190: break;
191: }
1.1 deanna 192: }
193:
194: int
195: initsensors(void)
196: {
1.13 canacar 197: field_view *v;
198:
199: memset(devnames, 0, sizeof(devnames));
200:
201: for (v = views_sn; v->name != NULL; v++)
202: add_view(v);
203:
204: return(1);
1.1 deanna 205: }
206:
1.13 canacar 207: static void
208: showsensor(struct sensinfo *s)
1.1 deanna 209: {
1.13 canacar 210: tb_start();
211: tbprintf("%s.%s%d", devnames[s->sn_dev],
212: sensor_type_s[s->sn_type], s->sn_numt);
213: print_fld_tb(FLD_SN_SENSOR);
214:
215: if (s->sn_desc[0] != '\0')
216: print_fld_str(FLD_SN_DESCR, s->sn_desc);
217:
218: tb_start();
219:
220: switch (s->sn_type) {
1.1 deanna 221: case SENSOR_TEMP:
1.13 canacar 222: tbprintf("%10.2f degC",
223: (s->sn_value - 273150000) / 1000000.0);
1.1 deanna 224: break;
225: case SENSOR_FANRPM:
1.13 canacar 226: tbprintf("%11lld RPM", s->sn_value);
1.1 deanna 227: break;
1.26 yuo 228: case SENSOR_VOLTS_DC:
229: tbprintf("%10.2f V DC",
230: s->sn_value / 1000000.0);
231: break;
1.25 yuo 232: case SENSOR_VOLTS_AC:
233: tbprintf("%10.2f V AC",
234: s->sn_value / 1000000.0);
235: break;
1.26 yuo 236: case SENSOR_OHMS:
237: tbprintf("%11lld ohm", s->sn_value);
1.18 cnst 238: break;
239: case SENSOR_WATTS:
240: tbprintf("%10.2f W", s->sn_value / 1000000.0);
1.1 deanna 241: break;
242: case SENSOR_AMPS:
1.13 canacar 243: tbprintf("%10.2f A", s->sn_value / 1000000.0);
1.1 deanna 244: break;
1.26 yuo 245: case SENSOR_WATTHOUR:
246: tbprintf("%12.2f Wh", s->sn_value / 1000000.0);
247: break;
248: case SENSOR_AMPHOUR:
249: tbprintf("%10.2f Ah", s->sn_value / 1000000.0);
250: break;
1.1 deanna 251: case SENSOR_INDICATOR:
1.13 canacar 252: tbprintf("%15s", s->sn_value ? "On" : "Off");
1.1 deanna 253: break;
254: case SENSOR_INTEGER:
1.13 canacar 255: tbprintf("%11lld raw", s->sn_value);
1.1 deanna 256: break;
257: case SENSOR_PERCENT:
1.13 canacar 258: tbprintf("%14.2f%%", s->sn_value / 1000.0);
1.1 deanna 259: break;
260: case SENSOR_LUX:
1.13 canacar 261: tbprintf("%15.2f lx", s->sn_value / 1000000.0);
1.1 deanna 262: break;
263: case SENSOR_DRIVE:
1.13 canacar 264: if (0 < s->sn_value &&
1.17 deraadt 265: s->sn_value < sizeof(drvstat)/sizeof(drvstat[0])) {
1.13 canacar 266: tbprintf("%15s", drvstat[s->sn_value]);
1.1 deanna 267: break;
268: }
1.3 deraadt 269: break;
1.1 deanna 270: case SENSOR_TIMEDELTA:
1.13 canacar 271: tbprintf("%15s", fmttime(s->sn_value / 1000000000.0));
1.19 yuo 272: break;
273: case SENSOR_HUMIDITY:
274: tbprintf("%3.2f%%", s->sn_value / 1000.0);
1.20 oga 275: break;
276: case SENSOR_FREQ:
1.25 yuo 277: tbprintf("%11.2f Hz", s->sn_value / 1000000.0);
1.22 deraadt 278: break;
279: case SENSOR_ANGLE:
1.23 deraadt 280: tbprintf("%3.4f degrees", s->sn_value / 1000000.0);
1.27 yuo 281: break;
282: case SENSOR_DISTANCE:
1.28 jasper 283: tbprintf("%.2f mm", s->sn_value / 1000.0);
1.27 yuo 284: break;
285: case SENSOR_PRESSURE:
1.28 jasper 286: tbprintf("%.2f Pa", s->sn_value / 1000.0);
1.27 yuo 287: break;
288: case SENSOR_ACCEL:
1.28 jasper 289: tbprintf("%2.4f m/s^2", s->sn_value / 1000000.0);
1.1 deanna 290: break;
291: default:
1.13 canacar 292: tbprintf("%10lld", s->sn_value);
1.3 deraadt 293: break;
1.1 deanna 294: }
1.2 deraadt 295:
1.13 canacar 296: print_fld_tb(FLD_SN_VALUE);
297:
298: switch (s->sn_status) {
1.8 deanna 299: case SENSOR_S_UNSPEC:
300: break;
1.1 deanna 301: case SENSOR_S_UNKNOWN:
1.13 canacar 302: print_fld_str(FLD_SN_STATUS, "unknown");
1.1 deanna 303: break;
304: case SENSOR_S_WARN:
1.13 canacar 305: print_fld_str(FLD_SN_STATUS, "WARNING");
1.1 deanna 306: break;
307: case SENSOR_S_CRIT:
1.13 canacar 308: print_fld_str(FLD_SN_STATUS, "CRITICAL");
1.1 deanna 309: break;
1.3 deraadt 310: case SENSOR_S_OK:
1.13 canacar 311: print_fld_str(FLD_SN_STATUS, "OK");
1.1 deanna 312: break;
313: }
1.13 canacar 314: end_line();
1.9 ckuethe 315: }
316:
317: #define SECS_PER_DAY 86400
318: #define SECS_PER_HOUR 3600
319: #define SECS_PER_MIN 60
320:
321: static char *
322: fmttime(double in)
323: {
324: int signbit = 1;
325: int tiny = 0;
326: char *unit;
327: #define LEN 32
328: static char outbuf[LEN];
329:
330: if (in < 0){
331: signbit = -1;
332: in *= -1;
333: }
334:
335: if (in >= SECS_PER_DAY ){
336: unit = "days";
337: in /= SECS_PER_DAY;
338: } else if (in >= SECS_PER_HOUR ){
339: unit = "hr";
340: in /= SECS_PER_HOUR;
341: } else if (in >= SECS_PER_MIN ){
342: unit = "min";
343: in /= SECS_PER_MIN;
344: } else if (in >= 1 ){
1.11 ckuethe 345: unit = "s";
1.9 ckuethe 346: /* in *= 1; */ /* no op */
1.10 ckuethe 347: } else if (in == 0 ){ /* direct comparisons to floats are scary */
1.11 ckuethe 348: unit = "s";
1.9 ckuethe 349: } else if (in >= 1e-3 ){
1.11 ckuethe 350: unit = "ms";
1.9 ckuethe 351: in *= 1e3;
352: } else if (in >= 1e-6 ){
1.11 ckuethe 353: unit = "us";
1.9 ckuethe 354: in *= 1e6;
355: } else if (in >= 1e-9 ){
1.11 ckuethe 356: unit = "ns";
1.9 ckuethe 357: in *= 1e9;
358: } else {
1.11 ckuethe 359: unit = "ps";
1.9 ckuethe 360: if (in < 1e-13)
361: tiny = 1;
362: in *= 1e12;
363: }
364:
365: snprintf(outbuf, LEN,
1.14 canacar 366: tiny ? "%s%f %s" : "%s%.3f %s",
1.9 ckuethe 367: signbit == -1 ? "-" : "", in, unit);
368:
369: return outbuf;
1.1 deanna 370: }