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