2 This file is part of GNUnet.
3 (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file sysmon/gnunet-service-sysmon.c
23 * @brief system monitoring service, can use libgtop to retrieve system information
24 * in a plattform independent way
25 * @author Matthias Wachs
28 #include "gnunet_util_lib.h"
29 #include "gnunet_statistics_service.h"
32 #include <glibtop/proclist.h>
33 #include <glibtop/procstate.h>
34 #include <glibtop/procargs.h>
35 #include <glibtop/procmem.h>
36 #include <glibtop/proctime.h>
37 #include <glibtop/netlist.h>
38 #include <glibtop/netload.h>
56 #define V_NUMERIC_STR "numeric"
57 #define V_STRING_STR "string"
66 * A system property to monitor
71 * Next element in in the DLL
73 struct SysmonProperty *next;
76 * Previous element in in the DLL
78 struct SysmonProperty *prev;
80 struct SysmonGtopProcProperty *gtop_proc_head;
81 struct SysmonGtopProcProperty *gtop_proc_tail;
84 * Description used for statistics valuesd
101 struct GNUNET_TIME_Relative interval;
114 * Command execution handle
116 void * cmd_exec_handle;
131 GNUNET_SCHEDULER_TaskIdentifier task_id;
136 GNUNET_SCHEDULER_Task task;
145 * A system property to monitor
147 struct SysmonGtopProcProperty
149 struct SysmonGtopProcProperty *prev;
150 struct SysmonGtopProcProperty *next;
162 * Configuration handle
164 const struct GNUNET_CONFIGURATION_Handle *cfg;
170 struct GNUNET_STATISTICS_Handle *stats;
175 GNUNET_SCHEDULER_TaskIdentifier end_task;
177 struct SysmonProperty *sp_head;
178 struct SysmonProperty *sp_tail;
180 struct SysmonGtopProcProperty *pp_head;
181 struct SysmonGtopProcProperty *pp_tail;
184 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
186 struct SysmonProperty *sp;
187 struct SysmonProperty *next;
188 struct SysmonGtopProcProperty *gt_cur;
189 struct SysmonGtopProcProperty *gt_next;
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sysdaemon stopping ... \n");
192 end_task = GNUNET_SCHEDULER_NO_TASK;
196 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
201 while (NULL != (sp = next))
204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping `%s' \n", sp->desc);
205 GNUNET_CONTAINER_DLL_remove (sp_head, sp_tail, sp);
206 if (GNUNET_SCHEDULER_NO_TASK != sp->task_id)
208 GNUNET_SCHEDULER_cancel (sp->task_id);
209 sp->task_id = GNUNET_SCHEDULER_NO_TASK;
211 GNUNET_free_non_null (sp->cmd);
212 GNUNET_free_non_null (sp->cmd_args);
213 GNUNET_free (sp->desc);
218 while (NULL != (gt_cur = gt_next))
220 gt_next = gt_cur->next;
221 GNUNET_CONTAINER_DLL_remove (pp_head, pp_tail, gt_cur);
222 GNUNET_free (gt_cur->srv);
223 GNUNET_free (gt_cur->binary);
224 GNUNET_free (gt_cur);
235 if (GNUNET_SCHEDULER_NO_TASK != end_task)
236 GNUNET_SCHEDULER_cancel (end_task);
237 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
241 to_lower_str (char * str)
244 for (c = 0; c <= strlen (str); c++)
245 str[c] = tolower(str[c]);
249 put_property (struct SysmonProperty *sp)
251 if (v_numeric ==sp->value_type)
253 fprintf (stderr, "%s : %s : %llu\n",
254 GNUNET_STRINGS_absolute_time_to_string(GNUNET_TIME_absolute_get()),
255 sp->desc, (unsigned long long) sp->num_val);
257 else if (v_string ==sp->value_type)
259 fprintf (stderr, "%s : %s : %s\n",
260 GNUNET_STRINGS_absolute_time_to_string(GNUNET_TIME_absolute_get()),
261 sp->desc, sp->str_val);
266 return GNUNET_SYSERR;
272 update_uptime (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
274 struct SysmonProperty *sp = cls;
275 static int first_run = GNUNET_YES;
277 if (GNUNET_YES == first_run)
278 first_run = GNUNET_NO;
280 sp->num_val += sp->interval.rel_value / 1000;
286 exec_cmd_proc (void *cls, const char *line)
288 struct SysmonProperty *sp = cls;
289 unsigned long long tmp;
290 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property output: `%s'\n", line);
293 GNUNET_OS_command_stop (sp->cmd_exec_handle);
294 sp->cmd_exec_handle = NULL;
298 switch (sp->value_type) {
300 if (1 != sscanf (line, "%llu", &tmp))
302 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Command output was not a numerical value: `%s'\n", line);
307 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "NOT IMPLEMENTED\n");
315 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property output: `%s'\n", line);
322 exec_cmd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
324 struct SysmonProperty *sp = cls;
325 GNUNET_assert (NULL != sp->cmd);
327 if (NULL != sp->cmd_exec_handle)
329 GNUNET_OS_command_stop (sp->cmd_exec_handle);
330 sp->cmd_exec_handle = NULL;
333 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property `%s': command `%s' `%s'\n", sp->desc, sp->cmd, sp->cmd_args);
334 if (NULL == (sp->cmd_exec_handle = GNUNET_OS_command_run (&exec_cmd_proc, sp,
335 GNUNET_TIME_UNIT_SECONDS,
339 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property `%s': command `%s' failed\n", sp->desc, sp->cmd);
344 exec_gtop_proc_mon (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
346 struct SysmonGtopProcProperty *sp = cls;
347 glibtop_proclist proc_list;
348 glibtop_proc_args proc_args;
349 glibtop_proc_mem proc_mem;
350 glibtop_proc_time proc_time;
355 /* get process list */
356 pids = glibtop_get_proclist(&proc_list, GLIBTOP_KERN_PROC_ALL, 0);
359 fprintf (stderr, "Could not retrieve process list!\n");
363 for (i = 0; i < proc_list.number; ++i)
365 //printf("PID %u:\n", pids[i]);
367 /* get process args */
368 argss = glibtop_get_proc_args (&proc_args, pids[i], 1024);
371 fprintf (stderr, "Could not retrieve process args!\n");
375 //printf ("\targument string: %s\n", argss);
376 if (NULL != strstr (argss, sp->binary))
378 /* get memory info */
379 glibtop_get_proc_mem (&proc_mem, pids[i]);
380 fprintf (stderr, "%s : %s process information\n",
381 GNUNET_STRINGS_absolute_time_to_string(GNUNET_TIME_absolute_get()),
383 fprintf (stderr, "\t%s memory information:\n", sp->binary);
384 fprintf (stderr, "\t%-50s: %llu\n", "total # of pages of memory", (long long unsigned int) proc_mem.size);
385 fprintf (stderr, "\t%-50s: %llu\n", "number of pages of virtual memory", (long long unsigned int) proc_mem.vsize);
386 fprintf (stderr, "\t%-50s: %llu\n", "number of resident set", (long long unsigned int) proc_mem.resident);
387 fprintf (stderr, "\t%-50s: %llu\n", "number of pages of shared (mmap'd) memory", (long long unsigned int) proc_mem.share);
388 fprintf (stderr, "\t%-50s: %llu\n", "resident set size", (long long unsigned int) proc_mem.rss);
391 glibtop_get_proc_time (&proc_time, pids[i]);
392 fprintf (stderr, "\t%s time information:\n", sp->binary);
393 fprintf (stderr, "\t%-50s: %llu\n", "real time accumulated by process", (long long unsigned int) proc_time.rtime);
394 fprintf (stderr, "\t%-50s: %llu\n", "user-mode CPU time accumulated by process", (long long unsigned int) proc_time.utime);
395 fprintf (stderr, "\t%-50s: %llu\n", "kernel-mode CPU time accumulated by process", (long long unsigned int) proc_time.stime);
406 exec_gtop_net_mon (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
408 glibtop_netlist netlist;
409 glibtop_netload netload;
414 char address6_string[INET6_ADDRSTRLEN];
415 char prefix6_string[INET6_ADDRSTRLEN];
417 tmp = glibtop_get_netlist (&netlist);
419 fprintf (stderr, "%s : Network information: %u devices\n",
420 GNUNET_STRINGS_absolute_time_to_string(GNUNET_TIME_absolute_get()),
422 for (i = 0; i < netlist.number; ++i)
424 fprintf (stderr, "Device %i: %s\n", i, tmp[i]);
425 glibtop_get_netload (&netload, tmp[i]);
426 address = (uint8_t *) &netload.address;
427 netmask = (uint8_t *) &netload.subnet;
428 inet_ntop (AF_INET6, netload.address6, address6_string, INET6_ADDRSTRLEN);
429 inet_ntop (AF_INET6, netload.prefix6, prefix6_string, INET6_ADDRSTRLEN);
430 fprintf (stderr, "\t%-50s: %u.%u.%u.%u\n", "IPv4 subnet", netmask[0], netmask[1], netmask[2],netmask[3]);
431 fprintf (stderr, "\t%-50s: %u.%u.%u.%u\n", "IPv4 address", address[0], address[1], address[2],address[3]);
432 fprintf (stderr, "\t%-50s: %s\n", "IPv6 prefix", prefix6_string);
433 fprintf (stderr, "\t%-50s: %s\n", "IPv6 address", address6_string);
436 fprintf (stderr, "\t%-50s: %llu\n", "bytes in", (long long unsigned int) netload.bytes_in);
437 fprintf (stderr, "\t%-50s: %llu\n", "bytes out", (long long unsigned int) netload.bytes_out);
438 fprintf (stderr, "\t%-50s: %llu\n", "bytes total", (long long unsigned int) netload.bytes_total);
440 fprintf (stderr, "\n");
445 load_property (void *cls,
448 struct GNUNET_CONFIGURATION_Handle *properties = cls;
449 struct SysmonProperty *sp;
452 if (NULL == strstr (section, "sysmon-"))
455 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading section `%s'\n", section);
457 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section, "TYPE"))
459 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
463 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"VALUE"))
465 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
469 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"DESCRIPTION"))
471 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
472 "DESCRIPTION", section);
475 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"CMD"))
477 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
481 sp = GNUNET_malloc (sizeof (struct SysmonProperty));
484 GNUNET_CONFIGURATION_get_value_string (properties, section, "DESCRIPTION", &sp->desc);
487 GNUNET_CONFIGURATION_get_value_string (properties, section, "CMD", &tmp);
489 if (NULL != strchr (tmp, ' '))
491 args = strchr (tmp, ' ');
492 if (strlen (args) > 1)
499 sp->cmd = GNUNET_strdup (tmp);
500 sp->cmd_args = GNUNET_strdup (args);
502 sp->task = &exec_cmd;
505 GNUNET_CONFIGURATION_get_value_string (properties, section, "TYPE", &tmp);
507 if (0 == strcasecmp(tmp, "static"))
509 else if (0 == strcasecmp(tmp, "continous"))
510 sp->type = t_continous;
513 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid value %s for %s in section `%s'\n",
514 tmp, "TYPE", section);
522 GNUNET_CONFIGURATION_get_value_string (properties, section, "VALUE", &tmp);
524 if (0 == strcasecmp(tmp, V_NUMERIC_STR))
525 sp->value_type = v_numeric;
526 else if (0 == strcasecmp(tmp, V_STRING_STR))
527 sp->value_type = v_string;
530 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid value %s for %s in section `%s'\n",
531 tmp, "VALUE", section);
539 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"INTERVAL"))
540 sp->interval = GNUNET_TIME_UNIT_MINUTES;
543 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (properties, section, "INTERVAL", &sp->interval))
545 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
546 _("Could not parse execution interval for `%s', set to default 60 sec.\n"), section);
547 sp->interval = GNUNET_TIME_UNIT_MINUTES;
551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded property `%s': %s, %s, interval %llu\n",
552 (NULL != sp->desc) ? sp->desc: "<undefined>",
553 (t_continous == sp->type) ? "continious" : "static",
554 (v_numeric == sp->value_type) ? "numeric" : "string",
555 sp->interval.rel_value);
557 GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
562 load_default_properties (void)
564 struct SysmonProperty *sp;
565 /* GNUnet version array */
568 /* GNUnet vcs revision */
569 unsigned int revision;
572 if (3 != sscanf (VERSION, "%u.%u.%u", &ver[0], &ver[1], &ver[2]))
577 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not parse version string `%s'\n", VERSION);
583 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Version string is undefined \n");
585 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Version: %u.%u.%u\n", ver[0], ver[1], ver[2]);
587 sp = GNUNET_malloc (sizeof (struct SysmonProperty));
588 sp->desc = GNUNET_strdup ("GNUnet version");
590 sp->value_type = v_numeric;
591 sp->num_val = 100 * ver[0] + 10 * ver[1] + ver[2];
592 GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
595 if (1 != sscanf (VCS_VERSION, "svn-%uM", &revision))
598 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not parse revision string `%s'\n", VCS_VERSION);
601 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "VCS revision string is undefined \n");
604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Revision: %u\n", revision);
605 sp = GNUNET_malloc (sizeof (struct SysmonProperty));
606 sp->desc = GNUNET_strdup ("GNUnet vcs revision");
608 sp->value_type = v_numeric;
609 sp->num_val = (uint64_t) revision;
610 GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
613 /* GNUnet startup time */
614 sp = GNUNET_malloc (sizeof (struct SysmonProperty));
615 sp->desc = GNUNET_strdup ("GNUnet startup time");
617 sp->value_type = v_numeric;
618 sp->num_val = (uint64_t) GNUNET_TIME_absolute_get().abs_value;
619 GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
622 /* GNUnet sysmon daemon uptime in seconds */
623 sp = GNUNET_malloc (sizeof (struct SysmonProperty));
624 sp->desc = GNUNET_strdup ("GNUnet uptime");
625 sp->type = t_continous;
626 sp->value_type = v_numeric;
627 sp->num_val = (uint64_t) 0;
628 sp->interval = GNUNET_TIME_UNIT_MINUTES;
629 sp->task_id = GNUNET_SCHEDULER_NO_TASK;
630 sp->task = update_uptime;
632 GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
638 load_gtop_properties (void)
643 struct SysmonGtopProcProperty *pp;
644 struct SysmonProperty *sp;
645 struct GNUNET_TIME_Relative interval;
647 /* Load service memory monitoring tasks */
648 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (cfg, "sysmon", "MONITOR_SERVICES"))
651 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "sysmon", "MONITOR_SERVICES", &services))
652 return GNUNET_SYSERR;
654 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,"sysmon", "MONITOR_SERVICES_INTERVAL", &interval))
655 interval = GNUNET_TIME_UNIT_MINUTES;
657 s = strtok (services, " ");
660 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, s, "BINARY", &binary))
662 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Monitoring service `%s' with binary `%s'\n", s, binary);
663 pp = GNUNET_malloc (sizeof (struct SysmonGtopProcProperty));
664 pp->srv = GNUNET_strdup (s);
666 GNUNET_CONTAINER_DLL_insert (pp_head, pp_tail, pp);
668 sp = GNUNET_malloc (sizeof (struct SysmonProperty));
669 GNUNET_asprintf(&sp->desc, "Process Monitoring for service %s", s);
670 sp->type = t_continous;
671 sp->value_type = v_numeric;
672 sp->num_val = (uint64_t) 0;
673 sp->interval = interval;
674 sp->task_id = GNUNET_SCHEDULER_NO_TASK;
675 sp->task = exec_gtop_proc_mon;
677 GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
679 s = strtok (NULL, " ");
681 GNUNET_free (services);
683 /* Load network monitoring tasks */
685 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,"sysmon", "MONITOR_NETWORK_INTERVAL", &interval))
686 interval = GNUNET_TIME_UNIT_MINUTES;
688 sp = GNUNET_malloc (sizeof (struct SysmonProperty));
689 GNUNET_asprintf(&sp->desc, "Network interface monitoring");
690 sp->type = t_continous;
691 sp->value_type = v_numeric;
692 sp->num_val = (uint64_t) 0;
693 sp->interval = interval;
694 sp->task_id = GNUNET_SCHEDULER_NO_TASK;
695 sp->task = exec_gtop_net_mon;
697 GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
705 run_property (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
707 struct SysmonProperty *sp = cls;
708 sp->task_id = GNUNET_SCHEDULER_NO_TASK;
709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running continous property `%s' \n", sp->desc);
710 sp->task (sp->task_cls, tc);
711 sp->task_id = GNUNET_SCHEDULER_add_delayed (sp->interval, &run_property, sp);
716 run_properties (void)
718 struct SysmonProperty *sp;
720 for (sp = sp_head; NULL != sp; sp = sp->next)
722 if (t_static == sp->type)
724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running static property `%s' \n", sp->desc);
729 if (NULL == sp->task)
734 sp->task_id = GNUNET_SCHEDULER_add_now (&run_property, sp);
742 * Process template requests.
745 * @param server the initialized server
746 * @param mycfg configuration to use
749 run (void *cls, struct GNUNET_SERVER_Handle *server,
750 const struct GNUNET_CONFIGURATION_Handle *mycfg)
752 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
753 /* FIXME: add handlers here! */
756 /* FIXME: do setup here */
757 GNUNET_SERVER_add_handlers (server, handlers);
759 struct GNUNET_CONFIGURATION_Handle *properties;
762 end_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL);
765 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sysmon starting ... \n");
767 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (mycfg, "sysmon", "CFGFILE", &file))
769 properties = GNUNET_CONFIGURATION_create();
770 if (NULL == properties)
777 if ((GNUNET_YES == GNUNET_DISK_file_test(file)) &&
778 (GNUNET_OK == GNUNET_CONFIGURATION_load (properties, file)))
779 GNUNET_CONFIGURATION_iterate_sections (properties, &load_property, properties);
781 GNUNET_CONFIGURATION_destroy (properties);
784 /* Creating statistics */
785 stats = GNUNET_STATISTICS_create ("sysmon", mycfg);
795 /* load properties */
796 if (GNUNET_SYSERR == load_default_properties ())
805 if (NULL != glibtop_init())
806 if ( GNUNET_SYSERR == load_gtop_properties ())
808 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to load gtop properties \n");
813 if (GNUNET_SYSERR == run_properties ())
824 * The main function for the sysmon service.
826 * @param argc number of arguments from the command line
827 * @param argv command line arguments
828 * @return 0 ok, 1 on error
831 main (int argc, char *const *argv)
834 GNUNET_SERVICE_run (argc, argv, "sysmon",
835 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
838 /* end of gnunet-service-sysmon.c */