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