envstat.c revision 1.2 1 /* $NetBSD: envstat.c,v 1.2 2000/04/14 06:26:53 simonb Exp $ */
2
3 /*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Bill Squier.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #ifndef lint
41 __RCSID("$NetBSD: envstat.c,v 1.2 2000/04/14 06:26:53 simonb Exp $");
42 #endif
43
44 #include <fcntl.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49
50 #include <sys/envsys.h>
51 #include <sys/ioctl.h>
52
53 extern char *__progname;
54 const char E_CANTENUM[] = "envsys: cannot enumerate sensors\n";
55
56 int main __P((int, char **));
57 void listsensors __P((envsys_basic_info_t *, int));
58 int numsensors __P((int));
59 int fillsensors __P((int, envsys_tre_data_t *, envsys_basic_info_t *, int));
60 int longestname __P((envsys_basic_info_t *, int));
61 int marksensors __P((envsys_basic_info_t *, int *, char *, int));
62 int strtosnum __P((envsys_basic_info_t *, const char *, int));
63 void header __P((unsigned, int, envsys_basic_info_t *, const int * const,
64 int));
65 void values __P((unsigned, int, envsys_tre_data_t *, const int * const, int));
66 void usage __P((void));
67
68
69 int
70 main(argc, argv)
71 int argc;
72 char **argv;
73 {
74 int c, fd, ns, ls, celsius;
75 unsigned int interval, width, headrep, headcnt;
76 envsys_tre_data_t *etds;
77 envsys_basic_info_t *ebis;
78 int *cetds;
79 char *sensors;
80
81 fd = -1;
82 ls = 0;
83 celsius = 1;
84 interval = 0;
85 width = 0;
86 sensors = NULL;
87 headrep = 22;
88
89 while ((c = getopt(argc, argv, "cfi:ln:s:w:")) != -1) {
90 switch(c) {
91 case 'i': /* wait time between displays */
92 interval = atoi(optarg);
93 break;
94 case 'w': /* minimum column width */
95 width = atoi(optarg);
96 break;
97 case 'l': /* list sensor names */
98 ls = 1;
99 break;
100 case 'n': /* repeat header every headrep lines */
101 headrep = atoi(optarg);
102 break;
103 case 's': /* restrict display to named sensors */
104 sensors = (char *)malloc(strlen(optarg) + 1);
105 if (sensors == NULL)
106 exit(1);
107 strcpy(sensors, optarg);
108 break;
109 case 'f': /* display temp in degF */
110 celsius = 0;
111 break;
112 case '?':
113 default:
114 usage();
115 /* NOTREACHED */
116 }
117 }
118
119 if (optind < argc) {
120 if ((fd = open(argv[optind], O_RDONLY)) == -1) {
121 perror("envstat");
122 exit(1);
123 }
124 } else {
125 fprintf(stderr, "envstat: no device specified\n");
126 usage();
127 }
128
129
130 /*
131 * Determine number of sensors, allocate and fill arrays with
132 * initial information. Determine column width
133 */
134 if ((ns = numsensors(fd)) <= 0) {
135 fprintf(stderr, E_CANTENUM);
136 exit(1);
137 }
138
139 cetds = (int *)malloc(ns * sizeof(int));
140 etds = (envsys_tre_data_t *)malloc(ns * sizeof(envsys_tre_data_t));
141 ebis = (envsys_basic_info_t *)malloc(ns * sizeof(envsys_basic_info_t));
142
143 if ((cetds == NULL) || (etds == NULL) || (ebis == NULL)) {
144 fprintf(stderr, "envstat: cannot allocate memory\n");
145 exit(1);
146 }
147
148 if (fillsensors(fd, etds, ebis, ns) == -1) {
149 fprintf(stderr, E_CANTENUM);
150 exit(1);
151 }
152
153
154 if (ls) {
155 listsensors(ebis, ns);
156 exit(0);
157 }
158
159
160 #define MAX(x, y) (((x) > (y)) ? (x) : (y))
161 if (!width) {
162 width = longestname(ebis, ns);
163 width = MAX(((79 - ns) / ns), width);
164 }
165
166 /* Mark which sensor numbers are to be displayed */
167 if (marksensors(ebis, cetds, sensors, ns) == -1)
168 exit(1);
169
170 /* If we didn't specify an interval value, print the sensors once */
171 if (!interval) {
172 if (headrep)
173 header(width, celsius, ebis, cetds, ns);
174 values(width, celsius, etds, cetds, ns);
175
176 exit (0);
177 }
178
179 headcnt = 0;
180 if (headrep)
181 header(width, celsius, ebis, cetds, ns);
182
183 for (;;) {
184 values(width, celsius, etds, cetds, ns);
185 if (headrep && (++headcnt == headrep)) {
186 headcnt = 0;
187 header(width, celsius, ebis, cetds, ns);
188 }
189
190 sleep(interval);
191
192 if (fillsensors(fd, etds, ebis, ns) == -1) {
193 fprintf(stderr, E_CANTENUM);
194 exit(1);
195 }
196 }
197
198 /* NOTREACHED */
199 return (0);
200 }
201
202
203 static const char *unit_str[] = {"degC", "RPM", "VAC", "Vcc", "Ohms", "Watts",
204 "Amps", "Ukn"};
205
206 /*
207 * pre: cetds[i] != 0 iff sensor i should appear in the output
208 * post: a column header line is displayed on stdout
209 */
210 void
211 header(width, celsius, ebis, cetds, ns)
212 unsigned width;
213 int celsius;
214 envsys_basic_info_t *ebis;
215 const int * const cetds;
216 int ns;
217 {
218 int i;
219 const char *s;
220
221 /* sensor names */
222 for (i = 0; i < ns; ++i)
223 if (cetds[i])
224 printf(" %*.*s", (int)width, (int)width, ebis[i].desc);
225
226 printf("\n");
227
228 /* units */
229 for (i = 0; i < ns; ++i)
230 if (cetds[i]) {
231 if ((ebis[i].units == ENVSYS_STEMP) &&
232 !celsius)
233 s = "degF";
234 else if (ebis[i].units > 6)
235 s = unit_str[7];
236 else
237 s = unit_str[ebis[i].units];
238
239 printf(" %*.*s", (int)width, (int)width, s);
240 }
241 printf("\n");
242 }
243
244 void
245 values(width, celsius, etds, cetds, ns)
246 unsigned width;
247 int celsius;
248 envsys_tre_data_t *etds;
249 const int * const cetds;
250 int ns;
251 {
252 int i;
253 double temp;
254
255 for (i = 0; i < ns; ++i)
256 if (cetds[i]) {
257
258 /* * sensors without valid data */
259 if ((etds[i].validflags & ENVSYS_FCURVALID) == 0) {
260 printf(" %*.*s", (int)width, (int)width, "*");
261 continue;
262 }
263
264 switch(etds[i].units) {
265 case ENVSYS_STEMP:
266 temp = (etds[i].cur.data_us / 1000000.0) -
267 273.15;
268 if (!celsius)
269 temp = (9.0 / 5.0) * temp + 32.0;
270 printf(" %*.2f", width, temp);
271 break;
272 case ENVSYS_SFANRPM:
273 printf(" %*u", width, etds[i].cur.data_us);
274 break;
275 default:
276 printf(" %*.2f", width, etds[i].cur.data_s /
277 1000000.0);
278 break;
279 }
280 }
281 printf("\n");
282 }
283
284
285 /*
286 * post: displays usage on stderr
287 */
288 void
289 usage()
290 {
291 fprintf(stderr, "usage: %s [-c] [-s s1,s2,...]", __progname);
292 fprintf(stderr, " [-i interval] [-n headrep] [-w width] device\n");
293 fprintf(stderr, " envstat -l device\n");
294 exit(1);
295 }
296
297
298 /*
299 * post: a list of sensor names supported by the device is displayed on stdout
300 */
301 void
302 listsensors(ebis, ns)
303 envsys_basic_info_t *ebis;
304 int ns;
305 {
306 int i;
307
308 for (i = 0; i < ns; ++i)
309 if (ebis[i].validflags & ENVSYS_FVALID)
310 printf("%s\n", ebis[i].desc);
311 }
312
313
314 /*
315 * pre: fd contains a valid file descriptor of an envsys(4) supporting device
316 * post: returns the number of valid sensors provided by the device
317 * or -1 on error
318 */
319 int
320 numsensors(fd)
321 int fd;
322 {
323 int count = 0, valid = 1;
324 envsys_tre_data_t etd;
325 etd.sensor = 0;
326
327 while (valid) {
328 if (ioctl(fd, ENVSYS_GTREDATA, &etd) == -1) {
329 fprintf(stderr, E_CANTENUM);
330 exit(1);
331 }
332
333 valid = etd.validflags & ENVSYS_FVALID;
334 if (valid)
335 ++count;
336
337 ++etd.sensor;
338 }
339
340 return count;
341 }
342
343 /*
344 * pre: fd contains a valid file descriptor of an envsys(4) supporting device
345 * && ns is the number of sensors
346 * && etds and ebis are arrays of sufficient size
347 * post: returns 0 and etds and ebis arrays are filled with sensor info
348 * or returns -1 on failure
349 */
350 int
351 fillsensors(fd, etds, ebis, ns)
352 int fd;
353 envsys_tre_data_t *etds;
354 envsys_basic_info_t *ebis;
355 int ns;
356 {
357 int i;
358
359 for (i = 0; i < ns; ++i) {
360 ebis[i].sensor = i;
361 if (ioctl(fd, ENVSYS_GTREINFO, &ebis[i]) == -1)
362 return -1;
363
364 etds[i].sensor = i;
365 if (ioctl(fd, ENVSYS_GTREDATA, &etds[i]) == -1)
366 return -1;
367 }
368
369 return 0;
370 }
371
372
373 /*
374 * post: returns the strlen() of the longest sensor name
375 */
376 int
377 longestname(ebis, ns)
378 envsys_basic_info_t *ebis;
379 int ns;
380 {
381 int i, maxlen, cur;
382
383 maxlen = 0;
384
385 for (i = 0; i < ns; ++i) {
386 cur = strlen(ebis[i].desc);
387 if (cur > maxlen)
388 maxlen = cur;
389 }
390
391 return maxlen;
392 }
393
394 /*
395 * post: returns 0 and cetds[i] != 0 iff sensor i should appear in the output
396 * or returns -1
397 */
398 int
399 marksensors(ebis, cetds, sensors, ns)
400 envsys_basic_info_t *ebis;
401 int *cetds;
402 char *sensors;
403 int ns;
404 {
405 int i;
406 char *s;
407
408 if (sensors == NULL) {
409 /* No sensors specified, include them all */
410 for (i = 0; i < ns; ++i)
411 cetds[i] = 1;
412
413 return 0;
414 }
415
416 /* Assume no sensors in display */
417 memset(cetds, 0, ns * sizeof(int));
418
419 s = strtok(sensors, ",");
420 while (s != NULL) {
421 if ((i = strtosnum(ebis, s, ns)) != -1)
422 cetds[i] = 1;
423 else {
424 fprintf(stderr, "envstat: unknown sensor %s\n", s);
425 return (-1);
426 }
427
428 s = strtok(NULL, ",");
429 }
430
431 /* Check if we have at least one sensor selected for output */
432 for (i = 0; i < ns; ++i)
433 if (cetds[i] == 1)
434 return (0);
435
436 fprintf(stderr, "envstat: no sensors selected for display\n");
437 return (-1);
438 }
439
440
441 /*
442 * returns -1 if s is not a valid sensor name for the device
443 * or the sensor number of a sensor which has that name
444 */
445 int
446 strtosnum(ebis, s, ns)
447 envsys_basic_info_t *ebis;
448 const char *s;
449 int ns;
450 {
451 int i;
452
453 for (i = 0; i < ns; ++i) {
454 if((ebis[i].validflags & ENVSYS_FVALID) &&
455 !strcmp(s, ebis[i].desc))
456 return ebis[i].sensor;
457 }
458
459 return -1;
460 }
461