Compare commits

..

1 Commits

Author SHA1 Message Date
1d7e3643c2 Use diskwatch only 2019-08-11 09:54:17 +02:00
13 changed files with 22 additions and 1450 deletions

View File

@ -7,7 +7,7 @@ PID_DIR = /var/run
# ############################ # ############################
SRC = $(wildcard *.c) SRC = $(wildcard *.c)
TARGET = qnapd TARGET = diskwatch
BUILD_DIR = build BUILD_DIR = build
CFLAGS = -O2 -g -pipe -Wall -Wno-unused-result -DPROGNAME='"$(TARGET)"' CFLAGS = -O2 -g -pipe -Wall -Wno-unused-result -DPROGNAME='"$(TARGET)"'
CFLAGS += -MMD -MF $(BUILD_DIR)/$(*D)/$(*F).d CFLAGS += -MMD -MF $(BUILD_DIR)/$(*D)/$(*F).d

8
TODO
View File

@ -1,8 +0,0 @@
- dynamic pages
- refresh of dynamic pages (clock, loadavg)
- disk utilization (MB/GB)
- mntpoints given in config
- network usage?
- cpu usage?

View File

@ -31,7 +31,6 @@
#include "configfile.h" #include "configfile.h"
#include "diskwatch.h" #include "diskwatch.h"
#include "event.h" #include "event.h"
#include "lcd.h"
#include "list.h" #include "list.h"
#include "logging.h" #include "logging.h"
@ -56,79 +55,11 @@ struct disk_entry {
struct diskwatch { struct diskwatch {
struct list_head disk_list; struct list_head disk_list;
struct lcddev *lcd;
struct event_timeout *check_timeout; struct event_timeout *check_timeout;
}; };
static struct diskwatch diskwatch_glob; static struct diskwatch diskwatch_glob;
static int diskwatch_check_standby(struct disk_entry *entry);
static int lcdpage_diskwatch(struct lcddev *lcd, int event, void *privdata)
{
static struct disk_entry *entry;
struct diskwatch *dwatch = (struct diskwatch *)privdata;
if (entry == NULL) {
if (list_empty(&dwatch->disk_list)) {
return LCDPAGE_COMMAND_NEXT;
}
entry = list_entry(dwatch->disk_list.next, struct disk_entry, list);
}
switch (event) {
case LCDPAGE_EVENT_BUTTON1:
if (entry->list.next == &dwatch->disk_list) {
entry = NULL;
return LCDPAGE_COMMAND_NEXT;
}
entry = list_entry(entry->list.next, struct disk_entry, list);
lcd_set_backlight(lcd, 1);
break;
case LCDPAGE_EVENT_ENTER:
entry = list_entry(dwatch->disk_list.next, struct disk_entry, list);
lcd_set_backlight(lcd, 1);
break;
case LCDPAGE_EVENT_BACKLIGHT:
case LCDPAGE_EVENT_EXIT:
return 0;
default:
break;
}
char line1[32];
char line2[32];
snprintf(line1, sizeof(line1), "DISK(%s):", entry->device);
if (entry->flags & F_PRESENT) {
diskwatch_check_standby(entry);
if (entry->flags & F_STANDBY) {
snprintf(line2, sizeof(line2), "STANDBY");
} else {
int timeout = entry->standby_timeout - time(NULL);
int hours = timeout / 3600;
timeout = timeout % 3600;
int minutes = timeout / 60;
timeout = timeout % 60;
snprintf(line2, sizeof(line2), "RUN -%02d:%02d:%02d", hours, minutes, timeout);
}
} else {
snprintf(line2, sizeof(line2), "not present");
}
lcd_setlines(lcd, line1, line2);
return 1000;
}
static int diskwatch_check_standby(struct disk_entry *entry) static int diskwatch_check_standby(struct disk_entry *entry)
{ {
if (!(entry->flags & F_PRESENT)) if (!(entry->flags & F_PRESENT))
@ -315,7 +246,7 @@ void diskwatch_exit(void)
} }
} }
int diskwatch_init(struct lcddev *lcd) int diskwatch_init(void)
{ {
struct diskwatch *dwatch = &diskwatch_glob; struct diskwatch *dwatch = &diskwatch_glob;
@ -331,10 +262,5 @@ int diskwatch_init(struct lcddev *lcd)
config_get_int("diskwatch", "check_interval", &check_interval, 60); config_get_int("diskwatch", "check_interval", &check_interval, 60);
dwatch->check_timeout = event_add_timeout_ms(check_interval * 1000, diskwatch_check_stats, 0, dwatch); dwatch->check_timeout = event_add_timeout_ms(check_interval * 1000, diskwatch_check_stats, 0, dwatch);
dwatch->lcd = lcd;
if (dwatch->lcd != NULL) {
lcd_addpage_cb(dwatch->lcd, 150, lcdpage_diskwatch, dwatch);
}
return 0; return 0;
} }

11
diskwatch.conf Normal file
View File

@ -0,0 +1,11 @@
[global]
pidfile diskwatch.pid
logfile diskwatch.log
[diskwatch]
check_interval 60
#disk /dev/sda,7200
disk /dev/sdb,120
#disk /dev/sdc,7200
#disk /dev/sdd,7200

View File

@ -1,9 +1,7 @@
#ifndef _DISKWATCH_H_ #ifndef _DISKWATCH_H_
#define _DISKWATCH_H_ #define _DISKWATCH_H_
#include "lcd.h"
void diskwatch_exit(void); void diskwatch_exit(void);
int diskwatch_init(struct lcddev *lcd); int diskwatch_init(void);
#endif /* _DISKWATCH_H_ */ #endif /* _DISKWATCH_H_ */

699
lcd.c
View File

@ -1,699 +0,0 @@
/***************************************************************************
* Copyright (C) 05/2011 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include "event.h"
#include "lcd.h"
#include "list.h"
#include "logging.h"
#define _LCD_DEBUG 0
#define _LCD_DUMMY 1
#define LCD_SCROLL_SPEED 750 /* 750ms */
#define LCD_RESET_TIMEOUT 250 /* 250ms */
#define LCD_RESET_RETRY_TIMEOUT 10000 /* 10s */
#define A125_CMD_GETBUTTON { 0x4D, 0x06 } // not tried
#define A125_CMD_SETLINE { 0x4D, 0x0C, 0x00, 0x10 } // [2] is line, append 16 chars
#define A125_CMD_CLEAR { 0x4D, 0x0D } // works, but slow
#define A125_CMD_BACKLIGHT { 0x4D, 0x5E, 0x00 } // [2] is on/off
#define A125_CMD_RESET { 0x4D, 0xFF }
#define A125_EVENT_ID { 0x53, 0x01 } // never seen
#define A125_EVENT_BUTTON1 { 0x53, 0x05, 0x00, 0x01 }
#define A125_EVENT_BUTTON2 { 0x53, 0x05, 0x00, 0x02 }
#define A125_EVENT_VERSION { 0x53, 0x08 } // never seen
#define A125_EVENT_ACTINFO { 0x53, 0xAA }
#define A125_EVENT_INVALID { 0x53, 0xFB } // never seen
struct lcdpage {
struct list_head list;
int priority;
int (*callback)(struct lcddev *dev, int event, void *privdata);
void *privdata;
};
enum lcdstate {
LCD_STATE_NOT_INITIALIZED = 0x00,
LCD_STATE_INITIALIZING,
LCD_STATE_INITIALIZING_FAILED,
LCD_STATE_READY,
};
struct lcddev {
int fd;
#if (_LCD_DUMMY)
struct event_fd *fakedevice_event;
#endif /* (_LCD_DUMMY) */
struct termios oldtio;
enum lcdstate state;
int backlight_enabled;
int backlight_timeout_ms;
struct list_head page_list;
struct lcdpage *current_page;
const char *line_data[2];
int line_length[2];
int scroll_pos;
int update_ms;
struct event_fd *read_event;
struct event_timeout *reset_timeout;
struct event_timeout *backlight_timeout;
struct event_timeout *scroll_timeout;
struct event_timeout *update_timeout;
};
static void lcd_pagecallback(struct lcddev *dev, int event);
void lcd_close(struct lcddev *dev)
{
if (dev->current_page) {
dev->current_page->callback(dev, LCDPAGE_EVENT_EXIT, dev->current_page->privdata);
dev->current_page = NULL;
}
struct lcdpage *search, *tmp;
list_for_each_entry_safe(search, tmp, &dev->page_list, list) {
free(search);
}
if (dev->reset_timeout) {
event_remove_timeout(dev->reset_timeout);
dev->reset_timeout = NULL;
}
if (dev->backlight_timeout) {
event_remove_timeout(dev->backlight_timeout);
dev->backlight_timeout = NULL;
}
if (dev->update_timeout) {
event_remove_timeout(dev->update_timeout);
dev->update_timeout = NULL;
}
if (dev->scroll_timeout) {
event_remove_timeout(dev->scroll_timeout);
dev->scroll_timeout = NULL;
}
if (dev->read_event) {
event_remove_fd(dev->read_event);
dev->read_event = NULL;
}
#if (_LCD_DUMMY)
if (dev->fakedevice_event != NULL) {
int fd = event_get_fd(dev->fakedevice_event);
event_remove_fd(dev->fakedevice_event);
dev->fakedevice_event = NULL;
close(fd);
} else
#endif /* (_LCD_DUMMY) */
{
tcsetattr(dev->fd, TCSANOW, &dev->oldtio);
}
close(dev->fd);
free(dev);
}
static int lcd_realdevice_open(struct lcddev *dev, const char *device)
{
dev->fd = open(device, O_RDWR | O_NOCTTY);
if (dev->fd < 0) {
log_print(LOG_ERROR, "%s(): failed to open '%s'", __FUNCTION__, device);
return -1;
}
if (fcntl(dev->fd, F_SETFD, FD_CLOEXEC) < 0) {
log_print(LOG_ERROR, "%s(): fcntl(FD_CLOEXEC)", __FUNCTION__);
close(dev->fd);
return -1;
}
tcgetattr(dev->fd, &dev->oldtio);
struct termios newtio;
memset(&newtio, 0, sizeof(newtio));
newtio.c_iflag |= IGNBRK;
newtio.c_lflag &= ~(ISIG | ICANON | ECHO);
newtio.c_cflag = B1200 | CS8 | CLOCAL | CREAD;
newtio.c_cc[VMIN] = 1;
newtio.c_cc[VTIME] = 0;
cfsetospeed(&newtio, B1200);
cfsetispeed(&newtio, B1200);
int err = tcsetattr(dev->fd, TCSAFLUSH, &newtio);
if (err < 0) {
log_print(LOG_ERROR, "%s(): failed to set termios", __FUNCTION__);
close(dev->fd);
return -1;
}
return 0;
}
#if (_LCD_DUMMY)
static int lcd_fakedevice_reply(int fd, void *privdata)
{
struct lcddev *dev = (struct lcddev *)privdata;
char buf[32];
if (read(fd, buf, sizeof(buf)) <= 0) {
dev->fakedevice_event = NULL;
return -1;
}
char reset_expect[] = A125_CMD_RESET;
if (memcmp(buf, reset_expect, sizeof(reset_expect)) == 0) {
char actinfo_cmd[] = A125_EVENT_ACTINFO;
write(fd, actinfo_cmd, sizeof(actinfo_cmd));
}
return 0;
}
static int lcd_fakedevice_open(struct lcddev *dev)
{
int fd[2];
if (socketpair(AF_LOCAL, SOCK_STREAM, 0 , fd) < 0) {
log_print(LOG_ERROR, "%s(): socketpair() failed", __FUNCTION__);
return -1;
}
if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0) {
log_print(LOG_ERROR, "%s(): fcntl(FD_CLOEXEC)", __FUNCTION__);
close(fd[0]);
close(fd[1]);
return -1;
}
if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) < 0) {
log_print(LOG_ERROR, "%s(): fcntl(FD_CLOEXEC)", __FUNCTION__);
close(fd[0]);
close(fd[1]);
return -1;
}
dev->fd = fd[0];
dev->fakedevice_event = event_add_readfd(NULL, fd[1], lcd_fakedevice_reply, dev);
return 0;
}
#endif /* (_LCD_DUMMY) */
#if (_LCD_DEBUG > 1)
static void lcd_dump(const char *prefix, int len, int size, const char *data)
{
int i;
int pos = 0;
char buf[256];
for (i = 0; i < len; i++) {
pos += snprintf(buf, sizeof(buf) - pos, "0x%X ", (unsigned char)data[i]);
}
log_print(LOG_DEBUG, "%s:[%d/%d]: %s", prefix, len, size, buf);
}
#endif /* (_LCD_DEBUG > 1) */
static int lcd_read(struct lcddev *dev, const char *buf, int len)
{
int retval = 0, cnt = 0;
while (cnt < len) {
retval = read(dev->fd, (char *)buf + cnt, len - cnt);
if (retval <= 0)
break;
cnt += retval;
}
#if (_LCD_DEBUG > 1)
lcd_dump(__FUNCTION__, cnt, len, buf);
#endif /* (_LCD_DEBUG > 1) */
return (cnt != 0) ? cnt : retval;
}
static int lcd_write(struct lcddev *dev, char *buf, int len)
{
int retval = write(dev->fd, buf, len);
#if (_LCD_DEBUG > 1)
lcd_dump(__FUNCTION__, retval, len, buf);
#endif /* (_LCD_DEBUG > 1) */
return retval;
}
static void lcd_reset(struct lcddev *dev);
static int lcd_reset_retry_timeout_cb(int timerid, void *privdata)
{
struct lcddev *dev = (struct lcddev *)privdata;
dev->reset_timeout = NULL;
lcd_reset(dev);
return -1; /* singleshot */
}
static int lcd_reset_timeout_cb(int timerid, void *privdata)
{
struct lcddev *dev = (struct lcddev *)privdata;
log_print(LOG_ERROR, "failed to initalize LCD");
dev->state = LCD_STATE_INITIALIZING_FAILED;
dev->reset_timeout = event_add_timeout_ms(LCD_RESET_RETRY_TIMEOUT, lcd_reset_retry_timeout_cb, 0, dev);
return -1; /* singleshot */
}
static void lcd_reset(struct lcddev *dev)
{
#if (_LCD_DEBUG > 0)
log_print(LOG_DEBUG, "%s()", __FUNCTION__);
#endif /* (_LCD_DEBUG > 0) */
char cmd[] = A125_CMD_RESET;
lcd_write(dev, cmd, sizeof(cmd));
/* force next backlight command */
dev->backlight_enabled = -1;
dev->state = LCD_STATE_INITIALIZING;
dev->reset_timeout = event_add_timeout_ms(LCD_RESET_TIMEOUT, lcd_reset_timeout_cb, 0, dev);
}
static int lcd_backlight(struct lcddev *dev, int enable)
{
if (dev->state != LCD_STATE_READY)
return -1;
#if (_LCD_DEBUG > 0)
log_print(LOG_DEBUG, "%s(%d)", __FUNCTION__, enable);
#endif /* (_LCD_DEBUG > 0) */
if (dev->backlight_enabled != enable) {
char cmd[] = A125_CMD_BACKLIGHT;
cmd[2] = (enable) ? 0x01 : 0x00;
lcd_write(dev, cmd, sizeof(cmd));
dev->backlight_enabled = enable;
}
return 0;
}
static int lcd_backlight_timeout_cb(int timerid, void *privdata)
{
struct lcddev *dev = (struct lcddev *)privdata;
dev->backlight_timeout = NULL;
lcd_set_backlight(dev, 0);
return -1; /* singleshot */
}
int lcd_set_backlight(struct lcddev *dev, int enable)
{
if (dev->backlight_timeout != NULL) {
event_remove_timeout(dev->backlight_timeout);
dev->backlight_timeout = NULL;
}
if (!enable) {
lcd_pagecallback(dev, LCDPAGE_EVENT_BACKLIGHT);
/* callback re-enabled backlight */
if (dev->backlight_timeout != NULL) {
return 0;
}
}
int retval = lcd_backlight(dev, enable);
if (enable) {
/* start backlight timeout */
dev->backlight_timeout = event_add_timeout_ms(dev->backlight_timeout_ms, lcd_backlight_timeout_cb, 0, dev);
} else {
/* disable updates (display is not visible) */
if (dev->update_timeout != NULL) {
event_remove_timeout(dev->update_timeout);
dev->update_timeout = NULL;
}
/* disable scrolling (display is not visible) */
if (dev->scroll_timeout != NULL) {
event_remove_timeout(dev->scroll_timeout);
dev->scroll_timeout = NULL;
}
}
return retval;
}
static int lcd_update_timeout_cb(int timerid, void *privdata)
{
struct lcddev *dev = (struct lcddev *)privdata;
dev->update_timeout = NULL;
lcd_pagecallback(dev, LCDPAGE_EVENT_UPDATE);
return -1; /* singleshot */
}
static void lcd_update_start(struct lcddev *dev, int update_ms)
{
dev->update_ms = update_ms;
if (dev->update_timeout != NULL) {
event_remove_timeout(dev->update_timeout);
dev->update_timeout = NULL;
}
if (update_ms > 0) {
dev->update_timeout = event_add_timeout_ms(update_ms, lcd_update_timeout_cb, 0, dev);
}
}
static int lcd_read_cb(int fd, void *privdata)
{
struct lcddev *dev = (struct lcddev *)privdata;
char buf[4];
int size = (dev->state != LCD_STATE_INITIALIZING) ? sizeof(buf) : 2;
int len = lcd_read(dev, buf, size);
if (dev->state == LCD_STATE_INITIALIZING) {
char expect[] = A125_EVENT_ACTINFO;
if (len != sizeof(expect))
return 0;
if (memcmp(buf, expect, sizeof(expect)) == 0) {
event_remove_timeout(dev->reset_timeout);
dev->reset_timeout = NULL;
dev->state = LCD_STATE_READY;
/* trigger application to set data */
lcd_pagecallback(dev, LCDPAGE_EVENT_ENTER);
}
} else if (dev->state == LCD_STATE_READY) {
char expect1[] = A125_EVENT_BUTTON1;
char expect2[] = A125_EVENT_BUTTON2;
if (len != sizeof(expect1) && len != sizeof(expect2))
return 0;
if (memcmp(buf, expect1, sizeof(buf)) == 0) {
lcd_pagecallback(dev, LCDPAGE_EVENT_BUTTON1);
} else if (memcmp(buf, expect2, sizeof(buf)) == 0) {
lcd_pagecallback(dev, LCDPAGE_EVENT_BUTTON2);
}
}
return 0;
}
static int lcd_setline(struct lcddev *dev, int line, int len, const char *buf)
{
if (dev->state != LCD_STATE_READY)
return -1;
char cmd[20 +1] = A125_CMD_SETLINE;
cmd[2] = line;
memset(cmd +4, ' ', 16);
memcpy(cmd +4, buf, (len > 16) ? 16 : len);
cmd[20] = '\0';
#if (_LCD_DEBUG > 0)
log_print(LOG_DEBUG, "%s(%d, '%-16s')", __FUNCTION__, line, cmd +4);
#endif /* (_LCD_DEBUG > 0) */
lcd_write(dev, cmd, 20);
return 0;
}
static int lcd_scroll_timeout_cb(int timerid, void *privdata)
{
struct lcddev *dev = (struct lcddev *)privdata;
int i, reset_pos = 0;
for (i = 0; i < 2; i++) {
int line_pos = dev->scroll_pos;
if (line_pos < 0)
line_pos = 0;
/* mark line as complete if one space is visible after message */
if ((dev->line_length[i] - line_pos) <= 15) {
reset_pos++;
}
/* do not scroll further if message is not visible */
if ((dev->line_length[i] - line_pos) < 0) {
line_pos = dev->line_length[i];
}
lcd_setline(dev, i, dev->line_length[i] - line_pos, dev->line_data[i] + line_pos);
}
dev->scroll_pos++;
if (reset_pos == 2)
dev->scroll_pos = -1;
/* periodic */
return 0;
}
static void lcd_scroll_start(struct lcddev *dev)
{
if (dev->scroll_timeout != NULL) {
event_remove_timeout(dev->scroll_timeout);
dev->scroll_timeout = NULL;
}
if ((dev->line_length[0] > 16) || (dev->line_length[1] > 16)) {
dev->scroll_timeout = event_add_timeout_ms(LCD_SCROLL_SPEED, lcd_scroll_timeout_cb, 0, dev);
}
}
int lcd_setlines(struct lcddev *dev, const char *line1, const char *line2)
{
int i;
int line_length[2] = { 0, 0 };
const char *line[2] = { line1, line2 };
for (i = 0; i < 2; i++) {
if (line[i] != NULL) {
line_length[i] = strlen(line[i]);
if ((line_length[i] == dev->line_length[i]) && (dev->line_data[i] != NULL)) {
if (memcmp(line[i], dev->line_data[i], line_length[i]) == 0) {
/* same data, no update needed */
continue;
}
}
}
if (dev->line_data[i] != NULL) {
free((void *)dev->line_data[i]);
dev->line_data[i] = NULL;
}
if (line[i] != NULL) {
dev->line_data[i] = strdup(line[i]);
}
dev->line_length[i] = line_length[i];
if (dev->backlight_enabled) {
lcd_setline(dev, i, dev->line_length[i], dev->line_data[i]);
dev->scroll_pos = 0;
lcd_scroll_start(dev);
}
}
return 0;
}
static void lcd_pagecallback(struct lcddev *dev, int event)
{
if (dev->state != LCD_STATE_READY) {
return;
}
if (dev->current_page == NULL) {
if (list_empty(&dev->page_list)) {
return;
}
dev->current_page = list_entry(dev->page_list.next, struct lcdpage, list);
}
if ((dev->backlight_enabled == 0x00) && ((event == LCDPAGE_EVENT_BUTTON1) || (event == LCDPAGE_EVENT_BUTTON2))) {
lcd_set_backlight(dev, 1);
event = LCDPAGE_EVENT_UPDATE;
/* restart scrolling if needed */
lcd_scroll_start(dev);
}
int next;
do {
#if (_LCD_DEBUG > 0)
log_print(LOG_DEBUG, "%s: cb(%p, 0x%x)", __FUNCTION__, dev->current_page, event);
#endif
int retval = dev->current_page->callback(dev, event, dev->current_page->privdata);
#if (_LCD_DEBUG > 0)
log_print(LOG_DEBUG, "%s: cb(%p, 0x%x) => 0x%x", __FUNCTION__, dev->current_page, event, retval);
#endif
next = (retval == LCDPAGE_COMMAND_NEXT);
if (next) {
struct lcdpage *page = dev->current_page;
if (page->list.next != &dev->page_list) {
page = list_entry(page->list.next, struct lcdpage, list);
} else {
page = list_entry(page->list.next->next, struct lcdpage, list);
}
/* no other page ready */
if (page == dev->current_page) {
break;
}
/* remove update interval for next page */
if (dev->update_timeout != NULL) {
event_remove_timeout(dev->update_timeout);
dev->update_timeout = NULL;
}
/* remove scroll interval for next page */
if (dev->scroll_timeout != NULL) {
event_remove_timeout(dev->scroll_timeout);
dev->scroll_timeout = NULL;
}
dev->current_page->callback(dev, LCDPAGE_EVENT_EXIT, dev->current_page->privdata);
dev->current_page = page;
event = LCDPAGE_EVENT_ENTER;
/* retval is update interval */
} else if ((event != LCDPAGE_EVENT_BACKLIGHT) && (event != LCDPAGE_EVENT_EXIT)) {
lcd_update_start(dev, retval);
}
} while (next);
}
int lcd_addpage_cb(struct lcddev *dev,
int priority,
int (*event_callback)(struct lcddev *dev, int event, void *privdata),
void *event_privdata)
{
struct lcdpage *page = malloc(sizeof(struct lcdpage));
if (page == NULL) {
log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__);
return -1;
}
page->priority = priority;
page->callback = event_callback;
page->privdata = event_privdata;
int inserted = 0;
struct lcdpage *search;
list_for_each_entry(search, &dev->page_list, list) {
if (page->priority > search->priority) {
list_add_tail(&page->list, &search->list);
inserted = 1;
break;
}
}
if (!inserted) {
list_add_tail(&page->list, &dev->page_list);
}
if (dev->current_page == NULL) {
lcd_pagecallback(dev, LCDPAGE_EVENT_ENTER);
}
return 0;
}
struct lcddev * lcd_open(const char *devicename, int backlight_timeout)
{
struct lcddev *dev = malloc(sizeof(struct lcddev));
if (dev == NULL) {
log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__);
return NULL;
}
memset(dev, 0, sizeof(struct lcddev));
INIT_LIST_HEAD(&dev->page_list);
int retval;
#if (_LCD_DUMMY)
if (strncmp(devicename, "dummy", 5) == 0) {
retval = lcd_fakedevice_open(dev);
} else
#endif /* (_LCD_DUMMY) */
{
retval = lcd_realdevice_open(dev, devicename);
}
if (retval < 0) {
free(dev);
return NULL;
}
dev->read_event = event_add_readfd(NULL, dev->fd, lcd_read_cb, dev);
dev->backlight_timeout_ms = backlight_timeout * 1000;
lcd_reset(dev);
return dev;
}

25
lcd.h
View File

@ -1,25 +0,0 @@
#ifndef _LCD_H_
#define _LCD_H_
struct lcddev; /* private data */
struct lcddev * lcd_open(const char *devicename, int backlight_timeout);
void lcd_close(struct lcddev *dev);
int lcd_set_backlight(struct lcddev *dev, int enable);
int lcd_setlines(struct lcddev *dev, const char *line1, const char *line2);
#define LCDPAGE_EVENT_BUTTON1 0xFFFFFF01 /* button "enter" pressed */
#define LCDPAGE_EVENT_BUTTON2 0xFFFFFF02 /* button "select" pressed */
#define LCDPAGE_EVENT_BACKLIGHT 0xFFFFFF03 /* backlight timeout */
#define LCDPAGE_EVENT_ENTER 0xFFFFFF05 /* page entered */
#define LCDPAGE_EVENT_EXIT 0xFFFFFF06 /* page left */
#define LCDPAGE_EVENT_UPDATE 0xFFFFFF07 /* update content */
#define LCDPAGE_COMMAND_NEXT 0xFFFFFF80 /* change to next page */
int lcd_addpage_cb(struct lcddev *dev,
int priority,
int (*event_callback)(struct lcddev *dev, int event, void *privdata),
void *event_privdata);
#endif /* _LCD_H_ */

238
lcdpage.c
View File

@ -1,238 +0,0 @@
/***************************************************************************
* Copyright (C) 12/2012 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/utsname.h>
#include <sys/sysinfo.h>
#include <time.h>
#include "lcd.h"
#include "lcdpage.h"
/*
* system:
* - os version done
* - kernel version done
* - hostname done
* - date/time done
* - uptime done
* - avgload done
* - cpu usage
* - memory/swap usage
* - temperature done (pic.c)
* - fan error done (pic.c)
*
* disk drives:
* - temperature -> disk
* - state (idle / running), time to idle -> disk
* - current i/o (aggregated?)
*
* partitions:
* - used / free / total
*
* ethernet interface:
* - link (10/100/1000)
* - current i/o
*
* ip interface:
* - ip address/netmask
* - default gateway
* - dns
*
*/
static int lcdpage_system(struct lcddev *dev, int event, void *privdata)
{
static int subpage;
int retval = 0;
char line1[64];
char line2[64];
memset(line1, 0x00, sizeof(line1));
memset(line2, 0x00, sizeof(line2));
switch (event) {
case LCDPAGE_EVENT_BUTTON1:
lcd_set_backlight(dev, 1);
subpage++;
break;
case LCDPAGE_EVENT_ENTER:
lcd_set_backlight(dev, 1);
subpage = 0;
break;
case LCDPAGE_EVENT_BACKLIGHT:
case LCDPAGE_EVENT_EXIT:
return 0;
default:
break;
}
if (subpage == 0) {
FILE *fp = fopen("/etc/issue.net", "r");
if (fp != NULL) {
fread(line1, 1, sizeof(line1), fp);
fclose(fp);
char *trim = memchr(line1, 0x0A, sizeof(line1));
if (trim != NULL)
*trim = '\0';
trim = memchr(line1, 0x0D, sizeof(line1));
if (trim != NULL)
*trim = '\0';
} else {
strcpy(line1, "<unknown>");
}
struct utsname utsbuf;
uname(&utsbuf);
snprintf(line2, sizeof(line2), "%s %s", utsbuf.sysname, utsbuf.release);
lcd_setlines(dev, line1, line2);
} else if (subpage == 1) {
/* copy hostname */
if (gethostname(line2, sizeof(line2)) < 0) {
strcpy(line2, "<unknown>");
}
int len = strlen(line2);
line2[len++] = '.';
/* append domainname */
if (getdomainname(line2 + len, sizeof(line2) - len) < 0) {
strcpy(line2 + len, "unknown");
}
lcd_setlines(dev, "Hostname:", line2);
} else if (subpage == 2) {
struct tm tmp;
time_t now;
time(&now);
localtime_r(&now, &tmp);
strftime(line1, sizeof(line1), "Time: %H:%M:%S", &tmp);
strftime(line2, sizeof(line2), "Date: %Y/%m/%d", &tmp);
lcd_setlines(dev, line1, line2);
retval = 1000; /* update every second */
} else if (subpage == 3) {
struct sysinfo info;
if (sysinfo(&info) < 0) {
return 0;
}
int tmp, days, hours, minutes;
days = info.uptime / 86400;
tmp = info.uptime % 86400;
hours = tmp / 3600;
tmp = tmp % 3600;
minutes = tmp / 60;
tmp = tmp % 60;
snprintf(line2, sizeof(line2), " %03dd %02d:%02d:%02d", days, hours, minutes, tmp);
lcd_setlines(dev, "Uptime:", line2);
retval = 1000;
} else if (subpage == 4) {
double loadavg[3];
if (getloadavg(loadavg, 3) < 0) {
return 0;
}
snprintf(line2, sizeof(line2), " %1.2f %1.2f %1.2f", loadavg[0], loadavg[1], loadavg[2]);
lcd_setlines(dev, "Load Average:", line2);
retval = 1000;
} else {
return LCDPAGE_COMMAND_NEXT;
}
/* update every 1000ms */
return retval;
}
static int lcdpage_network(struct lcddev *dev, int event, void *privdata)
{
static int subpage;
switch (event) {
case LCDPAGE_EVENT_BUTTON1:
lcd_set_backlight(dev, 1);
subpage++;
break;
case LCDPAGE_EVENT_ENTER:
lcd_set_backlight(dev, 1);
subpage = 0;
break;
case LCDPAGE_EVENT_BACKLIGHT:
case LCDPAGE_EVENT_EXIT:
return 0;
default:
break;
}
switch (subpage) {
case 0:
lcd_setlines(dev, "Address(br0):", "10.10.250.135");
break;
case 1:
lcd_setlines(dev, "Netmask(br0):", "255.255.0.0");
break;
case 2:
lcd_setlines(dev, "Gateway(br0):", "10.10.250.250");
break;
default:
return LCDPAGE_COMMAND_NEXT;
}
return 0;
}
void lcdpage_free(void)
{
/* nothing to do, lcdpages are cleaned up in lcd_close() */
}
int lcdpage_init(struct lcddev *dev)
{
lcd_addpage_cb(dev, 200, lcdpage_system, NULL);
lcd_addpage_cb(dev, 100, lcdpage_network, NULL);
return 0;
}

View File

@ -1,9 +0,0 @@
#ifndef _LCDPAGE_H_
#define _LCDPAGE_H_
#include "lcd.h"
int lcdpage_init(struct lcddev *dev);
void lcdpage_free(void);
#endif /* _LCDPAGE_H_ */

View File

@ -28,18 +28,13 @@
#include "configfile.h" #include "configfile.h"
#include "diskwatch.h" #include "diskwatch.h"
#include "event.h" #include "event.h"
#include "lcd.h"
#include "lcdpage.h"
#include "logging.h" #include "logging.h"
#include "pic.h"
#include "pidfile.h" #include "pidfile.h"
#include "signals.h" #include "signals.h"
#define DEFAULT_CONFIG "qnapd.conf" #define DEFAULT_CONFIG "diskwatch.conf"
#define DEFAULT_LOGFILE "qnapd.log" #define DEFAULT_LOGFILE "diskwatch.log"
#define DEFAULT_PIDFILE "qnapd.pid" #define DEFAULT_PIDFILE "diskwatch.pid"
#define LCD_TIMEOUT 15
static struct option opts[] = { static struct option opts[] = {
{ "config", 1, 0, 'c' }, { "config", 1, 0, 'c' },
@ -83,7 +78,7 @@ int main(int argc, char *argv[])
break; break;
case 'h': /* help */ case 'h': /* help */
printf("Usage: qnapd [options]\n" printf("Usage: diskwatch [options]\n"
"Options: \n" "Options: \n"
" --config -c configfile use this configfile\n" " --config -c configfile use this configfile\n"
" --debug -d do not fork and log to stderr\n" " --debug -d do not fork and log to stderr\n"
@ -109,7 +104,7 @@ int main(int argc, char *argv[])
/* check pidfile */ /* check pidfile */
const char *pidfile = config_get_string("global", "pidfile", DEFAULT_PIDFILE); const char *pidfile = config_get_string("global", "pidfile", DEFAULT_PIDFILE);
if (pidfile_check(pidfile, 1) != 0) { if (pidfile_check(pidfile, 1) != 0) {
log_print(LOG_ERROR, "qnapd already running"); log_print(LOG_ERROR, "diskwatch already running");
exit(1); exit(1);
} }
@ -134,42 +129,13 @@ int main(int argc, char *argv[])
signal_init(); signal_init();
signal_add_callback(SIGHUP, trigger_restart, NULL); signal_add_callback(SIGHUP, trigger_restart, NULL);
log_print(LOG_EVERYTIME, "qnapd started (pid:%d)", getpid()); log_print(LOG_EVERYTIME, "diskwatch started (pid:%d)", getpid());
while (1) { while (1) {
struct lcddev *lcd = NULL;
struct picdev *pic = NULL;
int abort = 0; int abort = 0;
do { do {
const char *devicename = config_get_string("global", "lcddevice", NULL); if (diskwatch_init() < 0) {
if (devicename != NULL) {
int lcdtimeout;
config_get_int("global", "lcdtimeout", &lcdtimeout, LCD_TIMEOUT);
lcd = lcd_open(devicename, lcdtimeout);
if (lcd == NULL) {
abort = 1;
break;
}
if (lcdpage_init(lcd) < 0) {
abort = 1;
break;
}
}
devicename = config_get_string("global", "picdevice", NULL);
if (devicename != NULL) {
pic = pic_open(devicename, lcd);
if (pic == NULL) {
abort = 1;
break;
}
}
if (diskwatch_init(lcd) < 0) {
abort = 1; abort = 1;
break; break;
} }
@ -180,15 +146,6 @@ int main(int argc, char *argv[])
diskwatch_exit(); diskwatch_exit();
if (pic != NULL) {
pic_close(pic);
}
if (lcd != NULL) {
lcdpage_free();
lcd_close(lcd);
}
config_free(); config_free();
if (abort) if (abort)
@ -201,7 +158,7 @@ int main(int argc, char *argv[])
if (!debug && log_init(logfile) < 0) if (!debug && log_init(logfile) < 0)
break; break;
log_print(LOG_EVERYTIME, "qnapd restarted (pid:%d) ", getpid()); log_print(LOG_EVERYTIME, "diskwatch restarted (pid:%d) ", getpid());
} }
return 0; return 0;

257
pic.c
View File

@ -1,257 +0,0 @@
/***************************************************************************
* Copyright (C) 02/2012 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include "event.h"
#include "lcd.h"
#include "logging.h"
#include "pic.h"
struct picdev {
int fd;
struct termios oldtio;
int fan_speed;
int fan_error;
int temperature;
struct event_fd *read_event;
};
static int pic_close_device(struct picdev *dev)
{
tcsetattr(dev->fd, TCSANOW, &dev->oldtio);
close(dev->fd);
return 0;
}
static int pic_open_device(struct picdev *dev, const char *device)
{
dev->fd = open(device, O_RDWR | O_NOCTTY);
if (dev->fd < 0) {
log_print(LOG_ERROR, "%s(): failed to open '%s'", __FUNCTION__, device);
return -1;
}
if (fcntl(dev->fd, F_SETFD, FD_CLOEXEC) < 0) {
log_print(LOG_ERROR, "%s(): fcntl(FD_CLOEXEC)", __FUNCTION__);
close(dev->fd);
return -1;
}
tcgetattr(dev->fd, &dev->oldtio);
struct termios newtio;
memset(&newtio, 0, sizeof(newtio));
newtio.c_iflag |= IGNBRK;
newtio.c_lflag &= ~(ISIG | ICANON | ECHO);
newtio.c_cflag = B19200 | CS8 | CLOCAL | CREAD;
newtio.c_cc[VMIN] = 1;
newtio.c_cc[VTIME] = 0;
cfsetospeed(&newtio, B19200);
cfsetispeed(&newtio, B19200);
int err = tcsetattr(dev->fd, TCSAFLUSH, &newtio);
if (err < 0) {
log_print(LOG_ERROR, "%s(): failed to set termios", __FUNCTION__);
close(dev->fd);
return -1;
}
return 0;
}
int pic_set_fanspeed(struct picdev *dev, char value)
{
if (value < PIC_CMD_FANSPEED_0 || value > PIC_CMD_FANSPEED_5)
return -1;
dev->fan_speed = value - PIC_CMD_FANSPEED_0;
write(dev->fd, &value, 1);
return 0;
}
int pic_set_buzzer(struct picdev *dev, char value)
{
if (value < PIC_CMD_BUZZ_SHORT || value > PIC_CMD_BUZZ_LONG)
return -1;
write(dev->fd, &value, 1);
return 0;
}
int pic_set_status_led(struct picdev *dev, char value)
{
if (value < PIC_CMD_STATUSLED_RED_2HZ || value > PIC_CMD_STATUSLED_REDGREEN_1HZ)
return -1;
write(dev->fd, &value, 1);
return 0;
}
int pic_set_usb_led(struct picdev *dev, char value)
{
if (value < PIC_CMD_USBLED_ON || value > PIC_CMD_USBLED_OFF)
return -1;
write(dev->fd, &value, 1);
return 0;
}
static int pic_read_cb(int fd, void *privdata)
{
struct picdev *dev = (struct picdev *)privdata;
unsigned char event;
int len = read(dev->fd, &event, 1);
if (len < 0)
return -1;
switch (event)
{
case PIC_EVENT_FAN1_ERR:
pic_set_buzzer(dev, PIC_CMD_BUZZ_SHORT);
dev->fan_error = 1;
break;
case PIC_EVENT_FAN1_OK:
dev->fan_error = 0;
break;
case PIC_EVENT_FAN2_ERR:
case PIC_EVENT_FAN2_OK:
break;
case PIC_EVENT_TEMP_RANGE_MIN ... PIC_EVENT_TEMP_RANGE_MAX:
dev->temperature = event - 128;
break;
case PIC_EVENT_TEMP_WARN:
pic_set_buzzer(dev, PIC_CMD_BUZZ_SHORT);
dev->temperature = 75;
break;
case PIC_EVENT_TEMP_CRIT:
dev->temperature = 80;
break;
default:
log_print(LOG_DEBUG, "%s(): unknown event 0x%02x", __FUNCTION__, event);
break;
}
return 0;
}
static int lcdpage_case(struct lcddev *lcd, int event, void *privdata)
{
struct picdev *dev = (struct picdev *)privdata;
switch (event) {
case LCDPAGE_EVENT_BUTTON1:
return LCDPAGE_COMMAND_NEXT;
case LCDPAGE_EVENT_BUTTON2:
{
int fan_speed = PIC_CMD_FANSPEED_0 + dev->fan_speed +1;
if (fan_speed > PIC_CMD_FANSPEED_5)
fan_speed = PIC_CMD_FANSPEED_0;
pic_set_fanspeed(dev, fan_speed);
lcd_set_backlight(lcd, 1);
break;
}
case LCDPAGE_EVENT_ENTER:
lcd_set_backlight(lcd, 1);
break;
case LCDPAGE_EVENT_BACKLIGHT:
case LCDPAGE_EVENT_EXIT:
return 0;
default:
break;
}
char line1_ok[] = "FAN(OK): TEMP:";
char line1_err[] = "FAN(ERR): TEMP:";
char line2[20];
snprintf(line2, sizeof(line2), "[ ] %02d C ", dev->temperature);
int i;
for (i = 1; i <= dev->fan_speed; i++) {
line2[i] = '#';
}
lcd_setlines(lcd, (dev->fan_error ? line1_err : line1_ok), line2);
return 1000;
}
struct picdev * pic_open(const char *devicename, struct lcddev *lcd)
{
struct picdev *dev = malloc(sizeof(struct picdev));
if (dev == NULL) {
log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__);
return NULL;
}
memset(dev, 0, sizeof(struct picdev));
if (pic_open_device(dev, devicename) < 0) {
free(dev);
return NULL;
}
dev->read_event = event_add_readfd(NULL, dev->fd, pic_read_cb, dev);
if (lcd != NULL) {
lcd_addpage_cb(lcd, 190, lcdpage_case, dev);
}
pic_set_fanspeed(dev, PIC_CMD_FANSPEED_1);
pic_set_status_led(dev, PIC_CMD_STATUSLED_GREENON);
return dev;
}
void pic_close(struct picdev *dev)
{
if (dev->read_event != NULL) {
event_remove_fd(dev->read_event);
dev->read_event = NULL;
}
pic_close_device(dev);
free(dev);
}

64
pic.h
View File

@ -1,64 +0,0 @@
#ifndef _PIC_H_
#define _PIC_H_
struct picdev; /* private data */
struct picdev * pic_open(const char *devicename, struct lcddev *lcd);
void pic_close(struct picdev *dev);
#define PIC_CMD_FANSPEED_0 0x30
#define PIC_CMD_FANSPEED_1 0x31
#define PIC_CMD_FANSPEED_2 0x32
#define PIC_CMD_FANSPEED_3 0x33
#define PIC_CMD_FANSPEED_4 0x34
#define PIC_CMD_FANSPEED_5 0x35
#define PIC_CMD_POWER_OFF 0x41
#define PIC_CMD_AUTOPOWER_ON 0x48
#define PIC_CMD_AUTOPOWER_OFF 0x49
#define PIC_EVENT_POWER_BUTTON 0x40
#define PIC_CMD_POWERLED_OFF 0x4B
#define PIC_CMD_POWERLED_2HZ 0x4C
#define PIC_CMD_POWERLED_ON 0x4D
#define PIC_CMD_POWERLED_1HZ 0x4E
#define PIC_CMD_BUZZ_SHORT 0x50
#define PIC_CMD_BUZZ_LONG 0x51
#define PIC_CMD_STATUSLED_RED_2HZ 0x54
#define PIC_CMD_STATUSLED_GREEN_2HZ 0x55
#define PIC_CMD_STATUSLED_GREENON 0x56
#define PIC_CMD_STATUSLED_REDON 0x57
#define PIC_CMD_STATUSLED_REDGREEN_2HZ 0x58
#define PIC_CMD_STATUSLED_OFF 0x59
#define PIC_CMD_STATUSLED_GREEN_1HZ 0x5A
#define PIC_CMD_STATUSLED_RED_1HZ 0x5B
#define PIC_CMD_STATUSLED_REDGREEN_1HZ 0x5C
#define PIC_CMD_USBLED_ON 0x60
#define PIC_CMD_USBLED_8HZ 0x61
#define PIC_CMD_USBLED_OFF 0x62
#define PIC_EVENT_FAN1_ERR 0x73
#define PIC_EVENT_FAN1_OK 0x74
#define PIC_EVENT_FAN2_ERR 0x75
#define PIC_EVENT_FAN2_OK 0x76
#define PIC_EVENT_FAN3_ERR 0x77
#define PIC_EVENT_FAN3_OK 0x78
#define PIC_EVENT_FAN4_ERR 0x79
#define PIC_EVENT_FAN4_OK 0x7A
#define PIC_EVENT_TEMP_RANGE_MIN 0x80 /* 0°C */
#define PIC_EVENT_TEMP_RANGE_MAX 0xC6 /* 70°C */
#define PIC_EVENT_TEMP_WARN 0x38 /* 71-79°C */
#define PIC_EVENT_TEMP_CRIT 0x39 /* >= 80°C */
int pic_set_fanspeed(struct picdev *dev, char value);
int pic_set_buzzer(struct picdev *dev, char value);
int pic_set_status_led(struct picdev *dev, char value);
int pic_set_usb_led(struct picdev *dev, char value);
#endif /* _PIC_H_ */

View File

@ -1,20 +0,0 @@
[global]
#lcddevice /dev/ttyS0
#picdevice /dev/ttyS1
#lcddevice dummy
lcdtimeout 15
pidfile qnapd.pid
logfile qnapd.log
[diskwatch]
check_interval 60
hddtemp_server 127.0.0.1:7634
#disk /dev/sda,7200
#disk /dev/sdb,7200
#disk /dev/sdc,7200
#disk /dev/sdd,7200