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