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