1 /* GKrellM
2 |  Copyright (C) 1999-2019 Bill Wilson
3 |
4 |  Author:  Bill Wilson    billw@gkrellm.net
5 |  Latest versions might be found at:  http://gkrellm.net
6 |
7 |
8 |  GKrellM is free software: you can redistribute it and/or modify it
9 |  under the terms of the GNU General Public License as published by
10 |  the Free Software Foundation, either version 3 of the License, or
11 |  (at your option) any later version.
12 |
13 |  GKrellM is distributed in the hope that it will be useful, but WITHOUT
14 |  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 |  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 |  License for more details.
17 |
18 |  You should have received a copy of the GNU General Public License
19 |  along with this program. If not, see http://www.gnu.org/licenses/
20 |
21 |
22 |  Additional permission under GNU GPL version 3 section 7
23 |
24 |  If you modify this program, or any covered work, by linking or
25 |  combining it with the OpenSSL project's OpenSSL library (or a
26 |  modified version of that library), containing parts covered by
27 |  the terms of the OpenSSL or SSLeay licenses, you are granted
28 |  additional permission to convey the resulting work.
29 |  Corresponding Source for a non-source form of such a combination
30 |  shall include the source code for the parts of OpenSSL used as well
31 |  as that of the covered work.
32 */
33 
34 
35 
36 /* A system dependent interface can include this file to get sensors
37 |  from daemons that can run under different operating systems.
38 */
39 
40 #define SENSORS_COMMON	1
41 
42 /* --------------- Interface to mbmon daemon sensor reading ---------
43 */
44 typedef struct
45 	{
46 	gchar	*name;
47 	gfloat	value;
48 	}
49 	MbmonSensor;
50 
51 static GList	*mbmon_list;
52 
53 static gchar	gkrellm_decimal_point,
54 				mbmon_decimal_point;
55 static gboolean	mbmon_need_decimal_point_fix;
56 
57 static gboolean (*mbmon_check_func)();
58 
59 static gboolean
60 mbmon_decimal_point_fix(gchar *buf)
61 	{
62 	gchar   *s;
63 
64 	for (s = buf; *s; ++s)
65 		if (*s == mbmon_decimal_point)
66 			{
67 			*s = gkrellm_decimal_point;
68 			return TRUE;
69 			}
70 	return FALSE;
71 	}
72 
73 static gboolean
74 mbmon_decimal_point_check(gchar *buf)
75 	{
76 	struct lconv	*lc;
77 	gchar			*s;
78 
79 	lc = localeconv();
80 	gkrellm_decimal_point = *lc->decimal_point;
81 
82 	mbmon_decimal_point = (gkrellm_decimal_point == ',' ? '.' : ',');
83 
84 	s = g_strdup(buf);
85 	if (mbmon_decimal_point_fix(s))
86 		{
87 		mbmon_need_decimal_point_fix = TRUE;
88 		gkrellm_debug(DEBUG_SENSORS, "mbmon_need_decimal_point_fix: %c -> %c\n",
89 					mbmon_decimal_point, gkrellm_decimal_point);
90 		}
91 	g_free(s);
92 
93 	return mbmon_need_decimal_point_fix;;
94 	}
95 
96 static MbmonSensor *
97 mbmon_lookup(gchar *name)
98 	{
99 	GList		*list;
100 	MbmonSensor	*mb;
101 
102 	for (list = mbmon_list; list; list = list->next)
103 		{
104 		mb = (MbmonSensor *) list->data;
105 		if (!strcmp(name, mb->name))
106 			return mb;
107 		}
108 	return NULL;
109 	}
110 
111   /* Read sensor data from the mbmon daemon, which must be run with the
112   |  -r option and no -f option:  mbmon -r -P port
113   |  and 'port' must be configured in the sensors config.
114   |  With '-r' mbmon output will be:
115   |		TEMP0 : 37.0
116   |		TEMP1 : 35.5
117   |		TEMP2 : 43.0
118   |		FAN0  : 1704
119   |		FAN1  : 2220
120   |		FAN2  : 2057
121   |		VC0   :  +1.71
122   |		VC1   :  +2.51
123   |		V33   :  +3.22
124   |		V50P  :  +4.87
125   |		V12P  : +11.80
126   |		V12N  : -12.12
127   |		V50N  :  -5.25
128   */
129 static gboolean
130 mbmon_daemon_read(void)
131 	{
132 	gchar				*server = "127.0.0.1";
133 	MbmonSensor			*mb;
134 	gchar				*default_label, *id_name;
135 	gchar				name[32], buf[256];
136 	gfloat				value;
137 	gint				fd, n, type;
138 	gboolean			result = FALSE;
139 	static GString		*mbmon_gstring;
140 	static gboolean		decimal_point_check_done;
141 
142 	if ((fd = gkrellm_connect_to(server, _GK.mbmon_port)) < 0)
143 		{
144 		gkrellm_debug(DEBUG_SENSORS,
145 			"mbmon_daemon_read: can't connect to %s:%d.\n", server,
146 			_GK.mbmon_port);
147 		return FALSE;
148 		}
149 
150 	if (!mbmon_gstring)
151 		mbmon_gstring = g_string_new("");
152 	mbmon_gstring = g_string_truncate(mbmon_gstring, 0);
153 
154 	while ((n = read(fd, buf, sizeof(buf) - 1)) > 0)
155 		{
156 		buf[n] = '\0';
157 		mbmon_gstring = g_string_append(mbmon_gstring, buf);
158 		}
159 	close(fd);
160 
161 	gkrellm_debug(DEBUG_SENSORS, "mbmon_daemon_read:\n%s\n", mbmon_gstring->str);
162 
163 	while (gkrellm_getline_from_gstring(&mbmon_gstring, buf, sizeof(buf)))
164 		{
165 		if (mbmon_need_decimal_point_fix)
166 			mbmon_decimal_point_fix(buf);
167 		if (   sscanf(buf, "%31s : %f", name, &value) != 2
168 		    || value == 0.0		/* Sensor not available */
169 		   )
170 			continue;
171 		if (name[0] == 'T')
172 			type = SENSOR_TEMPERATURE;
173 		else if (name[0] == 'F')
174 			type = SENSOR_FAN;
175 		else if (name[0] == 'V')
176 			type = SENSOR_VOLTAGE;
177 		else
178 			continue;
179 
180 		if (   !decimal_point_check_done
181 			&& (type == SENSOR_TEMPERATURE || type == SENSOR_VOLTAGE)
182 		   )
183 			{
184 			mbmon_decimal_point_check(buf);
185 			decimal_point_check_done = TRUE;
186 			}
187 
188 		if ((mb = mbmon_lookup(name)) == NULL)
189 			{
190 			mb = g_new0(MbmonSensor, 1);
191 			mbmon_list = g_list_append(mbmon_list, mb);
192 			mb->name = g_strdup(name);
193 			default_label = name;
194 			id_name = g_strdup_printf("mbmon/%s", name);
195 			gkrellm_sensors_add_sensor(type,
196 						name, id_name,
197 						0, 0, MBMON_INTERFACE,
198 						1.0, 0.0, NULL, default_label);
199 			g_free(id_name);
200 			}
201 		mb->value = value;		/* Assume centigrade, mbmon gives no units */
202 		result = TRUE;
203 		}
204 	return result;
205 	}
206 
207 
208 gboolean
209 gkrellm_sys_sensors_mbmon_check(gboolean force)
210 	{
211 	GList			*list;
212 	MbmonSensor		*mb;
213 	gboolean		result = TRUE;
214 	static gint		port;
215 	static gint		check_time = -1;
216 	static gboolean	tmp;
217 
218 	mbmon_check_func = gkrellm_sys_sensors_mbmon_check;
219 
220 	if (port > 0 && port != _GK.mbmon_port)
221 		{
222 		for (list = mbmon_list; list; list = list->next)
223 			{
224 			mb = (MbmonSensor *) list->data;
225 			g_free(mb->name);
226 			}
227 		gkrellm_free_glist_and_data(&mbmon_list);
228 		}
229 	if (_GK.mbmon_port <= 0)
230 		return FALSE;
231 	port = _GK.mbmon_port;
232 	if (check_time < _GK.time_now || force)
233 		{
234 		/* The first mbmon_daemon_read can set need_decimal_point_fix in
235 		|  which case don't update check_time so the mbmon daemon will be
236 		|  read again immediately at next call to this function.  The first
237 		|  call of this function should be made from gkrellm_sys_sensors_init()
238 		|  function where we just want to get the sensors loaded into
239 		|  sensors.c and we don't actually use the mbmon sensor values.
240 		*/
241 		tmp = mbmon_need_decimal_point_fix;
242 		result = mbmon_daemon_read();
243 		if (tmp == mbmon_need_decimal_point_fix)
244 			check_time = _GK.time_now + 3;	/* Interval < sensor update */
245 		}
246 	return result;
247 	}
248 
249 
250 gboolean
251 gkrellm_sys_sensors_mbmon_get_value(gchar *name, gfloat *value)
252 	{
253 	MbmonSensor	*mb;
254 
255 	if ((mb = mbmon_lookup(name)) != NULL)
256 		{
257 		*value = mb->value;
258 		return TRUE;
259 		}
260 	return FALSE;
261 	}
262 
263 
264 
265 /* --------------- Interface to hddtemp daemon sensor reading ---------
266 */
267   /* Use hddtemp default port.  Should make this configurable.
268   */
269 #define	HDDTEMP_PORT	7634
270 
271 typedef struct
272 	{
273 	gchar	*device;
274 	gfloat	value;
275 	gchar	unit;
276 	}
277 	HddtempSensor;
278 
279 static GList	*hddtemp_list;
280 
281 static HddtempSensor *
282 hddtemp_lookup(gchar *device)
283 	{
284 	GList			*list;
285 	HddtempSensor	*hdd;
286 
287 	for (list = hddtemp_list; list; list = list->next)
288 		{
289 		hdd = (HddtempSensor *) list->data;
290 		if (!strcmp(device, hdd->device))
291 			return hdd;
292 		}
293 	return NULL;
294 	}
295 
296   /* Read output from the hddtemp daemon which must have been started in
297   |  daemon mode:  hddtemp -d /dev/hda /dev/hdb ...
298   |  And example hddtemp output will be:
299   |
300   |		|/dev/hda|SAMSUNG SP1614N|30|C||/dev/hdc|SAMSUNG SP1614N|30|C|
301   |
302   */
303 static gboolean
304 hddtemp_daemon_read(void)
305 	{
306 	gchar			*server = "127.0.0.1";
307 	gpointer			sr;
308 	HddtempSensor		*hdd;
309 	gchar				**argv, **info, *id_name, *default_label;
310 	gchar				buf[256], sep;
311 	gint				fd, n, j;
312 	static GString		*hddtemp_gstring;
313 	gboolean			result = FALSE;
314 
315 	if ((fd = gkrellm_connect_to(server, HDDTEMP_PORT)) < 0)
316 		{
317 		gkrellm_debug(DEBUG_SENSORS,
318 			"hddtemp_daemon_read: can't connect to %s:%d.\n", server,
319 			HDDTEMP_PORT);
320 		return FALSE;
321 		}
322 
323 	if (!hddtemp_gstring)
324 		hddtemp_gstring = g_string_new("");
325 	hddtemp_gstring = g_string_truncate(hddtemp_gstring, 0);
326 
327 	while ((n = read(fd, buf, sizeof(buf) - 1)) > 0)
328 		{
329 		buf[n] = '\0';
330 		hddtemp_gstring = g_string_append(hddtemp_gstring, buf);
331 		}
332 	close(fd);
333 
334 	gkrellm_debug(DEBUG_SENSORS, "hddtemp_daemon_read (once a minute):\n\t%s\n",
335 					hddtemp_gstring->str);
336 
337 	sep = hddtemp_gstring->str[0];
338 	if (sep == '\0')
339 		return FALSE;
340 	sprintf(buf, "%c%c", sep, sep);
341 
342 	argv = g_strsplit(hddtemp_gstring->str + 1, buf, 20);
343 	buf[1] = '\0';
344 	for (n = 0; argv[n] != NULL; ++n)
345 		{
346 		info = g_strsplit(argv[n], buf, 4);
347 		for (j = 0; info[j] != NULL; ++j)
348 			;
349 		if (j < 4)
350 			{
351 			g_strfreev(info);
352 			continue;
353 			}
354 		if ((hdd = hddtemp_lookup(info[0])) == NULL)
355 			{
356 			hdd = g_new0(HddtempSensor, 1);
357 			hddtemp_list = g_list_append(hddtemp_list, hdd);
358 			hdd->device = g_strdup(info[0]);
359 			default_label = strrchr(hdd->device, '/');
360 			if (default_label)
361 				++default_label;
362 			else
363 				default_label = hdd->device;
364 			id_name = g_strdup_printf("hddtemp/%s", default_label);
365 			sr = gkrellm_sensors_add_sensor(SENSOR_TEMPERATURE,
366 						hdd->device, id_name,
367 						0, 0, HDDTEMP_INTERFACE,
368 						1.0, 0.0, NULL, default_label);
369 			gkrellm_sensors_set_group(sr, SENSOR_GROUP_DISK);
370 			g_free(id_name);
371 			}
372 		hdd->value = atof(info[2]);
373 		if (*info[3] == 'F')
374 			hdd->value = (hdd->value - 32.0) / 1.8;
375 		g_strfreev(info);
376 		result = TRUE;
377 		}
378 	g_strfreev(argv);
379 	return result;
380 	}
381 
382 void
383 gkrellm_sys_sensors_hddtemp_check(void)
384 	{
385 	static gint	check_time = -1;
386 
387 	/* hddtemp docs say shouldn't check more than once per minute.
388 	*/
389 	if (check_time < _GK.time_now)
390 		{
391 		hddtemp_daemon_read();
392 		check_time = _GK.time_now + 60;
393 		}
394 	}
395 
396 gboolean
397 gkrellm_sys_sensors_hddtemp_get_value(gchar *name, gfloat *value)
398 	{
399 	HddtempSensor	*hdd;
400 
401 	if ((hdd = hddtemp_lookup(name)) != NULL)
402 		{
403 		*value = hdd->value;
404 		return TRUE;
405 		}
406 	return FALSE;
407 	}
408 
409