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 #include "gkrellmd.h"
35 #include "gkrellmd-private.h"
36 #include <inttypes.h>
37 
38 GList			*gkrellmd_monitor_list;
39 
40 static GList	*serveflag_done_list;
41 
42 static struct tm	gkrellmd_current_tm;
43 
44 gint
45 gkrellm_get_timer_ticks(void)
46 	{
pmx(PlannerInfo * root,Gene * tour1,Gene * tour2,Gene * offspring,int num_gene)47 	return GK.timer_ticks;
48 	}
49 
50 gboolean
51 gkrellmd_check_client_version(GkrellmdMonitor *mon,
52 				gint major, gint minor, gint rev)
53 	{
54 	GkrellmdClient	*client = mon->privat->client;
55 
56 	if (   client->major_version > major
57 		|| (client->major_version == major && client->minor_version > minor)
58 	    || (   client->major_version == major && client->minor_version == minor
59 			&& client->rev_version >= rev
60 		   )
61 	   )
62 		return TRUE;
63 	return FALSE;
64 	}
65 
66 void
67 gkrellmd_add_serveflag_done(gboolean *flag)
68 	{
69 	serveflag_done_list = g_list_append(serveflag_done_list, flag);
70 	}
71 
72 
73 void
74 gkrellmd_set_serve_name(GkrellmdMonitor *mon, const gchar *tag)
75 	{
76 	GkrellmdMonitorPrivate	*mp = mon->privat;
77 
78 	mp->serve_name = tag;
79 	mp->serve_name_sent = FALSE;
80 	}
81 
82 void
83 gkrellmd_serve_data(GkrellmdMonitor *mon, gchar *line)
84 	{
85 	GkrellmdMonitorPrivate	*mp = mon->privat;
86 	gchar					buf[128];
87 
88 	if (!line || !*line)
89 		return;
90 	if (!mp->serve_name_sent)
91 		{
92 		if (mp->serve_name)
93 			{
94 			snprintf(buf, sizeof(buf), "<%s>\n", mp->serve_name);
95 			gkrellm_debug(DEBUG_SERVER, "%s", buf);
96 			mp->serve_gstring = g_string_append(mp->serve_gstring, buf);
97 			mp->serve_name_sent = TRUE;
98 			}
99 		else
100 			{
101 			g_warning("gkrellmd: %s forgot to gkrellmd_set_serve_name()\n",
102 					mon->name);
103 			return;
104 			}
105 		}
106 	gkrellm_debug(DEBUG_SERVER,"%s", line);
107 	mp->serve_gstring = g_string_append(mp->serve_gstring, line);
108 	}
109 
110 /* ======================================================= */
111 typedef struct
112 	{
113 	gint	instance;
114 	gulong	user,
115 			nice,
116 			sys,
117 			idle;
118 	}
119 	CpuData;
120 
121 static gchar	*n_cpus_setup;
122 static gboolean	nice_time_unsupported;
123 
124 static GList	*cpu_list;
125 static GList	*instance_list;
126 
127 void
128 gkrellm_cpu_set_number_of_cpus(gint n)
129 	{
130 	CpuData	*cpu;
131 	GList	*list;
132 	gint	i;
133 
134 	n_cpus_setup = g_strdup_printf("n_cpus %d\n", n);
135 	for (i = 0; i < n; ++i)
136 		{
137 		cpu = g_new0(CpuData, 1);
138 		cpu_list = g_list_append(cpu_list, cpu);
139 
140 		if (instance_list && (list = g_list_nth(instance_list, i)) != NULL)
141 			cpu->instance = GPOINTER_TO_INT(list->data);
142 		else
143 			cpu->instance = i;
144 		}
145 	}
146 
147 void
148 gkrellm_cpu_add_instance(gint instance)
149 	{
150 	instance_list = g_list_append(instance_list, GINT_TO_POINTER(instance));
151 	}
152 
153 void
154 gkrellm_cpu_nice_time_unsupported(void)
155 	{
156 	nice_time_unsupported = TRUE;
157 	}
158 
159 void
160 gkrellm_cpu_assign_composite_data(gulong user, gulong nice,
161 			gulong sys, gulong idle)
162 	{
163 	return;		/* let client gkrellm compute it */
164 	}
165 
166 void
167 gkrellm_cpu_assign_data(gint n, gulong user, gulong nice,
168 			gulong sys, gulong idle)
169 	{
170 	CpuData	*cpu = NULL;
171 	GList	*list;
172 
173 	for (list = cpu_list; list; list = list->next)
174 		{
175 		cpu = (CpuData *) list->data;
176 		if (cpu->instance == n)
177 			break;
178 		}
179 	if (list)
180 		{
181 		cpu->user = user;
182 		cpu->nice = nice;
183 		cpu->sys = sys;
184 		cpu->idle = idle;
185 		}
186 	}
187 
188 static void
189 update_cpu(GkrellmdMonitor *mon, gboolean first_update)
190 	{
191 	gkrellm_sys_cpu_read_data();
192 	gkrellmd_need_serve(mon);
193 	}
194 
195 static void
196 serve_cpu_data(GkrellmdMonitor *mon, gboolean first_serve)
197 	{
198 	CpuData	*cpu;
199 	GList	*list;
200 	gchar	buf[128];
201 
202 	gkrellmd_set_serve_name(mon, "cpu");
203 	for (list = cpu_list; list; list = list->next)
204 		{
205 		cpu = (CpuData *) list->data;
206 		snprintf(buf, sizeof(buf), "%d %lu %lu %lu %lu\n", cpu->instance,
207 				cpu->user, cpu->nice, cpu->sys, cpu->idle);
208 		gkrellmd_serve_data(mon, buf);
209 		}
210 	}
211 
212 static void
213 serve_cpu_setup(GkrellmdMonitor *mon)
214 	{
215 	GkrellmdClient	*client = mon->privat->client;
216 	GList			*list;
217 	gchar			buf[64];
218 
219 	gkrellmd_send_to_client(client, "<cpu_setup>\n");
220 	for (list = instance_list; list; list = list->next)
221 		{
222 		snprintf(buf, sizeof(buf), "cpu_instance %d\n",
223 				GPOINTER_TO_INT(list->data));
224 		gkrellmd_send_to_client(client, buf);
225 		}
226 	gkrellmd_send_to_client(client, n_cpus_setup);
227 	if (nice_time_unsupported)
228 		gkrellmd_send_to_client(client, "nice_time_unsupported\n");
229 	}
230 
231 static GkrellmdMonitor cpu_monitor =
232 	{
233 	"cpu",
234 	update_cpu,
235 	serve_cpu_data,
236 	serve_cpu_setup
237 	};
238 
239 
240 static GkrellmdMonitor *
241 init_cpu_monitor(void)
242 	{
243 	if (gkrellm_sys_cpu_init())
244 		return &cpu_monitor;
245 	return NULL;
246 	}
247 
248 /* ======================================================= */
249 struct
250 	{
251 	gboolean	changed;
252 	gint		n_processes,
253 				n_running,
254 				n_users;
255 	gulong		n_forks;
256 	gfloat		fload;
257 	}
258 	proc;
259 
260 void
261 gkrellm_proc_assign_data(gint n_processes, gint n_running,
262 			gulong n_forks, gfloat load)
263 	{
264 	if (   proc.n_processes != n_processes
265 		|| proc.n_running != n_running
266 		|| proc.n_forks != n_forks
267 		|| proc.fload != load
268 	   )
269 		{
270 		proc.n_processes = n_processes;
271 		proc.n_running = n_running;
272 		proc.n_forks = n_forks;
273 		proc.fload = load;
274 		proc.changed = TRUE;
275 		}
276 	}
277 
278 void
279 gkrellm_proc_assign_users(gint n_users)
280 	{
281 	if (proc.n_users != n_users)
282 		{
283 		proc.n_users = n_users;
284 		proc.changed = TRUE;
285 		}
286 	}
287 
288 static void
289 update_proc(GkrellmdMonitor *mon, gboolean first_update)
290 	{
291 	proc.changed = FALSE;
292 	gkrellm_sys_proc_read_data();
293 	if (first_update || GK.five_second_tick)
294 		gkrellm_sys_proc_read_users();
295 
296 	if (proc.changed)
297 		gkrellmd_need_serve(mon);
298 	}
299 
300 static void
301 serve_proc_data(GkrellmdMonitor *mon, gboolean first_serve)
302 	{
303 	gchar	buf[128];
304 
305 	gkrellmd_set_serve_name(mon, "proc");
306 	snprintf(buf, sizeof(buf), "%d %d %lu %.2f %d\n",
307 			 proc.n_processes, proc.n_running,
308 			 proc.n_forks, proc.fload, proc.n_users);
309 	gkrellmd_serve_data(mon, buf);
310 	}
311 
312 static GkrellmdMonitor proc_monitor =
313 	{
314 	"proc",
315 	update_proc,
316 	serve_proc_data,
317 	NULL
318 	};
319 
320 
321 static GkrellmdMonitor *
322 init_proc_monitor(void)
323 	{
324 	if (!gkrellm_sys_proc_init())
325 		return NULL;
326 	serveflag_done_list = g_list_append(serveflag_done_list, &proc.changed);
327 	return &proc_monitor;
328 	}
329 
330 /* ======================================================= */
331 typedef struct
332 	{
333 	gchar		*name;
334 	gchar		*subdisk_parent;
335 	gint		order,
336 				subdisk,
337 				changed;
338 	gint		device_number,
339 				unit_number;
340 	gboolean	virtual;
341 	guint64		rb,
342 				wb;
343 	}
344 	DiskData;
345 
346 static GList	*disk_list;
347 static gint		n_disks;
348 static gboolean	units_are_blocks;
349 
350 
351 static DiskData *
352 add_disk(const gchar *name, gint order, gint device_number, gint unit_number)
353 	{
354 	DiskData	*disk;
355 	GList		*list;
356 	gint		i;
357 
358 	disk = g_new0(DiskData, 1);
359 	disk->name = g_strdup(name);
360 	disk->order = order;
361 	disk->subdisk = -1;
362 	disk->device_number = device_number;
363 	disk->unit_number = unit_number;
364 	if (order >= 0)
365 		{
366 		for (i = 0, list = disk_list; list; list = list->next, ++i)
367 			if (disk->order < ((DiskData *) list->data)->order)
368 				break;
369 		disk_list = g_list_insert(disk_list, disk, i);
370 		}
371 	else
372 		disk_list = g_list_append(disk_list, disk);
373 	++n_disks;
374 	return disk;
375 	}
376 
377 static DiskData *
378 add_subdisk(gchar *subdisk_name, gchar *disk_name, gint subdisk)
379 	{
380 	DiskData	*sdisk = NULL;
381 	DiskData	*disk;
382 	GList		*list = NULL;
383 
384 	for (list = disk_list; list; list = list->next)
385 		{
386 		disk = (DiskData * ) list->data;
387 		if (!strcmp(disk_name, disk->name))
388 			break;
389 		}
390 	if (!list)
391 		return NULL;
392 	sdisk = g_new0(DiskData, 1);
393 	sdisk->name = g_strdup(subdisk_name);
394 	sdisk->subdisk_parent = g_strdup(disk_name);
395 	sdisk->order = disk->order;
396 	sdisk->subdisk = subdisk;
397 
398 	for (list = list->next; list; list = list->next)
399 		{
400 		disk = (DiskData * ) list->data;
401 		if (disk->subdisk == -1 || disk->subdisk > subdisk)
402 			break;
403 		}
404 	disk_list = g_list_insert_before(disk_list, list, sdisk);
405 	++n_disks;
406 	return sdisk;
407 	}
408 
409 static void
410 disk_assign_data(DiskData *disk, guint64 rb, guint64 wb, gboolean virtual)
411 	{
412 	if (disk)
413 		{
414 		if (disk->rb != rb || disk->wb != wb)
415 			disk->changed = TRUE;
416 		else
417 			disk->changed = FALSE;
418 		disk->rb = rb;
419 		disk->wb = wb;
420 		disk->virtual = virtual;
421 		}
422 	}
423 
424 void
425 gkrellm_disk_reset_composite(void)
426 	{
427 	/* Don't handle this. */
428 	}
429 
430 void
431 gkrellm_disk_units_are_blocks(void)
432 	{
433 	units_are_blocks = TRUE;
434 	}
435 
436 void
437 gkrellm_disk_add_by_name(const gchar *name, const gchar *label)
438 	{
439 	gint	order = -1;
440 
441     if (NULL == name) // Cannot add disk without a name
442 		return;
443     order = gkrellm_sys_disk_order_from_name(name);
444     /* FIXME: gkrellmd currently has no support for disk labels. Extend
445        network-protocol and server to support disks with both name and label. */
446     add_disk(name, order, 0, 0);
447 	}
448 
449 void
450 gkrellm_disk_assign_data_by_device(gint device_number, gint unit_number,
451 			guint64 rb, guint64 wb, gboolean virtual)
452 	{
453 	GList		*list;
454 	DiskData	*disk = NULL;
455 	gchar		*name;
456 	gint		order = -1;
457 
458 	for (list = disk_list; list; list = list->next)
459 		{
460 		disk = (DiskData * ) list->data;
461 		if (   disk->device_number == device_number
462 			&& disk->unit_number == unit_number
463 		   )
464 			break;
465 		disk = NULL;
466 		}
467 	if (!disk)
468 		{
469 		name = gkrellm_sys_disk_name_from_device(device_number,
470 					unit_number, &order);
471 		if (name)
472 			disk = add_disk(name, order, device_number, unit_number);
473 		}
474 	disk_assign_data(disk, rb, wb, virtual);
475 	}
476 
477 void
478 gkrellm_disk_assign_data_nth(gint n, guint64 rb, guint64 wb, gboolean virtual)
479 	{
480 	DiskData	*disk;
481 	gchar		name[32];
482 
483 	if (n < n_disks)
484 		disk = (DiskData *) g_list_nth_data(disk_list, n);
485 	else
486 		{
487 		snprintf(name, sizeof(name), "%s%c", _("Disk"), 'A' + n);
488 		disk = add_disk(name, n, 0, 0);
489 		}
490 	disk_assign_data(disk, rb, wb, virtual);
491 	}
492 
493 void
494 gkrellm_disk_assign_data_by_name(gchar *name,
495 			guint64 rb, guint64 wb, gboolean virtual)
496 	{
497 	GList		*list;
498 	DiskData	*disk = NULL;
499 	gint		order = -1;
500 
501 	for (list = disk_list; list; list = list->next)
502 		{
503 		disk = (DiskData * ) list->data;
504 		if (!strcmp(name, disk->name))
505 			break;
506 		disk = NULL;
507 		}
508 	if (!disk)
509 		{
510 		order = gkrellm_sys_disk_order_from_name(name);
511 		disk = add_disk(name, order, 0, 0);
512 		}
513 	disk_assign_data(disk, rb, wb, virtual);
514 	}
515 
516 void
517 gkrellm_disk_subdisk_assign_data_by_name(gchar *subdisk_name, gchar *disk_name,
518 				guint64 rb, guint64 wb)
519 	{
520 	GList		*list;
521 	DiskData	*disk = NULL;
522 	gchar		*s, *endptr;
523 	gint		subdisk;
524 
525 	if (!subdisk_name || !disk_name)
526 		return;
527 	for (list = disk_list; list; list = list->next)
528 		{
529 		disk = (DiskData * ) list->data;
530 		if (!strcmp(subdisk_name, disk->name))
531 			break;
532 		disk = NULL;
533 		}
534 	if (!disk)
535 		{
536 		/* A subdisk name is expected to be the disk_name with a number string
537 		|  appended.  Eg. "hda1" is a subdisk_name of disk_name "hda"
538 		*/
539 		s = subdisk_name + strlen(disk_name);
540 		if (*s == 'p')	/* except mmcblkN SD disks have "pN" partition numbers */
541 			++s;
542 		subdisk = strtol(s, &endptr, 0);
543 		if (!*s || *endptr)
544 			return;
545 		disk = add_subdisk(subdisk_name, disk_name, subdisk);
546 		}
547 	disk_assign_data(disk, rb, wb, FALSE);
548 	}
549 
550 static void
551 update_disk(GkrellmdMonitor *mon, gboolean first_update)
552 	{
553 	GList		*list;
554 	DiskData	*disk = NULL;
555 
556 	gkrellm_sys_disk_read_data();
557 	for (list = disk_list; list; list = list->next)
558 		{
559 		disk = (DiskData * ) list->data;
560 		if (disk->changed)
561 			{
562 			gkrellmd_need_serve(mon);
563 			break;
564 			}
565 		}
566 	}
567 
568 
569 static void
570 serve_disk_data(GkrellmdMonitor *mon, gboolean first_serve)
571 	{
572 	DiskData	*disk;
573 	GList		*list;
574 	gchar		*buf = NULL;
575 
576 	gkrellmd_set_serve_name(mon, "disk");
577 	for (list = disk_list; list; list = list->next)
578 		{
579 		disk = (DiskData *) list->data;
580 		if (!disk->changed && !first_serve)
581 			continue;
582 		if (!disk->subdisk_parent)
583 			{
584 			if (gkrellmd_check_client_version(mon, 2, 2, 7) && disk->virtual)
585                 buf = g_strdup_printf("%s virtual %" PRIu64 " %" PRIu64 "\n",
586 							disk->name, disk->rb, disk->wb);
587 			else
588 				buf = g_strdup_printf("%s %" PRIu64 " %" PRIu64 "\n",
589 							disk->name, disk->rb, disk->wb);
590 			}
591 		else if (mon->privat->client->feature_subdisk)
592 			buf = g_strdup_printf("%s %s %" PRIu64 " %" PRIu64 "\n",
593 						disk->name, disk->subdisk_parent, disk->rb, disk->wb);
594 		else
595 			continue;
596 		gkrellmd_serve_data(mon, buf);
597         g_free(buf);
598         buf = NULL;
599 		}
600 	}
601 
602 static void
603 serve_disk_setup(GkrellmdMonitor *mon)
604 	{
605 	GkrellmdClient	*client = mon->privat->client;
606 
607 	if (units_are_blocks)
608 		gkrellmd_send_to_client(client, "<disk_setup>\nunits_are_blocks\n");
609 	if (gkrellmd_check_client_version(mon, 2,1,3))
610 		client->feature_subdisk = TRUE;
611 	}
612 
613 static GkrellmdMonitor disk_monitor =
614 	{
615 	"disk",
616 	update_disk,
617 	serve_disk_data,
618 	serve_disk_setup
619 	};
620 
621 
622 static GkrellmdMonitor *
623 init_disk_monitor(void)
624 	{
625 	if (gkrellm_sys_disk_init())
626 		return &disk_monitor;
627 	return NULL;
628 	}
629 
630 /* ======================================================= */
631 #include "../src/inet.h"
632 
633 typedef struct
634 	{
635 	ActiveTCP	tcp;
636 	gboolean	alive,
637 				new_connection;
638 	}
639 	InetData;
640 
641 static GList	*inet_list,
642 				*inet_dead_list;
643 
644 static gboolean	inet_unsupported,
645 				inet_new;
646 
647 void
648 gkrellm_inet_log_tcp_port_data(gpointer data)
649 	{
650 	GList		*list;
651 	InetData	*in;
652 	ActiveTCP	*tcp, *active_tcp = NULL;
653 	gchar		*ap, *aap;
654 	gint		slen;
655 
656 	tcp = (ActiveTCP *) data;
657 	for (list = inet_list; list; list = list->next)
658 		{
659 		in = (InetData *) list->data;
660 		active_tcp = &in->tcp;
661 		if (tcp->family == AF_INET)
662 			{
663 			ap = (char *)&tcp->remote_addr;
664 			aap = (char *)&active_tcp->remote_addr;
665 			slen = sizeof(struct in_addr);
666 			}
667 #if defined(INET6)
668 		else if (tcp->family == AF_INET6)
669 			{
670 			ap = (char *)&tcp->remote_addr6;
671 			aap = (char *)&active_tcp->remote_addr6;
672 			slen = sizeof(struct in6_addr);
673 			}
674 #endif
675 		else
676 			return;
677 		if (   memcmp(aap, ap, slen) == 0
678 			&& active_tcp->remote_port == tcp->remote_port
679 			&& active_tcp->local_port == tcp->local_port
680 		   )
681 			{
682 			in->alive = TRUE;	/* Old alive connection still alive */
683 			return;
684 			}
685 		}
686 	inet_new = TRUE;
687 	in = g_new0(InetData, 1);
688 	in->tcp = *tcp;
689 	in->alive = TRUE;
690 	in->new_connection = TRUE;
691 	inet_list = g_list_append(inet_list, in);
692 	}
693 
694 static void
695 update_inet(GkrellmdMonitor *mon, gboolean first_update)
696 	{
697 	GList		*list;
698 	InetData	*in;
699 	static gint	check_tcp;
700 
701 
702 	if (!first_update && !GK.second_tick)
703 		return;
704 
705 	if (first_update || check_tcp == 0)
706 		{
707 		gkrellm_free_glist_and_data(&inet_dead_list);
708 		inet_new = FALSE;
709 		for (list = inet_list; list; list = list->next)
710 			{
711 			in = (InetData *) list->data;
712 			in->alive = FALSE;
713 			in->new_connection = FALSE;
714 			}
715 
716 		gkrellm_sys_inet_read_tcp_data();
717 
718 		for (list = inet_list; list; )
719 			{
720 			in = (InetData *) list->data;
721 			if (!in->alive)
722 				{
723 				if (list == inet_list)
724 					inet_list = inet_list->next;
725 				list = g_list_remove(list, in);
726 				inet_dead_list = g_list_append(inet_dead_list, in);
727 				}
728 			else
729 				list = list->next;
730 			}
731 		if (inet_new || inet_dead_list)
732 			gkrellmd_need_serve(mon);
733 		}
734 	check_tcp = (check_tcp + 1) % _GK.inet_interval;
735 	}
736 
737 static void
738 serve_inet_data(GkrellmdMonitor *mon, gboolean first_serve)
739 	{
740 	InetData	*in;
741 	ActiveTCP	*tcp;
742 	GList		*list;
743 	gchar		buf[NI_MAXHOST + 128], *cp;
744 #if defined(INET6) && defined(HAVE_GETADDRINFO)
745 	struct sockaddr_in6	sin6;
746 	char		addrbuf[NI_MAXHOST];
747 #endif
748 
749 	if (inet_new || first_serve)
750 		{
751 		gkrellmd_set_serve_name(mon, "inet");
752 		for (list = inet_list; list; list = list->next)
753 			{
754 			in = (InetData *) list->data;
755 			tcp = &in->tcp;
756 			if (   tcp->family == AF_INET
757 				&& (in->new_connection || first_serve)
758 			   )
759 				{
760 				cp = inet_ntoa(tcp->remote_addr);
761 				snprintf(buf, sizeof(buf), "+0 %x %s:%x\n",
762 							tcp->local_port, cp, tcp->remote_port);
763 				}
764 #if defined(INET6) && defined(HAVE_GETADDRINFO)
765 			else if (tcp->family == AF_INET6
766 				 && (in->new_connection || first_serve))
767 				{
768 				memset(&sin6, 0, sizeof(sin6));
769 				memcpy(&sin6.sin6_addr, &tcp->remote_addr6,
770 				       sizeof(struct in6_addr));
771 				sin6.sin6_family = AF_INET6;
772 #ifdef SIN6_LEN
773 				sin6.sin6_len = sizeof(struct sockaddr_in6);
774 #endif
775 				if (getnameinfo((struct sockaddr *)&sin6,
776 						sizeof(struct sockaddr_in6),
777 						addrbuf, sizeof(addrbuf),
778 						NULL, 0,
779 						NI_NUMERICHOST|NI_WITHSCOPEID)
780 				    != 0)
781 					continue;
782 				snprintf(buf, sizeof(buf), "+6 %x [%s]:%x\n",
783 					 tcp->local_port, addrbuf,
784 					 tcp->remote_port);
785 				}
786 #endif
787 			else
788 				continue;
789 
790 			gkrellmd_serve_data(mon, buf);
791 			}
792 		}
793 	if (!first_serve)
794 		{
795 		gkrellmd_set_serve_name(mon, "inet");
796 		for (list = inet_dead_list; list; list = list->next)
797 			{
798 			in = (InetData *) list->data;
799 			tcp = &in->tcp;
800 			if (tcp->family == AF_INET)
801 				{
802 				cp = inet_ntoa(tcp->remote_addr);
803 				snprintf(buf, sizeof(buf), "-0 %x %s:%x\n",
804 							tcp->local_port, cp, tcp->remote_port);
805 				}
806 #if defined(INET6) && defined(HAVE_GETADDRINFO)
807 			else if (tcp->family == AF_INET6)
808 				{
809 				memset(&sin6, 0, sizeof(sin6));
810 				memcpy(&sin6.sin6_addr, &tcp->remote_addr6,
811 				       sizeof(struct in6_addr));
812 				sin6.sin6_family = AF_INET6;
813 #ifdef SIN6_LEN
814 				sin6.sin6_len = sizeof(struct sockaddr_in6);
815 #endif
816 				if (getnameinfo((struct sockaddr *)&sin6,
817 						sizeof(struct sockaddr_in6),
818 						addrbuf, sizeof(addrbuf),
819 						NULL, 0,
820 						NI_NUMERICHOST|NI_WITHSCOPEID)
821 				    != 0)
822 					continue;
823 				snprintf(buf, sizeof(buf), "-6 %x [%s]:%x\n",
824 					 tcp->local_port, addrbuf,
825 					 tcp->remote_port);
826 				}
827 #endif
828 			else
829 				continue;
830 
831 			gkrellmd_serve_data(mon, buf);
832 			}
833 		}
834 	}
835 
836 static void
837 serve_inet_setup(GkrellmdMonitor *mon)
838 	{
839 	GkrellmdClient	*client = mon->privat->client;
840 
841 	if (inet_unsupported)
842 		gkrellmd_send_to_client(client, "<inet_setup>\ninet_unsupported\n");
843 	}
844 
845 static GkrellmdMonitor inet_monitor =
846 	{
847 	"inet",
848 	update_inet,
849 	serve_inet_data,
850 	serve_inet_setup
851 	};
852 
853 
854 static GkrellmdMonitor *
855 init_inet_monitor(void)
856 	{
857 	if (_GK.inet_interval > 0 && gkrellm_sys_inet_init())
858 		return &inet_monitor;
859 	inet_unsupported = TRUE;
860 	return NULL;
861 	}
862 
863 /* ======================================================= */
864 
865 #define TIMER_TYPE_NONE	0
866 #define TIMER_TYPE_PPP	1
867 #define TIMER_TYPE_IPPP	2
868 
869 typedef struct
870 	{
871 	gchar		*name;
872 	gboolean	changed,
873 				up,
874 				up_prev,
875 				up_event,
876 				down_event;
877 
878 	gboolean	timed_changed;
879 	time_t		up_time;
880 
881 	gulong		rx,
882 				tx;
883 	}
884 	NetData;
885 
886 static NetData	*net_timer;
887 
888 static GList	*net_list,
889 				*net_sys_list;
890 
891 static time_t	net_timer0;
892 static gint		net_timer_type;
893 
894 static gboolean	net_use_routed;
895 
896 
897 gchar *
898 gkrellm_net_mon_first(void)
899 	{
900 	gchar	*name = NULL;
901 
902 	net_sys_list = net_list;
903 	if (net_sys_list)
904 		{
905 		name = ((NetData *) (net_sys_list->data))->name;
906 		net_sys_list = net_sys_list->next;
907 		}
908 	return name;
909 	}
910 
911 gchar *
912 gkrellm_net_mon_next(void)
913 	{
914 	gchar	*name = NULL;
915 
916 	if (net_sys_list)
917 		{
918 		name = ((NetData *) (net_sys_list->data))->name;
919 		net_sys_list = net_sys_list->next;
920 		}
921 	return name;
922 	}
923 
924 void
925 gkrellm_net_use_routed(gboolean real_routed /* not applicable in server */)
926 	{
927 	net_use_routed = TRUE;
928 	}
929 
930 static NetData *
931 net_new(gchar *name)
932 	{
933 	NetData	*net;
934 
935 	net = g_new0(NetData, 1);
936 	net->name = g_strdup(name);
937 	net_list = g_list_append(net_list, net);
938 
939 	if (net_timer_type != TIMER_TYPE_NONE && !strcmp(_GK.net_timer, net->name))
940 		net_timer = net;
941 
942 	return net;
943 	}
944 
945 void
946 gkrellm_net_assign_data(gchar *name, gulong rx, gulong tx)
947 	{
948 	GList	*list;
949 	NetData	*net;
950 
951 	for (list = net_list; list; list = list->next)
952 		{
953 		net = (NetData *) list->data;
954 		if (!strcmp(net->name, name))
955 			{
956 			if (net->rx != rx || net->tx != tx)
957 				net->changed = TRUE;
958 			else
959 				net->changed = FALSE;
960 			break;
961 			}
962 		}
963 	if (!list)
964 		net = net_new(name);
965 
966 	if (GK.second_tick && !net_use_routed)
967 		net->up = TRUE;
968 	net->rx = rx;
969 	net->tx = tx;
970 	}
971 
972 void
973 gkrellm_net_routed_event(gchar *name, gboolean routed)
974 	{
975 	GList	*list;
976 	NetData	*net;
977 
978 	for (list = net_list; list; list = list->next)
979 		{
980 		net = (NetData *) list->data;
981 		if (!strcmp(net->name, name))
982 			break;
983 		}
984 	if (!list)
985 		net = net_new(name);
986 
987 	if (routed)
988 		net->up_event = TRUE;
989 	else
990 		net->down_event = TRUE;
991 	net->up = routed;
992 	}
993 
994 void
995 gkrellm_net_add_timer_type_ppp(gchar *name)
996 	{
997 	if (!_GK.net_timer || !name)
998 		return;
999 	if (name && !strncmp(_GK.net_timer, name, strlen(name) - 1))
1000 		net_timer_type = TIMER_TYPE_PPP;
1001 	}
1002 
1003 void
1004 gkrellm_net_add_timer_type_ippp(gchar *name)
1005 	{
1006 	if (!_GK.net_timer || !name)
1007 		return;
1008 	if (name && !strncmp(_GK.net_timer, name, strlen(name) - 1))
1009 		net_timer_type = TIMER_TYPE_IPPP;
1010 	}
1011 
1012 void
1013 gkrellm_net_set_lock_directory(gchar *dir)
1014 	{
1015 	/* Not supported remotely */
1016 	}
1017 
1018 static void
1019 update_net(GkrellmdMonitor *mon, gboolean first_update)
1020 	{
1021 	GList		*list;
1022 	NetData		*net;
1023 	gint		up_time = 0;
1024 
1025 	if (GK.second_tick)
1026 		{
1027 		if (!net_use_routed)
1028 			{
1029 			for (list = net_list; list; list = list->next)
1030 				{
1031 				net = (NetData *) list->data;
1032 				net->up_prev = net->up;
1033 				net->up = FALSE;
1034 				}
1035 			}
1036 		else
1037 			gkrellm_sys_net_check_routes();
1038 		}
1039 	gkrellm_sys_net_read_data();
1040 
1041 	if (GK.second_tick && !net_use_routed)
1042 		{
1043 		for (list = net_list; list; list = list->next)
1044 			{
1045 			net = (NetData *) list->data;
1046 			if (net->up && !net->up_prev)
1047 				net->up_event = TRUE;
1048 			else if (!net->up && net->up_prev)
1049 				net->down_event = TRUE;
1050 			}
1051 		}
1052 
1053 	if (net_timer && GK.second_tick)
1054 		{
1055 		if (net_timer_type == TIMER_TYPE_PPP)
1056 			{
1057 			struct stat		st;
1058 			gchar			buf[256];
1059 
1060 			if (net_timer->up_event)
1061 				{
1062 				snprintf(buf, sizeof(buf), "/var/run/%s.pid", net_timer->name);
1063 				if (g_stat(buf, &st) == 0)
1064 					net_timer0 = st.st_mtime;
1065 				else
1066 					time(&net_timer0);
1067 				}
1068 			if (net_timer->up)
1069 				up_time = (int) (time(0) - net_timer0);
1070 			}
1071 		else if (net_timer_type == TIMER_TYPE_IPPP)
1072 			{
1073 			/* get all isdn status from its connect state because the
1074 			|  net_timer->up can be UP even with isdn line not connected.
1075 			|  Can't get time history if gkrellmd started after connects.
1076 			*/
1077 			static gboolean		old_connected;
1078 			gboolean			connected;
1079 
1080 			connected = gkrellm_sys_net_isdn_online();
1081 			if (connected && !old_connected)
1082 				time(&net_timer0);			/* New session just started */
1083 			old_connected = connected;
1084 
1085 			up_time = (int) (time(0) - net_timer0);
1086 			}
1087 		if (up_time != net_timer->up_time)
1088 			net_timer->timed_changed = TRUE;
1089 		net_timer->up_time = up_time;
1090 		}
1091 
1092 	gkrellmd_need_serve(mon);	/* serve func checks for changed */
1093 	}
1094 
1095 static void
1096 serve_net_data(GkrellmdMonitor *mon, gboolean first_serve)
1097 	{
1098 	NetData		*net;
1099 	GList		*list;
1100 	gchar		buf[128];
1101 	gboolean	fake_up_event;
1102 
1103 	gkrellmd_set_serve_name(mon, "net");
1104 	for (list = net_list; list; list = list->next)
1105 		{
1106 		net = (NetData *) list->data;
1107 		if (net->changed || first_serve)
1108 			{
1109 			snprintf(buf, sizeof(buf), "%s %lu %lu\n", net->name, net->rx, net->tx);
1110 			gkrellmd_serve_data(mon, buf);
1111 			}
1112 		}
1113 
1114 	/* Since the server transmits changes only, use the routed interface
1115 	|  to the client regardless if the sysdep code uses routed.
1116 	*/
1117 	if (GK.second_tick || first_serve)
1118 		{
1119 		gkrellmd_set_serve_name(mon, "net_routed");
1120 		for (list = net_list; list; list = list->next)
1121 			{
1122 			net = (NetData *) list->data;
1123 			fake_up_event = (first_serve && net->up);
1124 			if (net->up_event || net->down_event || fake_up_event)
1125 				{
1126 				snprintf(buf, sizeof(buf), "%s %d\n", net->name,
1127 						fake_up_event ? TRUE : net->up_event);
1128 				gkrellmd_serve_data(mon, buf);
1129 				}
1130 			if (mon->privat->client->last_client)
1131 				net->up_event = net->down_event = FALSE;
1132 			}
1133 		}
1134 
1135 	if (net_timer && GK.second_tick)
1136 		{
1137 		if (net_timer->timed_changed || first_serve)
1138 			{
1139 			gkrellmd_set_serve_name(mon, "net_timer");
1140 			snprintf(buf, sizeof(buf), "%s %d\n", net_timer->name, (gint)net_timer->up_time);
1141 			gkrellmd_serve_data(mon, buf);
1142 			}
1143 		}
1144 	}
1145 
1146 static void
1147 serve_net_setup(GkrellmdMonitor *mon)
1148 	{
1149 	GkrellmdClient	*client = mon->privat->client;
1150 	gchar			buf[128];
1151 
1152 	/* The client <-> server link always uses routed mode, but the client
1153 	|  needs to know if server sysdep uses routed for config purposes.
1154 	*/
1155 	if (net_use_routed)
1156 		gkrellmd_send_to_client(client, "<net_setup>\nnet_use_routed\n");
1157 
1158 	if (net_timer_type != TIMER_TYPE_NONE)
1159 		{
1160 		snprintf(buf, sizeof(buf),
1161 				"<net_setup>\nnet_timer %s\n", _GK.net_timer);
1162 		gkrellmd_send_to_client(client, buf);
1163 		}
1164 	}
1165 
1166 static GkrellmdMonitor net_monitor =
1167 	{
1168 	"net",
1169 	update_net,
1170 	serve_net_data,
1171 	serve_net_setup
1172 	};
1173 
1174 
1175 static GkrellmdMonitor *
1176 init_net_monitor(void)
1177 	{
1178 	net_timer_type = TIMER_TYPE_NONE;
1179 	if (gkrellm_sys_net_init())
1180 		return &net_monitor;
1181 	return NULL;
1182 	}
1183 
1184 
1185 /* ======================================================= */
1186 struct
1187 	{
1188 	gboolean	mem_changed;
1189 	guint64		total,
1190 				used,
1191 				free,
1192 				shared,
1193 				buffers,
1194 				cached;
1195 
1196 	gboolean	swap_changed;
1197 	guint64		swap_total,
1198 				swap_used;
1199 	gulong		swap_in,
1200 				swap_out;
1201 	}
1202 	mem;
1203 
1204 void
1205 gkrellm_mem_assign_data(guint64 total, guint64 used, guint64 free,
1206 			guint64 shared, guint64 buffers, guint64 cached)
1207 	{
1208 	if (   mem.total != total
1209 		|| mem.used != used
1210 		|| mem.free != free
1211 		|| mem.shared != shared
1212 		|| mem.buffers != buffers
1213 		|| mem.cached != cached
1214 	   )
1215 		{
1216 		mem.total = total;
1217 		mem.used = used;
1218 		mem.free = free;
1219 		mem.shared = shared;
1220 		mem.buffers = buffers;
1221 		mem.cached = cached;
1222 		mem.mem_changed = TRUE;
1223 		}
1224 	}
1225 
1226 void
1227 gkrellm_swap_assign_data(guint64 total, guint64 used,
1228 			gulong swap_in, gulong swap_out)
1229 	{
1230 	if (   mem.swap_total != total
1231 		|| mem.swap_used != used
1232 		|| mem.swap_in != swap_in
1233 		|| mem.swap_out != swap_out
1234 	   )
1235 		{
1236 		mem.swap_total = total;
1237 		mem.swap_used = used;
1238 		mem.swap_in = swap_in;
1239 		mem.swap_out = swap_out;
1240 		mem.swap_changed = TRUE;
1241 		}
1242 	}
1243 
1244 static void
1245 update_mem(GkrellmdMonitor *mon, gboolean first_update)
1246 	{
1247 	mem.mem_changed = mem.swap_changed = FALSE;
1248 
1249 	gkrellm_sys_swap_read_data();
1250 	if (first_update || GK.five_second_tick)
1251 		gkrellm_sys_mem_read_data();
1252 
1253 	if (mem.mem_changed || mem.swap_changed)
1254 		gkrellmd_need_serve(mon);
1255 	}
1256 
1257 static void
1258 serve_mem_data(GkrellmdMonitor *mon, gboolean first_serve)
1259 	{
1260 	gchar	buf[128];
1261 
1262 	if (mem.mem_changed || first_serve)
1263 		{
1264 		gkrellmd_set_serve_name(mon, "mem");
1265 		snprintf(buf, sizeof(buf), "%" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
1266 				mem.total, mem.used, mem.free,
1267 				mem.shared, mem.buffers, mem.cached);
1268 		gkrellmd_serve_data(mon, buf);
1269 		}
1270 
1271 	if (mem.swap_changed || first_serve)
1272 		{
1273 		gkrellmd_set_serve_name(mon, "swap");
1274 		snprintf(buf, sizeof(buf), "%" PRIu64 " %" PRIu64 " %lu %lu\n",
1275 				mem.swap_total, mem.swap_used,
1276 				mem.swap_in, mem.swap_out);
1277 		gkrellmd_serve_data(mon, buf);
1278 		}
1279 	}
1280 
1281 static GkrellmdMonitor mem_monitor =
1282 	{
1283 	"mem",
1284 	update_mem,
1285 	serve_mem_data,
1286 	NULL
1287 	};
1288 
1289 
1290 static GkrellmdMonitor *
1291 init_mem_monitor(void)
1292 	{
1293 	if (!gkrellm_sys_mem_init())
1294 		return NULL;
1295 	serveflag_done_list = g_list_append(serveflag_done_list, &mem.mem_changed);
1296 	serveflag_done_list = g_list_append(serveflag_done_list,&mem.swap_changed);
1297 	return &mem_monitor;
1298 	}
1299 
1300 /* ======================================================= */
1301 typedef struct
1302 	{
1303 	gboolean	busy,
1304 				deleted,
1305 				is_mounted,
1306 				is_nfs,
1307 				changed;
1308 	gchar		*directory,
1309 				*device,
1310 				*type,
1311 				*options;
1312 	gint64		blocks,
1313 				bavail,
1314 				bfree,
1315 				bsize;
1316 	}
1317 	Mount;
1318 
1319 static GList	*mounts_list,
1320 				*fstab_list;
1321 
1322 static gboolean	nfs_check,
1323 				fs_check,
1324 				fs_need_serve,
1325 				fstab_list_modified,
1326 				mounts_list_modified,
1327 				mounting_unsupported;
1328 
1329 static gchar *remote_fs_types[] =
1330 	{
1331 	"cifs",
1332 	"nfs",
1333 	"smbfs"
1334 	};
1335 
1336 void
1337 gkrellm_fs_setup_eject(gchar *eject_tray, gchar *close_tray,
1338 			void (*eject_func)(), void (*close_func)())
1339 	{
1340 	/* Not supported remotely */
1341 	}
1342 
1343 void
1344 gkrellm_fs_add_to_mounts_list(gchar *dir, gchar *dev, gchar *type)
1345 	{
1346 	GList	*list;
1347 	Mount	*m;
1348 	gint	i;
1349 
1350 	for (list = mounts_list; list; list = list->next)
1351 		{
1352 		m = (Mount *) list->data;
1353 		if (   !strcmp(m->directory, dir)
1354 			&& !strcmp(m->device, dev)
1355 			&& !strcmp(m->type, type)
1356 		   )
1357 			break;
1358 		}
1359 	if (!list)
1360 		{
1361 		m = g_new0(Mount, 1);
1362 		m->directory = g_strdup(dir);
1363 		m->device = g_strdup(dev);
1364 		m->type = g_strdup(type);
1365 		mounts_list = g_list_append(mounts_list, m);
1366 		mounts_list_modified = TRUE;
1367 		serveflag_done_list = g_list_append(serveflag_done_list, &m->changed);
1368 
1369 		for (i = 0; i < (sizeof(remote_fs_types) / sizeof(gchar *)); ++i)
1370 			{
1371 			if (!strcmp(m->type, remote_fs_types[i]))
1372 				{
1373 				m->is_nfs = TRUE;
1374 				break;
1375 				}
1376 			}
1377 		}
1378 	m->is_mounted = TRUE;
1379 	}
1380 
1381 void
1382 gkrellm_fs_add_to_fstab_list(gchar *dir, gchar *dev, gchar *type, gchar *opt)
1383 	{
1384 	Mount	*m;
1385 
1386 	m = g_new0(Mount, 1);
1387 	m->directory = g_strdup(dir);
1388 	m->device = g_strdup(dev);
1389 	m->type = g_strdup(type);
1390 	fstab_list = g_list_append(fstab_list, m);
1391 	}
1392 
1393 void
1394 gkrellm_fs_assign_fsusage_data(gpointer pointer,
1395 		gint64 blocks, gint64 bavail, gint64 bfree, gint64 bsize)
1396 	{
1397 	Mount	*m = (Mount *) pointer;
1398 
1399 	if (   m->blocks != blocks
1400 		|| m->bavail != bavail
1401 		|| m->bfree  != bfree
1402 		|| m->bsize  != bsize
1403 	   )
1404 		{
1405 		m->blocks = blocks;
1406 		m->bavail = bavail;
1407 		m->bfree  = bfree;
1408 		m->bsize  = bsize;
1409 
1410 		m->changed = TRUE;
1411 		}
1412 	}
1413 
1414 void
1415 gkrellm_fs_mounting_unsupported(void)
1416 	{
1417 	mounting_unsupported = TRUE;
1418 	}
1419 
1420 static void
1421 refresh_mounts_list(void)
1422 	{
1423 	GList	*list;
1424 	Mount	*m;
1425 
1426 	for (list = mounts_list; list; list = list->next)
1427 		((Mount *) list->data)->is_mounted = FALSE;
1428 
1429 	gkrellm_sys_fs_get_mounts_list();
1430 
1431 	for (list = mounts_list; list; )
1432 		{
1433 		m = (Mount *) list->data;
1434 		if (!m->is_mounted)
1435 			{
1436 			if (list == mounts_list)
1437 				mounts_list = mounts_list->next;
1438 			list = g_list_remove_link(list, list);
1439 			g_free(m->directory);
1440 			g_free(m->device);
1441 			g_free(m->type);
1442 			serveflag_done_list = g_list_remove(serveflag_done_list,
1443 						&m->changed);
1444 			if (m->busy)
1445 				m->deleted = TRUE;
1446 			else
1447 				g_free(m);
1448 			mounts_list_modified = TRUE;
1449 			}
1450 		else
1451 			list = list->next;
1452 		}
1453 	}
1454 
1455 static void
1456 refresh_fstab_list(void)
1457 	{
1458 	Mount	*m;
1459 
1460 	while (fstab_list)
1461 		{
1462 		m = (Mount *) fstab_list->data;
1463 		g_free(m->directory);
1464 		g_free(m->device);
1465 		g_free(m->type);
1466 		g_free(m);
1467 		fstab_list = g_list_remove(fstab_list, fstab_list->data);
1468 		}
1469 	gkrellm_sys_fs_get_fstab_list();
1470 	fstab_list_modified = TRUE;
1471 	}
1472 
1473 static gpointer
1474 get_fsusage_thread(void *data)
1475 	{
1476 	Mount	*m = (Mount *) data;
1477 
1478 	gkrellm_sys_fs_get_fsusage(m, m->directory);
1479 
1480 	if (m->deleted)
1481 		g_free(m);
1482 	else
1483 		{
1484 		if (m->changed)
1485 			fs_need_serve = TRUE;
1486 		m->busy = FALSE;
1487 		}
1488 	return NULL;
1489 	}
1490 
1491 static void
1492 update_fs(GkrellmdMonitor *mon, gboolean first_update)
1493 	{
1494 	GThread		*gth;
1495 	GList		*list;
1496 	Mount		*m;
1497 	static gint	check_tick;
1498 
1499 	if (fs_need_serve)		/* Asynchronous change in fsusage thread? */
1500 		gkrellmd_need_serve(mon);
1501 	fs_need_serve = FALSE;
1502 
1503 	if (GK.second_tick)
1504 		++check_tick;
1505 	fs_check = !(check_tick % _GK.fs_interval);
1506 
1507 	if (_GK.nfs_interval > 0)
1508 		nfs_check = !(check_tick % _GK.nfs_interval);
1509 	else
1510 		nfs_check = 0;
1511 
1512 	if (!first_update && (!GK.second_tick || (!fs_check && !nfs_check)))
1513 		return;
1514 	refresh_mounts_list();
1515 	for (list = mounts_list; list; list = list->next)
1516 		{
1517 		m = (Mount *) list->data;
1518 		if (fs_check && !m->is_nfs)
1519 			gkrellm_sys_fs_get_fsusage(m, m->directory);
1520 		else if (nfs_check && m->is_nfs && !m->busy)
1521 			{
1522 			m->busy = TRUE;
1523 			gth = g_thread_new("get_fsusage", get_fsusage_thread, m);
1524 			g_thread_unref(gth);
1525 			}
1526 		}
1527 	if (first_update || gkrellm_sys_fs_fstab_modified())
1528 		refresh_fstab_list();
1529 
1530 	gkrellmd_need_serve(mon);
1531 	}
1532 
1533 static void
1534 serve_fs_data(GkrellmdMonitor *mon, gboolean first_serve)
1535 	{
1536 	Mount	*m;
1537 	GList	*list;
1538 	gchar	buf[128];
1539 
1540 	if (mounts_list_modified || first_serve)
1541 		{
1542 		gkrellmd_set_serve_name(mon, "fs_mounts");
1543 		gkrellmd_serve_data(mon, ".clear\n");
1544 		for (list = mounts_list; list; list = list->next)
1545 			{
1546 			m = (Mount *) list->data;
1547 			snprintf(buf, sizeof(buf),
1548 				"%s %s %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
1549 					m->directory, m->device, m->type,
1550 					m->blocks, m->bavail, m->bfree, m->bsize);
1551 			/*gkrellm_debug(DEBUG_SERVER,
1552 				"Adding mount-line for %s to serve-data\n", m->directory);*/
1553 			gkrellmd_serve_data(mon, buf);
1554 			}
1555 		}
1556 	else
1557 		{
1558 		gkrellmd_set_serve_name(mon, "fs");
1559 		for (list = mounts_list; list; list = list->next)
1560 			{
1561 			m = (Mount *) list->data;
1562 			if (!m->changed)
1563 				continue;
1564 			snprintf(buf, sizeof(buf),
1565 				"%s %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
1566 					m->directory, m->device,
1567 					m->blocks, m->bavail, m->bfree, m->bsize);
1568 			/*gkrellm_debug(DEBUG_SERVER,
1569 				"Updating fs %s in serve-data\n", m->directory);*/
1570 			gkrellmd_serve_data(mon, buf);
1571 			}
1572 		}
1573 	if (fstab_list_modified || first_serve)
1574 		{
1575 		gkrellmd_set_serve_name(mon, "fs_fstab");
1576 		gkrellmd_serve_data(mon, ".clear\n");
1577 		for (list = fstab_list; list; list = list->next)
1578 			{
1579 			m = (Mount *) list->data;
1580 			snprintf(buf, sizeof(buf), "%s %s %s\n",
1581 					m->directory, m->device, m->type);
1582 			/*gkrellm_debug(DEBUG_SERVER,
1583 				"Adding fstab-line for %s to serve-data\n", m->directory);*/
1584 			gkrellmd_serve_data(mon, buf);
1585 			}
1586 		}
1587 	}
1588 
1589 static void
1590 serve_fs_setup(GkrellmdMonitor *mon)
1591 	{
1592 	GkrellmdClient	*client = mon->privat->client;
1593 
1594 	if (mounting_unsupported)
1595 		gkrellmd_send_to_client(client, "<fs_setup>\nmounting_unsupported\n");
1596 	}
1597 
1598 static GkrellmdMonitor fs_monitor =
1599 	{
1600 	"fs",
1601 	update_fs,
1602 	serve_fs_data,
1603 	serve_fs_setup
1604 	};
1605 
1606 
1607 static GkrellmdMonitor *
1608 init_fs_monitor(void)
1609 	{
1610 	if (!gkrellm_sys_fs_init())
1611 		return NULL;
1612 	serveflag_done_list =
1613 				g_list_append(serveflag_done_list, &fstab_list_modified);
1614 	serveflag_done_list =
1615 				g_list_append(serveflag_done_list, &mounts_list_modified);
1616 	return &fs_monitor;
1617 	}
1618 
1619 /* ======================================================= */
1620 
1621 
1622 typedef struct
1623 	{
1624 	gboolean	changed,
1625 				have_data;
1626 
1627 	gint		id;
1628 	gboolean	present,
1629 				on_line,
1630 				charging;
1631 	gint		percent;
1632 	gint		time_left;
1633 	}
1634 	Battery;
1635 
1636 static GList	*battery_list;
1637 
1638 static Battery	*composite_battery;
1639 
1640 
1641 static Battery *
1642 battery_nth(gint n)
1643 	{
1644 	Battery		*bat;
1645 	static gint	n_batteries;
1646 
1647 	if (n > 10)
1648 		return NULL;
1649 	if (n < 0)
1650 		{
1651 		if (!composite_battery)
1652 			{
1653 			bat = g_new0(Battery, 1);
1654 			battery_list = g_list_prepend(battery_list, bat);
1655 			bat->id = GKRELLM_BATTERY_COMPOSITE_ID;
1656 			composite_battery = bat;
1657 			serveflag_done_list = g_list_append(serveflag_done_list,
1658 								&composite_battery->changed);
1659 			}
1660 		return composite_battery;
1661 		}
1662 
1663 	if (composite_battery)
1664 		++n;
1665 
1666 	while ((bat = (Battery *)g_list_nth_data(battery_list, n)) == NULL)
1667 		{
1668 		bat = g_new0(Battery, 1);
1669 		battery_list = g_list_append(battery_list, bat);
1670 		bat->id = n_batteries++;
1671 		serveflag_done_list = g_list_append(serveflag_done_list,
1672 								&bat->changed);
1673 		}
1674 	return bat;
1675 	}
1676 
1677 void
1678 gkrellm_battery_assign_data(gint id, gboolean present, gboolean on_line,
1679 			gboolean charging, gint percent, gint time_left)
1680 	{
1681 	Battery	*bat;
1682 
1683 	bat = battery_nth(id);
1684 	if (!bat)
1685 		return;
1686 
1687 	if (   present   != bat->present
1688 		|| on_line   != bat->on_line
1689 		|| charging  != bat->charging
1690 		|| percent   != bat->percent
1691 		|| time_left != bat->time_left
1692 	   )
1693 		{
1694 		bat->present = present;
1695 		bat->on_line = on_line;
1696 		bat->charging = charging;
1697 		bat->percent = percent;
1698 		bat->time_left = time_left;
1699 		bat->changed = TRUE;
1700 		}
1701 
1702 	bat->have_data = TRUE;
1703 	}
1704 
1705 gint
1706 gkrellm_battery_full_cap_fallback()
1707 	{
1708 	return 5000;	/* XXX Linux ACPI bug not handled by server */
1709 	}
1710 
1711 static void
1712 update_battery(GkrellmdMonitor *mon, gboolean first_update)
1713 	{
1714 	GList	*list;
1715 	Battery	*bat;
1716 
1717 	if (!first_update && !GK.five_second_tick)
1718 		return;
1719 
1720 	for (list = battery_list; list; list = list->next)
1721 		{
1722 		bat = (Battery *) list->data;
1723 		bat->have_data = FALSE;
1724 		bat->changed = FALSE;
1725 		}
1726 	gkrellm_sys_battery_read_data();
1727 
1728 	for (list = battery_list; list; list = list->next)
1729 		{
1730 		bat = (Battery *) list->data;
1731 		if (!bat->have_data && bat->present)
1732 			{
1733 			bat->present = FALSE;
1734 			bat->changed = TRUE;
1735 			}
1736 		if (bat->changed)
1737 			gkrellmd_need_serve(mon);
1738 		}
1739 	}
1740 
1741 static void
1742 serve_battery_data(GkrellmdMonitor *mon, gboolean first_serve)
1743 	{
1744 	Battery		*bat;
1745 	GList		*list;
1746 	gchar		buf[128];
1747 
1748 	gkrellmd_set_serve_name(mon, "battery");
1749 	for (list = battery_list; list; list = list->next)
1750 		{
1751 		bat = (Battery *) list->data;
1752 
1753 		if (   (!bat->changed && !first_serve)
1754 			|| (   !gkrellmd_check_client_version(mon, 2,1,9)
1755 				&& bat->id > 0
1756 			   )
1757 		   )
1758 			continue;
1759 		snprintf(buf, sizeof(buf), "%d %d %d %d %d %d\n",
1760 					bat->present, bat->on_line, bat->charging,
1761 					bat->percent, bat->time_left, bat->id);
1762 		gkrellmd_serve_data(mon, buf);
1763 		}
1764 	}
1765 
1766 static void
1767 serve_battery_setup(GkrellmdMonitor *mon)
1768 	{
1769 	GkrellmdClient	*client = mon->privat->client;
1770 
1771 	gkrellm_sys_battery_read_data();
1772 	if (battery_list)
1773 		gkrellmd_send_to_client(client,
1774 					"<battery_setup>\nbattery_available\n");
1775 	}
1776 
1777 static GkrellmdMonitor battery_monitor =
1778 	{
1779 	"battery",
1780 	update_battery,
1781 	serve_battery_data,
1782 	serve_battery_setup
1783 	};
1784 
1785 static GkrellmdMonitor *
1786 init_battery_monitor(void)
1787 	{
1788 	if (!gkrellm_sys_battery_init())
1789 		return NULL;
1790 	return &battery_monitor;
1791 	}
1792 
1793 /* ======================================================= */
1794 
1795 typedef struct
1796 	{
1797 	gboolean	changed;
1798 	gint		type;
1799 
1800 	gchar		*path;			/* Pathname to sensor data or device file */
1801 
1802 	gchar		*id_name;		/* These 4 are unique sensor identification */
1803 	gint		id;				/*   of a particular sensor type */
1804 	gint		iodev;			/* One or any combination may be used. */
1805 	gint		inter;
1806 
1807 	gchar		*vref;
1808 	gchar		*default_label;
1809 	gint		group;
1810 
1811 	gfloat		factor;
1812 	gfloat		offset;
1813 	gfloat		raw_value;
1814 	}
1815 	Sensor;
1816 
1817 static GList	*sensors_list;
1818 
1819 static gboolean thread_busy,
1820 				sensors_need_serve;
1821 
1822 static gpointer
1823 read_sensors(void *data)
1824 	{
1825 	GList		*list;
1826 	Sensor		*sensor;
1827 	gfloat		tmp;
1828 	gboolean	need_serve = FALSE;
1829 
1830 	for (list = sensors_list; list; list = list->next)
1831 		{
1832 		sensor = (Sensor *) list->data;
1833 		tmp = sensor->raw_value;
1834 		if (sensor->type == SENSOR_TEMPERATURE)
1835 			gkrellm_sys_sensors_get_temperature(sensor->path, sensor->id,
1836 				sensor->iodev, sensor->inter, &sensor->raw_value);
1837 		else if (sensor->type == SENSOR_FAN)
1838 			gkrellm_sys_sensors_get_fan(sensor->path, sensor->id,
1839 				sensor->iodev, sensor->inter, &sensor->raw_value);
1840 		else if (sensor->type == SENSOR_VOLTAGE)
1841 			gkrellm_sys_sensors_get_voltage(sensor->path, sensor->id,
1842 				sensor->iodev, sensor->inter, &sensor->raw_value);
1843 		if (sensor->raw_value != tmp)
1844 			{
1845 			sensor->changed = TRUE;
1846 			need_serve = TRUE;
1847 			}
1848 		else
1849 			sensor->changed = FALSE;
1850 		}
1851 	thread_busy = FALSE;
1852 	sensors_need_serve = need_serve; /* Thread, so set after data collected */
1853 
1854 	return NULL;
1855 	}
1856 
1857 static void
1858 run_sensors_thread(void)
1859 	{
1860 	GThread		*gth;
1861 
1862 	if (thread_busy)
1863 		return;
1864 	thread_busy = TRUE;
1865 	gth = g_thread_new("read_sensors", read_sensors, NULL);
1866 	g_thread_unref(gth);
1867 	}
1868 
1869 
1870 void
1871 gkrellm_sensors_config_migrate_connect(gboolean (*func)(), gint sysdep_version)
1872 	{
1873 	}
1874 
1875 void
1876 gkrellm_sensors_update_volt_order_base(void)
1877 	{
1878 	}
1879 
1880 void
1881 gkrellm_sensors_set_group(gpointer sr, gint group)
1882 	{
1883 	Sensor	*sensor = (Sensor *) sr;
1884 
1885 	if (sensor)
1886 		sensor->group = group;
1887 	}
1888 
1889 void
1890 gkrellm_sensors_sysdep_option(gchar *keyword, gchar *label, void (*func)())
1891 	{
1892 	}
1893 
1894   /* A sensor within a type is uniquely identified by its id_name.
1895   |  A sysdep interface may additionally use any of the triple integer
1896   |  set (id, iodev, inter) for internal identification.
1897   |  Monitor code here uses path to read the sensor values, but id_name is only
1898   |  passed to the client since that is all that is needed for identification
1899   |  (the client is no longer interfacing to sysdep code).
1900   */
1901 gpointer
1902 gkrellm_sensors_add_sensor(gint type, gchar *sensor_path, gchar *id_name,
1903 		gint id, gint iodev, gint inter,
1904 		gfloat factor, gfloat offset, gchar *vref, gchar *default_label)
1905 	{
1906 	Sensor	*sensor;
1907 
1908 	if (!id_name || !*id_name || type < 0 || type > 2)
1909 		return NULL;
1910 
1911 	sensor = g_new0(Sensor, 1);
1912 	sensor->id_name = g_strdup(id_name);
1913 
1914 	if (sensor_path)
1915 		sensor->path = g_strdup(sensor_path);
1916 	else
1917 		sensor->path = g_strdup(id_name);
1918 
1919 	sensor->vref = g_strdup(vref ? vref : "NONE");
1920 	sensor->default_label = g_strdup(default_label ? default_label : "NONE");
1921 
1922 	sensor->factor = factor;
1923 	sensor->offset = offset;
1924 	sensor->type = type;
1925 	sensor->id = id;
1926 	sensor->iodev = iodev;
1927 	sensor->inter = inter;
1928 	sensors_list = g_list_append(sensors_list, sensor);
1929 	return sensor;
1930 	}
1931 
1932 static void
1933 update_sensors(GkrellmdMonitor *mon, gboolean first_update)
1934 	{
1935 	if (sensors_need_serve)		/* Asynchronously set in thread */
1936 		gkrellmd_need_serve(mon);
1937 	sensors_need_serve = FALSE;
1938 
1939 	if (!GK.five_second_tick && !first_update)
1940 		return;
1941 	if (first_update)
1942 		read_sensors(NULL);		/* No thread on first read */
1943 	else
1944 		run_sensors_thread();
1945 	}
1946 
1947 static void
1948 serve_sensors_data(GkrellmdMonitor *mon, gboolean first_serve)
1949 	{
1950 	Sensor			*sr;
1951 	GList			*list;
1952 	gchar			buf[128];
1953 	gboolean		sensor_disk_ok;
1954 
1955 	gkrellmd_set_serve_name(mon, "sensors");
1956 	sensor_disk_ok = gkrellmd_check_client_version(mon, 2,2,0);
1957 	for (list = sensors_list; list; list = list->next)
1958 		{
1959 		sr = (Sensor *) list->data;
1960 		if (sr->group == SENSOR_GROUP_DISK && !sensor_disk_ok)
1961 			continue;
1962 		if (sr->changed || first_serve)
1963 			{
1964 			snprintf(buf, sizeof(buf), "%d \"%s\" %d %d %d %.2f\n",
1965 					sr->type, sr->id_name,
1966 					sr->id, sr->iodev, sr->inter, sr->raw_value);
1967 			gkrellmd_serve_data(mon, buf);
1968 			}
1969 		}
1970 	}
1971 
1972 static void
1973 serve_sensors_setup(GkrellmdMonitor *mon)
1974 	{
1975 	GkrellmdClient	*client = mon->privat->client;
1976 	GList			*list;
1977 	Sensor			*s;
1978 	gchar			buf[256];
1979 	gboolean		sensor_disk_ok;
1980 
1981 	gkrellmd_send_to_client(client, "<sensors_setup>\n");
1982 	sensor_disk_ok = gkrellmd_check_client_version(mon, 2,2,0);
1983 	for (list = sensors_list; list; list = list->next)
1984 		{
1985 		s = (Sensor *) list->data;
1986 		if (s->group == SENSOR_GROUP_DISK && !sensor_disk_ok)
1987 			continue;
1988 		if (sensor_disk_ok)
1989 			snprintf(buf, sizeof(buf), "%d \"%s\" %d %d %d %.4f %.4f \"%s\" \"%s\" %d\n",
1990 					s->type, s->id_name,
1991 					s->id, s->iodev, s->inter,
1992 					s->factor, s->offset, s->vref, s->default_label, s->group);
1993 		else
1994 			snprintf(buf, sizeof(buf), "%d \"%s\" %d %d %d %.4f %.4f \"%s\" \"%s\"\n",
1995 					s->type, s->id_name,
1996 					s->id, s->iodev, s->inter,
1997 					s->factor, s->offset, s->vref, s->default_label);
1998 		gkrellmd_send_to_client(client, buf);
1999 		}
2000 	}
2001 
2002 static GkrellmdMonitor sensors_monitor =
2003 	{
2004 	"sensors",
2005 	update_sensors,
2006 	serve_sensors_data,
2007 	serve_sensors_setup
2008 	};
2009 
2010 static GkrellmdMonitor *
2011 init_sensors_monitor(void)
2012 	{
2013 	if (!gkrellm_sys_sensors_init())
2014 		return NULL;
2015 	return &sensors_monitor;
2016 	}
2017 
2018 /* ======================================================= */
2019 static time_t	base_uptime,
2020 				up_seconds;
2021 static glong	up_minutes = -1;
2022 
2023 void
2024 gkrellm_uptime_set_base_uptime(time_t base)
2025 	{
2026 	base_uptime = base;
2027 	}
2028 
2029 static void
2030 update_uptime(GkrellmdMonitor *mon, gboolean first_update)
2031 	{
2032 	glong	prev_up;
2033 
2034 	if (GK.ten_second_tick || up_minutes < 0 || first_update)
2035 		{
2036 		prev_up = up_minutes;
2037 		up_seconds = gkrellm_sys_uptime_read_uptime();
2038 		if (up_seconds > 0)
2039 			up_minutes = (glong) (up_seconds / 60);
2040 		else
2041 			up_minutes = (glong)(time(0) - _GK.start_time + base_uptime) / 60;
2042 		if (up_minutes != prev_up)
2043 			gkrellmd_need_serve(mon);
2044 		}
2045 	}
2046 
2047 static void
2048 serve_uptime_data(GkrellmdMonitor *mon, gboolean first_serve)
2049 	{
2050 	gchar	buf[128];
2051 
2052 	gkrellmd_set_serve_name(mon, "uptime");
2053 	snprintf(buf, sizeof(buf), "%ld\n", (glong) (up_minutes >= 0 ? up_minutes : 0));
2054 	gkrellmd_serve_data(mon, buf);
2055 	}
2056 
2057 static GkrellmdMonitor uptime_monitor =
2058 	{
2059 	"uptime",
2060 	update_uptime,
2061 	serve_uptime_data,
2062 	NULL
2063 	};
2064 
2065 static GkrellmdMonitor *
2066 init_uptime_monitor(void)
2067 	{
2068 	if (!gkrellm_sys_uptime_init())
2069 		return NULL;
2070 	return &uptime_monitor;
2071 	}
2072 
2073 /* ======================================================= */
2074 static void
2075 send_time(GkrellmdClient *client)
2076 	{
2077 	struct tm	*t;
2078 	gchar		buf[128];
2079 
2080 	t = &gkrellmd_current_tm;
2081 	snprintf(buf, sizeof(buf), "<time>\n%d %d %d %d %d %d %d %d %d\n",
2082 		t->tm_sec, t->tm_min, t->tm_hour,
2083 		t->tm_mday, t->tm_mon, t->tm_year,
2084 		t->tm_wday, t->tm_yday, t->tm_isdst);
2085 	gkrellmd_send_to_client(client, buf);
2086 	}
2087 
2088 /* ======================================================= */
2089 
2090 void
2091 gkrellmd_plugin_serve_setup(GkrellmdMonitor *mon, gchar *name, gchar *line)
2092 	{
2093 	GkrellmdClient	*client = mon->privat->client;
2094 	gchar			buf[256];
2095 
2096 	if (!mon || !name || !line)
2097 		return;
2098 	gkrellmd_send_to_client(client, "<plugin_setup>\n");
2099 	snprintf(buf, sizeof(buf), "%s %s\n", name, line);
2100 	gkrellmd_send_to_client(client, buf);
2101 	}
2102 
2103 static void
2104 add_monitor(GkrellmdMonitor *mon)
2105 	{
2106 	if (!mon)
2107 		return;
2108 	mon->privat = g_new0(GkrellmdMonitorPrivate, 1);
2109 	mon->privat->serve_gstring = g_string_new("");
2110 	gkrellmd_monitor_list = g_list_append(gkrellmd_monitor_list, mon);
2111 	}
2112 
2113 void
2114 gkrellmd_load_monitors(void)
2115 	{
2116 	GList			*list;
2117 	GkrellmdMonitor	*mon;
2118 
2119 	add_monitor(init_sensors_monitor());
2120 	add_monitor(init_cpu_monitor());
2121 	add_monitor(init_proc_monitor());
2122 	add_monitor(init_disk_monitor());
2123 	add_monitor(init_net_monitor());
2124 	add_monitor(init_inet_monitor());
2125 	add_monitor(init_mem_monitor());
2126 	add_monitor(init_fs_monitor());
2127 	add_monitor(gkrellmd_init_mail_monitor());
2128 	add_monitor(init_battery_monitor());
2129 	add_monitor(init_uptime_monitor());
2130 
2131 	list = gkrellmd_plugins_load();
2132 	if (_GK.list_plugins)
2133 		exit(0);
2134 	if (_GK.log_plugins)
2135 		g_message("%s\n", plugin_install_log ? plugin_install_log :
2136 				_("No plugins found\n"));
2137 	for (  ; list; list = list->next)
2138 		{
2139 		mon = (GkrellmdMonitor *) list->data;
2140 		mon->privat->serve_gstring = g_string_new("");
2141 		mon->privat->is_plugin = TRUE;
2142 		gkrellmd_monitor_list = g_list_append(gkrellmd_monitor_list, mon);
2143 		}
2144 	}
2145 
2146 void
2147 gkrellmd_need_serve(GkrellmdMonitor *mon)
2148 	{
2149 	if (mon)
2150 		mon->privat->need_serve = TRUE;
2151 	}
2152 
2153 gint
2154 gkrellmd_update_monitors(void)
2155 	{
2156 	GList			*list, *c_list;
2157 	GkrellmdMonitor			*mon;
2158 	GkrellmdMonitorPrivate	*mp;
2159 	GkrellmdClient			*client;
2160 	struct tm				*pCur;
2161 	static time_t			time_prev;
2162 	gchar					buf[64];
2163 	static gboolean			first_update = TRUE;
2164 	static GString			*serve_gstring;
2165 
2166 	time(&_GK.time_now);
2167 	GK.second_tick = (_GK.time_now == time_prev) ? FALSE : TRUE;
2168 	time_prev = _GK.time_now;
2169 
2170 	if (GK.second_tick)
2171 		{
2172 		pCur = localtime(&_GK.time_now);
2173 		GK.two_second_tick  = ((pCur->tm_sec % 2) == 0) ? TRUE : FALSE;
2174 		GK.five_second_tick = ((pCur->tm_sec % 5) == 0) ? TRUE : FALSE;
2175 		GK.ten_second_tick  = ((pCur->tm_sec % 10) == 0) ? TRUE : FALSE;
2176 		GK.minute_tick = (pCur->tm_min  != gkrellmd_current_tm.tm_min);
2177 		gkrellmd_current_tm = *pCur;
2178 		}
2179 	else
2180 		{
2181 		GK.two_second_tick = FALSE;
2182 		GK.five_second_tick = FALSE;
2183 		GK.ten_second_tick = FALSE;
2184 		GK.minute_tick = FALSE;
2185 		}
2186 
2187 	for (list = gkrellmd_monitor_list; list; list = list->next)
2188 		{
2189 		mon = (GkrellmdMonitor *) list->data;
2190 		if (mon->update_monitor)
2191 			(*(mon->update_monitor))(mon, first_update);
2192 		}
2193 	++GK.timer_ticks;
2194 	if (!serve_gstring)
2195 		serve_gstring = g_string_new("");
2196 	for (c_list = gkrellmd_client_list; c_list; c_list = c_list->next)
2197 		{
2198 		client = (GkrellmdClient *) c_list->data;
2199 		client->last_client = !c_list->next;
2200 		if (!client->served)
2201 			gkrellmd_send_to_client(client, "<initial_update>\n");
2202 		for (list = gkrellmd_monitor_list; list; list = list->next)
2203 			{
2204 			mon = (GkrellmdMonitor *) list->data;
2205 			mp = mon->privat;
2206 			if (!mon->serve_data || (!mp->need_serve && client->served))
2207 				continue;
2208 			mp->client = client;
2209 			mp->serve_name_sent = FALSE;
2210 			(*(mon->serve_data))(mon, client->served ? FALSE : TRUE);
2211 			if (mp->serve_gstring->len > 0)
2212 				{
2213 				serve_gstring =
2214 					g_string_append(serve_gstring, mp->serve_gstring->str);
2215 				mp->serve_gstring = g_string_truncate(mp->serve_gstring, 0);
2216 				}
2217 			}
2218 		gkrellmd_send_to_client(client, serve_gstring->str);
2219 		serve_gstring = g_string_truncate(serve_gstring, 0);
2220 
2221 		if (GK.minute_tick || !client->served)
2222 			send_time(client);
2223 		else if (GK.second_tick)
2224 			{
2225 			snprintf(buf, sizeof(buf), "<.%d>\n", gkrellmd_current_tm.tm_sec);
2226 			gkrellmd_send_to_client(client, buf);
2227 			}
2228 
2229 		if (!client->served)
2230 			gkrellmd_send_to_client(client, "</initial_update>\n");
2231 		client->served = TRUE;
2232 		}
2233 
2234 	for (list = gkrellmd_monitor_list; list; list = list->next)
2235 		{
2236 		mon = (GkrellmdMonitor *) list->data;
2237 		mp = mon->privat;
2238 		mp->need_serve = FALSE;
2239 		}
2240 
2241 	for (list = serveflag_done_list; list; list = list->next)
2242 		*((gboolean *) list->data) = FALSE;
2243 
2244 	first_update = FALSE;
2245 	return TRUE;
2246 	}
2247 
2248 void
2249 gkrellmd_serve_setup(GkrellmdClient *client)
2250 	{
2251 	GList			*list;
2252 	GkrellmdMonitor	*mon;
2253 	struct lconv	*lc;
2254 	gchar			buf[32], *s, *name;
2255 
2256 	gkrellmd_send_to_client(client, "<gkrellmd_setup>\n");
2257 
2258 	s = g_strdup_printf("<version>\ngkrellmd %d.%d.%d%s\n",
2259 				GKRELLMD_VERSION_MAJOR, GKRELLMD_VERSION_MINOR,
2260 				GKRELLMD_VERSION_REV, GKRELLMD_EXTRAVERSION);
2261 	gkrellmd_send_to_client(client, s);
2262 	g_free(s);
2263 
2264 	lc = localeconv();
2265 	snprintf(buf, sizeof(buf), "%c\n", *lc->decimal_point);
2266 	s = g_strconcat("<decimal_point>\n", buf, "\n", NULL);
2267 	gkrellmd_send_to_client(client, s);
2268 	g_free(s);
2269 
2270 	for (list = gkrellmd_monitor_list; list; list = list->next)
2271 		{
2272 		mon = (GkrellmdMonitor *) list->data;
2273 		mon->privat->client = client;
2274 		if (mon->serve_setup)
2275 			(*(mon->serve_setup))(mon);
2276 		}
2277 	name = gkrellm_sys_get_host_name();
2278 	s = g_strconcat("<hostname>\n", name, "\n", NULL);
2279 	gkrellmd_send_to_client(client, s);
2280 	g_free(s);
2281 
2282 	name = gkrellm_sys_get_system_name();
2283 	s = g_strconcat("<sysname>\n", name, "\n", NULL);
2284 	gkrellmd_send_to_client(client, s);
2285 	g_free(s);
2286 
2287 	send_time(client);
2288 
2289 	gkrellmd_send_to_client(client, "<monitors>\n");
2290 	for (list = gkrellmd_monitor_list; list; list = list->next)
2291 		{
2292 		mon = (GkrellmdMonitor *) list->data;
2293 		snprintf(buf, sizeof(buf), "%s\n", mon->name);
2294 		gkrellmd_send_to_client(client, buf);
2295 		}
2296 
2297 	snprintf(buf, sizeof(buf), "%d\n", _GK.io_timeout);
2298 	s = g_strconcat("<io_timeout>\n", buf, "\n", NULL);
2299 	gkrellmd_send_to_client(client, s);
2300 	g_free(s);
2301 
2302 	snprintf(buf, sizeof(buf), "%d\n", _GK.reconnect_timeout);
2303 	s = g_strconcat("<reconnect_timeout>\n", buf, "\n", NULL);
2304 	gkrellmd_send_to_client(client, s);
2305 	g_free(s);
2306 
2307 	gkrellmd_send_to_client(client, "</gkrellmd_setup>\n");
2308 	}
2309 
2310 void
2311 gkrellmd_client_input_connect(GkrellmdMonitor *mon,
2312 			void (*func)(GkrellmdClient *, gchar *))
2313 	{
2314 	mon->privat->client_input_func = func;
2315 	}
2316 
2317 void
2318 gkrellmd_client_read(gint fd, gint nbytes)
2319 	{
2320 	GList					*list;
2321 	GkrellmdClient			*client = NULL;
2322 	GkrellmdMonitor			*mon;
2323 	GkrellmdMonitorPrivate	*mp;
2324 	gchar					buf[513], *s, *e;
2325 	gint					n, buflen;
2326 
2327 	for (list = gkrellmd_client_list; list; list = list->next)
2328 		{
2329 		client = (GkrellmdClient *) list->data;
2330 		if (client->fd != fd)
2331 			continue;
2332 
2333 		if (!client->input_gstring)
2334 			client->input_gstring = g_string_new("");
2335 
2336 		buflen = sizeof(buf) - 1;
2337 		while (nbytes > 0)
2338 			{
2339 			n = (nbytes > buflen) ? buflen : nbytes;
2340 			n = recv(fd, buf, n, 0);
2341 			if (n <= 0)
2342 				break;
2343 			nbytes -= n;
2344 			buf[n] = '\0';
2345 			client->input_gstring =
2346 						g_string_append(client->input_gstring, buf);
2347 			}
2348 		break;
2349 		}
2350 	if (!list)
2351 		return;
2352 
2353 	while (gkrellmd_getline_from_gstring(&client->input_gstring,
2354 				buf, sizeof(buf) - 1))
2355 		{
2356 		if (*buf == '<')
2357 			{
2358 			client->input_func = NULL;
2359 			s = buf + 1;
2360 			for (list = gkrellmd_monitor_list; list; list = list->next)
2361 				{
2362 				mon = (GkrellmdMonitor *) list->data;
2363 				mp = mon->privat;
2364 				if (!mp->serve_name)
2365 					continue;
2366 				n = strlen(mp->serve_name);
2367 				e = s + n;
2368 				if (*e == '>' && !strncmp(mp->serve_name, s, n))
2369 					{
2370 					client->input_func = mp->client_input_func;
2371 					break;
2372 					}
2373 				}
2374 			}
2375 		else if (client->input_func)
2376 			(*client->input_func)(client, buf);
2377 //		printf("%s: %s", client->hostname, buf);
2378 		}
2379 	}
2380