#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <sys/time.h>
#define STATE_UNKNOWN -1
#define STATE_OK 0
#define STATE_WARNING 1
#define STATE_CRITICAL 2
#define READ_LEN 6
#define READ_TIMEOUT 10
#define CMD_GET_TMP 0x20
#define PORT_SPEED B1200
int xread (int, void *, size_t);
int xopen (char *, int);
void *xmalloc (ssize_t);
char *xstrdup (char *);
void process_options (int, char **);
void send_command_byte (int, int);
void setup_terminal (int);
void wait_for_input (int);
char *decode_alert (int);
unsigned long warning_low, critical_low, warning_high, critical_high;
char *device;
int
main(int argc, char **argv)
{
int ret, fd, n, alert_state;
char *result, *buf;
float celsius, fahrenheit;
process_options(argc, argv);
buf = xmalloc(READ_LEN + 1);
memset(buf, 0, READ_LEN + 1);
fd = xopen(device, O_RDWR);
setup_terminal(fd);
send_command_byte(fd, CMD_GET_TMP);
for (n = 0; n < READ_LEN; n += ret) {
wait_for_input(fd);
ret = xread(fd, buf + n, READ_LEN - n);
}
if (sscanf(buf, "%f", &celsius) != 1) {
fprintf(stderr, "main: sscanf failed\n");
exit(EXIT_FAILURE);
}
fahrenheit = celsius * 9.0 / 5.0 + 32.0;
if (fahrenheit > warning_high ||
fahrenheit < warning_low) {
alert_state = STATE_WARNING;
if (fahrenheit > critical_high ||
fahrenheit < critical_low)
alert_state = STATE_CRITICAL;
} else
alert_state = STATE_OK;
printf("HLT: %s: %3.1f (C) %3.1f (F)\n", decode_alert(alert_state),
celsius, fahrenheit);
exit(alert_state);
}
void
setup_terminal(int fd)
{
struct termios tio;
if (tcgetattr(fd, &tio) == -1) {
perror("tcgetattr");
exit(EXIT_FAILURE);
}
tio.c_iflag = IGNPAR|INPCK;
tio.c_cflag = CLOCAL|CREAD|CS8;
memset(&tio.c_oflag, 0, sizeof tio.c_oflag);
memset(&tio.c_lflag, 0, sizeof tio.c_lflag);
if (cfsetispeed(&tio, (speed_t)PORT_SPEED) == -1) {
perror("cfsetispeed");
exit(EXIT_FAILURE);
}
if (cfsetospeed(&tio, (speed_t)PORT_SPEED) == -1) {
perror("cfsetospeed");
exit(EXIT_FAILURE);
}
if (tcsetattr(fd, TCSANOW, &tio) == -1) {
perror("tcsetattr");
exit(EXIT_FAILURE);
}
if (tcflush(fd, TCIOFLUSH) == -1) {
perror("tcflush");
exit(EXIT_FAILURE);
}
}
void
send_command_byte(int fd, int cmd)
{
if (write(fd, &cmd, 1) == -1) {
perror("write");
exit(EXIT_FAILURE);
}
}
void
wait_for_input(int fd)
{
fd_set fdset;
struct timeval tv;
memset(&tv, 0, sizeof tv);
tv.tv_sec = READ_TIMEOUT;
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
if (!(select(FD_SETSIZE, &fdset, NULL, NULL, &tv))) {
fprintf(stderr, "wait_for_input: input never became available"
"before READ_TIMEOUT (%d) seconds\n", READ_TIMEOUT);
exit(EXIT_FAILURE);
}
}
void
process_options(int count, char **vector)
{
int ret;
opterr = 0;
while ((ret = getopt(count, vector, "w:c:d:W:C:")) != -1) switch (ret) {
case 'w':
if (!(warning_low = strtoul(optarg, NULL, 10))) {
fprintf(stderr, "main: strtoul error (w)\n");
exit(EXIT_FAILURE);
}
continue;
case 'c':
if (!(critical_low = strtoul(optarg, NULL, 10))) {
fprintf(stderr, "main: strtoul error (c)\n");
exit(EXIT_FAILURE);
}
continue;
case 'W':
if (!(warning_high = strtoul(optarg, NULL, 10))) {
fprintf(stderr, "main: strtoul error (W)\n");
exit(EXIT_FAILURE);
}
continue;
case 'C':
if (!(critical_high = strtoul(optarg, NULL, 10))) {
fprintf(stderr, "main: strtoul error (C)\n");
exit(EXIT_FAILURE);
}
continue;
case 'd':
device = xstrdup(optarg);
continue;
case '?':
fprintf(stderr, "unknown option argument\n");
exit(EXIT_FAILURE);
case ':':
fprintf(stderr, "required option argument missing\n");
exit(EXIT_FAILURE);
default:
fprintf(stderr, "invalid option\n");
exit(EXIT_FAILURE);
}
if (!device ||
!warning_low || !critical_low ||
!warning_high || !critical_high) {
fprintf(stderr, "required arguments missing\n");
exit(STATE_UNKNOWN);
}
}
char *
decode_alert(int i)
{
switch (i) {
case STATE_UNKNOWN:
return (xstrdup("ERROR"));
case STATE_OK:
return (xstrdup("OK"));
case STATE_WARNING:
return (xstrdup("WARNING"));
case STATE_CRITICAL:
return (xstrdup("CRITICAL"));
default:
return (xstrdup("IMPOSSIBLE"));
}
}
int
xopen(char *name, int flags)
{
int fd;
if (!name) {
fprintf(stderr, "xopen: no name given!\n");
exit(EXIT_FAILURE);
}
if ((fd = open(name, flags)) == -1) {
perror("xopen");
exit(EXIT_FAILURE);
}
return fd;
}
int
xread(int fd, void *address, size_t count)
{
int ret;
if (!address) {
fprintf(stderr, "xread: address invalid\n");
exit(EXIT_FAILURE);
}
if ((ret = read(fd, address, count)) == -1) {
perror("xread: read");
exit(EXIT_FAILURE);
}
return ret;
}
void *
xmalloc(ssize_t sz)
{
void *p;
if (!(p = malloc(sz))) {
perror("xmalloc: allocation failure");
exit(EXIT_FAILURE);
}
return p;
}
char *
xstrdup(char *s)
{
char *p;
if (!s) {
fprintf(stderr, "xstrdup: null argument!\n");
exit(EXIT_FAILURE);
}
if (!(p = strdup(s))) {
perror("xstrdup");
exit(EXIT_FAILURE);
}
return p;
}