/* * Copyright (C) 2005 Alex Murray * * 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 #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #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; }