1 /* $OpenBSD: sensorsd.c,v 1.46 2008/06/14 00:16:10 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 <inttypes.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 fprintf(stderr, "usage: %s [-d] [-c check]\n", getprogname()); 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 const 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", __DECONST(char **, 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 const 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 const 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, "%"PRId64" RPM", value); 623 break; 624 case SENSOR_VOLTS_DC: 625 snprintf(fbuf, RFBUFSIZ, "%.2f V DC", value / 1000000.0); 626 break; 627 case SENSOR_AMPS: 628 snprintf(fbuf, RFBUFSIZ, "%.2f A", value / 1000000.0); 629 break; 630 case SENSOR_WATTHOUR: 631 snprintf(fbuf, RFBUFSIZ, "%.2f Wh", value / 1000000.0); 632 break; 633 case SENSOR_AMPHOUR: 634 snprintf(fbuf, RFBUFSIZ, "%.2f Ah", value / 1000000.0); 635 break; 636 case SENSOR_INDICATOR: 637 snprintf(fbuf, RFBUFSIZ, "%s", value? "On" : "Off"); 638 break; 639 case SENSOR_FREQ: 640 snprintf(fbuf, RFBUFSIZ, "%"PRId64" Hz", value); 641 break; 642 case SENSOR_ECC: 643 case SENSOR_INTEGER: 644 snprintf(fbuf, RFBUFSIZ, "%"PRId64, value); 645 break; 646 case SENSOR_PERCENT: 647 snprintf(fbuf, RFBUFSIZ, "%.2f%%", value / 1000.0); 648 break; 649 case SENSOR_LUX: 650 snprintf(fbuf, RFBUFSIZ, "%.2f lx", value / 1000000.0); 651 break; 652 case SENSOR_DRIVE: 653 if (0 < value && value < (int64_t)NELEM(drvstat)) 654 snprintf(fbuf, RFBUFSIZ, "%s", drvstat[value]); 655 else 656 snprintf(fbuf, RFBUFSIZ, "%"PRId64" ???", value); 657 break; 658 case SENSOR_TIMEDELTA: 659 snprintf(fbuf, RFBUFSIZ, "%.6f secs", value / 1000000000.0); 660 break; 661 default: 662 snprintf(fbuf, RFBUFSIZ, "%"PRId64" ???", value); 663 } 664 665 return (fbuf); 666 } 667 668 void 669 parse_config(char *cf) 670 { 671 struct sdlim_t *sdlim; 672 673 TAILQ_FOREACH(sdlim, &sdlims, entries) 674 parse_config_sdlim(sdlim, cf); 675 } 676 677 void 678 parse_config_sdlim(struct sdlim_t *sdlim, char *cf) 679 { 680 struct limits_t *p; 681 char *buf = NULL, *ebuf = NULL; 682 char node[48]; 683 char *cfa[2]; 684 685 cfa[0] = cf; 686 cfa[1] = NULL; 687 688 TAILQ_FOREACH(p, &sdlim->limits, entries) { 689 snprintf(node, sizeof(node), "hw.sensors.%s.%s%d", 690 sdlim->dxname, sensor_type_s[p->type], p->numt); 691 p->flags = 0; 692 if (cgetent(&buf, cfa, node) != 0) 693 if (cgetent(&buf, cfa, sensor_type_s[p->type]) != 0) 694 continue; 695 if (cgetcap(buf, "istatus", ':')) 696 p->flags |= SENSORSD_L_ISTATUS; 697 if (cgetstr(buf, "low", &ebuf) < 0) 698 ebuf = NULL; 699 p->lower = get_val(ebuf, 0, p->type); 700 if (cgetstr(buf, "high", &ebuf) < 0) 701 ebuf = NULL; 702 p->upper = get_val(ebuf, 1, p->type); 703 if (cgetstr(buf, "command", &ebuf) < 0) 704 ebuf = NULL; 705 if (ebuf) 706 asprintf(&(p->command), "%s", ebuf); 707 free(buf); 708 buf = NULL; 709 if (p->lower != LLONG_MIN || p->upper != LLONG_MAX) 710 p->flags |= SENSORSD_L_USERLIMIT; 711 } 712 } 713 714 int64_t 715 get_val(char *buf, int upper, enum sensor_type type) 716 { 717 double val; 718 int64_t rval = 0; 719 char *p; 720 721 if (buf == NULL) { 722 if (upper) 723 return (LLONG_MAX); 724 else 725 return (LLONG_MIN); 726 } 727 728 val = strtod(buf, &p); 729 if (buf == p) 730 err(1, "incorrect value: %s", buf); 731 732 switch(type) { 733 case SENSOR_TEMP: 734 switch(*p) { 735 case 'C': 736 printf("C"); 737 rval = val * 1000 * 1000 + 273150000; 738 break; 739 case 'F': 740 printf("F"); 741 rval = (val * 1000 * 1000 + 459670000) / 9 * 5; 742 break; 743 default: 744 errx(1, "unknown unit %s for temp sensor", p); 745 } 746 break; 747 case SENSOR_FANRPM: 748 rval = val; 749 break; 750 case SENSOR_VOLTS_DC: 751 if (*p != 'V') 752 errx(1, "unknown unit %s for voltage sensor", p); 753 rval = val * 1000 * 1000; 754 break; 755 case SENSOR_PERCENT: 756 rval = val * 1000.0; 757 break; 758 case SENSOR_FREQ: 759 case SENSOR_ECC: 760 case SENSOR_INDICATOR: 761 case SENSOR_INTEGER: 762 case SENSOR_DRIVE: 763 rval = val; 764 break; 765 case SENSOR_AMPS: 766 case SENSOR_WATTHOUR: 767 case SENSOR_AMPHOUR: 768 case SENSOR_LUX: 769 rval = val * 1000 * 1000; 770 break; 771 case SENSOR_TIMEDELTA: 772 rval = val * 1000 * 1000 * 1000; 773 break; 774 default: 775 errx(1, "unsupported sensor type"); 776 /* not reached */ 777 } 778 free(buf); 779 return (rval); 780 } 781 782 /* ARGSUSED */ 783 void 784 reparse_cfg(__unused int signo) 785 { 786 reload = 1; 787 } 788