envstat.c revision 1.1 1 /* $NetBSD: envstat.c,v 1.1 2000/03/10 05:51:58 groo 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.1 2000/03/10 05:51:58 groo 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 extern int optind;
75 extern char *optarg;
76 int c, fd, ns, ls, celsius;
77 unsigned int interval, width, headrep, headcnt;
78 envsys_tre_data_t *etds;
79 envsys_basic_info_t *ebis;
80 int *cetds;
81 char *sensors;
82
83 fd = -1;
84 ls = 0;
85 celsius = 1;
86 interval = 0;
87 width = 0;
88 sensors = NULL;
89 headrep = 22;
90
91 while ((c = getopt(argc, argv, "cfi:ln:s:w:")) != -1) {
92 switch(c) {
93 case 'i': /* wait time between displays */
94 interval = atoi(optarg);
95 break;
96 case 'w': /* minimum column width */
97 width = atoi(optarg);
98 break;
99 case 'l': /* list sensor names */
100 ls = 1;
101 break;
102 case 'n': /* repeat header every headrep lines */
103 headrep = atoi(optarg);
104 break;
105 case 's': /* restrict display to named sensors */
106 sensors = (char *)malloc(strlen(optarg) + 1);
107 if (sensors == NULL)
108 exit(1);
109 strcpy(sensors, optarg);
110 break;
111 case 'f': /* display temp in degF */
112 celsius = 0;
113 break;
114 case '?':
115 default:
116 usage();
117 /* NOTREACHED */
118 }
119 }
120
121 if (optind < argc) {
122 if ((fd = open(argv[optind], O_RDONLY)) == -1) {
123 perror("envstat");
124 exit(1);
125 }
126 } else {
127 fprintf(stderr, "envstat: no device specified\n");
128 usage();
129 }
130
131
132 /*
133 * Determine number of sensors, allocate and fill arrays with
134 * initial information. Determine column width
135 */
136 if ((ns = numsensors(fd)) <= 0) {
137 fprintf(stderr, E_CANTENUM);
138 exit(1);
139 }
140
141 cetds = (int *)malloc(ns * sizeof(int));
142 etds = (envsys_tre_data_t *)malloc(ns * sizeof(envsys_tre_data_t));
143 ebis = (envsys_basic_info_t *)malloc(ns * sizeof(envsys_basic_info_t));
144
145 if ((cetds == NULL) || (etds == NULL) || (ebis == NULL)) {
146 fprintf(stderr, "envstat: cannot allocate memory\n");
147 exit(1);
148 }
149
150 if (fillsensors(fd, etds, ebis, ns) == -1) {
151 fprintf(stderr, E_CANTENUM);
152 exit(1);
153 }
154
155
156 if (ls) {
157 listsensors(ebis, ns);
158 exit(0);
159 }
160
161
162 #define MAX(x, y) (((x) > (y)) ? (x) : (y))
163 if (!width) {
164 width = longestname(ebis, ns);
165 width = MAX(((79 - ns) / ns), width);
166 }
167
168 /* Mark which sensor numbers are to be displayed */
169 if (marksensors(ebis, cetds, sensors, ns) == -1)
170 exit(1);
171
172 /* If we didn't specify an interval value, print the sensors once */
173 if (!interval) {
174 if (headrep)
175 header(width, celsius, ebis, cetds, ns);
176 values(width, celsius, etds, cetds, ns);
177
178 exit (0);
179 }
180
181 headcnt = 0;
182 if (headrep)
183 header(width, celsius, ebis, cetds, ns);
184
185 for (;;) {
186 values(width, celsius, etds, cetds, ns);
187 if (headrep && (++headcnt == headrep)) {
188 headcnt = 0;
189 header(width, celsius, ebis, cetds, ns);
190 }
191
192 sleep(interval);
193
194 if (fillsensors(fd, etds, ebis, ns) == -1) {
195 fprintf(stderr, E_CANTENUM);
196 exit(1);
197 }
198 }
199
200 /* NOTREACHED */
201 return (0);
202 }
203
204
205 static const char *unit_str[] = {"degC", "RPM", "VAC", "Vcc", "Ohms", "Watts",
206 "Amps", "Ukn"};
207
208 /*
209 * pre: cetds[i] != 0 iff sensor i should appear in the output
210 * post: a column header line is displayed on stdout
211 */
212 void
213 header(width, celsius, ebis, cetds, ns)
214 unsigned width;
215 int celsius;
216 envsys_basic_info_t *ebis;
217 const int * const cetds;
218 int ns;
219 {
220 int i;
221 const char *s;
222
223 /* sensor names */
224 for (i = 0; i < ns; ++i)
225 if (cetds[i])
226 printf(" %*.*s", (int)width, (int)width, ebis[i].desc);
227
228 printf("\n");
229
230 /* units */
231 for (i = 0; i < ns; ++i)
232 if (cetds[i]) {
233 if ((ebis[i].units == ENVSYS_STEMP) &&
234 !celsius)
235 s = "degF";
236 else if (ebis[i].units > 6)
237 s = unit_str[7];
238 else
239 s = unit_str[ebis[i].units];
240
241 printf(" %*.*s", (int)width, (int)width, s);
242 }
243 printf("\n");
244 }
245
246 void
247 values(width, celsius, etds, cetds, ns)
248 unsigned width;
249 int celsius;
250 envsys_tre_data_t *etds;
251 const int * const cetds;
252 int ns;
253 {
254 int i;
255 double temp;
256
257 for (i = 0; i < ns; ++i)
258 if (cetds[i]) {
259
260 /* * sensors without valid data */
261 if ((etds[i].validflags & ENVSYS_FCURVALID) == 0) {
262 printf(" %*.*s", (int)width, (int)width, "*");
263 continue;
264 }
265
266 switch(etds[i].units) {
267 case ENVSYS_STEMP:
268 temp = (etds[i].cur.data_us / 1000000.0) -
269 273.15;
270 if (!celsius)
271 temp = (9.0 / 5.0) * temp + 32.0;
272 printf(" %*.2f", width, temp);
273 break;
274 case ENVSYS_SFANRPM:
275 printf(" %*u", width, etds[i].cur.data_us);
276 break;
277 default:
278 printf(" %*.2f", width, etds[i].cur.data_s /
279 1000000.0);
280 break;
281 }
282 }
283 printf("\n");
284 }
285
286
287 /*
288 * post: displays usage on stderr
289 */
290 void
291 usage()
292 {
293 fprintf(stderr, "usage: %s [-c] [-s s1,s2,...]", __progname);
294 fprintf(stderr, " [-i interval] [-n headrep] [-w width] device\n");
295 fprintf(stderr, " envstat -l device\n");
296 exit(1);
297 }
298
299
300 /*
301 * post: a list of sensor names supported by the device is displayed on stdout
302 */
303 void
304 listsensors(ebis, ns)
305 envsys_basic_info_t *ebis;
306 int ns;
307 {
308 int i;
309
310 for (i = 0; i < ns; ++i)
311 if (ebis[i].validflags & ENVSYS_FVALID)
312 printf("%s\n", ebis[i].desc);
313 }
314
315
316 /*
317 * pre: fd contains a valid file descriptor of an envsys(4) supporting device
318 * post: returns the number of valid sensors provided by the device
319 * or -1 on error
320 */
321 int
322 numsensors(fd)
323 int fd;
324 {
325 int count = 0, valid = 1;
326 envsys_tre_data_t etd;
327 etd.sensor = 0;
328
329 while (valid) {
330 if (ioctl(fd, ENVSYS_GTREDATA, &etd) == -1) {
331 fprintf(stderr, E_CANTENUM);
332 exit(1);
333 }
334
335 valid = etd.validflags & ENVSYS_FVALID;
336 if (valid)
337 ++count;
338
339 ++etd.sensor;
340 }
341
342 return count;
343 }
344
345 /*
346 * pre: fd contains a valid file descriptor of an envsys(4) supporting device
347 * && ns is the number of sensors
348 * && etds and ebis are arrays of sufficient size
349 * post: returns 0 and etds and ebis arrays are filled with sensor info
350 * or returns -1 on failure
351 */
352 int
353 fillsensors(fd, etds, ebis, ns)
354 int fd;
355 envsys_tre_data_t *etds;
356 envsys_basic_info_t *ebis;
357 int ns;
358 {
359 int i;
360
361 for (i = 0; i < ns; ++i) {
362 ebis[i].sensor = i;
363 if (ioctl(fd, ENVSYS_GTREINFO, &ebis[i]) == -1)
364 return -1;
365
366 etds[i].sensor = i;
367 if (ioctl(fd, ENVSYS_GTREDATA, &etds[i]) == -1)
368 return -1;
369 }
370
371 return 0;
372 }
373
374
375 /*
376 * post: returns the strlen() of the longest sensor name
377 */
378 int
379 longestname(ebis, ns)
380 envsys_basic_info_t *ebis;
381 int ns;
382 {
383 int i, maxlen, cur;
384
385 maxlen = 0;
386
387 for (i = 0; i < ns; ++i) {
388 cur = strlen(ebis[i].desc);
389 if (cur > maxlen)
390 maxlen = cur;
391 }
392
393 return maxlen;
394 }
395
396 /*
397 * post: returns 0 and cetds[i] != 0 iff sensor i should appear in the output
398 * or returns -1
399 */
400 int
401 marksensors(ebis, cetds, sensors, ns)
402 envsys_basic_info_t *ebis;
403 int *cetds;
404 char *sensors;
405 int ns;
406 {
407 int i;
408 char *s;
409
410 if (sensors == NULL) {
411 /* No sensors specified, include them all */
412 for (i = 0; i < ns; ++i)
413 cetds[i] = 1;
414
415 return 0;
416 }
417
418 /* Assume no sensors in display */
419 memset(cetds, 0, ns * sizeof(int));
420
421 s = strtok(sensors, ",");
422 while (s != NULL) {
423 if ((i = strtosnum(ebis, s, ns)) != -1)
424 cetds[i] = 1;
425 else {
426 fprintf(stderr, "envstat: unknown sensor %s\n", s);
427 return (-1);
428 }
429
430 s = strtok(NULL, ",");
431 }
432
433 /* Check if we have at least one sensor selected for output */
434 for (i = 0; i < ns; ++i)
435 if (cetds[i] == 1)
436 return (0);
437
438 fprintf(stderr, "envstat: no sensors selected for display\n");
439 return (-1);
440 }
441
442
443 /*
444 * returns -1 if s is not a valid sensor name for the device
445 * or the sensor number of a sensor which has that name
446 */
447 int
448 strtosnum(ebis, s, ns)
449 envsys_basic_info_t *ebis;
450 const char *s;
451 int ns;
452 {
453 int i;
454
455 for (i = 0; i < ns; ++i) {
456 if((ebis[i].validflags & ENVSYS_FVALID) &&
457 !strcmp(s, ebis[i].desc))
458 return ebis[i].sensor;
459 }
460
461 return -1;
462 }
463