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