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