Annotation of src/usr.bin/systat/sensors.c, Revision 1.16
1.16 ! okan 1: /* $OpenBSD: sensors.c,v 1.15 2009/06/25 20:39:02 okan 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:
46: char *devnames[MAXSENSORDEVICES];
47:
48: #define ADD_ALLOC 100
49: static size_t sensor_cnt = 0;
50: static size_t num_alloc = 0;
51: static struct sensinfo *sensors = NULL;
52:
53: static char *fmttime(double);
54: static void showsensor(struct sensinfo *s);
55:
56: void print_sn(void);
57: int read_sn(void);
58: int select_sn(void);
59:
60: const char *drvstat[] = {
61: NULL,
1.16 ! okan 62: "empty", "ready", "powering up", "online", "idle", "active",
! 63: "rebuilding", "powering down", "failed", "degraded"
1.13 canacar 64: };
65:
66:
67: field_def fields_sn[] = {
68: {"SENSOR", 16, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
69: {"VALUE", 16, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
70: {"STATUS", 5, 8, 1, FLD_ALIGN_CENTER, -1, 0, 0, 0},
71: {"DESCRIPTION", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}
72: };
73:
74: #define FIELD_ADDR(x) (&fields_sn[x])
75:
76: #define FLD_SN_SENSOR FIELD_ADDR(0)
77: #define FLD_SN_VALUE FIELD_ADDR(1)
78: #define FLD_SN_STATUS FIELD_ADDR(2)
79: #define FLD_SN_DESCR FIELD_ADDR(3)
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;
106: s = realloc(sensors, a * sizeof(struct sensinfo));
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.1 deanna 137: for (dev = 0; dev < MAXSENSORDEVICES; dev++) {
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) {
141: if (errno != ENOENT)
1.13 canacar 142: error("sysctl: %s", strerror(errno));
1.1 deanna 143: continue;
144: }
1.13 canacar 145:
146: if (devnames[dev] && strcmp(devnames[dev], sensordev.xname)) {
147: free(devnames[dev]);
148: devnames[dev] = NULL;
149: }
150: if (devnames[dev] == NULL)
151: devnames[dev] = strdup(sensordev.xname);
152:
1.1 deanna 153: for (type = 0; type < SENSOR_MAX_TYPES; type++) {
154: mib[3] = type;
155: for (numt = 0; numt < sensordev.maxnumt[type]; numt++) {
156: mib[4] = numt;
1.13 canacar 157: slen = sizeof(struct sensor);
1.2 deraadt 158: if (sysctl(mib, 5, &sensor, &slen, NULL, 0)
1.1 deanna 159: == -1) {
160: if (errno != ENOENT)
1.13 canacar 161: error("sysctl: %s", strerror(errno));
1.1 deanna 162: continue;
163: }
164: if (sensor.flags & SENSOR_FINVALID)
165: continue;
1.13 canacar 166:
167: s = next_sn();
168: s->sn_sensor = sensor;
169: s->sn_dev = dev;
1.1 deanna 170: }
171: }
172: }
1.13 canacar 173:
174: num_disp = sensor_cnt;
175: return 0;
1.1 deanna 176: }
177:
178:
179: void
1.13 canacar 180: print_sn(void)
1.1 deanna 181: {
1.13 canacar 182: int n, count = 0;
183:
184: for (n = dispstart; n < num_disp; n++) {
185: showsensor(sensors + n);
186: count++;
187: if (maxprint > 0 && count >= maxprint)
188: break;
189: }
1.1 deanna 190: }
191:
192: int
193: initsensors(void)
194: {
1.13 canacar 195: field_view *v;
196:
197: memset(devnames, 0, sizeof(devnames));
198:
199: for (v = views_sn; v->name != NULL; v++)
200: add_view(v);
201:
202: return(1);
1.1 deanna 203: }
204:
1.13 canacar 205: static void
206: showsensor(struct sensinfo *s)
1.1 deanna 207: {
1.13 canacar 208: tb_start();
209: tbprintf("%s.%s%d", devnames[s->sn_dev],
210: sensor_type_s[s->sn_type], s->sn_numt);
211: print_fld_tb(FLD_SN_SENSOR);
212:
213: if (s->sn_desc[0] != '\0')
214: print_fld_str(FLD_SN_DESCR, s->sn_desc);
215:
216: tb_start();
217:
218: switch (s->sn_type) {
1.1 deanna 219: case SENSOR_TEMP:
1.13 canacar 220: tbprintf("%10.2f degC",
221: (s->sn_value - 273150000) / 1000000.0);
1.1 deanna 222: break;
223: case SENSOR_FANRPM:
1.13 canacar 224: tbprintf("%11lld RPM", s->sn_value);
1.1 deanna 225: break;
226: case SENSOR_VOLTS_DC:
1.13 canacar 227: tbprintf("%10.2f V DC",
228: s->sn_value / 1000000.0);
1.1 deanna 229: break;
230: case SENSOR_AMPS:
1.13 canacar 231: tbprintf("%10.2f A", s->sn_value / 1000000.0);
1.1 deanna 232: break;
233: case SENSOR_INDICATOR:
1.13 canacar 234: tbprintf("%15s", s->sn_value ? "On" : "Off");
1.1 deanna 235: break;
236: case SENSOR_INTEGER:
1.13 canacar 237: tbprintf("%11lld raw", s->sn_value);
1.1 deanna 238: break;
239: case SENSOR_PERCENT:
1.13 canacar 240: tbprintf("%14.2f%%", s->sn_value / 1000.0);
1.1 deanna 241: break;
242: case SENSOR_LUX:
1.13 canacar 243: tbprintf("%15.2f lx", s->sn_value / 1000000.0);
1.1 deanna 244: break;
245: case SENSOR_DRIVE:
1.13 canacar 246: if (0 < s->sn_value &&
1.15 okan 247: s->sn_value < nitems(drvstat)) {
1.13 canacar 248: tbprintf("%15s", drvstat[s->sn_value]);
1.1 deanna 249: break;
250: }
1.3 deraadt 251: break;
1.1 deanna 252: case SENSOR_TIMEDELTA:
1.13 canacar 253: tbprintf("%15s", fmttime(s->sn_value / 1000000000.0));
1.1 deanna 254: break;
255: case SENSOR_WATTHOUR:
1.13 canacar 256: tbprintf("%12.2f Wh", s->sn_value / 1000000.0);
1.1 deanna 257: break;
258: case SENSOR_AMPHOUR:
1.13 canacar 259: tbprintf("%10.2f Ah", s->sn_value / 1000000.0);
1.1 deanna 260: break;
261: default:
1.13 canacar 262: tbprintf("%10lld", s->sn_value);
1.3 deraadt 263: break;
1.1 deanna 264: }
1.2 deraadt 265:
1.13 canacar 266: print_fld_tb(FLD_SN_VALUE);
267:
268: switch (s->sn_status) {
1.8 deanna 269: case SENSOR_S_UNSPEC:
270: break;
1.1 deanna 271: case SENSOR_S_UNKNOWN:
1.13 canacar 272: print_fld_str(FLD_SN_STATUS, "unknown");
1.1 deanna 273: break;
274: case SENSOR_S_WARN:
1.13 canacar 275: print_fld_str(FLD_SN_STATUS, "WARNING");
1.1 deanna 276: break;
277: case SENSOR_S_CRIT:
1.13 canacar 278: print_fld_str(FLD_SN_STATUS, "CRITICAL");
1.1 deanna 279: break;
1.3 deraadt 280: case SENSOR_S_OK:
1.13 canacar 281: print_fld_str(FLD_SN_STATUS, "OK");
1.1 deanna 282: break;
283: }
1.13 canacar 284: end_line();
1.9 ckuethe 285: }
286:
287: #define SECS_PER_DAY 86400
288: #define SECS_PER_HOUR 3600
289: #define SECS_PER_MIN 60
290:
291: static char *
292: fmttime(double in)
293: {
294: int signbit = 1;
295: int tiny = 0;
296: char *unit;
297: #define LEN 32
298: static char outbuf[LEN];
299:
300: if (in < 0){
301: signbit = -1;
302: in *= -1;
303: }
304:
305: if (in >= SECS_PER_DAY ){
306: unit = "days";
307: in /= SECS_PER_DAY;
308: } else if (in >= SECS_PER_HOUR ){
309: unit = "hr";
310: in /= SECS_PER_HOUR;
311: } else if (in >= SECS_PER_MIN ){
312: unit = "min";
313: in /= SECS_PER_MIN;
314: } else if (in >= 1 ){
1.11 ckuethe 315: unit = "s";
1.9 ckuethe 316: /* in *= 1; */ /* no op */
1.10 ckuethe 317: } else if (in == 0 ){ /* direct comparisons to floats are scary */
1.11 ckuethe 318: unit = "s";
1.9 ckuethe 319: } else if (in >= 1e-3 ){
1.11 ckuethe 320: unit = "ms";
1.9 ckuethe 321: in *= 1e3;
322: } else if (in >= 1e-6 ){
1.11 ckuethe 323: unit = "us";
1.9 ckuethe 324: in *= 1e6;
325: } else if (in >= 1e-9 ){
1.11 ckuethe 326: unit = "ns";
1.9 ckuethe 327: in *= 1e9;
328: } else {
1.11 ckuethe 329: unit = "ps";
1.9 ckuethe 330: if (in < 1e-13)
331: tiny = 1;
332: in *= 1e12;
333: }
334:
335: snprintf(outbuf, LEN,
1.14 canacar 336: tiny ? "%s%f %s" : "%s%.3f %s",
1.9 ckuethe 337: signbit == -1 ? "-" : "", in, unit);
338:
339: return outbuf;
1.1 deanna 340: }