1 /* $OpenBSD: sensorsd.c,v 1.47 2009/08/14 15:29:19 cnst Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 2005 Matthew Gream <matthew.gream@pobox.com> 6 * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/param.h> 22 #include <sys/sysctl.h> 23 #include <sys/sensors.h> 24 25 #include <err.h> 26 #include <errno.h> 27 #include <signal.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <syslog.h> 32 #include <time.h> 33 #include <unistd.h> 34 35 #define RFBUFSIZ 28 /* buffer size for print_sensor */ 36 #define RFBUFCNT 4 /* ring buffers */ 37 #define CHECK_PERIOD 20 /* check every n seconds */ 38 39 enum sensorsd_s_status { 40 SENSORSD_S_UNSPEC, /* status is unspecified */ 41 SENSORSD_S_INVALID, /* status is invalid, per SENSOR_FINVALID */ 42 SENSORSD_S_WITHIN, /* status is within limits */ 43 SENSORSD_S_ABOVE, /* status is above the higher limit */ 44 SENSORSD_S_BELOW /* status is below the lower limit */ 45 }; 46 47 struct limits_t { 48 TAILQ_ENTRY(limits_t) entries; 49 enum sensor_type type; /* sensor type */ 50 int numt; /* sensor number */ 51 int64_t last_val; 52 int64_t lower; /* lower limit */ 53 int64_t upper; /* upper limit */ 54 char *command; /* failure command */ 55 time_t astatus_changed; 56 time_t ustatus_changed; 57 enum sensor_status astatus; /* last automatic status */ 58 enum sensor_status astatus2; 59 enum sensorsd_s_status ustatus; /* last user-limit status */ 60 enum sensorsd_s_status ustatus2; 61 int acount; /* stat change counter */ 62 int ucount; /* stat change counter */ 63 u_int8_t flags; /* sensorsd limit flags */ 64 #define SENSORSD_L_USERLIMIT 0x0001 /* user specified limit */ 65 #define SENSORSD_L_ISTATUS 0x0002 /* ignore automatic status */ 66 }; 67 68 struct sdlim_t { 69 TAILQ_ENTRY(sdlim_t) entries; 70 char dxname[16]; /* device unix name */ 71 int dev; /* device number */ 72 int sensor_cnt; 73 TAILQ_HEAD(, limits_t) limits; 74 }; 75 76 void usage(void); 77 void create(void); 78 struct sdlim_t *create_sdlim(struct sensordev *); 79 void destroy_sdlim(struct sdlim_t *); 80 void check(time_t); 81 void check_sdlim(struct sdlim_t *, time_t); 82 void execute(char *); 83 void report(time_t); 84 void report_sdlim(struct sdlim_t *, time_t); 85 static char *print_sensor(enum sensor_type, int64_t); 86 void parse_config(char *); 87 void parse_config_sdlim(struct sdlim_t *, char *); 88 int64_t get_val(char *, int, enum sensor_type); 89 void reparse_cfg(int); 90 91 TAILQ_HEAD(sdlimhead_t, sdlim_t); 92 struct sdlimhead_t sdlims = TAILQ_HEAD_INITIALIZER(sdlims); 93 94 char *configfile; 95 volatile sig_atomic_t reload = 0; 96 int debug = 0; 97 98 void 99 usage(void) 100 { 101 extern char *__progname; 102 fprintf(stderr, "usage: %s [-d] [-c check]\n", __progname); 103 exit(1); 104 } 105 106 int 107 main(int argc, char *argv[]) 108 { 109 time_t last_report = 0, this_check; 110 int ch, check_period = CHECK_PERIOD; 111 const char *errstr; 112 113 while ((ch = getopt(argc, argv, "c:d")) != -1) { 114 switch (ch) { 115 case 'c': 116 check_period = strtonum(optarg, 1, 600, &errstr); 117 if (errstr) 118 errx(1, "check %s", errstr); 119 break; 120 case 'd': 121 debug = 1; 122 break; 123 default: 124 usage(); 125 } 126 } 127 128 argc -= optind; 129 argv += optind; 130 if (argc > 0) 131 usage(); 132 133 openlog("sensorsd", LOG_PID | LOG_NDELAY, LOG_DAEMON); 134 135 create(); 136 137 if (configfile == NULL) 138 if (asprintf(&configfile, "/etc/sensorsd.conf") == -1) 139 err(1, "out of memory"); 140 parse_config(configfile); 141 142 if (debug == 0 && daemon(0, 0) == -1) 143 err(1, "unable to fork"); 144 145 signal(SIGHUP, reparse_cfg); 146 signal(SIGCHLD, SIG_IGN); 147 148 for (;;) { 149 if (reload) { 150 parse_config(configfile); 151 syslog(LOG_INFO, "configuration reloaded"); 152 reload = 0; 153 } 154 this_check = time(NULL); 155 if (!(last_report < this_check)) 156 this_check = last_report + 1; 157 check(this_check); 158 report(last_report); 159 last_report = this_check; 160 sleep(check_period); 161 } 162 } 163 164 void 165 create(void) 166 { 167 struct sensordev sensordev; 168 struct sdlim_t *sdlim; 169 size_t sdlen = sizeof(sensordev); 170 int mib[3], dev, sensor_cnt = 0; 171 172 mib[0] = CTL_HW; 173 mib[1] = HW_SENSORS; 174 175 for (dev = 0; dev < MAXSENSORDEVICES; dev++) { 176 mib[2] = dev; 177 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) { 178 if (errno != ENOENT) 179 warn("sysctl"); 180 continue; 181 } 182 sdlim = create_sdlim(&sensordev); 183 TAILQ_INSERT_TAIL(&sdlims, sdlim, entries); 184 sensor_cnt += sdlim->sensor_cnt; 185 } 186 187 syslog(LOG_INFO, "startup, system has %d sensors", sensor_cnt); 188 } 189 190 struct sdlim_t * 191 create_sdlim(struct sensordev *snsrdev) 192 { 193 struct sensor sensor; 194 struct sdlim_t *sdlim; 195 struct limits_t *limit; 196 size_t slen = sizeof(sensor); 197 int mib[5], numt; 198 enum sensor_type type; 199 200 if ((sdlim = calloc(1, sizeof(struct sdlim_t))) == NULL) 201 err(1, "calloc"); 202 203 strlcpy(sdlim->dxname, snsrdev->xname, sizeof(sdlim->dxname)); 204 205 mib[0] = CTL_HW; 206 mib[1] = HW_SENSORS; 207 mib[2] = sdlim->dev = snsrdev->num; 208 209 TAILQ_INIT(&sdlim->limits); 210 211 for (type = 0; type < SENSOR_MAX_TYPES; type++) { 212 mib[3] = type; 213 for (numt = 0; numt < snsrdev->maxnumt[type]; numt++) { 214 mib[4] = numt; 215 if (sysctl(mib, 5, &sensor, &slen, NULL, 0) == -1) { 216 if (errno != ENOENT) 217 warn("sysctl"); 218 continue; 219 } 220 if ((limit = calloc(1, sizeof(struct limits_t))) == 221 NULL) 222 err(1, "calloc"); 223 limit->type = type; 224 limit->numt = numt; 225 TAILQ_INSERT_TAIL(&sdlim->limits, limit, entries); 226 sdlim->sensor_cnt++; 227 } 228 } 229 230 return (sdlim); 231 } 232 233 void 234 destroy_sdlim(struct sdlim_t *sdlim) 235 { 236 struct limits_t *limit; 237 238 while((limit = TAILQ_FIRST(&sdlim->limits)) != NULL) { 239 TAILQ_REMOVE(&sdlim->limits, limit, entries); 240 if (limit->command != NULL) 241 free(limit->command); 242 free(limit); 243 } 244 free(sdlim); 245 } 246 247 void 248 check(time_t this_check) 249 { 250 struct sensordev sensordev; 251 struct sdlim_t *sdlim, *next; 252 int mib[3]; 253 int h, t, i; 254 size_t sdlen = sizeof(sensordev); 255 256 if (TAILQ_EMPTY(&sdlims)) { 257 h = 0; 258 t = -1; 259 } else { 260 h = TAILQ_FIRST(&sdlims)->dev; 261 t = TAILQ_LAST(&sdlims, sdlimhead_t)->dev; 262 } 263 sdlim = TAILQ_FIRST(&sdlims); 264 265 mib[0] = CTL_HW; 266 mib[1] = HW_SENSORS; 267 /* look ahead for 4 more sensordevs */ 268 for (i = h; i <= t + 4; i++) { 269 if (sdlim != NULL && i > sdlim->dev) 270 sdlim = TAILQ_NEXT(sdlim, entries); 271 if (sdlim == NULL && i <= t) 272 syslog(LOG_ALERT, "inconsistent sdlim logic"); 273 mib[2] = i; 274 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) { 275 if (errno != ENOENT) 276 warn("sysctl"); 277 if (sdlim != NULL && i == sdlim->dev) { 278 next = TAILQ_NEXT(sdlim, entries); 279 TAILQ_REMOVE(&sdlims, sdlim, entries); 280 syslog(LOG_INFO, "%s has disappeared", 281 sdlim->dxname); 282 destroy_sdlim(sdlim); 283 sdlim = next; 284 } 285 continue; 286 } 287 if (sdlim != NULL && i == sdlim->dev) { 288 if (strcmp(sdlim->dxname, sensordev.xname) == 0) { 289 check_sdlim(sdlim, this_check); 290 continue; 291 } else { 292 next = TAILQ_NEXT(sdlim, entries); 293 TAILQ_REMOVE(&sdlims, sdlim, entries); 294 syslog(LOG_INFO, "%s has been replaced", 295 sdlim->dxname); 296 destroy_sdlim(sdlim); 297 sdlim = next; 298 } 299 } 300 next = create_sdlim(&sensordev); 301 /* inserting next before sdlim */ 302 if (sdlim != NULL) 303 TAILQ_INSERT_BEFORE(sdlim, next, entries); 304 else 305 TAILQ_INSERT_TAIL(&sdlims, next, entries); 306 syslog(LOG_INFO, "%s has appeared", next->dxname); 307 sdlim = next; 308 parse_config_sdlim(sdlim, configfile); 309 check_sdlim(sdlim, this_check); 310 } 311 312 if (TAILQ_EMPTY(&sdlims)) 313 return; 314 /* Ensure that our queue is consistent. */ 315 for (sdlim = TAILQ_FIRST(&sdlims); 316 (next = TAILQ_NEXT(sdlim, entries)) != NULL; 317 sdlim = next) 318 if (sdlim->dev > next->dev) 319 syslog(LOG_ALERT, "inconsistent sdlims queue"); 320 } 321 322 void 323 check_sdlim(struct sdlim_t *sdlim, time_t this_check) 324 { 325 struct sensor sensor; 326 struct limits_t *limit; 327 size_t len; 328 int mib[5]; 329 330 mib[0] = CTL_HW; 331 mib[1] = HW_SENSORS; 332 mib[2] = sdlim->dev; 333 len = sizeof(sensor); 334 335 TAILQ_FOREACH(limit, &sdlim->limits, entries) { 336 if ((limit->flags & SENSORSD_L_ISTATUS) && 337 !(limit->flags & SENSORSD_L_USERLIMIT)) 338 continue; 339 340 mib[3] = limit->type; 341 mib[4] = limit->numt; 342 if (sysctl(mib, 5, &sensor, &len, NULL, 0) == -1) 343 err(1, "sysctl"); 344 345 if (!(limit->flags & SENSORSD_L_ISTATUS)) { 346 enum sensor_status newastatus = sensor.status; 347 348 if (limit->astatus != newastatus) { 349 if (limit->astatus2 != newastatus) { 350 limit->astatus2 = newastatus; 351 limit->acount = 0; 352 } else if (++limit->acount >= 3) { 353 limit->last_val = sensor.value; 354 limit->astatus2 = 355 limit->astatus = newastatus; 356 limit->astatus_changed = this_check; 357 } 358 } 359 } 360 361 if (limit->flags & SENSORSD_L_USERLIMIT) { 362 enum sensorsd_s_status newustatus; 363 364 if (sensor.flags & SENSOR_FINVALID) 365 newustatus = SENSORSD_S_INVALID; 366 else if (sensor.value > limit->upper) 367 newustatus = SENSORSD_S_ABOVE; 368 else if (sensor.value < limit->lower) 369 newustatus = SENSORSD_S_BELOW; 370 else 371 newustatus = SENSORSD_S_WITHIN; 372 373 if (limit->ustatus != newustatus) { 374 if (limit->ustatus2 != newustatus) { 375 limit->ustatus2 = newustatus; 376 limit->ucount = 0; 377 } else if (++limit->ucount >= 3) { 378 limit->last_val = sensor.value; 379 limit->ustatus2 = 380 limit->ustatus = newustatus; 381 limit->ustatus_changed = this_check; 382 } 383 } 384 } 385 } 386 } 387 388 void 389 execute(char *command) 390 { 391 char *argp[] = {"sh", "-c", command, NULL}; 392 393 switch (fork()) { 394 case -1: 395 syslog(LOG_CRIT, "execute: fork() failed"); 396 break; 397 case 0: 398 execv("/bin/sh", argp); 399 _exit(1); 400 /* NOTREACHED */ 401 default: 402 break; 403 } 404 } 405 406 void 407 report(time_t last_report) 408 { 409 struct sdlim_t *sdlim; 410 411 TAILQ_FOREACH(sdlim, &sdlims, entries) 412 report_sdlim(sdlim, last_report); 413 } 414 415 void 416 report_sdlim(struct sdlim_t *sdlim, time_t last_report) 417 { 418 struct limits_t *limit; 419 420 TAILQ_FOREACH(limit, &sdlim->limits, entries) { 421 if ((limit->astatus_changed <= last_report) && 422 (limit->ustatus_changed <= last_report)) 423 continue; 424 425 if (limit->astatus_changed > last_report) { 426 const char *as = NULL; 427 428 switch (limit->astatus) { 429 case SENSOR_S_UNSPEC: 430 as = ""; 431 break; 432 case SENSOR_S_OK: 433 as = ", OK"; 434 break; 435 case SENSOR_S_WARN: 436 as = ", WARN"; 437 break; 438 case SENSOR_S_CRIT: 439 as = ", CRITICAL"; 440 break; 441 case SENSOR_S_UNKNOWN: 442 as = ", UNKNOWN"; 443 break; 444 } 445 syslog(limit->astatus == SENSOR_S_OK ? LOG_INFO : 446 LOG_ALERT, "%s.%s%d: %s%s", 447 sdlim->dxname, sensor_type_s[limit->type], 448 limit->numt, 449 print_sensor(limit->type, limit->last_val), as); 450 } 451 452 if (limit->ustatus_changed > last_report) { 453 char us[BUFSIZ]; 454 455 switch (limit->ustatus) { 456 case SENSORSD_S_UNSPEC: 457 snprintf(us, sizeof(us), 458 "ustatus uninitialised"); 459 break; 460 case SENSORSD_S_INVALID: 461 snprintf(us, sizeof(us), "marked invalid"); 462 break; 463 case SENSORSD_S_WITHIN: 464 snprintf(us, sizeof(us), "within limits: %s", 465 print_sensor(limit->type, limit->last_val)); 466 break; 467 case SENSORSD_S_ABOVE: 468 snprintf(us, sizeof(us), "exceeds limits: %s is above %s", 469 print_sensor(limit->type, limit->last_val), 470 print_sensor(limit->type, limit->upper)); 471 break; 472 case SENSORSD_S_BELOW: 473 snprintf(us, sizeof(us), "exceeds limits: %s is below %s", 474 print_sensor(limit->type, limit->last_val), 475 print_sensor(limit->type, limit->lower)); 476 break; 477 } 478 syslog(limit->ustatus == SENSORSD_S_WITHIN ? LOG_INFO : 479 LOG_ALERT, "%s.%s%d: %s", 480 sdlim->dxname, sensor_type_s[limit->type], 481 limit->numt, us); 482 } 483 484 if (limit->command) { 485 int i = 0, n = 0, r; 486 char *cmd = limit->command; 487 char buf[BUFSIZ]; 488 int len = sizeof(buf); 489 490 buf[0] = '\0'; 491 for (i = n = 0; n < len; ++i) { 492 if (cmd[i] == '\0') { 493 buf[n++] = '\0'; 494 break; 495 } 496 if (cmd[i] != '%') { 497 buf[n++] = limit->command[i]; 498 continue; 499 } 500 i++; 501 if (cmd[i] == '\0') { 502 buf[n++] = '\0'; 503 break; 504 } 505 506 switch (cmd[i]) { 507 case 'x': 508 r = snprintf(&buf[n], len - n, "%s", 509 sdlim->dxname); 510 break; 511 case 't': 512 r = snprintf(&buf[n], len - n, "%s", 513 sensor_type_s[limit->type]); 514 break; 515 case 'n': 516 r = snprintf(&buf[n], len - n, "%d", 517 limit->numt); 518 break; 519 case 'l': 520 { 521 char *s = ""; 522 switch(limit->ustatus){ 523 case SENSORSD_S_UNSPEC: 524 s = "uninitialised"; 525 break; 526 case SENSORSD_S_INVALID: 527 s = "invalid"; 528 break; 529 case SENSORSD_S_WITHIN: 530 s = "within"; 531 break; 532 case SENSORSD_S_ABOVE: 533 s = "above"; 534 break; 535 case SENSORSD_S_BELOW: 536 s = "below"; 537 break; 538 } 539 r = snprintf(&buf[n], len - n, "%s", 540 s); 541 break; 542 } 543 case 's': 544 { 545 char *s; 546 switch(limit->astatus){ 547 case SENSOR_S_UNSPEC: 548 s = "UNSPEC"; 549 break; 550 case SENSOR_S_OK: 551 s = "OK"; 552 break; 553 case SENSOR_S_WARN: 554 s = "WARNING"; 555 break; 556 case SENSOR_S_CRIT: 557 s = "CRITICAL"; 558 break; 559 default: 560 s = "UNKNOWN"; 561 } 562 r = snprintf(&buf[n], len - n, "%s", 563 s); 564 break; 565 } 566 case '2': 567 r = snprintf(&buf[n], len - n, "%s", 568 print_sensor(limit->type, 569 limit->last_val)); 570 break; 571 case '3': 572 r = snprintf(&buf[n], len - n, "%s", 573 print_sensor(limit->type, 574 limit->lower)); 575 break; 576 case '4': 577 r = snprintf(&buf[n], len - n, "%s", 578 print_sensor(limit->type, 579 limit->upper)); 580 break; 581 default: 582 r = snprintf(&buf[n], len - n, "%%%c", 583 cmd[i]); 584 break; 585 } 586 if (r < 0 || (r >= len - n)) { 587 syslog(LOG_CRIT, "could not parse " 588 "command"); 589 return; 590 } 591 if (r > 0) 592 n += r; 593 } 594 if (buf[0]) 595 execute(buf); 596 } 597 } 598 } 599 600 const char *drvstat[] = { 601 NULL, "empty", "ready", "powerup", "online", "idle", "active", 602 "rebuild", "powerdown", "fail", "pfail" 603 }; 604 605 static char * 606 print_sensor(enum sensor_type type, int64_t value) 607 { 608 static char rfbuf[RFBUFCNT][RFBUFSIZ]; /* ring buffer */ 609 static int idx; 610 char *fbuf; 611 612 fbuf = rfbuf[idx++]; 613 if (idx == RFBUFCNT) 614 idx = 0; 615 616 switch (type) { 617 case SENSOR_TEMP: 618 snprintf(fbuf, RFBUFSIZ, "%.2f degC", 619 (value - 273150000) / 1000000.0); 620 break; 621 case SENSOR_FANRPM: 622 snprintf(fbuf, RFBUFSIZ, "%lld RPM", value); 623 break; 624 case SENSOR_VOLTS_DC: 625 snprintf(fbuf, RFBUFSIZ, "%.2f V DC", value / 1000000.0); 626 break; 627 case SENSOR_WATTS: 628 snprintf(fbuf, RFBUFSIZ, "%.2f W", value / 1000000.0); 629 break; 630 case SENSOR_AMPS: 631 snprintf(fbuf, RFBUFSIZ, "%.2f A", value / 1000000.0); 632 break; 633 case SENSOR_WATTHOUR: 634 snprintf(fbuf, RFBUFSIZ, "%.2f Wh", value / 1000000.0); 635 break; 636 case SENSOR_AMPHOUR: 637 snprintf(fbuf, RFBUFSIZ, "%.2f Ah", value / 1000000.0); 638 break; 639 case SENSOR_INDICATOR: 640 snprintf(fbuf, RFBUFSIZ, "%s", value? "On" : "Off"); 641 break; 642 case SENSOR_INTEGER: 643 snprintf(fbuf, RFBUFSIZ, "%lld", value); 644 break; 645 case SENSOR_PERCENT: 646 snprintf(fbuf, RFBUFSIZ, "%.2f%%", value / 1000.0); 647 break; 648 case SENSOR_LUX: 649 snprintf(fbuf, RFBUFSIZ, "%.2f lx", value / 1000000.0); 650 break; 651 case SENSOR_DRIVE: 652 if (0 < value && value < sizeof(drvstat)/sizeof(drvstat[0])) 653 snprintf(fbuf, RFBUFSIZ, "%s", drvstat[value]); 654 else 655 snprintf(fbuf, RFBUFSIZ, "%lld ???", value); 656 break; 657 case SENSOR_TIMEDELTA: 658 snprintf(fbuf, RFBUFSIZ, "%.6f secs", value / 1000000000.0); 659 break; 660 default: 661 snprintf(fbuf, RFBUFSIZ, "%lld ???", value); 662 } 663 664 return (fbuf); 665 } 666 667 void 668 parse_config(char *cf) 669 { 670 struct sdlim_t *sdlim; 671 672 TAILQ_FOREACH(sdlim, &sdlims, entries) 673 parse_config_sdlim(sdlim, cf); 674 } 675 676 void 677 parse_config_sdlim(struct sdlim_t *sdlim, char *cf) 678 { 679 struct limits_t *p; 680 char *buf = NULL, *ebuf = NULL; 681 char node[48]; 682 char *cfa[2]; 683 684 cfa[0] = cf; 685 cfa[1] = NULL; 686 687 TAILQ_FOREACH(p, &sdlim->limits, entries) { 688 snprintf(node, sizeof(node), "hw.sensors.%s.%s%d", 689 sdlim->dxname, sensor_type_s[p->type], p->numt); 690 p->flags = 0; 691 if (cgetent(&buf, cfa, node) != 0) 692 if (cgetent(&buf, cfa, sensor_type_s[p->type]) != 0) 693 continue; 694 if (cgetcap(buf, "istatus", ':')) 695 p->flags |= SENSORSD_L_ISTATUS; 696 if (cgetstr(buf, "low", &ebuf) < 0) 697 ebuf = NULL; 698 p->lower = get_val(ebuf, 0, p->type); 699 if (cgetstr(buf, "high", &ebuf) < 0) 700 ebuf = NULL; 701 p->upper = get_val(ebuf, 1, p->type); 702 if (cgetstr(buf, "command", &ebuf) < 0) 703 ebuf = NULL; 704 if (ebuf) 705 asprintf(&(p->command), "%s", ebuf); 706 free(buf); 707 buf = NULL; 708 if (p->lower != LLONG_MIN || p->upper != LLONG_MAX) 709 p->flags |= SENSORSD_L_USERLIMIT; 710 } 711 } 712 713 int64_t 714 get_val(char *buf, int upper, enum sensor_type type) 715 { 716 double val; 717 int64_t rval = 0; 718 char *p; 719 720 if (buf == NULL) { 721 if (upper) 722 return (LLONG_MAX); 723 else 724 return (LLONG_MIN); 725 } 726 727 val = strtod(buf, &p); 728 if (buf == p) 729 err(1, "incorrect value: %s", buf); 730 731 switch(type) { 732 case SENSOR_TEMP: 733 switch(*p) { 734 case 'C': 735 printf("C"); 736 rval = val * 1000 * 1000 + 273150000; 737 break; 738 case 'F': 739 printf("F"); 740 rval = (val * 1000 * 1000 + 459670000) / 9 * 5; 741 break; 742 default: 743 errx(1, "unknown unit %s for temp sensor", p); 744 } 745 break; 746 case SENSOR_FANRPM: 747 rval = val; 748 break; 749 case SENSOR_VOLTS_DC: 750 if (*p != 'V') 751 errx(1, "unknown unit %s for voltage sensor", p); 752 rval = val * 1000 * 1000; 753 break; 754 case SENSOR_PERCENT: 755 rval = val * 1000.0; 756 break; 757 case SENSOR_INDICATOR: 758 case SENSOR_INTEGER: 759 case SENSOR_DRIVE: 760 rval = val; 761 break; 762 case SENSOR_WATTS: 763 case SENSOR_AMPS: 764 case SENSOR_WATTHOUR: 765 case SENSOR_AMPHOUR: 766 case SENSOR_LUX: 767 rval = val * 1000 * 1000; 768 break; 769 case SENSOR_TIMEDELTA: 770 rval = val * 1000 * 1000 * 1000; 771 break; 772 default: 773 errx(1, "unsupported sensor type"); 774 /* not reached */ 775 } 776 free(buf); 777 return (rval); 778 } 779 780 /* ARGSUSED */ 781 void 782 reparse_cfg(int signo) 783 { 784 reload = 1; 785 } 786