changes
[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 #endif
38
39
40 enum operation
41 {
42   o_internal,
43   o_ligbtop,
44   o_command
45 };
46
47
48 enum type
49 {
50   t_static,
51   t_continous
52 };
53
54 #define V_NUMERIC_STR "numeric"
55 #define V_STRING_STR "string"
56
57 enum value
58 {
59   v_numeric,
60   v_string
61 };
62
63 /**
64  * A system property to monitor
65  */
66 struct SysmonProperty
67 {
68   /**
69    * Next element in in the DLL
70    */
71   struct SysmonProperty *next;
72
73   /**
74    * Previous element in in the DLL
75    */
76   struct SysmonProperty *prev;
77
78         struct SysmonGtopProcProperty *gtop_proc_head;
79         struct SysmonGtopProcProperty *gtop_proc_tail;
80
81   /**
82    * Description used for statistics valuesd
83    */
84   char * desc;
85
86   /**
87    * Type
88    */
89   int type;
90
91   /**
92    * Value type
93    */
94   int value_type;
95
96   /**
97    * Execution interval
98    */
99   struct GNUNET_TIME_Relative interval;
100
101   /**
102    * Command
103    */
104   char * cmd;
105
106   /**
107    * Command arguments
108    */
109   char * cmd_args;
110
111   /**
112    * Command execution handle
113    */
114   void * cmd_exec_handle;
115
116   /**
117    * Numerical value
118    */
119   uint64_t num_val;
120
121   /**
122    * String value
123    */
124   char * str_val;
125
126   /**
127    * Task id
128    */
129   GNUNET_SCHEDULER_TaskIdentifier task_id;
130
131   /**
132    * Task handle
133    */
134   GNUNET_SCHEDULER_Task task;
135
136   /**
137    * Task closure
138    */
139   void *task_cls;
140 };
141
142 /**
143  * A system property to monitor
144  */
145 struct SysmonGtopProcProperty
146 {
147         struct SysmonGtopProcProperty *prev;
148         struct SysmonGtopProcProperty *next;
149         char * binary;
150 };
151
152
153 /**
154  * Final status code.
155  */
156 static int ret;
157
158 /**
159  * Configuration handle
160  */
161 const struct GNUNET_CONFIGURATION_Handle *cfg;
162
163
164 /**
165  * Statistics handle
166  */
167 struct GNUNET_STATISTICS_Handle *stats;
168
169 /**
170  * Shutdown task
171  */
172 GNUNET_SCHEDULER_TaskIdentifier end_task;
173
174 struct SysmonProperty *sp_head;
175 struct SysmonProperty *sp_tail;
176
177 struct SysmonGtopProcProperty *pp_head;
178 struct SysmonGtopProcProperty *pp_tail;
179
180 static void
181 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
182 {
183   struct SysmonProperty *sp;
184   struct SysmonProperty *next;
185         struct SysmonGtopProcProperty *gt_cur;
186         struct SysmonGtopProcProperty *gt_next;
187
188   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sysdaemon stopping ... \n");
189   end_task = GNUNET_SCHEDULER_NO_TASK;
190
191   if (NULL != stats)
192   {
193     GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
194     stats = NULL;
195   }
196
197   next = sp_head;
198   while (NULL != (sp = next))
199   {
200                 next = sp->next;
201                 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping `%s' \n", sp->desc);
202       GNUNET_CONTAINER_DLL_remove (sp_head, sp_tail, sp);
203       if (GNUNET_SCHEDULER_NO_TASK != sp->task_id)
204       {
205         GNUNET_SCHEDULER_cancel (sp->task_id);
206         sp->task_id = GNUNET_SCHEDULER_NO_TASK;
207       }
208       GNUNET_free_non_null (sp->cmd);
209       GNUNET_free_non_null (sp->cmd_args);
210       GNUNET_free (sp->desc);
211       GNUNET_free (sp);
212   }
213
214   gt_next = pp_head;
215         while (NULL != (gt_cur = gt_next))
216         {
217                         gt_next = gt_cur->next;
218                         GNUNET_CONTAINER_DLL_remove (pp_head, pp_tail, gt_cur);
219                         GNUNET_free (gt_cur->binary);
220                         GNUNET_free (gt_cur);
221         }
222
223 #if HAVE_LIBGTOP
224   glibtop_close();
225 #endif
226 }
227
228 static void
229 shutdown_now (void)
230 {
231   if (GNUNET_SCHEDULER_NO_TASK != end_task)
232     GNUNET_SCHEDULER_cancel (end_task);
233   GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
234 }
235
236 static void
237 to_lower_str (char * str)
238 {
239   int c;
240   for (c = 0; c <= strlen (str); c++)
241     str[c] = tolower(str[c]);
242 }
243
244 static int
245 put_property (struct SysmonProperty *sp)
246 {
247   if (v_numeric ==sp->value_type)
248   {
249                 fprintf (stderr, "%s : %s : %llu\n",
250                                 GNUNET_STRINGS_absolute_time_to_string(GNUNET_TIME_absolute_get()),
251                                 sp->desc, (unsigned long long) sp->num_val);
252   }
253   else if (v_string ==sp->value_type)
254   {
255                 fprintf (stderr, "%s : %s : %s\n",
256                                 GNUNET_STRINGS_absolute_time_to_string(GNUNET_TIME_absolute_get()),
257                                 sp->desc, sp->str_val);
258   }
259   else
260   {
261     GNUNET_break (0);
262     return GNUNET_SYSERR;
263   }
264   return GNUNET_OK;
265 }
266
267 static void
268 update_uptime (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
269 {
270         struct SysmonProperty *sp = cls;
271         static int first_run = GNUNET_YES;
272
273         if (GNUNET_YES == first_run)
274                         first_run = GNUNET_NO;
275         else
276                         sp->num_val += sp->interval.rel_value / 1000;
277
278   put_property (sp);
279 }
280
281 static void
282 exec_cmd_proc (void *cls, const char *line)
283 {
284   struct SysmonProperty *sp = cls;
285   unsigned long long tmp;
286   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property output: `%s'\n", line);
287   if (NULL == line)
288   {
289       GNUNET_OS_command_stop (sp->cmd_exec_handle);
290       sp->cmd_exec_handle = NULL;
291       return;
292   }
293
294   switch (sp->value_type) {
295     case v_numeric:
296       if (1 != sscanf (line, "%llu", &tmp))
297       {
298         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Command output was not a numerical value: `%s'\n", line);
299         return;
300       }
301       break;
302     case v_string:
303       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "NOT IMPLEMENTED\n");
304       break;
305     default:
306       break;
307
308   }
309   sp->num_val = tmp;
310
311   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property output: `%s'\n", line);
312   put_property (sp);
313
314
315 }
316
317 static void
318 exec_cmd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
319 {
320   struct SysmonProperty *sp = cls;
321   GNUNET_assert (NULL != sp->cmd);
322
323   if (NULL != sp->cmd_exec_handle)
324   {
325     GNUNET_OS_command_stop (sp->cmd_exec_handle);
326     sp->cmd_exec_handle = NULL;
327     GNUNET_break (0);
328   }
329   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property `%s': command `%s' `%s'\n", sp->desc, sp->cmd, sp->cmd_args);
330   if (NULL == (sp->cmd_exec_handle = GNUNET_OS_command_run (&exec_cmd_proc, sp,
331       GNUNET_TIME_UNIT_SECONDS,
332       sp->cmd, sp->cmd,
333       sp->cmd_args,
334       NULL)))
335     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Property `%s': command `%s' failed\n", sp->desc, sp->cmd);
336 }
337
338 #if HAVE_LIBGTOP
339 static void
340 exec_gtop_proc_mon (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
341 {
342    struct SysmonGtopProcProperty *sp = cls;
343    glibtop_proclist proc_list;
344    glibtop_proc_args proc_args;
345    glibtop_proc_mem proc_mem;
346    glibtop_proc_time proc_time;
347    pid_t *pids = NULL;
348    unsigned i;
349    char *argss;
350
351    /* get process list */
352    pids = glibtop_get_proclist(&proc_list, GLIBTOP_KERN_PROC_ALL, 0);
353    if (NULL == pids)
354    {
355      fprintf (stderr, "Could not retrieve process list!\n");
356      ret = 1;
357      return;
358    }
359
360    printf("Found %lu processes\n", (unsigned long) proc_list.number);
361    for (i = 0; i < proc_list.number; ++i)
362    {
363        //printf("PID %u:\n", pids[i]);
364
365        /* get process args */
366        argss = glibtop_get_proc_args (&proc_args, pids[i], 1024);
367        if (NULL == argss)
368        {
369          fprintf (stderr, "Could not retrieve process args!\n");
370          ret = 1;
371          return;
372        }
373        //printf ("\targument string: %s\n", argss);
374        if (NULL != strstr (argss, sp->binary))
375        {
376                                  /* get memory info */
377                                  glibtop_get_proc_mem (&proc_mem, pids[i]);
378                                  printf ("\tMemory information:\n");
379                                  printf ("\t%-50s: %llu\n", "total # of pages of memory", (long long unsigned int) proc_mem.size);
380                                  printf ("\t%-50s: %llu\n", "number of pages of virtual memory", (long long unsigned int) proc_mem.vsize);
381                                  printf ("\t%-50s: %llu\n", "number of resident set", (long long unsigned int) proc_mem.resident);
382                                  printf ("\t%-50s: %llu\n", "number of pages of shared (mmap'd) memory", (long long unsigned int) proc_mem.share);
383                                  printf ("\t%-50s: %llu\n", "resident set size", (long long unsigned int) proc_mem.rss);
384
385                                  /* get time info */
386                                  glibtop_get_proc_time (&proc_time, pids[i]);
387                                  printf ("\tTime information:\n");
388                                  printf ("\t%-50s: %llu\n", "real time accumulated by process", (long long unsigned int) proc_time.rtime);
389                                  printf ("\t%-50s: %llu\n", "user-mode CPU time accumulated by process", (long long unsigned int) proc_time.utime);
390                                  printf ("\t%-50s: %llu\n", "kernel-mode CPU time accumulated by process", (long long unsigned int) proc_time.stime);
391                  }
392        g_free (argss);
393    }
394
395    g_free(pids);
396    pids = NULL;
397 }
398 #endif
399
400 static void
401 load_property (void *cls,
402                const char *section)
403 {
404   struct GNUNET_CONFIGURATION_Handle *properties = cls;
405   struct SysmonProperty *sp;
406   char *tmp;
407
408   if (NULL == strstr (section, "sysmon-"))
409     return;
410
411   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading section `%s'\n", section);
412
413   if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section, "TYPE"))
414   {
415     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
416         "TYPE", section);
417     return;
418   }
419   if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"VALUE"))
420   {
421     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
422         "VALUE", section);
423     return;
424   }
425   if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"DESCRIPTION"))
426   {
427     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
428         "DESCRIPTION", section);
429     return;
430   }
431   if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"CMD"))
432   {
433     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
434         "CMD", section);
435     return;
436   }
437   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
438
439   /* description */
440   GNUNET_CONFIGURATION_get_value_string (properties, section, "DESCRIPTION", &sp->desc);
441
442   /* cmd */
443   GNUNET_CONFIGURATION_get_value_string (properties, section, "CMD", &tmp);
444   char *args = "";
445   if (NULL != strchr (tmp, ' '))
446   {
447       args = strchr (tmp, ' ');
448       if (strlen (args) > 1)
449       {
450           args[0] = '\0';
451           args++;
452       }
453   }
454   sp->task_cls = sp;
455   sp->cmd = GNUNET_strdup (tmp);
456   sp->cmd_args = GNUNET_strdup (args);
457   GNUNET_free (tmp);
458   sp->task = &exec_cmd;
459
460   /* type */
461   GNUNET_CONFIGURATION_get_value_string (properties, section, "TYPE", &tmp);
462   to_lower_str (tmp);
463   if (0 == strcasecmp(tmp, "static"))
464     sp->type = t_static;
465   else if (0 == strcasecmp(tmp, "continous"))
466     sp->type = t_continous;
467   else
468   {
469     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid value %s for %s in section `%s'\n",
470         tmp, "TYPE", section);
471     GNUNET_free (tmp);
472     GNUNET_free (sp);
473     return;
474   }
475   GNUNET_free (tmp);
476
477   /* value */
478   GNUNET_CONFIGURATION_get_value_string (properties, section, "VALUE", &tmp);
479   to_lower_str (tmp);
480   if (0 == strcasecmp(tmp, V_NUMERIC_STR))
481     sp->value_type = v_numeric;
482   else if (0 == strcasecmp(tmp, V_STRING_STR))
483     sp->value_type = v_string;
484   else
485   {
486     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid value %s for %s in section `%s'\n",
487         tmp, "VALUE", section);
488     GNUNET_free (tmp);
489     GNUNET_free (sp);
490     return;
491   }
492   GNUNET_free (tmp);
493
494   /* interval */
495   if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (properties, section,"INTERVAL"))
496     sp->interval = GNUNET_TIME_UNIT_MINUTES;
497   else
498   {
499     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (properties, section, "INTERVAL", &sp->interval))
500     {
501         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
502             _("Could not parse execution interval for `%s', set to default 60 sec.\n"), section);
503         sp->interval = GNUNET_TIME_UNIT_MINUTES;
504     }
505   }
506
507   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded property `%s': %s, %s, interval %llu\n",
508       (NULL != sp->desc) ? sp->desc: "<undefined>",
509       (t_continous == sp->type) ? "continious" : "static",
510       (v_numeric == sp->value_type) ? "numeric" : "string",
511       sp->interval.rel_value);
512
513   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
514
515 }
516
517 static int
518 load_default_properties (void)
519 {
520   struct SysmonProperty *sp;
521   /* GNUnet version array */
522   unsigned int ver[3];
523
524   /* GNUnet vcs revision */
525   unsigned int revision;
526   /* version */
527 #ifdef VERSION
528   if (3 != sscanf (VERSION, "%u.%u.%u", &ver[0], &ver[1], &ver[2]))
529   {
530     ver[0] = 0;
531     ver[1] = 0;
532     ver[2] = 0;
533     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not parse version string `%s'\n", VERSION);
534   }
535 #else
536   ver[0] = 0;
537   ver[1] = 0;
538   ver[2] = 0;
539   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Version string is undefined \n");
540 #endif
541   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Version: %u.%u.%u\n", ver[0], ver[1], ver[2]);
542
543   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
544   sp->desc = GNUNET_strdup ("GNUnet version");
545   sp->type = t_static;
546   sp->value_type = v_numeric;
547   sp->num_val = 100 * ver[0] + 10  * ver[1] + ver[2];
548   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
549   /* revision */
550 #ifdef VCS_VERSION
551   if (1 != sscanf (VCS_VERSION, "svn-%uM", &revision))
552   {
553     revision = 0;
554     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not parse revision string `%s'\n", VCS_VERSION);
555   }
556 #else
557   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "VCS revision string is undefined \n");
558   revision = 0;
559 #endif
560   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Revision: %u\n", revision);
561   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
562   sp->desc = GNUNET_strdup ("GNUnet vcs revision");
563   sp->type = t_static;
564   sp->value_type = v_numeric;
565   sp->num_val = (uint64_t) revision;
566   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
567
568
569   /* GNUnet startup time  */
570   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
571   sp->desc = GNUNET_strdup ("GNUnet startup time");
572   sp->type = t_static;
573   sp->value_type = v_numeric;
574   sp->num_val = (uint64_t) GNUNET_TIME_absolute_get().abs_value;
575   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
576
577
578   /* GNUnet sysmon daemon uptime in seconds */
579   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
580   sp->desc = GNUNET_strdup ("GNUnet uptime");
581   sp->type = t_continous;
582   sp->value_type = v_numeric;
583   sp->num_val = (uint64_t) 0;
584   sp->interval = GNUNET_TIME_UNIT_MINUTES;
585   sp->task_id = GNUNET_SCHEDULER_NO_TASK;
586   sp->task = update_uptime;
587   sp->task_cls = sp;
588   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
589   return GNUNET_OK;
590 }
591
592 #if HAVE_LIBGTOP
593 static int
594 load_gtop_properties (void)
595 {
596         char *services;
597         char *s;
598         char *binary;
599         struct SysmonGtopProcProperty *pp;
600         struct SysmonProperty *sp;
601         /* Load network monitoring tasks */
602
603         /* Load service memory monitoring tasks */
604         if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (cfg, "sysmon", "MONITOR_SERVICES"))
605                 return GNUNET_OK;
606
607         if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "sysmon", "MONITOR_SERVICES", &services))
608                 return GNUNET_SYSERR;
609
610         s = strtok (services, " ");
611         while (NULL != s)
612         {
613                 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, s, "BINARY", &binary))
614                 {
615                         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Monitoring service `%s' with binary `%s'\n", s, binary);
616                         pp = GNUNET_malloc (sizeof (struct SysmonGtopProcProperty));
617                         pp->binary = binary;
618                         GNUNET_CONTAINER_DLL_insert (pp_head, pp_tail, pp);
619
620                   /* GNUnet sysmon daemon uptime in seconds */
621
622                   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
623                   GNUNET_asprintf(&sp->desc, "Process Monitoring for service %s", s);
624                   sp->type = t_continous;
625                   sp->value_type = v_numeric;
626                   sp->num_val = (uint64_t) 0;
627                   sp->interval = GNUNET_TIME_UNIT_MINUTES;
628                   sp->task_id = GNUNET_SCHEDULER_NO_TASK;
629                   sp->task = exec_gtop_proc_mon;
630                   sp->task_cls = pp;
631                   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
632                 }
633                 s = strtok (NULL, " ");
634         }
635         GNUNET_free (services);
636
637         return GNUNET_OK;
638 }
639 #endif
640
641 static void
642 run_property (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
643 {
644   struct SysmonProperty *sp = cls;
645   sp->task_id = GNUNET_SCHEDULER_NO_TASK;
646   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running continous property `%s' \n", sp->desc);
647   sp->task (sp->task_cls, tc);
648   sp->task_id = GNUNET_SCHEDULER_add_delayed (sp->interval, &run_property, sp);
649 }
650
651
652 static int
653 run_properties (void)
654 {
655   struct SysmonProperty *sp;
656
657   for (sp = sp_head; NULL != sp; sp = sp->next)
658   {
659       if (t_static == sp->type)
660       {
661           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running static property `%s' \n", sp->desc);
662           put_property (sp);
663       }
664       else
665       {
666           if (NULL == sp->task)
667           {
668             GNUNET_break (0);
669             continue;
670           }
671           sp->task_id = GNUNET_SCHEDULER_add_now (&run_property, sp);
672       }
673   }
674   return GNUNET_OK;
675 }
676
677
678 /**
679  * Process template requests.
680  *
681  * @param cls closure
682  * @param server the initialized server
683  * @param mycfg configuration to use
684  */
685 static void
686 run (void *cls, struct GNUNET_SERVER_Handle *server,
687      const struct GNUNET_CONFIGURATION_Handle *mycfg)
688 {
689         static const struct GNUNET_SERVER_MessageHandler handlers[] = {
690     /* FIXME: add handlers here! */
691     {NULL, NULL, 0, 0}
692   };
693   /* FIXME: do setup here */
694   GNUNET_SERVER_add_handlers (server, handlers);
695
696   struct GNUNET_CONFIGURATION_Handle *properties;
697   char *file;
698
699   end_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL);
700   cfg = mycfg;
701
702   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sysmon starting ... \n");
703
704   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (mycfg, "sysmon", "CFGFILE", &file))
705   {
706           properties = GNUNET_CONFIGURATION_create();
707           if (NULL == properties)
708           {
709             GNUNET_break (0);
710             shutdown_now();
711             ret = 1;
712             return;
713           }
714           if ((GNUNET_YES == GNUNET_DISK_file_test(file)) &&
715                         (GNUNET_OK == GNUNET_CONFIGURATION_load (properties, file)))
716           GNUNET_CONFIGURATION_iterate_sections (properties, &load_property, properties);
717
718           GNUNET_CONFIGURATION_destroy (properties);
719           GNUNET_free (file);
720
721           /* Creating statistics */
722           stats = GNUNET_STATISTICS_create ("sysmon", mycfg);
723           if (NULL == stats)
724           {
725             GNUNET_break (0);
726             shutdown_now();
727             ret = 1;
728             return;
729           }
730   }
731
732   /* load properties */
733   if (GNUNET_SYSERR == load_default_properties ())
734   {
735     GNUNET_break (0);
736     shutdown_now();
737     ret = 1;
738     return;
739   }
740
741 #if HAVE_LIBGTOP
742   if (NULL != glibtop_init())
743                 if ( GNUNET_SYSERR == load_gtop_properties ())
744                 {
745                                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to load gtop properties \n");
746                 }
747 #endif
748
749   /* run properties */
750   if (GNUNET_SYSERR == run_properties ())
751   {
752     GNUNET_break (0);
753     shutdown_now();
754     ret = 1;
755     return;
756   }
757 }
758
759
760 /**
761  * The main function for the sysmon service.
762  *
763  * @param argc number of arguments from the command line
764  * @param argv command line arguments
765  * @return 0 ok, 1 on error
766  */
767 int
768 main (int argc, char *const *argv)
769 {
770   return (GNUNET_OK ==
771           GNUNET_SERVICE_run (argc, argv, "sysmon",
772                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
773 }
774
775 /* end of gnunet-service-sysmon.c */