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-daemon-sysmon.c
23 * @brief system monitoring daemon
24 * @author Matthias Wachs
27 #include "gnunet_util_lib.h"
28 #include "gnunet_statistics_service.h"
50 * A system property to monitor
55 * Next element in in the DLL
57 struct SysmonProperty *next;
60 * Previous element in in the DLL
62 struct SysmonProperty *prev;
65 * Description used for statistics valuesd
82 struct GNUNET_TIME_Relative interval;
95 * Command execution handle
97 void * cmd_exec_handle;
112 GNUNET_SCHEDULER_TaskIdentifier task_id;
117 GNUNET_SCHEDULER_Task task;
127 * Configuration handle
129 const struct GNUNET_CONFIGURATION_Handle *cfg;
135 struct GNUNET_STATISTICS_Handle *stats;
140 GNUNET_SCHEDULER_TaskIdentifier end_task;
142 struct SysmonProperty *sp_head;
143 struct SysmonProperty *sp_tail;
146 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
148 struct SysmonProperty *sp;
149 struct SysmonProperty *next;
151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sysdaemon stopping ... \n");
153 end_task = GNUNET_SCHEDULER_NO_TASK;
157 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
162 while (NULL != (sp = next))
164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping `%s' \n", sp->desc);
165 GNUNET_CONTAINER_DLL_remove (sp_head, sp_tail, sp);
167 if (GNUNET_SCHEDULER_NO_TASK != sp->task_id)
169 GNUNET_SCHEDULER_cancel (sp->task_id);
170 sp->task_id = GNUNET_SCHEDULER_NO_TASK;
172 GNUNET_free_non_null (sp->cmd);
173 GNUNET_free_non_null (sp->cmd_args);
174 GNUNET_free (sp->desc);
183 if (GNUNET_SCHEDULER_NO_TASK != end_task)
184 GNUNET_SCHEDULER_cancel (end_task);
185 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
189 to_lower_str (char * str)
192 for (c = 0; c <= strlen (str); c++)
193 str[c] = tolower(str[c]);
197 put_property (struct SysmonProperty *sp)
199 if (v_numeric ==sp->value_type)
201 GNUNET_STATISTICS_set (stats, sp->desc, sp->num_val, GNUNET_NO);
203 else if (v_string ==sp->value_type)
205 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "NOT IMPLEMENTED\n");
210 return GNUNET_SYSERR;
216 update_uptime (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
218 struct SysmonProperty *sp = cls;
224 exec_cmd_proc (void *cls, const char *line)
226 struct SysmonProperty *sp = cls;
227 unsigned long long tmp;
228 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property output: `%s'\n", line);
231 GNUNET_OS_command_stop (sp->cmd_exec_handle);
232 sp->cmd_exec_handle = NULL;
236 switch (sp->value_type) {
238 if (1 != sscanf (line, "%llu", &tmp))
240 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Command output was not a numerical value: `%s'\n", line);
245 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "NOT IMPLEMENTED\n");
253 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property output: `%s'\n", line);
260 exec_cmd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
262 struct SysmonProperty *sp = cls;
263 GNUNET_assert (NULL != sp->cmd);
265 if (NULL != sp->cmd_exec_handle)
267 GNUNET_OS_command_stop (sp->cmd_exec_handle);
268 sp->cmd_exec_handle = NULL;
271 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property `%s': command `%s' `%s'\n", sp->desc, sp->cmd, sp->cmd_args);
272 if (NULL == (sp->cmd_exec_handle = GNUNET_OS_command_run (&exec_cmd_proc, sp,
273 GNUNET_TIME_UNIT_SECONDS,
277 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property `%s': command `%s' failed\n", sp->desc, sp->cmd);
281 load_property (void *cls,
284 struct GNUNET_CONFIGURATION_Handle *properties = cls;
285 struct SysmonProperty *sp;
288 if (NULL == strstr (section, "sysmon-"))
291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading section `%s'\n", section);
293 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section, "TYPE"))
295 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
299 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"VALUE"))
301 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
305 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"DESCRIPTION"))
307 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
308 "DESCRIPTION", section);
311 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"CMD"))
313 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
317 sp = GNUNET_malloc (sizeof (struct SysmonProperty));
320 GNUNET_CONFIGURATION_get_value_string (properties, section, "DESCRIPTION", &sp->desc);
323 GNUNET_CONFIGURATION_get_value_string (properties, section, "CMD", &tmp);
325 if (NULL != strchr (tmp, ' '))
327 args = strchr (tmp, ' ');
328 if (strlen (args) > 1)
334 sp->cmd = GNUNET_strdup (tmp);
335 sp->cmd_args = GNUNET_strdup (args);
337 sp->task = &exec_cmd;
340 GNUNET_CONFIGURATION_get_value_string (properties, section, "TYPE", &tmp);
342 if (0 == strcasecmp(tmp, "static"))
344 else if (0 == strcasecmp(tmp, "continous"))
345 sp->type = t_continous;
348 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid value %s for %s in section `%s'\n",
349 tmp, "TYPE", section);
357 GNUNET_CONFIGURATION_get_value_string (properties, section, "VALUE", &tmp);
359 if (0 == strcasecmp(tmp, "numeric"))
360 sp->value_type = v_numeric;
361 else if (0 == strcasecmp(tmp, "string"))
362 sp->value_type = v_string;
365 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid value %s for %s in section `%s'\n",
366 tmp, "VALUE", section);
374 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"INTERVAL"))
375 sp->interval = GNUNET_TIME_UNIT_MINUTES;
378 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (properties, section, "INTERVAL", &sp->interval))
380 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
381 _("Could not parse execution interval for `%s', set to default 60 sec.\n"), section);
382 sp->interval = GNUNET_TIME_UNIT_MINUTES;
386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded property `%s': %s, %s, interval %llu\n",
387 (NULL != sp->desc) ? sp->desc: "<undefined>",
388 (t_continous == sp->type) ? "continious" : "static",
389 (v_numeric == sp->value_type) ? "numeric" : "string",
390 sp->interval.rel_value);
392 GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
397 load_default_properties (void)
399 struct SysmonProperty *sp;
400 /* GNUnet version array */
403 /* GNUnet vcs revision */
404 unsigned int revision;
408 if (3 != sscanf (VERSION, "%u.%u.%u", &ver[0], &ver[1], &ver[2]))
413 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not parse version string `%s'\n", VERSION);
419 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Version string is undefined \n");
421 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Version: %u.%u.%u\n", ver[0], ver[1], ver[2]);
423 sp = GNUNET_malloc (sizeof (struct SysmonProperty));
424 sp->desc = GNUNET_strdup ("GNUnet version");
426 sp->value_type = v_numeric;
427 sp->num_val = 100 * ver[0] + 10 * ver[1] + ver[2];
428 GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
432 if (1 != sscanf (VCS_VERSION, "svn-%uM", &revision))
435 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not parse revision string `%s'\n", VCS_VERSION);
438 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "VCS revision string is undefined \n");
441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Revision: %u\n", revision);
443 sp = GNUNET_malloc (sizeof (struct SysmonProperty));
444 sp->desc = GNUNET_strdup ("GNUnet vcs revision");
446 sp->value_type = v_numeric;
447 sp->num_val = (uint64_t) revision;
448 GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
451 /* GNUnet startup time */
452 sp = GNUNET_malloc (sizeof (struct SysmonProperty));
453 sp->desc = GNUNET_strdup ("GNUnet startup time");
455 sp->value_type = v_numeric;
456 sp->num_val = (uint64_t) GNUNET_TIME_absolute_get().abs_value;
457 GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
460 /* GNUnet sysmon daemon uptime */
461 sp = GNUNET_malloc (sizeof (struct SysmonProperty));
462 sp->desc = GNUNET_strdup ("GNUnet uptime");
463 sp->type = t_continous;
464 sp->value_type = v_numeric;
465 sp->num_val = (uint64_t) 0;
466 sp->interval = GNUNET_TIME_UNIT_SECONDS;
467 sp->task_id = GNUNET_SCHEDULER_NO_TASK;
468 sp->task = update_uptime;
469 GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
476 run_property (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
478 struct SysmonProperty *sp = cls;
479 sp->task_id = GNUNET_SCHEDULER_NO_TASK;
480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running continous property `%s' \n", sp->desc);
482 sp->task_id = GNUNET_SCHEDULER_add_delayed (sp->interval, &run_property, sp);
487 run_properties (void)
489 struct SysmonProperty *sp;
491 for (sp = sp_head; NULL != sp; sp = sp->next)
493 if (t_static == sp->type)
495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running static property `%s' \n", sp->desc);
500 if (NULL == sp->task)
505 sp->task_id = GNUNET_SCHEDULER_add_now (&run_property, sp);
512 * Main function that will be run by the scheduler.
515 * @param args remaining command-line arguments
516 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
517 * @param cfg configuration
520 run (void *cls, char *const *args, const char *cfgfile,
521 const struct GNUNET_CONFIGURATION_Handle *mycfg)
523 struct GNUNET_CONFIGURATION_Handle *properties;
526 end_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL);
529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sysdaemon starting ... \n");
531 if (GNUNET_SYSERR ==GNUNET_CONFIGURATION_get_value_filename (mycfg, "sysmon", "CFGFILE", &file))
533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Sysmon configuration file not set, exit! \n");
539 properties = GNUNET_CONFIGURATION_create();
540 if (NULL == properties)
547 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (properties, file))
550 GNUNET_CONFIGURATION_destroy (properties);
557 GNUNET_CONFIGURATION_iterate_sections (properties, &load_property, properties);
559 GNUNET_CONFIGURATION_destroy (properties);
561 /* Creating statistics */
562 stats = GNUNET_STATISTICS_create ("sysmon", mycfg);
571 /* load properties */
572 if (GNUNET_SYSERR == load_default_properties ())
581 if (GNUNET_SYSERR == run_properties ())
595 * @param argc number of arguments from the command line
596 * @param argv command line arguments
597 * @return 0 ok, 1 on error
600 main (int argc, char *const *argv)
602 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
603 GNUNET_GETOPT_OPTION_END
605 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
609 GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-sysmon",
610 gettext_noop ("GNUnet system monitoring and information daemon"), options, &run,
612 GNUNET_free ((void*) argv);
616 /* end of gnunet-daemon-sysmon.c */