config.c revision 1.15 1 /* $NetBSD: config.c,v 1.15 2024/10/06 19:08:34 rillig Exp $ */
2
3 /*-
4 * Copyright (c) 2007 Juan Romero Pardines.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
15 *
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.
26 */
27
28 #include <sys/cdefs.h>
29 #ifndef lint
30 __RCSID("$NetBSD: config.c,v 1.15 2024/10/06 19:08:34 rillig Exp $");
31 #endif /* not lint */
32
33 #include <inttypes.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <sys/queue.h>
41 #include <prop/proplib.h>
42
43 #include "envstat.h"
44
45 /*
46 * Singly linked list for dictionaries that store properties
47 * in a sensor.
48 */
49 static SLIST_HEAD(, sensor_block) sensor_block_list =
50 SLIST_HEAD_INITIALIZER(&sensor_block_list);
51
52 /*
53 * Singly linked list for devices that store a proplib array
54 * device with a device name.
55 */
56 static SLIST_HEAD(, device_block) device_block_list =
57 SLIST_HEAD_INITIALIZER(&device_block_list);
58
59 enum {
60 VALUE_ERR,
61 PROP_ERR,
62 SENSOR_ERR,
63 DEV_ERR
64 };
65
66 static prop_dictionary_t cfdict, sensordict, refreshdict;
67 __dead static void config_errmsg(int, const char *, const char *);
68
69 static void
70 config_errmsg(int lvl, const char *key, const char *key2)
71 {
72 (void)printf("envstat: ");
73
74 switch (lvl) {
75 case VALUE_ERR:
76 (void)printf("invalid value for '%s' in `%s'\n",
77 key, key2);
78 break;
79 case PROP_ERR:
80 (void)printf("the '%s' property is not allowed "
81 "in `%s'\n", key, key2);
82 break;
83 case SENSOR_ERR:
84 (void)printf("'%s' is not a valid sensor in the "
85 "`%s' device\n", key, key2);
86 break;
87 case DEV_ERR:
88 (void)printf("device `%s' doesn't exist\n", key);
89 break;
90 }
91
92 (void)printf("envstat: please fix the configuration file!\n");
93 exit(EXIT_FAILURE);
94 }
95
96 /*
97 * Adds a property into a temporary dictionary.
98 */
99 void
100 config_dict_add_prop(const char *key, char *value)
101 {
102
103 if (!key || !value)
104 return;
105
106 if (!sensordict) {
107 sensordict = prop_dictionary_create();
108 if (!sensordict)
109 err(EXIT_FAILURE, "sensordict");
110 }
111
112 if (!prop_dictionary_set_string(sensordict, key, value))
113 err(EXIT_FAILURE, "prop_dict_set_string");
114 }
115
116 /*
117 * Marks sensor's dictionary to say that it's the last property
118 * and the dictionary should be added into the singly linked list.
119 */
120 void
121 config_dict_mark(void)
122 {
123 struct sensor_block *sb;
124
125 sb = calloc(1, sizeof(*sb));
126 if (!sb)
127 err(EXIT_FAILURE, "!sb");
128
129 sb->dict = prop_dictionary_create();
130 if (!sb->dict)
131 err(EXIT_FAILURE, "!sb->dict");
132
133 sb->dict = prop_dictionary_copy(sensordict);
134 SLIST_INSERT_HEAD(&sensor_block_list, sb, sb_head);
135 config_dict_destroy(sensordict);
136 }
137
138 /*
139 * Show raw data
140 */
141 void
142 config_dict_dump(prop_dictionary_t d)
143 {
144 char *buf;
145
146 buf = prop_dictionary_externalize(d);
147 (void)printf("%s", buf);
148 free(buf);
149 }
150
151 static void
152 display_object(prop_object_t obj, bool nflag)
153 {
154 char *xml;
155 prop_object_t next_obj;
156 prop_object_iterator_t iter;
157
158 if (obj == NULL)
159 exit(EXIT_FAILURE);
160 switch (prop_object_type(obj)) {
161 case PROP_TYPE_BOOL:
162 printf("%s\n", prop_bool_true(obj) ? "true" : "false");
163 break;
164 case PROP_TYPE_NUMBER:
165 printf("%" PRId64 "\n", prop_number_signed_value(obj));
166 break;
167 case PROP_TYPE_STRING:
168 printf("%s\n", prop_string_value(obj));
169 break;
170 case PROP_TYPE_DICTIONARY:
171 xml = prop_dictionary_externalize(obj);
172 printf("%s", xml);
173 free(xml);
174 break;
175 case PROP_TYPE_ARRAY:
176 iter = prop_array_iterator(obj);
177 if (!nflag)
178 printf("Array:\n");
179 while ((next_obj = prop_object_iterator_next(iter)) != NULL)
180 display_object(next_obj, nflag);
181 break;
182 default:
183 errx(EXIT_FAILURE, "Unhandled type %d", prop_object_type(obj));
184 }
185 }
186
187 void
188 config_dict_extract(prop_dictionary_t dict, const char *prop, bool nflag)
189 {
190 char *s, *p, *cur, *ep = NULL;
191 prop_object_t obj;
192 unsigned long ind;
193
194 obj = dict;
195 cur = NULL;
196 s = strdup(prop);
197 p = strtok_r(s, "/", &ep);
198 while (p) {
199 cur = p;
200 p = strtok_r(NULL, "/", &ep);
201
202 switch (prop_object_type(obj)) {
203 case PROP_TYPE_DICTIONARY:
204 obj = prop_dictionary_get(obj, cur);
205 if (obj == NULL)
206 exit(EXIT_FAILURE);
207 break;
208 case PROP_TYPE_ARRAY:
209 ind = strtoul(cur, NULL, 0);
210 obj = prop_array_get(obj, ind);
211 if (obj == NULL)
212 exit(EXIT_FAILURE);
213 break;
214 default:
215 errx(EXIT_FAILURE, "Select neither dict nor array with"
216 " `%s'", cur);
217 }
218 }
219
220 if (obj != NULL && cur != NULL)
221 display_object(obj, nflag);
222
223 free(s);
224 }
225
226 /*
227 * Returns the global dictionary.
228 */
229 prop_dictionary_t
230 config_dict_parsed(void)
231 {
232 return cfdict;
233 }
234
235 /*
236 * To add device properties into the global array, for now only the
237 * 'refresh-timeout' property is accepted.
238 */
239 void
240 config_dict_adddev_prop(const char *key, const char *value, int line)
241 {
242 prop_dictionary_t d = NULL;
243 uint64_t timo;
244 size_t len;
245 char *endptr, *strval;
246 bool minutes, hours;
247
248 minutes = hours = false;
249
250 /*
251 * Check what was specified: seconds, minutes or hours.
252 */
253 if (strchr(value, 's')) {
254 /*
255 * do nothing, by default the value will be sent as seconds.
256 */
257 } else if (strchr(value, 'm')) {
258 minutes = true;
259 } else if (strchr(value, 'h')) {
260 hours = true;
261 } else
262 goto bad;
263
264 len = strlen(value);
265 strval = calloc(len, sizeof(*value));
266 if (!strval)
267 err(EXIT_FAILURE, "calloc");
268
269 (void)strlcpy(strval, value, len);
270
271 timo = strtoul(strval, &endptr, 10);
272 if (*endptr != '\0') {
273 free(strval);
274 goto bad;
275 }
276
277 free(strval);
278
279 refreshdict = prop_dictionary_create();
280 if (!refreshdict)
281 err(EXIT_FAILURE, "prop_dict_create refresh");
282
283 d = prop_dictionary_create();
284 if (!d)
285 err(EXIT_FAILURE, "prop_dict_create refresh 1");
286
287 if (minutes)
288 timo *= 60;
289 else if (hours) {
290 /*
291 * Make sure the value is not too high...
292 */
293 if (timo > 999)
294 goto bad;
295 timo *= 60 * 60;
296 } else {
297 /*
298 * 1 second is the lowest value allowed.
299 */
300 if (timo < 1)
301 goto bad;
302 }
303
304 if (!prop_dictionary_set_uint64(d, key, timo))
305 err(EXIT_FAILURE, "%s", key);
306
307 if (!prop_dictionary_set(refreshdict, "device-properties", d))
308 err(EXIT_FAILURE, "device-properties %s", key);
309
310 prop_object_release(d);
311 return;
312
313 bad:
314 (void)printf("envstat: invalid value for the '%s' "
315 "property at line %d\n", key, line);
316 (void)printf("envstat: please fix the configuration file!\n");
317 if (d)
318 prop_object_release(d);
319
320 exit(EXIT_FAILURE);
321 }
322
323 /*
324 * Destroys all objects from a dictionary.
325 */
326 void
327 config_dict_destroy(prop_dictionary_t d)
328 {
329 prop_object_iterator_t iter;
330 prop_object_t obj;
331
332 iter = prop_dictionary_iterator(d);
333 if (!iter)
334 err(EXIT_FAILURE, "!iter");
335
336 while ((obj = prop_object_iterator_next(iter)) != NULL) {
337 prop_dictionary_remove(d,
338 prop_dictionary_keysym_value(obj));
339 prop_object_iterator_reset(iter);
340 }
341
342 prop_object_iterator_release(iter);
343 }
344
345 /*
346 * Parses all properties on the device and adds the device
347 * into the singly linked list for devices and the global dictionary.
348 */
349 void
350 config_devblock_add(const char *key, prop_dictionary_t kdict)
351 {
352 struct device_block *db;
353 struct sensor_block *sb;
354 prop_array_t array;
355 prop_object_iterator_t iter;
356 prop_dictionary_t sdict;
357 prop_object_t obj;
358 prop_string_t lindex;
359 const char *sensor;
360 bool sensor_found = false;
361
362 if (!key)
363 err(EXIT_FAILURE, "devblock !key");
364
365 array = prop_dictionary_get(kdict, key);
366 if (!array)
367 config_errmsg(DEV_ERR, key, NULL);
368
369 SLIST_FOREACH(sb, &sensor_block_list, sb_head) {
370 /* get the index object value from configuration */
371 lindex = prop_dictionary_get(sb->dict, "index");
372 sensor = prop_string_value(lindex);
373
374 iter = prop_array_iterator(array);
375 if (!iter)
376 err(EXIT_FAILURE, "prop_array_iterator devblock");
377
378 /*
379 * Get the correct sensor's dictionary from kernel's
380 * dictionary.
381 */
382 while ((sdict = prop_object_iterator_next(iter)) != NULL) {
383 obj = prop_dictionary_get(sdict, "index");
384 if (prop_string_equals(lindex, obj)) {
385 sensor_found = true;
386 break;
387 }
388 }
389
390 if (!sensor_found) {
391 prop_object_iterator_release(iter);
392 config_errmsg(SENSOR_ERR, sensor, key);
393 }
394
395 config_devblock_check_sensorprops(sdict, sb->dict, sensor);
396 prop_object_iterator_release(iter);
397 }
398
399 db = calloc(1, sizeof(*db));
400 if (!db)
401 err(EXIT_FAILURE, "calloc db");
402
403 db->array = prop_array_create();
404 if (!db->array)
405 err(EXIT_FAILURE, "prop_array_create devblock");
406
407 /*
408 * Add all dictionaries into the array.
409 */
410 SLIST_FOREACH(sb, &sensor_block_list, sb_head)
411 if (!prop_array_add(db->array, sb->dict))
412 err(EXIT_FAILURE, "prop_array_add");
413
414 /*
415 * Add the device-properties dictionary into the array.
416 */
417 if (refreshdict) {
418 if (!prop_array_add(db->array, refreshdict))
419 err(EXIT_FAILURE, "prop_array_add refreshdict");
420 prop_object_release(refreshdict);
421 }
422
423 /*
424 * Add this device block into our list.
425 */
426 db->dev_key = strdup(key);
427 SLIST_INSERT_HEAD(&device_block_list, db, db_head);
428
429 /*
430 * Remove all items in the list, but just decrement
431 * the refcnt in the dictionaries... they are in use.
432 */
433 while (!SLIST_EMPTY(&sensor_block_list)) {
434 sb = SLIST_FIRST(&sensor_block_list);
435 SLIST_REMOVE_HEAD(&sensor_block_list, sb_head);
436 prop_object_release(sb->dict);
437 free(sb);
438 }
439
440 /*
441 * Now the properties on the array has been parsed,
442 * add it into the global dict.
443 */
444 if (!cfdict) {
445 cfdict = prop_dictionary_create();
446 if (!cfdict)
447 err(EXIT_FAILURE, "prop_dictionary_create cfdict");
448 }
449
450 if (!prop_dictionary_set(cfdict, key, db->array))
451 err(EXIT_FAILURE, "prop_dictionary_set db->array");
452
453 /*
454 * refreshdict must be NULLed to avoid false positives in
455 * next matches.
456 */
457 refreshdict = NULL;
458 }
459
460 /*
461 * Returns the dictionary that has 'sensor_key' in the 'dvname'
462 * array.
463 */
464 prop_dictionary_t
465 config_devblock_getdict(const char *dvname, const char *sensor_key)
466 {
467 struct device_block *db;
468 prop_object_iterator_t iter;
469 prop_object_t obj, obj2;
470
471 if (!dvname || !sensor_key)
472 return NULL;
473
474 SLIST_FOREACH(db, &device_block_list, db_head)
475 if (strcmp(db->dev_key, dvname) == 0)
476 break;
477
478 if (!db)
479 return NULL;
480
481 iter = prop_array_iterator(db->array);
482 if (!iter)
483 return NULL;
484
485 while ((obj = prop_object_iterator_next(iter)) != NULL) {
486 obj2 = prop_dictionary_get(obj, "index");
487 if (prop_string_equals_string(obj2, sensor_key))
488 break;
489 }
490
491 prop_object_iterator_release(iter);
492 return obj;
493 }
494
495 /*
496 * Checks that all properties specified in the configuration file
497 * are valid and updates the objects with proper values.
498 */
499 void
500 config_devblock_check_sensorprops(prop_dictionary_t ksdict,
501 prop_dictionary_t csdict,
502 const char *sensor)
503 {
504 prop_object_t obj, obj2, obj3;
505 const char *strval;
506 char *endptr;
507 double val;
508
509 /*
510 * rfact property set?
511 */
512 obj = prop_dictionary_get(csdict, "rfact");
513 if (obj) {
514 obj2 = prop_dictionary_get(ksdict, "allow-rfact");
515 if (prop_bool_true(obj2)) {
516 strval = prop_string_value(obj);
517 val = strtod(strval, &endptr);
518 if (*endptr != '\0')
519 config_errmsg(VALUE_ERR, "rfact", sensor);
520
521 if (!prop_dictionary_set_uint32(csdict, "rfact", val))
522 err(EXIT_FAILURE, "dict_set rfact");
523 } else
524 config_errmsg(PROP_ERR, "rfact", sensor);
525 }
526
527 /*
528 * critical-capacity property set?
529 */
530 obj = prop_dictionary_get(csdict, "critical-capacity");
531 if (obj) {
532 obj2 = prop_dictionary_get(ksdict, "want-percentage");
533 obj3 = prop_dictionary_get(ksdict, "monitoring-supported");
534 if (prop_bool_true(obj2) && prop_bool_true(obj3)) {
535 strval = prop_string_value(obj);
536 val = strtod(strval, &endptr);
537 if ((*endptr != '\0') || (val < 0 || val > 100))
538 config_errmsg(VALUE_ERR,
539 "critical-capacity",
540 sensor);
541 /*
542 * Convert the value to a valid percentage.
543 */
544 obj = prop_dictionary_get(ksdict, "max-value");
545 val = (val / 100) * prop_number_signed_value(obj);
546
547 if (!prop_dictionary_set_uint32(csdict,
548 "critical-capacity",
549 val))
550 err(EXIT_FAILURE, "dict_set critcap");
551 } else
552 config_errmsg(PROP_ERR, "critical-capacity", sensor);
553 }
554
555 /*
556 * warning-capacity property set?
557 */
558 obj = prop_dictionary_get(csdict, "warning-capacity");
559 if (obj) {
560 obj2 = prop_dictionary_get(ksdict, "want-percentage");
561 obj3 = prop_dictionary_get(ksdict, "monitoring-supported");
562 if (prop_bool_true(obj2) && prop_bool_true(obj3)) {
563 strval = prop_string_value(obj);
564 val = strtod(strval, &endptr);
565 if ((*endptr != '\0') || (val < 0 || val > 100))
566 config_errmsg(VALUE_ERR,
567 "warning-capacity",
568 sensor);
569 /*
570 * Convert the value to a valid percentage.
571 */
572 obj = prop_dictionary_get(ksdict, "max-value");
573 val = (val / 100) * prop_number_signed_value(obj);
574
575 if (!prop_dictionary_set_uint32(csdict,
576 "warning-capacity",
577 val))
578 err(EXIT_FAILURE, "dict_set warncap");
579 } else
580 config_errmsg(PROP_ERR, "warning-capacity", sensor);
581 }
582
583 /*
584 * high-capacity property set?
585 */
586 obj = prop_dictionary_get(csdict, "high-capacity");
587 if (obj) {
588 obj2 = prop_dictionary_get(ksdict, "want-percentage");
589 obj3 = prop_dictionary_get(ksdict, "monitoring-supported");
590 if (prop_bool_true(obj2) && prop_bool_true(obj3)) {
591 strval = prop_string_value(obj);
592 val = strtod(strval, &endptr);
593 if ((*endptr != '\0') || (val < 0 || val > 100))
594 config_errmsg(VALUE_ERR,
595 "high-capacity",
596 sensor);
597 /*
598 * Convert the value to a valid percentage.
599 */
600 obj = prop_dictionary_get(ksdict, "max-value");
601 val = (val / 100) * prop_number_signed_value(obj);
602
603 if (!prop_dictionary_set_uint32(csdict,
604 "high-capacity",
605 val))
606 err(EXIT_FAILURE, "dict_set highcap");
607 } else
608 config_errmsg(PROP_ERR, "high-capacity", sensor);
609 }
610
611 /*
612 * maximum-capacity property set?
613 */
614 obj = prop_dictionary_get(csdict, "maximum-capacity");
615 if (obj) {
616 obj2 = prop_dictionary_get(ksdict, "want-percentage");
617 obj3 = prop_dictionary_get(ksdict, "monitoring-supported");
618 if (prop_bool_true(obj2) && prop_bool_true(obj3)) {
619 strval = prop_string_value(obj);
620 val = strtod(strval, &endptr);
621 if ((*endptr != '\0') || (val < 0 || val > 100))
622 config_errmsg(VALUE_ERR,
623 "maximum-capacity",
624 sensor);
625 /*
626 * Convert the value to a valid percentage.
627 */
628 obj = prop_dictionary_get(ksdict, "max-value");
629 val = (val / 100) * prop_number_signed_value(obj);
630
631 if (!prop_dictionary_set_uint32(csdict,
632 "maximum-capacity",
633 val))
634 err(EXIT_FAILURE, "dict_set maxcap");
635 } else
636 config_errmsg(PROP_ERR, "maximum-capacity", sensor);
637 }
638
639 /*
640 * critical-max property set?
641 */
642 obj = prop_dictionary_get(csdict, "critical-max");
643 if (obj) {
644 obj2 = prop_dictionary_get(ksdict, "monitoring-supported");
645 if (!prop_bool_true(obj2))
646 config_errmsg(PROP_ERR, "critical-max", sensor);
647
648 strval = prop_string_value(obj);
649 obj = convert_val_to_pnumber(ksdict, "critical-max",
650 sensor, strval);
651 if (!prop_dictionary_set(csdict, "critical-max", obj))
652 err(EXIT_FAILURE, "prop_dict_set cmax");
653 }
654
655 /*
656 * critical-min property set?
657 */
658 obj = prop_dictionary_get(csdict, "critical-min");
659 if (obj) {
660 obj2 = prop_dictionary_get(ksdict, "monitoring-supported");
661 if (!prop_bool_true(obj2))
662 config_errmsg(PROP_ERR, "critical-min", sensor);
663
664 strval = prop_string_value(obj);
665 obj = convert_val_to_pnumber(ksdict, "critical-min",
666 sensor, strval);
667 if (!prop_dictionary_set(csdict, "critical-min", obj))
668 err(EXIT_FAILURE, "prop_dict_set cmin");
669 }
670
671 /*
672 * warning-max property set?
673 */
674 obj = prop_dictionary_get(csdict, "warning-max");
675 if (obj) {
676 obj2 = prop_dictionary_get(ksdict, "monitoring-supported");
677 if (!prop_bool_true(obj2))
678 config_errmsg(PROP_ERR, "warning-max", sensor);
679
680 strval = prop_string_value(obj);
681 obj = convert_val_to_pnumber(ksdict, "warning-max",
682 sensor, strval);
683 if (!prop_dictionary_set(csdict, "warning-max", obj))
684 err(EXIT_FAILURE, "prop_dict_set wmax");
685 }
686 /*
687 * warning-min property set?
688 */
689 obj = prop_dictionary_get(csdict, "warning-min");
690 if (obj) {
691 obj2 = prop_dictionary_get(ksdict, "monitoring-supported");
692 if (!prop_bool_true(obj2))
693 config_errmsg(PROP_ERR, "warning-min", sensor);
694
695 strval = prop_string_value(obj);
696 obj = convert_val_to_pnumber(ksdict, "warning-min",
697 sensor, strval);
698 if (!prop_dictionary_set(csdict, "warning-min", obj))
699 err(EXIT_FAILURE, "prop_dict_set wmin");
700 }
701 }
702
703 /*
704 * Conversions for {critical,warning}-{max,min} properties.
705 */
706 prop_number_t
707 convert_val_to_pnumber(prop_dictionary_t kdict, const char *prop,
708 const char *sensor, const char *value)
709 {
710 prop_object_t obj;
711 prop_number_t num;
712 double val, max, min;
713 char *strval, *endptr;
714 bool celsius;
715 size_t len;
716
717 val = max = min = 0;
718
719 /*
720 * Not allowed in battery sensors.
721 */
722 obj = prop_dictionary_get(kdict, "type");
723 if (prop_string_equals_string(obj, "Battery capacity"))
724 config_errmsg(PROP_ERR, prop, sensor);
725
726 /*
727 * Make the conversion for sensor's type.
728 */
729 if (prop_string_equals_string(obj, "Temperature")) {
730 if (strchr(value, 'C'))
731 celsius = true;
732 else {
733 if (!strchr(value, 'F'))
734 config_errmsg(VALUE_ERR, prop, sensor);
735
736 celsius = false;
737 }
738
739 len = strlen(value);
740 strval = calloc(len, sizeof(*value));
741 if (!strval)
742 err(EXIT_FAILURE, "calloc");
743
744 (void)strlcpy(strval, value, len);
745 val = strtod(strval, &endptr);
746 if (*endptr != '\0') {
747 free(strval);
748 config_errmsg(VALUE_ERR, prop, sensor);
749 }
750
751 /* convert to fahrenheit */
752 if (!celsius)
753 val = (val - 32.0) * (5.0 / 9.0);
754
755 /* convert to microKelvin */
756 val = val * 1000000 + 273150000;
757 num = prop_number_create_unsigned(val);
758 free(strval);
759
760 } else if (prop_string_equals_string(obj, "Fan") ||
761 prop_string_equals_string(obj, "Integer")) {
762 /* no conversion */
763 val = strtod(value, &endptr);
764 if (*endptr != '\0')
765 config_errmsg(VALUE_ERR, prop, sensor);
766
767 num = prop_number_create_unsigned(val);
768
769 } else {
770 obj = prop_dictionary_get(kdict, "max-value");
771 if (obj)
772 max = prop_number_signed_value(obj);
773
774 obj = prop_dictionary_get(kdict, "min-value");
775 if (obj)
776 min = prop_number_signed_value(obj);
777
778 val = strtod(value, &endptr);
779 if (*endptr != '\0')
780 config_errmsg(VALUE_ERR, prop, sensor);
781
782 /* convert to m[V,W,Ohms] again */
783 val *= 1000000.0;
784
785 /*
786 * trying to set a value higher than the max
787 * assigned?
788 */
789 if (max && val > max)
790 config_errmsg(VALUE_ERR, prop, sensor);
791
792 /*
793 * trying to set a value lower than the min
794 * assigned?
795 */
796 if (min && val < min)
797 config_errmsg(VALUE_ERR, prop, sensor);
798
799 num = prop_number_create_signed(val);
800 }
801
802 return num;
803 }
804