495 lines
11 KiB
C
495 lines
11 KiB
C
/* $NetBSD: envstat.c,v 1.13 2003/02/21 07:23:43 martin Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Bill Squier.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the NetBSD
|
|
* Foundation, Inc. and its contributors.
|
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
#ifndef lint
|
|
__RCSID("$NetBSD: envstat.c,v 1.13 2003/02/21 07:23:43 martin Exp $");
|
|
#endif
|
|
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <err.h>
|
|
#include <paths.h>
|
|
|
|
#define ENVSYSUNITNAMES
|
|
#include <sys/envsys.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
int main(int, char **);
|
|
void listsensors(envsys_basic_info_t *, size_t);
|
|
size_t numsensors(int);
|
|
void fillsensors(int, envsys_tre_data_t *, envsys_basic_info_t *, size_t);
|
|
size_t longestname(envsys_basic_info_t *, size_t);
|
|
int marksensors(envsys_basic_info_t *, int *, char *, size_t);
|
|
int strtosnum(envsys_basic_info_t *, const char *, size_t);
|
|
void header(size_t, int, envsys_basic_info_t *, const int * const, size_t);
|
|
void values(size_t, int, envsys_tre_data_t *, const int * const, size_t);
|
|
void usage(void);
|
|
|
|
int rflag = 0;
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
int c, fd, ls, celsius;
|
|
size_t ns;
|
|
size_t interval, width, headrep, headcnt;
|
|
envsys_tre_data_t *etds;
|
|
envsys_basic_info_t *ebis;
|
|
int *cetds;
|
|
char *sensors;
|
|
const char *dev;
|
|
|
|
fd = -1;
|
|
ls = 0;
|
|
celsius = 1;
|
|
interval = 0;
|
|
width = 0;
|
|
sensors = NULL;
|
|
headrep = 22;
|
|
|
|
while ((c = getopt(argc, argv, "cfi:ln:rs:w:r")) != -1) {
|
|
switch(c) {
|
|
case 'r':
|
|
rflag= 1;
|
|
break;
|
|
case 'i': /* wait time between displays */
|
|
interval = atoi(optarg);
|
|
break;
|
|
case 'w': /* minimum column width */
|
|
width = atoi(optarg);
|
|
break;
|
|
case 'l': /* list sensor names */
|
|
ls = 1;
|
|
break;
|
|
case 'n': /* repeat header every headrep lines */
|
|
headrep = atoi(optarg);
|
|
break;
|
|
case 's': /* restrict display to named sensors */
|
|
sensors = (char *)malloc(strlen(optarg) + 1);
|
|
if (sensors == NULL)
|
|
exit(1);
|
|
strcpy(sensors, optarg);
|
|
break;
|
|
case 'f': /* display temp in degF */
|
|
celsius = 0;
|
|
break;
|
|
case '?':
|
|
default:
|
|
usage();
|
|
/* NOTREACHED */
|
|
}
|
|
}
|
|
|
|
if (optind < argc)
|
|
dev = argv[optind];
|
|
else
|
|
dev = _PATH_SYSMON;
|
|
|
|
if ((fd = open(dev, O_RDONLY)) == -1)
|
|
err(1, "unable to open %s", dev);
|
|
|
|
/*
|
|
* Determine number of sensors, allocate and fill arrays with
|
|
* initial information. Determine column width
|
|
*/
|
|
if ((ns = numsensors(fd)) == 0)
|
|
errx(1, "No sensors found");
|
|
|
|
cetds = (int *)malloc(ns * sizeof(int));
|
|
etds = (envsys_tre_data_t *)malloc(ns * sizeof(envsys_tre_data_t));
|
|
ebis = (envsys_basic_info_t *)malloc(ns * sizeof(envsys_basic_info_t));
|
|
|
|
if ((cetds == NULL) || (etds == NULL) || (ebis == NULL))
|
|
err(1, "Out of memory");
|
|
|
|
fillsensors(fd, etds, ebis, ns);
|
|
|
|
if (ls) {
|
|
listsensors(ebis, ns);
|
|
exit(0);
|
|
}
|
|
|
|
|
|
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
|
if (!width) {
|
|
width = longestname(ebis, ns);
|
|
width = MAX(((79 - ns) / ns), width);
|
|
}
|
|
|
|
/* Mark which sensor numbers are to be displayed */
|
|
if (marksensors(ebis, cetds, sensors, ns) == -1)
|
|
exit(1);
|
|
|
|
if (rflag) {
|
|
int i;
|
|
|
|
for (i = 0 ; i < ns ; i++) {
|
|
if (ebis[i].units == ENVSYS_INDICATOR) {
|
|
if (etds[i].cur.data_s) {
|
|
printf("%*.*s\n",
|
|
(int)width,
|
|
(int)width,
|
|
ebis[i].desc);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (ebis[i].units == ENVSYS_INTEGER) {
|
|
printf("%*.*s:", (int)width, (int)width,
|
|
ebis[i].desc);
|
|
printf(" %10d\n", etds[i].cur.data_s);
|
|
continue;
|
|
}
|
|
|
|
printf("%*.*s:", (int)width, (int)width, ebis[i].desc);
|
|
/* different units need some magic */
|
|
switch (ebis[i].units)
|
|
{
|
|
case ENVSYS_INDICATOR:
|
|
printf(" %10s", etds[i].cur.data_us ?
|
|
"ON" : "OFF");
|
|
break;
|
|
case ENVSYS_STEMP:
|
|
{
|
|
double temp =
|
|
(etds[i].cur.data_s / 1000000.0)
|
|
- 273.15;
|
|
if (celsius)
|
|
printf(" %10.3f degC",
|
|
temp);
|
|
else
|
|
{
|
|
temp = (9.0 / 5.0) * temp + 32.0;
|
|
printf(" %10.3f degF",
|
|
temp);
|
|
}
|
|
}
|
|
break;
|
|
case ENVSYS_SFANRPM:
|
|
printf(" %10u RPM",
|
|
etds[i].cur.data_us);
|
|
break;
|
|
default:
|
|
printf(" %10.3f %s",
|
|
etds[i].cur.data_s / 1000000.0,
|
|
envsysunitnames[ebis[i].units]);
|
|
break;
|
|
}
|
|
if (etds[i].validflags & ENVSYS_FFRACVALID) {
|
|
printf(" (%5.2f%%)",
|
|
(etds[i].cur.data_s * 100.0) /
|
|
etds[i].max.data_s);
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
|
|
|
|
/* If we didn't specify an interval value, print the sensors once */
|
|
if (!interval) {
|
|
if (headrep)
|
|
header(width, celsius, ebis, cetds, ns);
|
|
values(width, celsius, etds, cetds, ns);
|
|
|
|
exit (0);
|
|
}
|
|
|
|
headcnt = 0;
|
|
if (headrep)
|
|
header(width, celsius, ebis, cetds, ns);
|
|
|
|
for (;;) {
|
|
values(width, celsius, etds, cetds, ns);
|
|
if (headrep && (++headcnt == headrep)) {
|
|
headcnt = 0;
|
|
header(width, celsius, ebis, cetds, ns);
|
|
}
|
|
|
|
sleep(interval);
|
|
|
|
fillsensors(fd, etds, ebis, ns);
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
* pre: cetds[i] != 0 iff sensor i should appear in the output
|
|
* post: a column header line is displayed on stdout
|
|
*/
|
|
void
|
|
header(size_t width, int celsius, envsys_basic_info_t *ebis,
|
|
const int * const cetds, size_t ns)
|
|
{
|
|
int i;
|
|
const char *s;
|
|
|
|
/* sensor names */
|
|
for (i = 0; i < ns; ++i)
|
|
if (cetds[i])
|
|
printf(" %*.*s", (int)width, (int)width, ebis[i].desc);
|
|
|
|
printf("\n");
|
|
|
|
/* units */
|
|
for (i = 0; i < ns; ++i)
|
|
if (cetds[i]) {
|
|
if ((ebis[i].units == ENVSYS_STEMP) &&
|
|
!celsius)
|
|
s = "degF";
|
|
else if (ebis[i].units >= ENVSYS_NSENSORS)
|
|
s = envsysunitnames[ENVSYS_NSENSORS];
|
|
else
|
|
s = envsysunitnames[ebis[i].units];
|
|
|
|
printf(" %*.*s", (int)width, (int)width, s);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
void
|
|
values(size_t width, int celsius, envsys_tre_data_t *etds,
|
|
const int * const cetds, size_t ns)
|
|
{
|
|
int i;
|
|
double temp;
|
|
|
|
for (i = 0; i < ns; ++i)
|
|
if (cetds[i]) {
|
|
|
|
/* * sensors without valid data */
|
|
if ((etds[i].validflags & ENVSYS_FCURVALID) == 0) {
|
|
printf(" %*.*s", (int)width, (int)width, "*");
|
|
continue;
|
|
}
|
|
|
|
switch(etds[i].units) {
|
|
case ENVSYS_INDICATOR:
|
|
printf(" %*.*s", (int)width, (int)width,
|
|
etds[i].cur.data_us ? "ON" : "OFF");
|
|
break;
|
|
case ENVSYS_STEMP:
|
|
temp = (etds[i].cur.data_us / 1000000.0) -
|
|
273.15;
|
|
if (!celsius)
|
|
temp = (9.0 / 5.0) * temp + 32.0;
|
|
printf(" %*.2f", (int)width, temp);
|
|
break;
|
|
case ENVSYS_SFANRPM:
|
|
printf(" %*u", (int)width, etds[i].cur.data_us);
|
|
break;
|
|
default:
|
|
printf(" %*.2f", (int)width, etds[i].cur.data_s /
|
|
1000000.0);
|
|
break;
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
/*
|
|
* post: displays usage on stderr
|
|
*/
|
|
void
|
|
usage(void)
|
|
{
|
|
|
|
(void)fprintf(stderr, "Usage: %s [-cr] [-s s1,s2,...]", getprogname());
|
|
(void)fprintf(stderr, " [-i interval] [-n headrep] [-w width]");
|
|
(void)fprintf(stderr, " [device]\n");
|
|
(void)fprintf(stderr, " %s -l [device]\n", getprogname());
|
|
exit(1);
|
|
}
|
|
|
|
|
|
/*
|
|
* post: a list of sensor names supported by the device is displayed on stdout
|
|
*/
|
|
void
|
|
listsensors(envsys_basic_info_t *ebis, size_t ns)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ns; ++i)
|
|
if (ebis[i].validflags & ENVSYS_FVALID)
|
|
printf("%s\n", ebis[i].desc);
|
|
}
|
|
|
|
|
|
/*
|
|
* pre: fd contains a valid file descriptor of an envsys(4) supporting device
|
|
* post: returns the number of valid sensors provided by the device
|
|
* or -1 on error
|
|
*/
|
|
size_t
|
|
numsensors(int fd)
|
|
{
|
|
int count = 0, valid = 1;
|
|
envsys_tre_data_t etd;
|
|
etd.sensor = 0;
|
|
|
|
while (valid) {
|
|
if (ioctl(fd, ENVSYS_GTREDATA, &etd) == -1)
|
|
err(1, "Can't get sensor data");
|
|
|
|
valid = etd.validflags & ENVSYS_FVALID;
|
|
if (valid)
|
|
++count;
|
|
|
|
++etd.sensor;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/*
|
|
* pre: fd contains a valid file descriptor of an envsys(4) supporting device
|
|
* && ns is the number of sensors
|
|
* && etds and ebis are arrays of sufficient size
|
|
* post: returns 0 and etds and ebis arrays are filled with sensor info
|
|
* or returns -1 on failure
|
|
*/
|
|
void
|
|
fillsensors(int fd, envsys_tre_data_t *etds, envsys_basic_info_t *ebis,
|
|
size_t ns)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ns; ++i) {
|
|
ebis[i].sensor = i;
|
|
if (ioctl(fd, ENVSYS_GTREINFO, &ebis[i]) == -1)
|
|
err(1, "Can't get sensor info for sensor %d", i);
|
|
|
|
etds[i].sensor = i;
|
|
if (ioctl(fd, ENVSYS_GTREDATA, &etds[i]) == -1)
|
|
err(1, "Can't get sensor data for sensor %d", i);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* post: returns the strlen() of the longest sensor name
|
|
*/
|
|
size_t
|
|
longestname(envsys_basic_info_t *ebis, size_t ns)
|
|
{
|
|
size_t i, maxlen, cur;
|
|
|
|
maxlen = 0;
|
|
|
|
for (i = 0; i < ns; ++i) {
|
|
cur = strlen(ebis[i].desc);
|
|
if (cur > maxlen)
|
|
maxlen = cur;
|
|
}
|
|
|
|
return maxlen;
|
|
}
|
|
|
|
/*
|
|
* post: returns 0 and cetds[i] != 0 iff sensor i should appear in the output
|
|
* or returns -1
|
|
*/
|
|
int
|
|
marksensors(envsys_basic_info_t *ebis, int *cetds, char *sensors, size_t ns)
|
|
{
|
|
size_t i;
|
|
char *s;
|
|
|
|
if (sensors == NULL) {
|
|
/* No sensors specified, include them all */
|
|
for (i = 0; i < ns; ++i)
|
|
cetds[i] = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Assume no sensors in display */
|
|
memset(cetds, 0, ns * sizeof(int));
|
|
|
|
s = strtok(sensors, ",");
|
|
while (s != NULL) {
|
|
int snum;
|
|
if ((snum = strtosnum(ebis, s, ns)) != -1)
|
|
cetds[snum] = 1;
|
|
else {
|
|
warnx("Unknown sensor %s", s);
|
|
return (-1);
|
|
}
|
|
|
|
s = strtok(NULL, ",");
|
|
}
|
|
|
|
/* Check if we have at least one sensor selected for output */
|
|
for (i = 0; i < ns; ++i)
|
|
if (cetds[i] == 1)
|
|
return (0);
|
|
|
|
warnx("No sensors selected for display");
|
|
return (-1);
|
|
}
|
|
|
|
|
|
/*
|
|
* returns -1 if s is not a valid sensor name for the device
|
|
* or the sensor number of a sensor which has that name
|
|
*/
|
|
int
|
|
strtosnum(envsys_basic_info_t *ebis, const char *s, size_t ns)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < ns; ++i) {
|
|
if((ebis[i].validflags & ENVSYS_FVALID) &&
|
|
!strcmp(s, ebis[i].desc))
|
|
return ebis[i].sensor;
|
|
}
|
|
|
|
return -1;
|
|
}
|