summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorxtraeme <xtraeme@NetBSD.org>2007-07-01 07:39:45 +0000
committerxtraeme <xtraeme@NetBSD.org>2007-07-01 07:39:45 +0000
commitaf211bb4e3c79fdc4e4644b7acb8564151316a4d (patch)
treebc4250211dd14debde531558d27682404fe1b757 /usr.sbin
parentda3f163bd280223c1d17fd1ff78946be2df177b8 (diff)
Imported envsys 2, a brief description of the new features:
(Part 3: userland) * Support for detachable sensors. * Cleaned up the API for simplicity and efficiency. * Ability to send capacity/critical/warning events to powerd(8). * Adapted all the code to the new locking order. * Compatibility with the old envsys API: the ENVSYS_GTREINFO and ENVSYS_GTREDATA ioctl(2)s are supported. * Added support for a 'dictionary based communication channel' between sysmon_power(9) and powerd(8), that means there is no 32 bytes event size restriction anymore. * Binary compatibility with old envstat(8) and powerd(8) via COMPAT_40. * All drivers with the n^2 gtredata bug were fixed, PR kern/36226. Tested by: blymn: smsc(4). bouyer: ipmi(4), mfi(4). kefren: ug(4). njoly: viaenv(4), adt7463.c. riz: owtemp(4). xtraeme: acpiacad(4), acpibat(4), acpitz(4), aiboost(4), it(4), lm(4).
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/envstat/Makefile10
-rw-r--r--usr.sbin/envstat/envstat.8310
-rw-r--r--usr.sbin/envstat/envstat.c1118
-rw-r--r--usr.sbin/powerd/Makefile6
-rw-r--r--usr.sbin/powerd/powerd.883
-rw-r--r--usr.sbin/powerd/powerd.c104
6 files changed, 1153 insertions, 478 deletions
diff --git a/usr.sbin/envstat/Makefile b/usr.sbin/envstat/Makefile
index 7bba8ba5498..463ae6919f8 100644
--- a/usr.sbin/envstat/Makefile
+++ b/usr.sbin/envstat/Makefile
@@ -1,7 +1,11 @@
-# $NetBSD: Makefile,v 1.1 2000/03/10 05:51:57 groo Exp $
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $NetBSD: Makefile,v 1.2 2007/07/01 07:39:45 xtraeme Exp $
PROG= envstat
-MAN= envstat.8
+
+LDADD= -lprop
+DPADD= ${LIBPROP}
+
+MAN= ${PROG}.8
+WARNS= 4
.include <bsd.prog.mk>
diff --git a/usr.sbin/envstat/envstat.8 b/usr.sbin/envstat/envstat.8
index 227c66b3549..5bdee4fb66f 100644
--- a/usr.sbin/envstat/envstat.8
+++ b/usr.sbin/envstat/envstat.8
@@ -1,10 +1,10 @@
-.\" $NetBSD: envstat.8,v 1.15 2007/05/07 11:01:28 xtraeme Exp $
+.\" $NetBSD: envstat.8,v 1.16 2007/07/01 07:39:46 xtraeme Exp $
.\"
-.\" Copyright (c) 2000 The NetBSD Foundation, Inc.
+.\" Copyright (c) 2000, 2007 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
-.\" by Bill Squier.
+.\" by Juan Romero Pardines and Bill Squier.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -34,40 +34,52 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd May 7, 2007
+.Dd June 15, 2007
.Dt ENVSTAT 8
.Os
.Sh NAME
.Nm envstat
-.Nd display environmental sensor readings
+.Nd utility to handle environmental sensors
.Sh SYNOPSIS
.Nm
-.Op Fl flr
+.Op Fl Dflx
+.Op Fl d Ar device
.Op Fl i Ar interval
-.Op Fl n Ar headrep
+.Op Fl m Ar critical=... critmax=... critmin=... desc=... rfact=...
.Op Fl s Ar sensor1,sensor2,...
.Op Fl w Ar width
-.Op Ar device
.Sh DESCRIPTION
.Nm
-displays sensor readings from any device which supports the
+is a utility that handles various aspects of the sensors
+registered with the
.Xr envsys 4
-API.
-Readings are displayed in columns, one column per sensor.
-Column widths as well as displayed sensors are fully customizable.
-The column headers display the name (stored in the device driver) as
-well as the units of each sensor.
+framework.
+It is capable of displaying sensor values as well as
+changing parameters and setting critical limits for the sensors.
.Pp
-The options are as follows:
+In display mode, column widths as well as displayed sensors
+are fully customizable.
+Critical limits can be set in a per-sensor basis.
+If critical limits were set previously, the display mode will show
+the critical limits in addition to the current values.
+.Pp
+The following options are available:
.Bl -tag -width flag
+.It Fl D
+Display the names of the drivers that were registered with
+the
+.Xr envsys 4
+framework, one per line.
+.It Fl d
+Display only the sensors for a given
+.Ar driver .
+This is useful when there are multiple drivers registered and
+you want to only see those from a specific driver.
.It Fl f
-Display any temperature values in degrees Fahrenheit.
+Display temperature values in degrees Fahrenheit.
The default is to display temperature values in degrees Celsius.
-.It Fl l
-List the names of all supported sensors, one per line.
-Use of this flag causes
-.Nm
-to ignore all other option flags.
+When changing properties on a sensor and this flag is specified,
+the value provided must be in degress Fahrenheit too.
.It Fl i
Repeat the display every
.Ar interval
@@ -78,17 +90,23 @@ See the individual device's manual page for meaningful values for
If not specified, or specified as 0,
.Nm
produces one line of values and exits.
-.It Fl n
-Display a new header every
-.Ar headrep
-lines.
-An argument of 0 disables header line printing completely.
-The default is every 22 lines.
-.It Fl r
-Display the sensors row wise.
-This is useful when the number of sensors is large.
-This option also displays fractional values when present
-(e.g., the percentage battery charge).
+.It Fl l
+List the names of all supported sensors, one per line.
+Use of this flag causes
+.Nm
+to ignore all other option flags.
+.It Fl m
+This flag can be used to change a description of a sensor, to
+change the rfact (resistor factor) in a voltage sensor or
+to set critical capacity for (battery sensors) and critical
+min and max limits (for all supported sensors).
+Recognized keywords are:
+.Ar critical , critmax , critmin , desc ,
+and
+.Ar rfact .
+See the
+.Sx EXAMPLES
+section for more information.
.It Fl s
Restrict the display to the named sensors.
The sensor names must be supplied as a comma separated list.
@@ -98,15 +116,218 @@ Use
.Ar width
as the column width for the output.
Each column is additionally separated by a single space.
-The default is either the length of the longest sensor
-name or spread evenly to fill 80 columns, whichever is greater.
+The default is the length of the longest sensor name.
+.It Fl x
+Shows the property list used by the
+.Xr sysmon_envsys 9
+framework that contains details about all registered drivers
+and sensors.
.El
+.Ss CRITICAL LIMITS
+Starting with
+.Tn envsys 2 ,
+it is possible to set critical limits on a specified sensor.
+Only one critical limit can be set at a time for a sensor.
+For example, you cannot assign multiple limits for the same
+sensor or for different sensors.
+.Pp
+There are three types of
+critical limits:
+.Ar capacity ,
+.Ar max ,
+and
+.Ar min .
+When one of them is set and sensor's current value reaches
+it, an event will be sent to
+.Xr powerd 8 .
+.Pp
+Three arguments are required to set/remove a critical/capacity limit,
+to change a description or to change the rfact:
+.Pp
+.Bl -item -offset indent -compact
+.It
+.Fl d
+is required to specify the device that is handling
+the sensor.
+.It
+.Fl m
+is required to set the new target mode.
+.It
+.Fl s
+is required to specify sensor's name.
+.El
+.Pp
+The available targets for the
+.Fl m
+flag are:
+.Pp
+.Bl -bullet -compact -offset indent
+.It
+.Ar critical
+accepts a percentage number for battery sensors (those showing
+a percentage in display mode), also the
+.Sy remove
+keyword can be used to remove the limit.
+.It
+.Ar critmax
+accepts a number that will be used for the max critical limit
+or accepts the
+.Sy remove
+keyword.
+.It
+.Ar critmin
+accepts a number that will be used for the min critical limit
+or accepts the
+.Sy remove
+keyword.
+.It
+.Ar desc
+accepts a new string that will be used as new description.
+.It
+.Ar rfact
+accepts a number that will be used as new rfact in voltage sensors.
+.El
+.Pp
+Also is possible to remove a critical limit if one was set before,
+with the
+.Ar remove
+keyword passed to the
+.Ar critical ,
+.Ar critmax ,
+or
+.Ar critmin
+target.
+See the
+.Sx EXAMPLES
+for information how to use it.
+.Pp
+.Ss CONFIGURATION FILE
+It's possible to change properties with the
+.Pa /etc/envsys.conf
+configuration file. The syntax for this file is the following:
+.Bd -literal
+device:sensor name:target:value
+
+aiboost0:CPU Temperature:critmax:70
+lm0:Temp0:desc:CPU Temperature
+smsc0:+3.3V:rfact:56000
+.Ed
+.Pp
+In the example configuration file the first argument is the name of
+the device, second argument is the name of the sensor that we want to change,
+third argument is the target that will be used for the
+.Ar -m
+flag and finally the four arguments in the value that will be used for the
+target.
+.Pp
+The first example sets a critical over limit of
+.Dq 70
+degC to the
+.Dq CPU Temperature
+sensor in the
+.Dq aiboost0
+device. By default the value specified on temperature sensors must be
+in degrees Celsius but also is possible to specify it in degrees Fahrenheit too.
+The
+.Em value
+argument will have to contain the
+.Dq degF
+keyword:
+.Bd -literal
+aiboost0:CPU Temperature:critmax:120degF
+.Ed
+.Pp
+The second example in the configuration file sets the description
+.Dq CPU Temperature
+to the sensor
+.Dq Temp0
+in the
+.Dq lm0
+device.
+.Pp
+The last example in the configuration file sets the rfact value to
+.Em 56000
+to the
+.Dq +3.3V
+sensor in the
+.Dq smsc0
+device.
+.Pp
+It's possible to set all these properties at boot time with the
+.Xr rc.d 8
+script available at
+.Pa /etc/rc.d/envsys .
+.Pp
.Sh EXAMPLES
Display the
-.Do acpibat0 charge
-.Dc sensor on one line (row format) every ten seconds:
-.Dl envstat -s \*qacpibat0 charge\*q -r -i 10
+.Dq acpibat0 charge
+sensor on one line every ten seconds:
+.Pp
+.Dl $ envstat -s \*qacpibat0 charge\*q -i 10
+.Pp
+Lists the drivers that are currently registered with
+.Xr envsys 4 :
+.Pp
+.Dl $ envstat -D
+.Pp
+Display the sensors of the driver
+.Ar aiboost0 :
+.Pp
+.Dl $ envstat -d aiboost0
+.Pp
+Change the description string for the
+.Dq +3.3V
+sensor to
+.Dq +3.3 Volts
+in the
+.Ar aiboost0
+device:
+.Pp
+.Dl $ envstat -s \*q+3.3V\*q -d aiboost0 -m desc=\*q+3.3 Volts\*q
+.Pp
+Set a critical max limit to 60 degC for the
+.Dq CPU Temp
+sensor, in the
+.Ar aiboost0
+device:
+.Pp
+.Dl $ envstat -s \*qCPU Temp\*q -d aiboost0 -m critmax=60
+.Pp
+Set a critical min limit to 1000 RPMs for the
+.Dq CPU Fan
+sensor, in the
+.Ar aiboost0
+device:
+.Pp
+.Dl $ envstat -s \*qCPU Fan\*q -d aiboost0 -m critmin=1000
+.Pp
+Remove a max critical limit for the
+.Dq CPU Temp
+sensor, in the
+.Ar aiboost0
+device:
+.Pp
+.Dl $ envstat -s \*qCPU Temp\*q -d aiboost0 -m critmax=remove
+.Pp
+Change the resistor factor (rfact) to 56000 for the
+.Dq +3.3V
+sensor, in the
+.Ar lm0
+device:
+.Pp
+.Dl $ envstat -s \*q+3.3V\*q -d lm0 -m rfact=56000
+.Pp
+Set a critical capacity to
+.Sy 10%
+for the
+.Dq acpibat0 charge
+sensor, in the
+.Ar acpibat0
+device:
+.Pp
+.Dl $ envstat -s \*qacpibat0 charge\*q -dacpibat0 -m critical=10
.Sh SEE ALSO
+.Xr proplib 3 ,
.Xr acpiacad 4 ,
.Xr acpibat 4 ,
.Xr acpitz 4 ,
@@ -122,10 +343,23 @@ Display the
.Xr owtemp 4 ,
.Xr sparc/tctrl 4 ,
.Xr sparc64/envctrl 4 ,
+.Xr smsc 4 ,
.Xr tm121temp 4 ,
.Xr ug 4 ,
-.Xr viaenv 4 .
+.Xr viaenv 4
.Sh HISTORY
.Nm
appeared in
.Nx 1.5 .
+It was completely rewritten from scratch for
+.Nx 5.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility that appeared in
+.Nx 5.0
+was written by
+.An Juan Romero Pardines .
+The previous version was written by
+.An Bill Squier .
diff --git a/usr.sbin/envstat/envstat.c b/usr.sbin/envstat/envstat.c
index b2c5b684ca8..343837665cc 100644
--- a/usr.sbin/envstat/envstat.c
+++ b/usr.sbin/envstat/envstat.c
@@ -1,11 +1,11 @@
-/* $NetBSD: envstat.c,v 1.24 2007/05/01 17:18:56 bouyer Exp $ */
+/* $NetBSD: envstat.c,v 1.25 2007/07/01 07:39:46 xtraeme Exp $ */
/*-
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Bill Squier.
+ * by Juan Romero Pardines.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -17,8 +17,8 @@
* 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.
+ * This product includes software developed by Juan Romero Pardines
+ * for 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.
@@ -36,83 +36,119 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-#ifndef lint
-__RCSID("$NetBSD: envstat.c,v 1.24 2007/05/01 17:18:56 bouyer Exp $");
-#endif
+/*
+ * TODO:
+ *
+ * o Some checks should be added to ensure that the user does not
+ * set unwanted values for the critical limits.
+ */
-#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
#include <unistd.h>
+#include <fcntl.h>
#include <err.h>
-#include <paths.h>
-
-#define ENVSYSUNITNAMES
+#include <errno.h>
+#include <prop/proplib.h>
#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);
-void printrow(int *, envsys_tre_data_t *, envsys_basic_info_t *, int, int,
- size_t);
-
-int rflag = 0;
-
-int
-main(int argc, char **argv)
+
+#define _PATH_DEV_SYSMON "/dev/sysmon"
+
+#define ENVSYS_DFLAG 0x00000001 /* list registered devices */
+#define ENVSYS_FFLAG 0x00000002 /* show temp in farenheit */
+#define ENVSYS_LFLAG 0x00000004 /* list sensors */
+#define ENVSYS_XFLAG 0x00000008 /* externalize dictionary */
+
+/*
+ * Operation flags for -m.
+ */
+#define USERF_SCRITICAL 0x00000001 /* set a critical limit */
+#define USERF_RCRITICAL 0x00000002 /* remove a critical limit */
+#define USERF_SCRITMAX 0x00000004 /* set a critical max limit */
+#define USERF_RCRITMAX 0x00000008 /* remove a critical max limit */
+#define USERF_SCRITMIN 0x00000010 /* set a critical min limit */
+#define USERF_RCRITMIN 0x00000020 /* remove a critical min limit */
+#define USERF_SRFACT 0x00000040 /* set a new rfact */
+#define USERF_SDESCR 0x00000080 /* set a new description */
+
+struct envsys_sensor {
+ bool visible;
+ bool percentage;
+ int32_t cur_value;
+ int32_t max_value;
+ int32_t min_value;
+ int32_t avg_value;
+ int32_t critcap_value;
+ int32_t critmin_value;
+ int32_t critmax_value;
+ char desc[ENVSYS_DESCLEN];
+ char type[ENVSYS_DESCLEN];
+ char drvstate[ENVSYS_DESCLEN];
+};
+
+static int interval, flags, width;
+static char *mydevname, *sensors, *userreq;
+static struct envsys_sensor *gesen;
+static size_t gnelems;
+
+static int parse_dictionary(int);
+static int send_dictionary(int);
+static int find_sensors(prop_array_t);
+static void print_sensors(struct envsys_sensor *, size_t);
+static int check_sensors(struct envsys_sensor *, char *, size_t);
+static int usage(void);
+
+
+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, "fi:ln:rs:w:")) != -1) {
- switch(c) {
- case 'r':
- rflag = 1;
+ prop_dictionary_t dict;
+ int c, fd, rval;
+ char *endptr;
+
+ rval = flags = interval = width = 0;
+
+ setprogname(argv[0]);
+
+ while ((c = getopt(argc, argv, "Dd:fi:lm:s:w:x")) != -1) {
+ switch (c) {
+ case 'd': /* show sensors of a specific device */
+ mydevname = strdup(optarg);
+ if (mydevname == NULL)
+ err(ENOMEM, "out of memory");
+ break;
+ case 'i': /* wait time between intervals */
+ interval = strtoul(optarg, &endptr, 10);
+ if (*endptr != '\0')
+ errx(1, "interval must be an integer");
break;
- case 'i': /* wait time between displays */
- interval = atoi(optarg);
+ case 'D': /* list registered devices */
+ flags |= ENVSYS_DFLAG;
break;
- case 'w': /* minimum column width */
- width = atoi(optarg);
+ case 'f': /* display temperature in Farenheit */
+ flags |= ENVSYS_FFLAG;
break;
- case 'l': /* list sensor names */
- ls = 1;
+ case 'l': /* list sensors */
+ flags |= ENVSYS_LFLAG;
break;
- case 'n': /* repeat header every headrep lines */
- headrep = atoi(optarg);
+ case 'w': /* width value for the lines */
+ width = strtoul(optarg, &endptr, 10);
+ if (*endptr != '\0')
+ errx(1, "width must be an integer");
break;
- case 's': /* restrict display to named sensors */
- sensors = (char *)malloc(strlen(optarg) + 1);
+ case 'x': /* print the dictionary in raw format */
+ flags |= ENVSYS_XFLAG;
+ break;
+ case 's': /* only show specified sensors */
+ sensors = strdup(optarg);
if (sensors == NULL)
- exit(1);
- strcpy(sensors, optarg);
+ err(ENOMEM, "out of memory");
break;
- case 'f': /* display temp in degF */
- celsius = 0;
+ case 'm':
+ userreq = strdup(optarg);
+ if (userreq == NULL)
+ err(ENOMEM, "out of memory");
break;
case '?':
default:
@@ -121,392 +157,736 @@ main(int argc, char **argv)
}
}
- if (optind < argc)
- dev = argv[optind];
- else
- dev = _PATH_SYSMON;
+ if ((fd = open(_PATH_DEV_SYSMON, O_RDONLY)) == -1)
+ err(EXIT_FAILURE, "open");
- if ((fd = open(dev, O_RDONLY)) == -1)
- err(1, "unable to open %s", dev);
+ if (!interval && (flags & ENVSYS_XFLAG)) {
+ if (prop_dictionary_recv_ioctl(fd,
+ ENVSYS_GETDICTIONARY,
+ &dict)) {
+ (void)close(fd);
+ err(EINVAL, "recv_ioctl");
+ }
+ }
- /*
- * Determine number of sensors, allocate and fill arrays with
- * initial information. Determine column width
- */
- if ((ns = numsensors(fd)) == 0)
- errx(1, "No sensors found");
+ if (argc == 1) {
+ rval = parse_dictionary(fd);
- 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));
+ } else if (userreq) {
+ if (!sensors || !mydevname) {
+ (void)fprintf(stderr, "%s: -m cannot be used without "
+ "-s and -d\n", getprogname());
+ return EINVAL;
+ }
+
+ rval = send_dictionary(fd);
+ goto out;
+
+ } else if (interval) {
+ for (;;) {
+ rval = parse_dictionary(fd);
+ if (rval)
+ goto out;
+ (void)fflush(stdout);
+ (void)sleep(interval);
+ }
- if ((cetds == NULL) || (etds == NULL) || (ebis == NULL))
- err(1, "Out of memory");
+ } else if (!interval) {
+ if (flags & ENVSYS_XFLAG)
+ (void)printf("%s", prop_dictionary_externalize(dict));
+ else
+ rval = parse_dictionary(fd);
+
+ } else
+ usage();
+
+out:
+ if (sensors)
+ free(sensors);
+ if (userreq)
+ free(userreq);
+ if (mydevname)
+ free(mydevname);
+ (void)close(fd);
+ return rval;
+}
- fillsensors(fd, etds, ebis, ns);
+static int
+send_dictionary(int fd)
+{
+ prop_dictionary_t dict, udict;
+ prop_object_t obj;
+ char *buf, *target, *endptr;
+ int error, i, uflag;
+ double val;
+
+ error = uflag = val = 0;
+
+ /*
+ * part 1: kernel dictionary.
+ *
+ * This parts consists in parsing the kernel dictionary
+ * to check for unknown device or sensor and we must
+ * know what type of sensor are we trying to set
+ * a critical condition.
+ */
+ if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &dict))
+ return EINVAL;
+
+ if (mydevname) {
+ obj = prop_dictionary_get(dict, mydevname);
+ if (prop_object_type(obj) != PROP_TYPE_ARRAY) {
+ warnx("unknown device `%s'", mydevname);
+ prop_object_release(dict);
+ return EINVAL;
+ }
- if (ls) {
- listsensors(ebis, ns);
- exit(0);
+ if (find_sensors(obj)) {
+ prop_object_release(dict);
+ return EINVAL;
+ }
}
+ /* find the type for selected sensor */
+ for (i = 0; i < gnelems; i++)
+ if (strcmp(sensors, gesen[i].desc) == 0)
+ break;
-#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);
+ /* we know the type of the sensor now, release kernel dict */
+ prop_object_release(dict);
- if (rflag) {
- if (interval == 0) {
- printrow(cetds, etds, ebis, ns, celsius, width);
- exit(0);
- }
+ /*
+ * part 2: userland dictionary.
+ *
+ * This parts consists in setting the values provided
+ * by the user and convert when necesssary to send
+ * them to the kernel again.
+ */
+ udict = prop_dictionary_create();
- while (1) {
- printrow(cetds, etds, ebis, ns, celsius, width);
- sleep(interval);
- fillsensors(fd, etds, ebis, ns);
- printf("\n");
- }
+ /* create the driver-name object */
+ obj = prop_string_create_cstring_nocopy(mydevname);
+ if (obj == NULL || !prop_dictionary_set(udict, "driver-name", obj)) {
+ error = EINVAL;
+ goto out;
}
+ prop_object_release(obj);
+ /* create the sensor-name object */
+ obj = prop_string_create_cstring_nocopy(sensors);
+ if (obj == NULL || !prop_dictionary_set(udict, "sensor-name", obj)) {
+ error = EINVAL;
+ goto out;
+ }
- /* 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);
+ prop_object_release(obj);
+ /*
+ * parse the -m argument; we understand the following ways:
+ *
+ * -m critical/crit{max,min}=value
+ * -m critical/crit{max,min}=remove
+ * -m desc="BLAH"
+ * -m rfact=value
+ */
+ if (userreq) {
+ buf = strtok(userreq, "=");
+ target = strdup(buf);
+ if (target == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
- exit (0);
+ while (buf != NULL) {
+ /*
+ * skip current string if it's the same
+ * than target requested.
+ */
+ if (strcmp(target, buf) == 0)
+ buf = strtok(NULL, "=");
+
+ /* check what target was requested */
+ if (strcmp(target, "desc") == 0) {
+ uflag |= USERF_SDESCR;
+ obj = prop_string_create_cstring_nocopy(buf);
+ break;
+#define SETNCHECKVAL(a, b) \
+do { \
+ if (strcmp(buf, "remove") == 0) \
+ uflag |= (a); \
+ else { \
+ uflag |= (b); \
+ val = strtod(buf, &endptr); \
+ if (*endptr != '\0') { \
+ (void)printf("%s: invalid value\n", \
+ getprogname()); \
+ error = EINVAL; \
+ goto out; \
+ } \
+ } \
+} while (/* CONSTCOND */ 0)
+
+ } else if (strcmp(target, "critical") == 0) {
+ SETNCHECKVAL(USERF_RCRITICAL, USERF_SCRITICAL);
+ break;
+ } else if (strcmp(target, "critmax") == 0) {
+ SETNCHECKVAL(USERF_RCRITMAX, USERF_SCRITMAX);
+ break;
+ } else if (strcmp(target, "critmin") == 0) {
+ SETNCHECKVAL(USERF_RCRITMIN, USERF_SCRITMIN);
+ break;
+ } else if (strcmp(target, "rfact") == 0) {
+ uflag |= USERF_SRFACT;
+ val = strtod(buf, &endptr);
+ if (*endptr != '\0') {
+ (void)printf("%s: invalid value\n",
+ getprogname());
+ error = EINVAL;
+ goto out;
+ }
+ break;
+ } else {
+ (void)printf("%s: invalid target\n",
+ getprogname());
+ error = EINVAL;
+ goto out;
+ }
+ }
+ free(target);
}
- 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);
+ /* critical capacity for percentage sensors */
+ if (uflag & USERF_SCRITICAL) {
+ /* sanity check */
+ if (val < 0 || val > 100) {
+ (void)printf("%s: invalid value (0><100)\n",
+ getprogname());
+ error = EINVAL;
+ goto out;
}
- fflush(stdout);
- sleep(interval);
+ /* ok... convert the value */
+ val = (val / 100) * gesen[i].max_value;
+ obj = prop_number_create_unsigned_integer(val);
+ }
- fillsensors(fd, etds, ebis, ns);
+ /*
+ * conversions required to send a proper value to the kernel.
+ */
+ if ((uflag & USERF_SCRITMAX) || (uflag & USERF_SCRITMIN)) {
+ /* temperatures */
+ if (strcmp(gesen[i].type, "Temperature") == 0) {
+ /* convert from farenheit to celsius */
+ if (flags & ENVSYS_FFLAG)
+ val = (val - 32.0) * (5.0 / 9.0);
+
+ /* convert to microKelvin */
+ val = val * 1000000 + 273150000;
+ /* printf("val=%d\n", (int)val); */
+ obj = prop_number_create_unsigned_integer(val);
+ /* fans */
+ } else if (strcmp(gesen[i].type, "Fan") == 0) {
+ if (val < 0 || val > 10000) {
+ error = EINVAL;
+ goto out;
+ }
+ /* printf("val=%d\n", (int)val); */
+ obj = prop_number_create_unsigned_integer(val);
+
+ /* volts, watts, ohms, etc */
+ } else {
+ /* convert to m[V,W,Ohms] again */
+ val *= 1000000.0;
+ /* printf("val=%5.0f\n", val); */
+ obj = prop_number_create_integer(val);
+ }
}
- /* NOTREACHED */
- return (0);
-}
+ /* user wanted to set a new description */
+ if (uflag & USERF_SDESCR) {
+ if (!prop_dictionary_set(udict, "new-description", obj)) {
+ error = EINVAL;
+ goto out;
+ }
-/*
- * row wise processing
- */
-void
-printrow(int *cetds, envsys_tre_data_t *etds, envsys_basic_info_t *ebis,
- int ns, int celsius, size_t width)
-{
- int i;
+ /* user wanted to set a new critical capacity */
+ } else if (uflag & USERF_SCRITICAL) {
+ if (!prop_dictionary_set(udict, "critical-capacity", obj)) {
+ error = EINVAL;
+ goto out;
+ }
- for (i = 0 ; i < ns ; i++) {
- if (cetds[i] == 0)
- continue;
+ } else if (uflag & USERF_RCRITICAL) {
+ obj = prop_bool_create(1);
+ if (!prop_dictionary_set(udict, "remove-critical-cap", obj)) {
+ error = EINVAL;
+ goto out;
+ }
- if ((etds[i].validflags & ENVSYS_FCURVALID) == 0)
- continue;
+ /* user wanted to remove a critical min limit */
+ } else if (uflag & USERF_RCRITMIN) {
+ obj = prop_bool_create(1);
+ if (!prop_dictionary_set(udict, "remove-cmin-limit", obj)) {
+ error = EINVAL;
+ goto out;
+ }
- if (ebis[i].units == ENVSYS_INDICATOR &&
- etds[i].cur.data_s == 0)
- continue;
+ /* user wanted to remove a critical max limit */
+ } else if (uflag & USERF_RCRITMAX) {
+ obj = prop_bool_create(1);
+ if (!prop_dictionary_set(udict, "remove-cmax-limit", obj)) {
+ error = EINVAL;
+ goto out;
+ }
- printf("%*.*s", (int)width, (int)width, ebis[i].desc);
- /* different units need some magic */
- switch (ebis[i].units)
- {
- case ENVSYS_DRIVE:
- printf(": drive %s",
- envsysdrivestatus[etds[i].cur.data_us]);
- case ENVSYS_INDICATOR:
- break;
- case ENVSYS_INTEGER:
- printf(": %10d", etds[i].cur.data_s);
- 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;
+ /* user wanted to set a new critical min value */
+ } else if (uflag & USERF_SCRITMIN) {
+ if (!prop_dictionary_set(udict, "critical-min-limit", obj)) {
+ error = EINVAL;
+ goto out;
}
- 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;
+
+ /* user wanted to set a new critical max value */
+ } else if (uflag & USERF_SCRITMAX) {
+ if (!prop_dictionary_set(udict, "critical-max-limit", obj)) {
+ error = EINVAL;
+ goto out;
}
- if (etds[i].validflags & ENVSYS_FFRACVALID) {
- printf(" (%5.2f%%)",
- (etds[i].cur.data_s * 100.0) /
- etds[i].max.data_s);
+ /* user wanted to set a new rfact */
+ } else if (uflag & USERF_SRFACT) {
+ obj = prop_number_create_integer(val);
+ if (!prop_dictionary_set(udict, "new-rfact", obj)) {
+ error = EINVAL;
+ goto out;
}
- printf("\n");
+ } else {
+ (void)printf("%s: unknown operation\n", getprogname());
+ error = EINVAL;
+ goto out;
}
-}
+ prop_object_release(obj);
-/*
- * 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];
+#if 0
+ printf("%s", prop_dictionary_externalize(udict));
+ return error;
+#endif
- printf(" %*.*s", (int)width, (int)width, s);
- }
- printf("\n");
+ /* all done? send our dictionary now */
+ error = prop_dictionary_send_ioctl(udict, fd, ENVSYS_SETDICTIONARY);
+
+ if (error)
+ (void)printf("%s: %s\n", getprogname(), strerror(error));
+out:
+ prop_object_release(udict);
+ return error;
}
-void
-values(size_t width, int celsius, envsys_tre_data_t *etds,
- const int * const cetds, size_t ns)
+static int
+parse_dictionary(int fd)
{
- int i;
- double temp;
+ prop_array_t array;
+ prop_dictionary_t dict;
+ prop_object_iterator_t iter;
+ prop_object_t obj;
+ const char *dnp = NULL;
+ int rval = 0;
+
+ /* receive dictionary from kernel */
+ if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &dict))
+ return EINVAL;
+
+ if (mydevname) {
+ obj = prop_dictionary_get(dict, mydevname);
+ if (prop_object_type(obj) != PROP_TYPE_ARRAY) {
+ warnx("unknown device `%s'", mydevname);
+ rval = EINVAL;
+ goto out;
+ }
- for (i = 0; i < ns; ++i)
- if (cetds[i]) {
+ rval = find_sensors(obj);
+ if (rval)
+ goto out;
- /* * sensors without valid data */
- if ((etds[i].validflags & ENVSYS_FCURVALID) == 0) {
- printf(" %*.*s", (int)width, (int)width, "*");
- continue;
+ if (interval)
+ (void)printf("\n");
+
+ } else {
+ iter = prop_dictionary_iterator(dict);
+ if (iter == NULL) {
+ rval = EINVAL;
+ goto out;
+ }
+
+ /* iterate over the dictionary returned by the kernel */
+ while ((obj = prop_object_iterator_next(iter)) != NULL) {
+
+ array = prop_dictionary_get_keysym(dict, obj);
+ if (prop_object_type(array) != PROP_TYPE_ARRAY) {
+ warnx("no sensors found");
+ rval = EINVAL;
+ goto out;
}
- switch(etds[i].units) {
- case ENVSYS_DRIVE:
- printf(" %*.*s", (int)width, (int)width,
- envsysdrivestatus[etds[i].cur.data_us]);
- break;
- 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;
+ dnp = prop_dictionary_keysym_cstring_nocopy(obj);
+
+ if (flags & ENVSYS_DFLAG) {
+ (void)printf("%s", dnp);
+ } else {
+ rval = find_sensors(array);
+ if (rval)
+ goto out;
}
+ if (prop_dictionary_count(dict) > 1 || interval)
+ (void)printf("\n");
}
- printf("\n");
-}
+ prop_object_iterator_release(iter);
+ if ((flags & ENVSYS_DFLAG) && prop_dictionary_count(dict) == 1)
+ (void)printf("\n");
+ }
+out:
+ prop_object_release(dict);
+ return rval;
+}
-/*
- * post: displays usage on stderr
- */
-void
-usage(void)
+static int
+find_sensors(prop_array_t array)
{
+ prop_object_iterator_t iter;
+ prop_object_t obj, obj1;
+ prop_string_t state, desc = NULL;
+ struct envsys_sensor *esen;
+ int i, rval;
+ size_t nelems = 0;
+ char *str = NULL;
+
+ i = rval = 0;
+
+ esen = (struct envsys_sensor *)calloc(prop_array_count(array),
+ sizeof(struct envsys_sensor));
+ if (esen == NULL)
+ return ENOMEM;
+
+ iter = prop_array_iterator(array);
+ if (iter == NULL) {
+ rval = EINVAL;
+ goto out;
+ }
- (void)fprintf(stderr, "usage: %s [-fr] [-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);
-}
+ /* iterate over the array of dictionaries */
+ while ((obj = prop_object_iterator_next(iter)) != NULL) {
+ /* check sensor's state */
+ state = prop_dictionary_get(obj, "state");
+ /* skip invalid sensors */
+ if (prop_string_equals_cstring(state, "invalid"))
+ continue;
-/*
- * 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;
+ /* description string */
+ desc = prop_dictionary_get(obj, "description");
+ /* copy description */
+ (void)strlcpy(esen[i].desc, prop_string_cstring_nocopy(desc),
+ sizeof(esen[i].desc));
+
+ /* type string */
+ obj1 = prop_dictionary_get(obj, "type");
+ /* copy type */
+ (void)strlcpy(esen[i].type, prop_string_cstring_nocopy(obj1),
+ sizeof(esen[i].type));
+
+ /* get current drive state string */
+ obj1 = prop_dictionary_get(obj, "drive-state");
+ if (obj1 != NULL)
+ (void)strlcpy(esen[i].drvstate,
+ prop_string_cstring_nocopy(obj1),
+ sizeof(esen[i].drvstate));
+
+ /* get current value */
+ obj1 = prop_dictionary_get(obj, "cur-value");
+ esen[i].cur_value = prop_number_integer_value(obj1);
+
+ /* get max value */
+ obj1 = prop_dictionary_get(obj, "max-value");
+ if (obj1 != NULL)
+ esen[i].max_value = prop_number_integer_value(obj1);
+
+ /* get min value */
+ obj1 = prop_dictionary_get(obj, "min-value");
+ if (obj1 != NULL)
+ esen[i].min_value = prop_number_integer_value(obj1);
+
+ /* get avg value */
+ obj1 = prop_dictionary_get(obj, "avg-value");
+ if (obj1 != NULL)
+ esen[i].avg_value = prop_number_integer_value(obj1);
+
+ /* get percentage flag */
+ obj1 = prop_dictionary_get(obj, "want-percentage");
+ if (obj1 != NULL)
+ esen[i].percentage = prop_bool_true(obj1);
+
+ /* get critical max value if available */
+ obj1 = prop_dictionary_get(obj, "critical-max-limit");
+ if (obj1 != NULL) {
+ esen[i].critmax_value =
+ prop_number_integer_value(obj1);
+ }
- for (i = 0; i < ns; ++i)
- if (ebis[i].validflags & ENVSYS_FVALID)
- printf("%s\n", ebis[i].desc);
-}
+ /* get critical min value if available */
+ obj1 = prop_dictionary_get(obj, "critical-min-limit");
+ if (obj1 != NULL) {
+ esen[i].critmin_value =
+ prop_number_integer_value(obj1);
+ }
+ /* get critical capacity value if available */
+ obj1 = prop_dictionary_get(obj, "critical-capacity");
+ if (obj1 != NULL) {
+ esen[i].critcap_value =
+ prop_number_integer_value(obj1);
+ }
-/*
- * 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;
+ /* pass to the next struct */
+ i++;
+ nelems++;
+
+ /* print sensor names if -l was given */
+ if (flags & ENVSYS_LFLAG) {
+ if (width)
+ (void)printf("%*s\n", width,
+ prop_string_cstring_nocopy(desc));
+ else
+ (void)printf("%s\n",
+ prop_string_cstring_nocopy(desc));
+ }
+ }
+
+ /* free memory */
+ prop_object_iterator_release(iter);
+
+ /*
+ * if -s was specified, we need a way to mark if a sensor
+ * was found.
+ */
+ if (sensors) {
+ str = strdup(sensors);
+ if (str == NULL)
+ return ENOMEM;
+
+ rval = check_sensors(esen, str, nelems);
+ if (rval)
+ goto out;
- while (valid) {
- if (ioctl(fd, ENVSYS_GTREDATA, &etd) == -1)
- err(1, "Can't get sensor data");
+ free(str);
+ }
- valid = etd.validflags & ENVSYS_FVALID;
- if (valid)
- ++count;
+ gesen = esen;
+ gnelems = nelems;
- ++etd.sensor;
+ if (userreq == NULL) {
+ if ((flags & ENVSYS_LFLAG) == 0)
+ print_sensors(esen, nelems);
}
- return count;
+out:
+ free(esen);
+ return rval;
}
-/*
- * 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)
+static int
+check_sensors(struct envsys_sensor *es, char *str, size_t nelems)
{
int i;
+ char *sname;
- 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);
+ sname = strtok(str, ",");
+ while (sname != NULL) {
+ for (i = 0; i < nelems; i++) {
+ if (strcmp(sname, es[i].desc) == 0) {
+ es[i].visible = true;
+ break;
+ }
+ }
+ if (i >= nelems) {
+ if (mydevname) {
+ warnx("unknown sensor `%s' for device `%s'",
+ sname, mydevname);
+ return EINVAL;
+ } else {
+ warnx("unknown sensor `%s'", sname);
+ return EINVAL;
+ }
+ }
+ sname = strtok(NULL, ",");
+ }
- etds[i].sensor = i;
- if (ioctl(fd, ENVSYS_GTREDATA, &etds[i]) == -1)
- err(1, "Can't get sensor data for sensor %d", i);
+ /* check if all sensors were ok, and error out if not */
+ for (i = 0; i < nelems; i++) {
+ if (es[i].visible)
+ return 0;
}
-}
+ warnx("no sensors selected to display");
+ return EINVAL;
+}
-/*
- * post: returns the strlen() of the longest sensor name
- */
-size_t
-longestname(envsys_basic_info_t *ebis, size_t ns)
+static void
+print_sensors(struct envsys_sensor *es, size_t nelems)
{
- size_t i, maxlen, cur;
-
- maxlen = 0;
+ size_t maxlen = 0;
+ double temp = 0;
+ const char *degrees = NULL;
+ int i;
- for (i = 0; i < ns; ++i) {
- cur = strlen(ebis[i].desc);
- if (cur > maxlen)
- maxlen = cur;
+ /* find the longest description */
+ for (i = 0; i < nelems; ++i) {
+ if (strlen(es[i].desc) > maxlen)
+ maxlen = strlen(es[i].desc);
}
- return maxlen;
-}
+ if (width)
+ maxlen = width;
-/*
- * 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;
+ /* print the sensors */
+ for (i = 0; i < nelems; ++i) {
- if (sensors == NULL) {
- /* No sensors specified, include them all */
- for (i = 0; i < ns; ++i)
- cetds[i] = 1;
+ /* skip sensors that were not marked as visible */
+ if (sensors && !es[i].visible)
+ continue;
- return 0;
- }
+ /* skip indicator sensor if value is 0 */
+ if ((strcmp(es[i].type, "Indicator") == 0) &&
+ es[i].cur_value == 0)
+ continue;
+
+ /* skip other sensors if value is 0 */
+ if (es[i].cur_value == 0)
+ continue;
- /* 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);
+ /* we have a winner... */
+ (void)printf("%*.*s", (int)maxlen, (int)maxlen, es[i].desc);
+
+ if (strcmp(es[i].type, "Indicator") == 0) {
+ (void)printf("\n");
+ continue;
}
- s = strtok(NULL, ",");
- }
+/* converts the value to degC or degF */
+#define CONVERTTEMP(a, b, c) \
+do { \
+ (a) = ((b) / 1000000.0) - 273.15; \
+ if (flags & ENVSYS_FFLAG) { \
+ (a) = (9.0 / 5.0) * (a) + 32.0; \
+ (c) = "degF"; \
+ } else \
+ (c) = "degC"; \
+} while (/* CONSTCOND */ 0)
+
+
+ /* temperatures */
+ if (strcmp(es[i].type, "Temperature") == 0) {
+
+ CONVERTTEMP(temp, es[i].cur_value, degrees);
+ (void)printf(": %10.3f %s", temp, degrees);
+
+ if (es[i].critmax_value || es[i].critmin_value)
+ (void)printf(" ");
+
+ if (es[i].critmax_value) {
+ CONVERTTEMP(temp, es[i].critmax_value, degrees);
+ (void)printf("max: %8.3f %s ", temp, degrees);
+ }
- /* Check if we have at least one sensor selected for output */
- for (i = 0; i < ns; ++i)
- if (cetds[i] == 1)
- return (0);
+ if (es[i].critmin_value) {
+ CONVERTTEMP(temp, es[i].critmin_value, degrees);
+ (void)printf("min: %8.3f %s", temp, degrees);
+ }
- warnx("No sensors selected for display");
- return (-1);
-}
+ /* fans */
+ } else if (strcmp(es[i].type, "Fan") == 0) {
+
+ (void)printf(": %10u RPM", es[i].cur_value);
+
+ if (es[i].critmax_value || es[i].critmin_value)
+ (void)printf(" ");
+ if (es[i].critmax_value)
+ (void)printf("max: %8u RPM ",
+ es[i].critmax_value);
+ if (es[i].critmin_value)
+ (void)printf("min: %8u RPM",
+ es[i].critmin_value);
+
+ /* integers */
+ } else if (strcmp(es[i].type, "Integer") == 0) {
+
+ (void)printf(": %10d", es[i].cur_value);
+
+ /* drives */
+ } else if (strcmp(es[i].type, "Drive") == 0) {
+ (void)printf(": %s", es[i].drvstate);
+
+ /* everything else */
+ } else {
+ const char *type;
+
+ if (strcmp(es[i].type, "Voltage DC") == 0)
+ type = "V";
+ else if (strcmp(es[i].type, "Voltage AC") == 0)
+ type = "VAC";
+ else if (strcmp(es[i].type, "Ampere") == 0)
+ type = "A";
+ else if (strcmp(es[i].type, "Watts") == 0)
+ type = "W";
+ else if (strcmp(es[i].type, "Ohms") == 0)
+ type = "Ohms";
+ else if (strcmp(es[i].type, "Watt hour") == 0)
+ type = "Wh";
+ else if (strcmp(es[i].type, "Ampere hour") == 0)
+ type = "Ah";
+ else
+ type = NULL;
+ (void)printf(": %10.3f %s",
+ es[i].cur_value / 1000000.0, type);
-/*
- * 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;
+ if (es[i].percentage && es[i].max_value) {
+ (void)printf(" (%5.2f%%)",
+ (es[i].cur_value * 100.0) /
+ es[i].max_value);
+ }
+
+ if (es[i].critcap_value) {
+ (void)printf(" critical (%5.2f%%)",
+ (es[i].critcap_value * 100.0) /
+ es[i].max_value);
+ }
+
+ if (es[i].critmax_value || es[i].critmin_value)
+ (void)printf(" ");
+ if (es[i].critmax_value)
+ (void)printf("max: %8.3f %s ",
+ es[i].critmax_value / 1000000.0,
+ type);
+ if (es[i].critmin_value)
+ (void)printf("min: %8.3f %s",
+ es[i].critmin_value / 1000000.0,
+ type);
+
+ }
- for (i = 0; i < ns; ++i) {
- if((ebis[i].validflags & ENVSYS_FVALID) &&
- !strcmp(s, ebis[i].desc))
- return ebis[i].sensor;
+ (void)printf("\n");
}
+}
- return -1;
+static int
+usage(void)
+{
+ (void)fprintf(stderr, "Usage: %s [-Dflx] ", getprogname());
+ (void)fprintf(stderr, "[-m ...] [-s s1,s2 ] [-w num] ");
+ (void)fprintf(stderr, "[-i num] [-d ...]\n");
+ exit(EXIT_FAILURE);
+ /* NOTREACHED */
}
diff --git a/usr.sbin/powerd/Makefile b/usr.sbin/powerd/Makefile
index f878aeadd51..ff40e7e0b85 100644
--- a/usr.sbin/powerd/Makefile
+++ b/usr.sbin/powerd/Makefile
@@ -1,11 +1,11 @@
-# $NetBSD: Makefile,v 1.3 2006/02/05 14:11:18 christos Exp $
+# $NetBSD: Makefile,v 1.4 2007/07/01 07:39:47 xtraeme Exp $
PROG= powerd
SRCS= powerd.c
WARNS?= 4
-DPADD+= ${LIBUTIL}
-LDADD+= -lutil
+DPADD+= ${LIBPROP} ${LIBUTIL}
+LDADD+= -lprop -lutil
MAN= powerd.8
diff --git a/usr.sbin/powerd/powerd.8 b/usr.sbin/powerd/powerd.8
index 1303ccf8e1a..8a244663887 100644
--- a/usr.sbin/powerd/powerd.8
+++ b/usr.sbin/powerd/powerd.8
@@ -1,4 +1,4 @@
-.\" $NetBSD: powerd.8,v 1.9 2006/12/14 02:34:32 reed Exp $
+.\" $NetBSD: powerd.8,v 1.10 2007/07/01 07:39:47 xtraeme Exp $
.\"
.\" Copyright (c) 2003 Wasabi Systems, Inc.
.\" All rights reserved.
@@ -33,7 +33,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd May 3, 2004
+.Dd June 15, 2007
.Dt POWERD 8
.Os
.Sh NAME
@@ -64,7 +64,7 @@ will stay in the foreground of the controlling terminal.
.El
.Sh CONFIGURATION SCRIPTS
All of
-.Nm Ns 's
+.Nm
configuration is encapsulated into scripts that are run when power
management events occur.
.Nm
@@ -108,7 +108,8 @@ This script is called when an event occurs on a sleep button device.
.It lid_switch
This script is called when an event occurs on a lid switch device.
.It acadapter
-This script is called when an online or offline event occurs on an AC adapter device.
+This script is called when an online or offline event occurs on an
+AC adapter device.
.El
.Pp
The following events are defined for power switch devices:
@@ -126,17 +127,89 @@ when a power button is pressed by the operator:
.Bd -literal -offset indent
/etc/powerd/scripts/power_button acpi0 pressed
.Ed
+.Ss ENVSYS SCRIPTS
+.Xr envsys 4
+scripts are called when a critical condition was triggered in
+a sensor.
+These scripts are called with three arguments: the
+device associated, the event type, and sensor's name.
+The
+.Sy sensor_drive
+sensor uses a fourth argument: state description.
+.Pp
+The following envsys script names are defined:
+.Bl -tag -width "sensor_temperature"
+.It sensor_battery
+This script is called when an event occurs on a battery sensor (Wh/Ah).
+.It sensor_drive
+This script is called when an event occurs on a drive sensor.
+.It sensor_fan
+This script is called when an event occurs on a fan sensor.
+.It sensor_power
+This script is called when an event occurs on a power sensor (W/Ampere).
+.It sensor_resistance
+This script is called when an event occurs on a resistance sensor (Ohm).
+.It sensor_temperature
+This script is called when an event occurs on a temperature sensor.
+.It sensor_voltage
+This script is called when an event occurs on a voltage sensor.
+.El
+.Pp
+The following event is defined for all scripts but is only sent after
+a critical/warning or any other event was previously sent:
+.Bl -tag -width "sensor_temperature"
+.It normal
+A normal state/capacity/condition was triggered.
+.El
+.Pp
+The following events are defined for battery, fan, power, resistance,
+temperature, and voltage sensors:
+.Bl -tag -width "sensor_temperature"
+.It critical
+A critical condition was triggered.
+.It critical-under
+A critical under condition was triggered.
+.It critical-over
+A critical over condition was triggered.
+.It warning-under
+A warning under condition was triggered.
+.It warning-over
+A warning over condition was triggered.
+.El
+.Pp
+The following events are defined for battery sensors:
+.Bl -tag -width "sensor_temperature"
+.It user-capacity
+A capacity limit set by the user was triggered.
+.El
+.Pp
+The following events are defined for drive sensors:
+.Bl -tag -width "sensor_temperature"
+.It state-changed
+The state on the sensor changed and it's not in a valid state.
+.El
+.Pp
+The following is an example of how a temperature sensor script might be
+invoked when a critical over condition is triggered:
+.Bd -literal -offset indent
+/etc/powerd/scripts/sensor_temperature lm0 critical-over "CPU Temp"
+.Ed
.Sh SEE ALSO
.Xr acpi 4 ,
.Xr acpiacad 4 ,
.Xr acpibut 4 ,
.Xr acpilid 4 ,
-.Xr apm 4
+.Xr envsys 4 ,
+.Xr i386/apm 4
.\" .Xr sysmon 4
.Sh HISTORY
.Nm
first appeared in
.Nx 2.0 .
+Support to handle
+.Xr envsys 4
+events appeared in
+.Nx 5.0 .
.Sh AUTHORS
.Nm
was written by
diff --git a/usr.sbin/powerd/powerd.c b/usr.sbin/powerd/powerd.c
index 9ed4b50beaa..8842b937256 100644
--- a/usr.sbin/powerd/powerd.c
+++ b/usr.sbin/powerd/powerd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: powerd.c,v 1.7 2007/05/07 02:33:35 xtraeme Exp $ */
+/* $NetBSD: powerd.c,v 1.8 2007/07/01 07:39:47 xtraeme Exp $ */
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
@@ -52,6 +52,7 @@
#include <syslog.h>
#include <unistd.h>
#include <util.h>
+#include <prop/proplib.h>
int debug;
@@ -65,7 +66,7 @@ static void run_script(const char *[]);
static struct kevent *allocchange(void);
static int wait_for_events(struct kevent *, size_t);
static void dispatch_dev_power(struct kevent *);
-static void dispatch_power_event_switch_state_change(power_event_t *);
+static void dispatch_power_event_state_change(int, power_event_t *);
static const char *script_paths[] = {
NULL,
@@ -250,47 +251,6 @@ wait_for_events(struct kevent *events, size_t nevents)
return rv;
}
-static const char *
-pswitch_type_name(int type)
-{
-
- switch (type) {
- case PSWITCH_TYPE_POWER:
- return "power_button";
-
- case PSWITCH_TYPE_SLEEP:
- return "sleep_button";
-
- case PSWITCH_TYPE_LID:
- return "lid_switch";
-
- case PSWITCH_TYPE_RESET:
- return "reset_button";
-
- case PSWITCH_TYPE_ACADAPTER:
- return "acadapter";
-
- default:
- return "=unknown pswitch type=";
- }
-}
-
-static const char *
-pswitch_event_name(int type)
-{
-
- switch (type) {
- case PSWITCH_EVENT_PRESSED:
- return "pressed";
-
- case PSWITCH_EVENT_RELEASED:
- return "released";
-
- default:
- return "=unknown pswitch event=";
- }
-}
-
static void
dispatch_dev_power(struct kevent *ev)
{
@@ -298,8 +258,9 @@ dispatch_dev_power(struct kevent *ev)
int fd = ev->ident;
if (debug)
- (void)fprintf(stderr, "dispatch_dev_power: %" PRId64
- " events available\n", ev->data);
+ (void)fprintf(stderr, "%s: %" PRId64
+ " event%s available\n", __func__,
+ ev->data, ev->data > 1 ? "s" : "");
again:
if (read(fd, &pev, sizeof(pev)) != sizeof(pev)) {
@@ -309,16 +270,15 @@ dispatch_dev_power(struct kevent *ev)
exit(EX_OSERR);
}
- if (debug) {
- (void)fprintf(stderr, "dispatch_dev_power: event type %d\n",
- pev.pev_type);
- }
+ if (debug)
+ (void)fprintf(stderr, "%s: event type %d\n",
+ __func__, pev.pev_type);
switch (pev.pev_type) {
+ case POWER_EVENT_ENVSYS_STATE_CHANGE:
case POWER_EVENT_SWITCH_STATE_CHANGE:
- dispatch_power_event_switch_state_change(&pev);
+ dispatch_power_event_state_change(fd, &pev);
break;
-
default:
syslog(LOG_INFO, "unknown %s event type: %d",
_PATH_DEV_POWER, pev.pev_type);
@@ -328,18 +288,42 @@ dispatch_dev_power(struct kevent *ev)
}
static void
-dispatch_power_event_switch_state_change(power_event_t *pev)
+dispatch_power_event_state_change(int fd, power_event_t *pev)
{
- const char *argv[4];
+ prop_dictionary_t dict;
+ prop_object_t obj;
+ const char *argv[6];
+ int error;
+
+ error = prop_dictionary_recv_ioctl(fd, POWER_EVENT_RECVDICT, &dict);
+ if (error) {
+ if (debug)
+ printf("%s: prop_dictionary_recv_ioctl error=%d\n",
+ __func__, error);
+ return;
+ }
+
+ if (debug)
+ printf("%s", prop_dictionary_externalize(dict));
- argv[0] = pswitch_type_name(pev->pev_switch.psws_type);
- argv[1] = pev->pev_switch.psws_name;
- argv[2] = pswitch_event_name(pev->pev_switch.psws_state);
- argv[3] = NULL;
+ obj = prop_dictionary_get(dict, "powerd-script-name");
+ argv[0] = prop_string_cstring_nocopy(obj);
- if (debug)
- (void)fprintf(stderr, "%s on %s %s\n", argv[0], argv[1],
- argv[2]);
+ obj = prop_dictionary_get(dict, "driver-name");
+ argv[1] = prop_string_cstring_nocopy(obj);
+
+ obj = prop_dictionary_get(dict, "powerd-event-name");
+ argv[2] = prop_string_cstring_nocopy(obj);
+
+ obj = prop_dictionary_get(dict, "sensor-name");
+ argv[3] = prop_string_cstring_nocopy(obj);
+
+ obj = prop_dictionary_get(dict, "drive-state-desc");
+ argv[4] = prop_string_cstring_nocopy(obj);
+
+ argv[5] = NULL;
+
+ prop_object_release(dict);
run_script(argv);
}