- distribute peers equally among island nodes on SuperMUC
[oweals/gnunet.git] / src / sysmon / gnunet-service-sysmon.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20
21 /**
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
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_statistics_service.h"
30 #if HAVE_LIBGTOP
31 #include <glibtop.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>
39 #endif
40
41
42 enum operation
43 {
44   o_internal,
45   o_ligbtop,
46   o_command
47 };
48
49
50 enum type
51 {
52   t_static,
53   t_continous
54 };
55
56 #define V_NUMERIC_STR "numeric"
57 #define V_STRING_STR "string"
58
59 enum value
60 {
61   v_numeric,
62   v_string
63 };
64
65 /**
66  * A system property to monitor
67  */
68 struct SysmonProperty
69 {
70   /**
71    * Next element in in the DLL
72    */
73   struct SysmonProperty *next;
74
75   /**
76    * Previous element in in the DLL
77    */
78   struct SysmonProperty *prev;
79
80         struct SysmonGtopProcProperty *gtop_proc_head;
81         struct SysmonGtopProcProperty *gtop_proc_tail;
82
83   /**
84    * Description used for statistics valuesd
85    */
86   char * desc;
87
88   /**
89    * Type
90    */
91   int type;
92
93   /**
94    * Value type
95    */
96   int value_type;
97
98   /**
99    * Execution interval
100    */
101   struct GNUNET_TIME_Relative interval;
102
103   /**
104    * Command
105    */
106   char * cmd;
107
108   /**
109    * Command arguments
110    */
111   char * cmd_args;
112
113   /**
114    * Command execution handle
115    */
116   void * cmd_exec_handle;
117
118   /**
119    * Numerical value
120    */
121   uint64_t num_val;
122
123   /**
124    * String value
125    */
126   char * str_val;
127
128   /**
129    * Task id
130    */
131   GNUNET_SCHEDULER_TaskIdentifier task_id;
132
133   /**
134    * Task handle
135    */
136   GNUNET_SCHEDULER_Task task;
137
138   /**
139    * Task closure
140    */
141   void *task_cls;
142 };
143
144 /**
145  * A system property to monitor
146  */
147 struct SysmonGtopProcProperty
148 {
149         struct SysmonGtopProcProperty *prev;
150         struct SysmonGtopProcProperty *next;
151         char * srv;
152         char * binary;
153 };
154
155
156 /**
157  * Final status code.
158  */
159 static int ret;
160
161 /**
162  * Configuration handle
163  */
164 const struct GNUNET_CONFIGURATION_Handle *cfg;
165
166
167 /**
168  * Statistics handle
169  */
170 struct GNUNET_STATISTICS_Handle *stats;
171
172 /**
173  * Shutdown task
174  */
175 GNUNET_SCHEDULER_TaskIdentifier end_task;
176
177 struct SysmonProperty *sp_head;
178 struct SysmonProperty *sp_tail;
179
180 struct SysmonGtopProcProperty *pp_head;
181 struct SysmonGtopProcProperty *pp_tail;
182
183 static void
184 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
185 {
186   struct SysmonProperty *sp;
187   struct SysmonProperty *next;
188         struct SysmonGtopProcProperty *gt_cur;
189         struct SysmonGtopProcProperty *gt_next;
190
191   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sysdaemon stopping ... \n");
192   end_task = GNUNET_SCHEDULER_NO_TASK;
193
194   if (NULL != stats)
195   {
196     GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
197     stats = NULL;
198   }
199
200   next = sp_head;
201   while (NULL != (sp = next))
202   {
203                 next = 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)
207       {
208         GNUNET_SCHEDULER_cancel (sp->task_id);
209         sp->task_id = GNUNET_SCHEDULER_NO_TASK;
210       }
211       GNUNET_free_non_null (sp->cmd);
212       GNUNET_free_non_null (sp->cmd_args);
213       GNUNET_free (sp->desc);
214       GNUNET_free (sp);
215   }
216
217   gt_next = pp_head;
218         while (NULL != (gt_cur = gt_next))
219         {
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);
225         }
226
227 #if HAVE_LIBGTOP
228   glibtop_close();
229 #endif
230 }
231
232 static void
233 shutdown_now (void)
234 {
235   if (GNUNET_SCHEDULER_NO_TASK != end_task)
236     GNUNET_SCHEDULER_cancel (end_task);
237   GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
238 }
239
240 static void
241 to_lower_str (char * str)
242 {
243   int c;
244   for (c = 0; c <= strlen (str); c++)
245     str[c] = tolower(str[c]);
246 }
247
248 static int
249 put_property (struct SysmonProperty *sp)
250 {
251   if (v_numeric ==sp->value_type)
252   {
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);
256   }
257   else if (v_string ==sp->value_type)
258   {
259                 fprintf (stderr, "%s : %s : %s\n",
260                                 GNUNET_STRINGS_absolute_time_to_string(GNUNET_TIME_absolute_get()),
261                                 sp->desc, sp->str_val);
262   }
263   else
264   {
265     GNUNET_break (0);
266     return GNUNET_SYSERR;
267   }
268   return GNUNET_OK;
269 }
270
271 static void
272 update_uptime (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
273 {
274         struct SysmonProperty *sp = cls;
275         static int first_run = GNUNET_YES;
276
277         if (GNUNET_YES == first_run)
278                         first_run = GNUNET_NO;
279         else
280                         sp->num_val += sp->interval.rel_value / 1000;
281
282   put_property (sp);
283 }
284
285 static void
286 exec_cmd_proc (void *cls, const char *line)
287 {
288   struct SysmonProperty *sp = cls;
289   unsigned long long tmp;
290   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property output: `%s'\n", line);
291   if (NULL == line)
292   {
293       GNUNET_OS_command_stop (sp->cmd_exec_handle);
294       sp->cmd_exec_handle = NULL;
295       return;
296   }
297
298   switch (sp->value_type) {
299     case v_numeric:
300       if (1 != sscanf (line, "%llu", &tmp))
301       {
302         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Command output was not a numerical value: `%s'\n", line);
303         return;
304       }
305       break;
306     case v_string:
307       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "NOT IMPLEMENTED\n");
308       break;
309     default:
310       break;
311
312   }
313   sp->num_val = tmp;
314
315   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property output: `%s'\n", line);
316   put_property (sp);
317
318
319 }
320
321 static void
322 exec_cmd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
323 {
324   struct SysmonProperty *sp = cls;
325   GNUNET_assert (NULL != sp->cmd);
326
327   if (NULL != sp->cmd_exec_handle)
328   {
329     GNUNET_OS_command_stop (sp->cmd_exec_handle);
330     sp->cmd_exec_handle = NULL;
331     GNUNET_break (0);
332   }
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,
336       sp->cmd, sp->cmd,
337       sp->cmd_args,
338       NULL)))
339     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property `%s': command `%s' failed\n", sp->desc, sp->cmd);
340 }
341
342 #if HAVE_LIBGTOP
343 static void
344 exec_gtop_proc_mon (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
345 {
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;
351    pid_t *pids = NULL;
352    unsigned i;
353    char *argss;
354
355    /* get process list */
356    pids = glibtop_get_proclist(&proc_list, GLIBTOP_KERN_PROC_ALL, 0);
357    if (NULL == pids)
358    {
359      fprintf (stderr, "Could not retrieve process list!\n");
360      ret = 1;
361      return;
362    }
363    for (i = 0; i < proc_list.number; ++i)
364    {
365        //printf("PID %u:\n", pids[i]);
366
367        /* get process args */
368        argss = glibtop_get_proc_args (&proc_args, pids[i], 1024);
369        if (NULL == argss)
370        {
371          fprintf (stderr, "Could not retrieve process args!\n");
372          ret = 1;
373          return;
374        }
375        //printf ("\targument string: %s\n", argss);
376        if (NULL != strstr (argss, sp->binary))
377        {
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()),
382                                                         sp->srv);
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);
389
390                                  /* get time info */
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);
396                  }
397        g_free (argss);
398    }
399    g_free(pids);
400    pids = NULL;
401 }
402 #endif
403
404 #if HAVE_LIBGTOP
405 static void
406 exec_gtop_net_mon (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
407 {
408    glibtop_netlist netlist;
409    glibtop_netload netload;
410    int i;
411    char ** tmp;
412    uint8_t *address;
413    uint8_t *netmask;
414    char address6_string[INET6_ADDRSTRLEN];
415    char prefix6_string[INET6_ADDRSTRLEN];
416
417    tmp = glibtop_get_netlist (&netlist);
418
419          fprintf (stderr, "%s : Network information: %u devices\n",
420                                 GNUNET_STRINGS_absolute_time_to_string(GNUNET_TIME_absolute_get()),
421                                 netlist.number);
422    for (i = 0; i < netlist.number; ++i)
423    {
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);
434
435
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);
439    }
440    fprintf (stderr, "\n");
441 }
442 #endif
443
444 static void
445 load_property (void *cls,
446                const char *section)
447 {
448   struct GNUNET_CONFIGURATION_Handle *properties = cls;
449   struct SysmonProperty *sp;
450   char *tmp;
451
452   if (NULL == strstr (section, "sysmon-"))
453     return;
454
455   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading section `%s'\n", section);
456
457   if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section, "TYPE"))
458   {
459     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
460         "TYPE", section);
461     return;
462   }
463   if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"VALUE"))
464   {
465     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
466         "VALUE", section);
467     return;
468   }
469   if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"DESCRIPTION"))
470   {
471     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
472         "DESCRIPTION", section);
473     return;
474   }
475   if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"CMD"))
476   {
477     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
478         "CMD", section);
479     return;
480   }
481   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
482
483   /* description */
484   GNUNET_CONFIGURATION_get_value_string (properties, section, "DESCRIPTION", &sp->desc);
485
486   /* cmd */
487   GNUNET_CONFIGURATION_get_value_string (properties, section, "CMD", &tmp);
488   char *args = "";
489   if (NULL != strchr (tmp, ' '))
490   {
491       args = strchr (tmp, ' ');
492       if (strlen (args) > 1)
493       {
494           args[0] = '\0';
495           args++;
496       }
497   }
498   sp->task_cls = sp;
499   sp->cmd = GNUNET_strdup (tmp);
500   sp->cmd_args = GNUNET_strdup (args);
501   GNUNET_free (tmp);
502   sp->task = &exec_cmd;
503
504   /* type */
505   GNUNET_CONFIGURATION_get_value_string (properties, section, "TYPE", &tmp);
506   to_lower_str (tmp);
507   if (0 == strcasecmp(tmp, "static"))
508     sp->type = t_static;
509   else if (0 == strcasecmp(tmp, "continous"))
510     sp->type = t_continous;
511   else
512   {
513     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid value %s for %s in section `%s'\n",
514         tmp, "TYPE", section);
515     GNUNET_free (tmp);
516     GNUNET_free (sp);
517     return;
518   }
519   GNUNET_free (tmp);
520
521   /* value */
522   GNUNET_CONFIGURATION_get_value_string (properties, section, "VALUE", &tmp);
523   to_lower_str (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;
528   else
529   {
530     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid value %s for %s in section `%s'\n",
531         tmp, "VALUE", section);
532     GNUNET_free (tmp);
533     GNUNET_free (sp);
534     return;
535   }
536   GNUNET_free (tmp);
537
538   /* interval */
539   if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"INTERVAL"))
540     sp->interval = GNUNET_TIME_UNIT_MINUTES;
541   else
542   {
543     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (properties, section, "INTERVAL", &sp->interval))
544     {
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;
548     }
549   }
550
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);
556
557   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
558
559 }
560
561 static int
562 load_default_properties (void)
563 {
564   struct SysmonProperty *sp;
565   /* GNUnet version array */
566   unsigned int ver[3];
567
568   /* GNUnet vcs revision */
569   unsigned int revision;
570   /* version */
571 #ifdef VERSION
572   if (3 != sscanf (VERSION, "%u.%u.%u", &ver[0], &ver[1], &ver[2]))
573   {
574     ver[0] = 0;
575     ver[1] = 0;
576     ver[2] = 0;
577     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not parse version string `%s'\n", VERSION);
578   }
579 #else
580   ver[0] = 0;
581   ver[1] = 0;
582   ver[2] = 0;
583   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Version string is undefined \n");
584 #endif
585   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Version: %u.%u.%u\n", ver[0], ver[1], ver[2]);
586
587   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
588   sp->desc = GNUNET_strdup ("GNUnet version");
589   sp->type = t_static;
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);
593   /* revision */
594 #ifdef VCS_VERSION
595   if (1 != sscanf (VCS_VERSION, "svn-%uM", &revision))
596   {
597     revision = 0;
598     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not parse revision string `%s'\n", VCS_VERSION);
599   }
600 #else
601   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "VCS revision string is undefined \n");
602   revision = 0;
603 #endif
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");
607   sp->type = t_static;
608   sp->value_type = v_numeric;
609   sp->num_val = (uint64_t) revision;
610   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
611
612
613   /* GNUnet startup time  */
614   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
615   sp->desc = GNUNET_strdup ("GNUnet startup time");
616   sp->type = t_static;
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);
620
621
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;
631   sp->task_cls = sp;
632   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
633   return GNUNET_OK;
634 }
635
636 #if HAVE_LIBGTOP
637 static int
638 load_gtop_properties (void)
639 {
640         char *services;
641         char *s;
642         char *binary;
643         struct SysmonGtopProcProperty *pp;
644         struct SysmonProperty *sp;
645         struct GNUNET_TIME_Relative interval;
646
647         /* Load service memory monitoring tasks */
648         if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (cfg, "sysmon", "MONITOR_SERVICES"))
649                 return GNUNET_OK;
650
651         if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "sysmon", "MONITOR_SERVICES", &services))
652                 return GNUNET_SYSERR;
653
654         if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,"sysmon", "MONITOR_SERVICES_INTERVAL", &interval))
655                 interval = GNUNET_TIME_UNIT_MINUTES;
656
657         s = strtok (services, " ");
658         while (NULL != s)
659         {
660                 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, s, "BINARY", &binary))
661                 {
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);
665                         pp->binary = binary;
666                         GNUNET_CONTAINER_DLL_insert (pp_head, pp_tail, pp);
667
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;
676                   sp->task_cls = pp;
677                   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
678                 }
679                 s = strtok (NULL, " ");
680         }
681         GNUNET_free (services);
682
683         /* Load network monitoring tasks */
684
685         if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,"sysmon", "MONITOR_NETWORK_INTERVAL", &interval))
686                 interval = GNUNET_TIME_UNIT_MINUTES;
687
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;
696   sp->task_cls = sp;
697   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
698
699         return GNUNET_OK;
700 }
701 #endif
702
703
704 static void
705 run_property (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
706 {
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);
712 }
713
714
715 static int
716 run_properties (void)
717 {
718   struct SysmonProperty *sp;
719
720   for (sp = sp_head; NULL != sp; sp = sp->next)
721   {
722       if (t_static == sp->type)
723       {
724           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running static property `%s' \n", sp->desc);
725           put_property (sp);
726       }
727       else
728       {
729           if (NULL == sp->task)
730           {
731             GNUNET_break (0);
732             continue;
733           }
734           sp->task_id = GNUNET_SCHEDULER_add_now (&run_property, sp);
735       }
736   }
737   return GNUNET_OK;
738 }
739
740
741 /**
742  * Process template requests.
743  *
744  * @param cls closure
745  * @param server the initialized server
746  * @param mycfg configuration to use
747  */
748 static void
749 run (void *cls, struct GNUNET_SERVER_Handle *server,
750      const struct GNUNET_CONFIGURATION_Handle *mycfg)
751 {
752         static const struct GNUNET_SERVER_MessageHandler handlers[] = {
753     /* FIXME: add handlers here! */
754     {NULL, NULL, 0, 0}
755   };
756   /* FIXME: do setup here */
757   GNUNET_SERVER_add_handlers (server, handlers);
758
759   struct GNUNET_CONFIGURATION_Handle *properties;
760   char *file;
761
762   end_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL);
763   cfg = mycfg;
764
765   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sysmon starting ... \n");
766
767   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (mycfg, "sysmon", "CFGFILE", &file))
768   {
769           properties = GNUNET_CONFIGURATION_create();
770           if (NULL == properties)
771           {
772             GNUNET_break (0);
773             shutdown_now();
774             ret = 1;
775             return;
776           }
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);
780
781           GNUNET_CONFIGURATION_destroy (properties);
782           GNUNET_free (file);
783
784           /* Creating statistics */
785           stats = GNUNET_STATISTICS_create ("sysmon", mycfg);
786           if (NULL == stats)
787           {
788             GNUNET_break (0);
789             shutdown_now();
790             ret = 1;
791             return;
792           }
793   }
794
795   /* load properties */
796   if (GNUNET_SYSERR == load_default_properties ())
797   {
798     GNUNET_break (0);
799     shutdown_now();
800     ret = 1;
801     return;
802   }
803
804 #if HAVE_LIBGTOP
805   if (NULL != glibtop_init())
806                 if ( GNUNET_SYSERR == load_gtop_properties ())
807                 {
808                                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to load gtop properties \n");
809                 }
810 #endif
811
812   /* run properties */
813   if (GNUNET_SYSERR == run_properties ())
814   {
815     GNUNET_break (0);
816     shutdown_now();
817     ret = 1;
818     return;
819   }
820 }
821
822
823 /**
824  * The main function for the sysmon service.
825  *
826  * @param argc number of arguments from the command line
827  * @param argv command line arguments
828  * @return 0 ok, 1 on error
829  */
830 int
831 main (int argc, char *const *argv)
832 {
833   return (GNUNET_OK ==
834           GNUNET_SERVICE_run (argc, argv, "sysmon",
835                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
836 }
837
838 /* end of gnunet-service-sysmon.c */