1 /* $NetBSD: config.c,v 1.7 2008/02/02 01:44:04 xtraeme Exp $ */
4 * Copyright (c) 2007 Juan Romero Pardines.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: config.c,v 1.7 2008/02/02 01:44:04 xtraeme Exp $");
38 #include <sys/queue.h>
39 #include <prop/proplib.h>
44 * Singly linked list for dictionaries that store properties
47 static SLIST_HEAD(, sensor_block
) sensor_block_list
=
48 SLIST_HEAD_INITIALIZER(&sensor_block_list
);
51 * Singly linked list for devices that store a proplib array
52 * device with a device name.
54 static SLIST_HEAD(, device_block
) device_block_list
=
55 SLIST_HEAD_INITIALIZER(&device_block_list
);
64 static prop_dictionary_t cfdict
, sensordict
, refreshdict
;
65 static void config_errmsg(int, const char *, const char *);
68 config_errmsg(int lvl
, const char *key
, const char *key2
)
70 (void)printf("envstat: ");
74 (void)printf("invalid value for '%s' in `%s'\n",
78 (void)printf("the '%s' property is not allowed "
79 "in `%s'\n", key
, key2
);
82 (void)printf("'%s' is not a valid sensor in the "
83 "`%s' device\n", key
, key2
);
86 (void)printf("device `%s' doesn't exist\n", key
);
90 (void)printf("envstat: please fix the configuration file!\n");
95 * Adds a property into a temporary dictionary.
98 config_dict_add_prop(const char *key
, char *value
)
104 sensordict
= prop_dictionary_create();
106 err(EXIT_FAILURE
, "sensordict");
109 if (!prop_dictionary_set_cstring(sensordict
, key
, value
))
110 err(EXIT_FAILURE
, "prop_dict_set_cstring");
114 * Marks sensor's dictionary to say that it's the last property
115 * and the dictionary should be added into the singly linked list.
118 config_dict_mark(void)
120 struct sensor_block
*sb
;
122 sb
= calloc(1, sizeof(*sb
));
124 err(EXIT_FAILURE
, "!sb");
126 sb
->dict
= prop_dictionary_create();
128 err(EXIT_FAILURE
, "!sb->dict");
130 sb
->dict
= prop_dictionary_copy(sensordict
);
131 SLIST_INSERT_HEAD(&sensor_block_list
, sb
, sb_head
);
132 config_dict_destroy(sensordict
);
136 * Only used for debugging purposses.
139 config_dict_dump(prop_dictionary_t d
)
143 buf
= prop_dictionary_externalize(d
);
144 (void)printf("%s", buf
);
149 * Returns the global dictionary.
152 config_dict_parsed(void)
158 * To add device properties into the global array, for now only the
159 * 'refresh-timeout' property is accepted.
162 config_dict_adddev_prop(const char *key
, const char *value
, int line
)
164 prop_dictionary_t d
= NULL
;
167 char *endptr
, *tmp
, *strval
;
170 minutes
= hours
= false;
173 * Check what was specified: seconds, minutes or hours.
175 if ((tmp
= strchr(value
, 's'))) {
177 * do nothing, by default the value will be sent as seconds.
179 } else if ((tmp
= strchr(value
, 'm'))) {
181 } else if ((tmp
= strchr(value
, 'h'))) {
187 strval
= calloc(len
, sizeof(*value
));
189 err(EXIT_FAILURE
, "calloc");
191 (void)strlcpy(strval
, value
, len
);
193 timo
= strtoul(strval
, &endptr
, 10);
194 if (*endptr
!= '\0') {
201 refreshdict
= prop_dictionary_create();
203 err(EXIT_FAILURE
, "prop_dict_create refresh");
205 d
= prop_dictionary_create();
207 err(EXIT_FAILURE
, "prop_dict_create refresh 1");
213 * Make sure the value is not too high...
220 * 1 second is the lowest value allowed.
226 if (!prop_dictionary_set_uint64(d
, key
, timo
))
227 err(EXIT_FAILURE
, "%s", key
);
229 if (!prop_dictionary_set(refreshdict
, "device-properties", d
))
230 err(EXIT_FAILURE
, "device-properties %s", key
);
232 prop_object_release(d
);
236 (void)printf("envstat: invalid value for the '%s' "
237 "property at line %d\n", key
, line
);
238 (void)printf("envstat: please fix the configuration file!\n");
240 prop_object_release(d
);
246 * Destroys all objects from a dictionary.
249 config_dict_destroy(prop_dictionary_t d
)
251 prop_object_iterator_t iter
;
254 iter
= prop_dictionary_iterator(d
);
256 err(EXIT_FAILURE
, "!iter");
258 while ((obj
= prop_object_iterator_next(iter
)) != NULL
) {
259 prop_dictionary_remove(d
,
260 prop_dictionary_keysym_cstring_nocopy(obj
));
261 prop_object_iterator_reset(iter
);
264 prop_object_iterator_release(iter
);
268 * Parses all properties on the device and adds the device
269 * into the singly linked list for devices and the global dictionary.
272 config_devblock_add(const char *key
, prop_dictionary_t kdict
)
274 struct device_block
*db
;
275 struct sensor_block
*sb
;
277 prop_object_iterator_t iter
;
278 prop_dictionary_t sdict
;
280 prop_string_t lindex
;
282 bool sensor_found
= false;
285 err(EXIT_FAILURE
, "devblock !key");
287 array
= prop_dictionary_get(kdict
, key
);
289 config_errmsg(DEV_ERR
, key
, NULL
);
291 SLIST_FOREACH(sb
, &sensor_block_list
, sb_head
) {
292 /* get the index object value from configuration */
293 lindex
= prop_dictionary_get(sb
->dict
, "index");
294 sensor
= prop_string_cstring_nocopy(lindex
);
296 iter
= prop_array_iterator(array
);
298 err(EXIT_FAILURE
, "prop_array_iterator devblock");
301 * Get the correct sensor's dictionary from kernel's
304 while ((sdict
= prop_object_iterator_next(iter
)) != NULL
) {
305 obj
= prop_dictionary_get(sdict
, "index");
306 if (prop_string_equals(lindex
, obj
)) {
313 prop_object_iterator_release(iter
);
314 config_errmsg(SENSOR_ERR
, sensor
, key
);
317 config_devblock_check_sensorprops(sdict
, sb
->dict
, sensor
);
318 prop_object_iterator_release(iter
);
321 db
= calloc(1, sizeof(*db
));
323 err(EXIT_FAILURE
, "calloc db");
325 db
->array
= prop_array_create();
327 err(EXIT_FAILURE
, "prop_array_create devblock");
330 * Add all dictionaries into the array.
332 SLIST_FOREACH(sb
, &sensor_block_list
, sb_head
)
333 if (!prop_array_add(db
->array
, sb
->dict
))
334 err(EXIT_FAILURE
, "prop_array_add");
337 * Add the device-properties dictionary into the array.
340 if (!prop_array_add(db
->array
, refreshdict
))
341 err(EXIT_FAILURE
, "prop_array_add refreshdict");
342 prop_object_release(refreshdict
);
346 * Add this device block into our list.
348 db
->dev_key
= strdup(key
);
349 SLIST_INSERT_HEAD(&device_block_list
, db
, db_head
);
352 * Remove all items in the list, but just decrement
353 * the refcnt in the dictionaries... they are in use.
355 while (!SLIST_EMPTY(&sensor_block_list
)) {
356 sb
= SLIST_FIRST(&sensor_block_list
);
357 SLIST_REMOVE_HEAD(&sensor_block_list
, sb_head
);
358 prop_object_release(sb
->dict
);
363 * Now the properties on the array has been parsed,
364 * add it into the global dict.
367 cfdict
= prop_dictionary_create();
369 err(EXIT_FAILURE
, "prop_dictionary_create cfdict");
372 if (!prop_dictionary_set(cfdict
, key
, db
->array
))
373 err(EXIT_FAILURE
, "prop_dictionary_set db->array");
376 * refreshdict must be NULLed to avoid false positives in
383 * Returns the dictionary that has 'sensor_key' in the 'dvname'
387 config_devblock_getdict(const char *dvname
, const char *sensor_key
)
389 struct device_block
*db
;
390 prop_object_iterator_t iter
;
391 prop_object_t obj
, obj2
;
393 if (!dvname
|| !sensor_key
)
396 SLIST_FOREACH(db
, &device_block_list
, db_head
)
397 if (strcmp(db
->dev_key
, dvname
) == 0)
403 iter
= prop_array_iterator(db
->array
);
407 while ((obj
= prop_object_iterator_next(iter
)) != NULL
) {
408 obj2
= prop_dictionary_get(obj
, "index");
409 if (prop_string_equals_cstring(obj2
, sensor_key
))
413 prop_object_iterator_release(iter
);
418 * Checks that all properties specified in the configuration file
419 * are valid and updates the objects with proper values.
422 config_devblock_check_sensorprops(prop_dictionary_t ksdict
,
423 prop_dictionary_t csdict
,
426 prop_object_t obj
, obj2
, obj3
;
427 char *strval
, *endptr
;
431 * rfact property set?
433 obj
= prop_dictionary_get(csdict
, "rfact");
435 obj2
= prop_dictionary_get(ksdict
, "allow-rfact");
436 if (prop_bool_true(obj2
)) {
437 strval
= prop_string_cstring(obj
);
438 val
= strtod(strval
, &endptr
);
440 config_errmsg(VALUE_ERR
, "rfact", sensor
);
442 if (!prop_dictionary_set_uint32(csdict
, "rfact", val
))
443 err(EXIT_FAILURE
, "dict_set rfact");
445 config_errmsg(PROP_ERR
, "rfact", sensor
);
449 * critical-capacity property set?
451 obj
= prop_dictionary_get(csdict
, "critical-capacity");
453 obj2
= prop_dictionary_get(ksdict
, "want-percentage");
454 obj3
= prop_dictionary_get(ksdict
, "monitoring-supported");
455 if (prop_bool_true(obj2
) && prop_bool_true(obj3
)) {
456 strval
= prop_string_cstring(obj
);
457 val
= strtod(strval
, &endptr
);
458 if ((*endptr
!= '\0') || (val
< 0 || val
> 100))
459 config_errmsg(VALUE_ERR
,
463 * Convert the value to a valid percentage.
465 obj
= prop_dictionary_get(ksdict
, "max-value");
466 val
= (val
/ 100) * prop_number_integer_value(obj
);
468 if (!prop_dictionary_set_uint32(csdict
,
471 err(EXIT_FAILURE
, "dict_set critcap");
473 config_errmsg(PROP_ERR
, "critical-capacity", sensor
);
477 * warning-capacity property set?
479 obj
= prop_dictionary_get(csdict
, "warning-capacity");
481 obj2
= prop_dictionary_get(ksdict
, "want-percentage");
482 obj3
= prop_dictionary_get(ksdict
, "monitoring-supported");
483 if (prop_bool_true(obj2
) && prop_bool_true(obj3
)) {
484 strval
= prop_string_cstring(obj
);
485 val
= strtod(strval
, &endptr
);
486 if ((*endptr
!= '\0') || (val
< 0 || val
> 100))
487 config_errmsg(VALUE_ERR
,
491 * Convert the value to a valid percentage.
493 obj
= prop_dictionary_get(ksdict
, "max-value");
494 val
= (val
/ 100) * prop_number_integer_value(obj
);
496 if (!prop_dictionary_set_uint32(csdict
,
499 err(EXIT_FAILURE
, "dict_set warncap");
501 config_errmsg(PROP_ERR
, "warning-capacity", sensor
);
505 * critical-max property set?
507 obj
= prop_dictionary_get(csdict
, "critical-max");
509 obj2
= prop_dictionary_get(ksdict
, "monitoring-supported");
510 if (!prop_bool_true(obj2
))
511 config_errmsg(PROP_ERR
, "critical-max", sensor
);
513 strval
= prop_string_cstring(obj
);
514 obj
= convert_val_to_pnumber(ksdict
, "critical-max",
516 if (!prop_dictionary_set(csdict
, "critical-max", obj
))
517 err(EXIT_FAILURE
, "prop_dict_set cmax");
521 * critical-min property set?
523 obj
= prop_dictionary_get(csdict
, "critical-min");
525 obj2
= prop_dictionary_get(ksdict
, "monitoring-supported");
526 if (!prop_bool_true(obj2
))
527 config_errmsg(PROP_ERR
, "critical-min", sensor
);
529 strval
= prop_string_cstring(obj
);
530 obj
= convert_val_to_pnumber(ksdict
, "critical-min",
532 if (!prop_dictionary_set(csdict
, "critical-min", obj
))
533 err(EXIT_FAILURE
, "prop_dict_set cmin");
537 * warning-max property set?
539 obj
= prop_dictionary_get(csdict
, "warning-max");
541 obj2
= prop_dictionary_get(ksdict
, "monitoring-supported");
542 if (!prop_bool_true(obj2
))
543 config_errmsg(PROP_ERR
, "warning-max", sensor
);
545 strval
= prop_string_cstring(obj
);
546 obj
= convert_val_to_pnumber(ksdict
, "warning-max",
548 if (!prop_dictionary_set(csdict
, "warning-max", obj
))
549 err(EXIT_FAILURE
, "prop_dict_set wmax");
552 * warning-min property set?
554 obj
= prop_dictionary_get(csdict
, "warning-min");
556 obj2
= prop_dictionary_get(ksdict
, "monitoring-supported");
557 if (!prop_bool_true(obj2
))
558 config_errmsg(PROP_ERR
, "warning-min", sensor
);
560 strval
= prop_string_cstring(obj
);
561 obj
= convert_val_to_pnumber(ksdict
, "warning-min",
563 if (!prop_dictionary_set(csdict
, "warning-min", obj
))
564 err(EXIT_FAILURE
, "prop_dict_set wmin");
569 * Conversions for critical-max and critical-min properties.
572 convert_val_to_pnumber(prop_dictionary_t kdict
, const char *prop
,
573 const char *sensor
, char *value
)
577 double val
, max
, min
;
578 char *strval
, *tmp
, *endptr
;
585 * critical-max and critical-min are not allowed in
588 obj
= prop_dictionary_get(kdict
, "want-percentage");
589 if (prop_bool_true(obj
))
590 config_errmsg(PROP_ERR
, prop
, sensor
);
593 * Make the conversion for sensor's type.
595 obj
= prop_dictionary_get(kdict
, "type");
596 if (prop_string_equals_cstring(obj
, "Temperature")) {
597 tmp
= strchr(value
, 'C');
601 tmp
= strchr(value
, 'F');
603 config_errmsg(VALUE_ERR
, prop
, sensor
);
609 strval
= calloc(len
, sizeof(*value
));
611 err(EXIT_FAILURE
, "calloc");
613 (void)strlcpy(strval
, value
, len
);
614 val
= strtod(strval
, &endptr
);
615 if (*endptr
!= '\0') {
617 config_errmsg(VALUE_ERR
, prop
, sensor
);
620 /* convert to fahrenheit */
622 val
= (val
- 32.0) * (5.0 / 9.0);
624 /* convert to microKelvin */
625 val
= val
* 1000000 + 273150000;
626 num
= prop_number_create_unsigned_integer(val
);
629 } else if (prop_string_equals_cstring(obj
, "Fan")) {
631 val
= strtod(value
, &endptr
);
633 config_errmsg(VALUE_ERR
, prop
, sensor
);
635 num
= prop_number_create_unsigned_integer(val
);
638 obj
= prop_dictionary_get(kdict
, "max-value");
640 max
= prop_number_integer_value(obj
);
642 obj
= prop_dictionary_get(kdict
, "min-value");
644 min
= prop_number_integer_value(obj
);
646 val
= strtod(value
, &endptr
);
648 config_errmsg(VALUE_ERR
, prop
, sensor
);
650 /* convert to m[V,W,Ohms] again */
654 * trying to set a value higher than the max
657 if (max
&& val
> max
)
658 config_errmsg(VALUE_ERR
, prop
, sensor
);
661 * trying to set a value lower than the min
664 if (min
&& val
< min
)
665 config_errmsg(VALUE_ERR
, prop
, sensor
);
667 num
= prop_number_create_integer(val
);