/*
* Copyright (C) 2005 Alex Murray <pragmatine@gmail.com>
*
* 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
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include "hddtemp-sensors-interface.h"
#include "sensors-applet.h"
#define HDDTEMP_SERVER_IP_ADDRESS "127.0.0.1"
#define HDDTEMP_PORT_NUMBER 7634
#define HDDTEMP_OUTPUT_BUFFER_LENGTH 1024
/* for error handling */
#define HDDTEMP_ERROR (hddtemp_sensors_interface_error_quark())
enum {
HDDTEMP_SOCKET_OPEN_ERROR,
HDDTEMP_SOCKET_CONNECT_ERROR,
HDDTEMP_GIOCHANNEL_ERROR,
HDDTEMP_GIOCHANNEL_READ_ERROR
};
/* for error handling */
static GQuark hddtemp_sensors_interface_error_quark(void) {
static GQuark quark = 0;
gchar *string;
if (quark == 0) {
string = g_strdup_printf("%s-device-file-error", sensor_interface[HDDTEMP]);
quark = g_quark_from_string(string);
g_free(string);
}
return quark;
}
static const gchar *hddtemp_sensors_interface_query_hddtemp_daemon(GError **error) {
int sockfd;
ssize_t n = 1;
gboolean first_run = FALSE;
gint output_length = 0;
gchar *pc;
struct sockaddr_in address;
static char* buffer = NULL;
static GTimeVal previous_query_time;
GTimeVal current_query_time;
if (NULL == buffer) {
// initialise buffer and current time
buffer = g_new0(char, HDDTEMP_OUTPUT_BUFFER_LENGTH);
g_get_current_time(&previous_query_time);
first_run = TRUE;
}
g_get_current_time(¤t_query_time);
/* only actually query if more than 60 seconds has elapsed as
hddtemp daemon will only actually send a new value if is > 60
seconds */
if (first_run || current_query_time.tv_sec - previous_query_time.tv_sec > 60) {
previous_query_time = current_query_time;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
// couldn't open socket
g_set_error(error, HDDTEMP_ERROR, HDDTEMP_SOCKET_OPEN_ERROR, "Error opening socket for hddtemp");
return NULL;
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(HDDTEMP_SERVER_IP_ADDRESS);
address.sin_port = htons(HDDTEMP_PORT_NUMBER);
if (connect(sockfd, (struct sockaddr *)&address, (socklen_t)sizeof(address)) == -1) {
g_set_error(error, HDDTEMP_ERROR, HDDTEMP_SOCKET_CONNECT_ERROR, "Error connecting to hddtemp daemon on port %i on %s", htons(HDDTEMP_PORT_NUMBER), HDDTEMP_SERVER_IP_ADDRESS);
return NULL;
}
pc = buffer;
while ((n = read(sockfd, pc, HDDTEMP_OUTPUT_BUFFER_LENGTH - output_length)) > 0) {
output_length += n;
pc = &pc[n];
}
/* terminate with pipe if not already terminated */
if (buffer[n - 1] != '|') {
buffer[n++] = '|';
}
/* always null terminate the end of the buffer
* regardless of how much stuff is in it already */
buffer[output_length] = '\0';
close(sockfd);
}
return buffer;
}
static void hddtemp_sensors_interface_get_sensors(SensorsApplet *sensors_applet) {
GError *error = NULL;
const gchar *hddtemp_output;
gchar **output_vector = NULL, **pv;
hddtemp_output = hddtemp_sensors_interface_query_hddtemp_daemon(&error);
if (error) {
g_error_free(error);
return;
}
if (hddtemp_output[0] != '|') {
g_debug("Error in format of string returned from hddtemp daemon: char at [0] should be \"|\", instead whole output is: \"%s\"", hddtemp_output);
return;
}
/* for each sensor the output will contain four strings ie
|/dev/hda|WDC WD800JB-00ETA0|32|C||/dev/hdb|???|ERR|*|
note the repetition -----^ */
/*
pv[0 + 5*n] empty
pv[1 + 5*n] device name
pv[2 + 5*n] disk label
pv[3 + 5*n] temperature
pv[4 + 5*n] unit
pv[5 + 5*n] empty
*/
pv = output_vector = g_strsplit(hddtemp_output, "|", -1);
while(pv[1] != NULL) {
if (pv[2] != "" && pv [3] != "" && pv[4] != "" && (!(g_ascii_strcasecmp(pv[2], "???") == 0 || g_ascii_strcasecmp(pv[3], "ERR") == 0 || g_ascii_strcasecmp(pv[4], "*") == 0))) {
sensors_applet_add_sensor(sensors_applet,
pv[1],
pv[1],
pv[2],
HDDTEMP,
FALSE,
TEMP_SENSOR,
HDD_ICON);
}
pv += 5;
}
g_strfreev(output_vector);
}
/* to be called to setup for hddtemp sensors */
void hddtemp_sensors_interface_init(SensorsApplet *sensors_applet) {
sensors_applet_register_sensors_interface(sensors_applet,
HDDTEMP,
hddtemp_sensors_interface_get_sensor_value);
/* call function to recursively look for sensors
starting at the defined base directory */
hddtemp_sensors_interface_get_sensors(sensors_applet);
}
/* returns the value of the sensor_list at the given iter, or if an
error occurs, instatiates error with an error message */
gdouble hddtemp_sensors_interface_get_sensor_value(const gchar *path,
const gchar *id,
SensorType type,
GError **error) {
const gchar *hddtemp_output;
gchar **output_vector = NULL, **pv;
gfloat sensor_value = -1.0f;
hddtemp_output = hddtemp_sensors_interface_query_hddtemp_daemon(error);
if (*error) {
return sensor_value;
}
if (hddtemp_output[0] != '|') {
g_debug("Error in format of string returned from hddtemp daemon: char at [0] should be \"|\", instead whole output is: \"%s\"", hddtemp_output);
return sensor_value;
}
/* for each sensor the output will contain four strings ie
|/dev/hda|WDC WD800JB-00ETA0|32|C||/dev/hdb|???|ERR|*|
note the repetition -----^
pv[0 + 5*n] empty
pv[1 + 5*n] device name
pv[2 + 5*n] disk label
pv[3 + 5*n] temperature
pv[4 + 5*n] unit
pv[5 + 5*n] empty
*/
pv = output_vector = g_strsplit(hddtemp_output, "|", -1);
while(pv[1] != NULL) {
if (g_ascii_strcasecmp(pv[1], path) == 0) {
sensor_value = (gfloat)(g_ascii_strtod(pv[3], NULL));
/* always return sensor values in celsius */
if (pv[4][0] == 'F') {
sensor_value = (sensor_value - 32.0) * 5.0 / 9.0;
}
break;
}
pv += 5;
}
g_strfreev(output_vector);
return (gdouble)sensor_value;
}
syntax highlighted by Code2HTML, v. 0.9.1