1 /* $OpenBSD: sensorsd.c,v 1.45 2008/06/11 21:21:50 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 /* Ensure that our queue is consistent. */ 313 for (sdlim = TAILQ_FIRST(&sdlims); 314 (next = TAILQ_NEXT(sdlim, entries)) != NULL; 315 sdlim = next) 316 if (sdlim->dev > next->dev) 317 syslog(LOG_ALERT, "inconsistent sdlims queue"); 318 } 319 320 void 321 check_sdlim(struct sdlim_t *sdlim, time_t this_check) 322 { 323 struct sensor sensor; 324 struct limits_t *limit; 325 size_t len; 326 int mib[5]; 327 328 mib[0] = CTL_HW; 329 mib[1] = HW_SENSORS; 330 mib[2] = sdlim->dev; 331 len = sizeof(sensor); 332 333 TAILQ_FOREACH(limit, &sdlim->limits, entries) { 334 if ((limit->flags & SENSORSD_L_ISTATUS) && 335 !(limit->flags & SENSORSD_L_USERLIMIT)) 336 continue; 337 338 mib[3] = limit->type; 339 mib[4] = limit->numt; 340 if (sysctl(mib, 5, &sensor, &len, NULL, 0) == -1) 341 err(1, "sysctl"); 342 343 if (!(limit->flags & SENSORSD_L_ISTATUS)) { 344 enum sensor_status newastatus = sensor.status; 345 346 if (limit->astatus != newastatus) { 347 if (limit->astatus2 != newastatus) { 348 limit->astatus2 = newastatus; 349 limit->acount = 0; 350 } else if (++limit->acount >= 3) { 351 limit->last_val = sensor.value; 352 limit->astatus2 = 353 limit->astatus = newastatus; 354 limit->astatus_changed = this_check; 355 } 356 } 357 } 358 359 if (limit->flags & SENSORSD_L_USERLIMIT) { 360 enum sensorsd_s_status newustatus; 361 362 if (sensor.flags & SENSOR_FINVALID) 363 newustatus = SENSORSD_S_INVALID; 364 else if (sensor.value > limit->upper) 365 newustatus = SENSORSD_S_ABOVE; 366 else if (sensor.value < limit->lower) 367 newustatus = SENSORSD_S_BELOW; 368 else 369 newustatus = SENSORSD_S_WITHIN; 370 371 if (limit->ustatus != newustatus) { 372 if (limit->ustatus2 != newustatus) { 373 limit->ustatus2 = newustatus; 374 limit->ucount = 0; 375 } else if (++limit->ucount >= 3) { 376 limit->last_val = sensor.value; 377 limit->ustatus2 = 378 limit->ustatus = newustatus; 379 limit->ustatus_changed = this_check; 380 } 381 } 382 } 383 } 384 } 385 386 void 387 execute(char *command) 388 { 389 char *argp[] = {"sh", "-c", command, NULL}; 390 391 switch (fork()) { 392 case -1: 393 syslog(LOG_CRIT, "execute: fork() failed"); 394 break; 395 case 0: 396 execv("/bin/sh", argp); 397 _exit(1); 398 /* NOTREACHED */ 399 default: 400 break; 401 } 402 } 403 404 void 405 report(time_t last_report) 406 { 407 struct sdlim_t *sdlim; 408 409 TAILQ_FOREACH(sdlim, &sdlims, entries) 410 report_sdlim(sdlim, last_report); 411 } 412 413 void 414 report_sdlim(struct sdlim_t *sdlim, time_t last_report) 415 { 416 struct limits_t *limit; 417 418 TAILQ_FOREACH(limit, &sdlim->limits, entries) { 419 if ((limit->astatus_changed <= last_report) && 420 (limit->ustatus_changed <= last_report)) 421 continue; 422 423 if (limit->astatus_changed > last_report) { 424 const char *as = NULL; 425 426 switch (limit->astatus) { 427 case SENSOR_S_UNSPEC: 428 as = ""; 429 break; 430 case SENSOR_S_OK: 431 as = ", OK"; 432 break; 433 case SENSOR_S_WARN: 434 as = ", WARN"; 435 break; 436 case SENSOR_S_CRIT: 437 as = ", CRITICAL"; 438 break; 439 case SENSOR_S_UNKNOWN: 440 as = ", UNKNOWN"; 441 break; 442 } 443 syslog(limit->astatus == SENSOR_S_OK ? LOG_INFO : 444 LOG_ALERT, "%s.%s%d: %s%s", 445 sdlim->dxname, sensor_type_s[limit->type], 446 limit->numt, 447 print_sensor(limit->type, limit->last_val), as); 448 } 449 450 if (limit->ustatus_changed > last_report) { 451 char us[BUFSIZ]; 452 453 switch (limit->ustatus) { 454 case SENSORSD_S_UNSPEC: 455 snprintf(us, sizeof(us), 456 "ustatus uninitialised"); 457 break; 458 case SENSORSD_S_INVALID: 459 snprintf(us, sizeof(us), "marked invalid"); 460 break; 461 case SENSORSD_S_WITHIN: 462 snprintf(us, sizeof(us), "within limits: %s", 463 print_sensor(limit->type, limit->last_val)); 464 break; 465 case SENSORSD_S_ABOVE: 466 snprintf(us, sizeof(us), "exceeds limits: %s is above %s", 467 print_sensor(limit->type, limit->last_val), 468 print_sensor(limit->type, limit->upper)); 469 break; 470 case SENSORSD_S_BELOW: 471 snprintf(us, sizeof(us), "exceeds limits: %s is below %s", 472 print_sensor(limit->type, limit->last_val), 473 print_sensor(limit->type, limit->lower)); 474 break; 475 } 476 syslog(limit->ustatus == SENSORSD_S_WITHIN ? LOG_INFO : 477 LOG_ALERT, "%s.%s%d: %s", 478 sdlim->dxname, sensor_type_s[limit->type], 479 limit->numt, us); 480 } 481 482 if (limit->command) { 483 int i = 0, n = 0, r; 484 char *cmd = limit->command; 485 char buf[BUFSIZ]; 486 int len = sizeof(buf); 487 488 buf[0] = '\0'; 489 for (i = n = 0; n < len; ++i) { 490 if (cmd[i] == '\0') { 491 buf[n++] = '\0'; 492 break; 493 } 494 if (cmd[i] != '%') { 495 buf[n++] = limit->command[i]; 496 continue; 497 } 498 i++; 499 if (cmd[i] == '\0') { 500 buf[n++] = '\0'; 501 break; 502 } 503 504 switch (cmd[i]) { 505 case 'x': 506 r = snprintf(&buf[n], len - n, "%s", 507 sdlim->dxname); 508 break; 509 case 't': 510 r = snprintf(&buf[n], len - n, "%s", 511 sensor_type_s[limit->type]); 512 break; 513 case 'n': 514 r = snprintf(&buf[n], len - n, "%d", 515 limit->numt); 516 break; 517 case 'l': 518 { 519 char *s = ""; 520 switch(limit->ustatus){ 521 case SENSORSD_S_UNSPEC: 522 s = "uninitialised"; 523 break; 524 case SENSORSD_S_INVALID: 525 s = "invalid"; 526 break; 527 case SENSORSD_S_WITHIN: 528 s = "within"; 529 break; 530 case SENSORSD_S_ABOVE: 531 s = "above"; 532 break; 533 case SENSORSD_S_BELOW: 534 s = "below"; 535 break; 536 } 537 r = snprintf(&buf[n], len - n, "%s", 538 s); 539 break; 540 } 541 case 's': 542 { 543 char *s; 544 switch(limit->astatus){ 545 case SENSOR_S_UNSPEC: 546 s = "UNSPEC"; 547 break; 548 case SENSOR_S_OK: 549 s = "OK"; 550 break; 551 case SENSOR_S_WARN: 552 s = "WARNING"; 553 break; 554 case SENSOR_S_CRIT: 555 s = "CRITICAL"; 556 break; 557 default: 558 s = "UNKNOWN"; 559 } 560 r = snprintf(&buf[n], len - n, "%s", 561 s); 562 break; 563 } 564 case '2': 565 r = snprintf(&buf[n], len - n, "%s", 566 print_sensor(limit->type, 567 limit->last_val)); 568 break; 569 case '3': 570 r = snprintf(&buf[n], len - n, "%s", 571 print_sensor(limit->type, 572 limit->lower)); 573 break; 574 case '4': 575 r = snprintf(&buf[n], len - n, "%s", 576 print_sensor(limit->type, 577 limit->upper)); 578 break; 579 default: 580 r = snprintf(&buf[n], len - n, "%%%c", 581 cmd[i]); 582 break; 583 } 584 if (r < 0 || (r >= len - n)) { 585 syslog(LOG_CRIT, "could not parse " 586 "command"); 587 return; 588 } 589 if (r > 0) 590 n += r; 591 } 592 if (buf[0]) 593 execute(buf); 594 } 595 } 596 } 597 598 const char *drvstat[] = { 599 NULL, "empty", "ready", "powerup", "online", "idle", "active", 600 "rebuild", "powerdown", "fail", "pfail" 601 }; 602 603 static char * 604 print_sensor(enum sensor_type type, int64_t value) 605 { 606 static char rfbuf[RFBUFCNT][RFBUFSIZ]; /* ring buffer */ 607 static int idx; 608 char *fbuf; 609 610 fbuf = rfbuf[idx++]; 611 if (idx == RFBUFCNT) 612 idx = 0; 613 614 switch (type) { 615 case SENSOR_TEMP: 616 snprintf(fbuf, RFBUFSIZ, "%.2f degC", 617 (value - 273150000) / 1000000.0); 618 break; 619 case SENSOR_FANRPM: 620 snprintf(fbuf, RFBUFSIZ, "%lld RPM", value); 621 break; 622 case SENSOR_VOLTS_DC: 623 snprintf(fbuf, RFBUFSIZ, "%.2f V DC", value / 1000000.0); 624 break; 625 case SENSOR_AMPS: 626 snprintf(fbuf, RFBUFSIZ, "%.2f A", value / 1000000.0); 627 break; 628 case SENSOR_WATTHOUR: 629 snprintf(fbuf, RFBUFSIZ, "%.2f Wh", value / 1000000.0); 630 break; 631 case SENSOR_AMPHOUR: 632 snprintf(fbuf, RFBUFSIZ, "%.2f Ah", value / 1000000.0); 633 break; 634 case SENSOR_INDICATOR: 635 snprintf(fbuf, RFBUFSIZ, "%s", value? "On" : "Off"); 636 break; 637 case SENSOR_INTEGER: 638 snprintf(fbuf, RFBUFSIZ, "%lld", value); 639 break; 640 case SENSOR_PERCENT: 641 snprintf(fbuf, RFBUFSIZ, "%.2f%%", value / 1000.0); 642 break; 643 case SENSOR_LUX: 644 snprintf(fbuf, RFBUFSIZ, "%.2f lx", value / 1000000.0); 645 break; 646 case SENSOR_DRIVE: 647 if (0 < value && value < sizeof(drvstat)/sizeof(drvstat[0])) 648 snprintf(fbuf, RFBUFSIZ, "%s", drvstat[value]); 649 else 650 snprintf(fbuf, RFBUFSIZ, "%lld ???", value); 651 break; 652 case SENSOR_TIMEDELTA: 653 snprintf(fbuf, RFBUFSIZ, "%.6f secs", value / 1000000000.0); 654 break; 655 default: 656 snprintf(fbuf, RFBUFSIZ, "%lld ???", value); 657 } 658 659 return (fbuf); 660 } 661 662 void 663 parse_config(char *cf) 664 { 665 struct sdlim_t *sdlim; 666 667 TAILQ_FOREACH(sdlim, &sdlims, entries) 668 parse_config_sdlim(sdlim, cf); 669 } 670 671 void 672 parse_config_sdlim(struct sdlim_t *sdlim, char *cf) 673 { 674 struct limits_t *p; 675 char *buf = NULL, *ebuf = NULL; 676 char node[48]; 677 char *cfa[2]; 678 679 cfa[0] = cf; 680 cfa[1] = NULL; 681 682 TAILQ_FOREACH(p, &sdlim->limits, entries) { 683 snprintf(node, sizeof(node), "hw.sensors.%s.%s%d", 684 sdlim->dxname, sensor_type_s[p->type], p->numt); 685 p->flags = 0; 686 if (cgetent(&buf, cfa, node) != 0) 687 if (cgetent(&buf, cfa, sensor_type_s[p->type]) != 0) 688 continue; 689 if (cgetcap(buf, "istatus", ':')) 690 p->flags |= SENSORSD_L_ISTATUS; 691 if (cgetstr(buf, "low", &ebuf) < 0) 692 ebuf = NULL; 693 p->lower = get_val(ebuf, 0, p->type); 694 if (cgetstr(buf, "high", &ebuf) < 0) 695 ebuf = NULL; 696 p->upper = get_val(ebuf, 1, p->type); 697 if (cgetstr(buf, "command", &ebuf) < 0) 698 ebuf = NULL; 699 if (ebuf) 700 asprintf(&(p->command), "%s", ebuf); 701 free(buf); 702 buf = NULL; 703 if (p->lower != LLONG_MIN || p->upper != LLONG_MAX) 704 p->flags |= SENSORSD_L_USERLIMIT; 705 } 706 } 707 708 int64_t 709 get_val(char *buf, int upper, enum sensor_type type) 710 { 711 double val; 712 int64_t rval = 0; 713 char *p; 714 715 if (buf == NULL) { 716 if (upper) 717 return (LLONG_MAX); 718 else 719 return (LLONG_MIN); 720 } 721 722 val = strtod(buf, &p); 723 if (buf == p) 724 err(1, "incorrect value: %s", buf); 725 726 switch(type) { 727 case SENSOR_TEMP: 728 switch(*p) { 729 case 'C': 730 printf("C"); 731 rval = val * 1000 * 1000 + 273150000; 732 break; 733 case 'F': 734 printf("F"); 735 rval = (val * 1000 * 1000 + 459670000) / 9 * 5; 736 break; 737 default: 738 errx(1, "unknown unit %s for temp sensor", p); 739 } 740 break; 741 case SENSOR_FANRPM: 742 rval = val; 743 break; 744 case SENSOR_VOLTS_DC: 745 if (*p != 'V') 746 errx(1, "unknown unit %s for voltage sensor", p); 747 rval = val * 1000 * 1000; 748 break; 749 case SENSOR_PERCENT: 750 rval = val * 1000.0; 751 break; 752 case SENSOR_INDICATOR: 753 case SENSOR_INTEGER: 754 case SENSOR_DRIVE: 755 rval = val; 756 break; 757 case SENSOR_AMPS: 758 case SENSOR_WATTHOUR: 759 case SENSOR_AMPHOUR: 760 case SENSOR_LUX: 761 rval = val * 1000 * 1000; 762 break; 763 case SENSOR_TIMEDELTA: 764 rval = val * 1000 * 1000 * 1000; 765 break; 766 default: 767 errx(1, "unsupported sensor type"); 768 /* not reached */ 769 } 770 free(buf); 771 return (rval); 772 } 773 774 /* ARGSUSED */ 775 void 776 reparse_cfg(int signo) 777 { 778 reload = 1; 779 } 780