cfd075debe658a9b8e5911b7f911c6c0c05c1d2c
[oweals/gnunet.git] / src / sysmon / gnunet-daemon-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-daemon-sysmon.c
23  * @brief system monitoring daemon
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_statistics_service.h"
29
30 enum type
31 {
32   t_static,
33   t_continous
34 };
35
36 enum value
37 {
38   v_numeric,
39   v_string
40 };
41
42 struct SysmonProperty
43 {
44   struct SysmonProperty *next;
45   struct SysmonProperty *prev;
46
47  char * desc;
48  int type;
49  int value_type;
50  struct GNUNET_TIME_Relative interval;
51
52  uint64_t num_val;
53  char * str_val;
54
55  GNUNET_SCHEDULER_TaskIdentifier task_id;
56  GNUNET_SCHEDULER_Task task;
57
58 };
59
60 /**
61  * Final status code.
62  */
63 static int ret;
64
65 /**
66  * Configuration handle
67  */
68 const struct GNUNET_CONFIGURATION_Handle *cfg;
69
70
71 /**
72  * Statistics handle
73  */
74 struct GNUNET_STATISTICS_Handle *stats;
75
76 /**
77  * Shutdown task
78  */
79
80 GNUNET_SCHEDULER_TaskIdentifier end_task;
81
82 struct SysmonProperty *sp_head;
83 struct SysmonProperty *sp_tail;
84
85 static void
86 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
87 {
88   struct SysmonProperty *sp;
89   struct SysmonProperty *next;
90
91   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sysdaemon stopping ... \n");
92
93   end_task = GNUNET_SCHEDULER_NO_TASK;
94
95   if (NULL != stats)
96   {
97     GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
98     stats = NULL;
99   }
100
101   next = sp_head;
102   while (NULL != (sp = next))
103   {
104       GNUNET_CONTAINER_DLL_remove (sp_head, sp_tail, sp);
105       next = sp->next;
106       if (GNUNET_SCHEDULER_NO_TASK != sp->task_id)
107       {
108         GNUNET_SCHEDULER_cancel (sp->task_id);
109         sp->task_id = GNUNET_SCHEDULER_NO_TASK;
110       }
111       GNUNET_free_non_null (sp->desc);
112       GNUNET_free (sp);
113   }
114
115 }
116
117 static void
118 shutdown_now (void)
119 {
120   if (GNUNET_SCHEDULER_NO_TASK != end_task)
121     GNUNET_SCHEDULER_cancel (end_task);
122   GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
123 }
124
125 static void
126 to_lower_str (char * str)
127 {
128   int c;
129   for (c = 0; c <= strlen (str); c++)
130     str[c] = tolower(str[c]);
131 }
132
133 static int
134 put_property (struct SysmonProperty *sp)
135 {
136   if (v_numeric ==sp->value_type)
137   {
138       GNUNET_STATISTICS_set (stats, sp->desc, sp->num_val, GNUNET_NO);
139   }
140   else if (v_string ==sp->value_type)
141   {
142       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "NOT IMPLEMENTED\n");
143   }
144   else
145   {
146     GNUNET_break (0);
147     return GNUNET_SYSERR;
148   }
149   return GNUNET_OK;
150 }
151
152 static void
153 load_property (void *cls,
154                const char *section)
155 {
156   struct GNUNET_CONFIGURATION_Handle *properties = cls;
157   struct SysmonProperty *sp;
158   char *tmp;
159
160   if (NULL == strstr (section, "sysmon-"))
161     return;
162
163   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading section `%s'\n", section);
164
165   if (GNUNET_NO == GNUNET_CONFIGURATION_have_value(properties, section, "TYPE"))
166   {
167     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
168         "TYPE", section);
169     return;
170   }
171   if (GNUNET_NO == GNUNET_CONFIGURATION_have_value(properties, section,"VALUE"))
172   {
173     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing value %s in section `%s'\n",
174         "VALUE", section);
175     return;
176   }
177   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
178
179   /* description */
180   GNUNET_CONFIGURATION_get_value_string(properties, section, "DESCRIPTION", &sp->desc);
181
182   /* type */
183   GNUNET_CONFIGURATION_get_value_string(properties, section, "TYPE", &tmp);
184   to_lower_str (tmp);
185   if (0 == strcasecmp(tmp, "static"))
186     sp->type = t_static;
187   else if (0 == strcasecmp(tmp, "continous"))
188     sp->type = t_continous;
189   else
190   {
191     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid value %s for %s in section `%s'\n",
192         tmp, "TYPE", section);
193     GNUNET_free (tmp);
194     GNUNET_free (sp);
195     return;
196   }
197   GNUNET_free (tmp);
198
199   /* value */
200   GNUNET_CONFIGURATION_get_value_string(properties, section, "VALUE", &tmp);
201   to_lower_str (tmp);
202   if (0 == strcasecmp(tmp, "numeric"))
203     sp->value_type = v_numeric;
204   else if (0 == strcasecmp(tmp, "string"))
205     sp->value_type = v_string;
206   else
207   {
208     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid value %s for %s in section `%s'\n",
209         tmp, "VALUE", section);
210     GNUNET_free (tmp);
211     GNUNET_free (sp);
212     return;
213   }
214   GNUNET_free (tmp);
215
216   /* interval */
217
218   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded property `%s': type %u, value %u,\n",
219       (NULL != sp->desc) ? sp->desc: "<undefined>",
220       sp->type, sp->value_type);
221
222   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
223
224 }
225
226 static void
227 update_uptime (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
228 {
229   struct SysmonProperty *sp = cls;
230   sp->task_id = GNUNET_SCHEDULER_NO_TASK;
231   sp->num_val ++;
232   put_property (sp);
233   sp->task_id = GNUNET_SCHEDULER_add_delayed (sp->interval, sp->task, sp);
234 }
235
236 static int
237 load_default_properties (void)
238 {
239   struct SysmonProperty *sp;
240   /* GNUnet version array */
241   unsigned int ver[3];
242
243   /* GNUnet vcs revision */
244   unsigned int revision;
245
246   /* version */
247 #ifdef VERSION
248   if (3 != sscanf (VERSION, "%u.%u.%u", &ver[0], &ver[1], &ver[2]))
249   {
250     ver[0] = 0;
251     ver[1] = 0;
252     ver[2] = 0;
253     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not parse version string `%s'\n", VERSION);
254   }
255 #else
256   ver[0] = 0;
257   ver[1] = 0;
258   ver[2] = 0;
259   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Version string is undefined \n");
260 #endif
261   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Version: %u.%u.%u\n", ver[0], ver[1], ver[2]);
262
263   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
264   sp->desc = GNUNET_strdup ("GNUnet version");
265   sp->type = t_static;
266   sp->value_type = v_numeric;
267   sp->num_val = 100 * ver[0] + 10  * ver[1] + ver[2];
268   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
269
270   /* revision */
271 #ifdef VCS_VERSION
272   if (1 != sscanf (VCS_VERSION, "svn-%uM", &revision))
273   {
274     revision = 0;
275     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not parse revision string `%s'\n", VCS_VERSION);
276   }
277 #else
278   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "VCS revision string is undefined \n");
279   revision = 0;
280 #endif
281   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Revision: %u\n", revision);
282
283   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
284   sp->desc = GNUNET_strdup ("GNUnet vcs revision");
285   sp->type = t_static;
286   sp->value_type = v_numeric;
287   sp->num_val = (uint64_t) revision;
288   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
289
290
291   /* GNUnet startup time  */
292   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
293   sp->desc = GNUNET_strdup ("GNUnet startup time");
294   sp->type = t_static;
295   sp->value_type = v_numeric;
296   sp->num_val = (uint64_t) GNUNET_TIME_absolute_get().abs_value;
297   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
298
299
300   /* GNUnet sysmon daemon uptime */
301   sp = GNUNET_malloc (sizeof (struct SysmonProperty));
302   sp->desc = GNUNET_strdup ("GNUnet uptime");
303   sp->type = t_continous;
304   sp->value_type = v_numeric;
305   sp->num_val = (uint64_t) 0;
306   sp->interval = GNUNET_TIME_UNIT_SECONDS;
307   sp->task_id = GNUNET_SCHEDULER_NO_TASK;
308   sp->task = update_uptime;
309   GNUNET_CONTAINER_DLL_insert (sp_head, sp_tail, sp);
310
311   return GNUNET_OK;
312 }
313
314 static int
315 run_properties (void)
316 {
317   struct SysmonProperty *sp;
318
319   for (sp = sp_head; NULL != sp; sp = sp->next)
320   {
321       if (t_static == sp->type)
322       {
323           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running static property `%s' \n", sp->desc);
324           put_property (sp);
325       }
326       else
327       {
328           if (NULL == sp->task)
329           {
330             continue;
331             GNUNET_break (0);
332           }
333           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running continous property `%s' \n", sp->desc);
334           sp->task_id = GNUNET_SCHEDULER_add_now (&update_uptime, sp);
335       }
336   }
337   return GNUNET_OK;
338 }
339
340 /**
341  * Main function that will be run by the scheduler.
342  *
343  * @param cls closure
344  * @param args remaining command-line arguments
345  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
346  * @param cfg configuration
347  */
348 static void
349 run (void *cls, char *const *args, const char *cfgfile,
350      const struct GNUNET_CONFIGURATION_Handle *mycfg)
351 {
352   struct GNUNET_CONFIGURATION_Handle *properties;
353   char *file;
354
355   end_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL);
356   cfg = mycfg;
357
358   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sysdaemon starting ... \n");
359
360   if (GNUNET_SYSERR ==GNUNET_CONFIGURATION_get_value_filename (mycfg, "sysmon", "CFGFILE", &file))
361   {
362     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Sysmon configuration file not set, exit! \n");
363     shutdown_now();
364     ret = 1;
365     return;
366   }
367
368   properties = GNUNET_CONFIGURATION_create();
369   if (NULL == properties)
370   {
371     GNUNET_break (0);
372     shutdown_now();
373     ret = 1;
374     return;
375   }
376   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (properties, file))
377   {
378       GNUNET_break (0);
379       GNUNET_CONFIGURATION_destroy (properties);
380       GNUNET_free (file);
381       ret = 1;
382       shutdown_now();
383       return;
384   }
385   GNUNET_free (file);
386   GNUNET_CONFIGURATION_iterate_sections (properties, &load_property, properties);
387
388   GNUNET_CONFIGURATION_destroy (properties);
389
390   /* Creating statistics */
391   stats = GNUNET_STATISTICS_create ("sysmon", mycfg);
392   if (NULL == stats)
393   {
394     GNUNET_break (0);
395     shutdown_now();
396     ret = 1;
397     return;
398   }
399
400   /* load properties */
401   if (GNUNET_SYSERR == load_default_properties ())
402   {
403     GNUNET_break (0);
404     shutdown_now();
405     ret = 1;
406     return;
407   }
408
409   /* run properties */
410   if (GNUNET_SYSERR == run_properties ())
411   {
412     GNUNET_break (0);
413     shutdown_now();
414     ret = 1;
415     return;
416   }
417
418 }
419
420
421 /**
422  * The main function.
423  *
424  * @param argc number of arguments from the command line
425  * @param argv command line arguments
426  * @return 0 ok, 1 on error
427  */
428 int
429 main (int argc, char *const *argv)
430 {
431   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
432     GNUNET_GETOPT_OPTION_END
433   };
434   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
435     return 2;
436
437   ret = (GNUNET_OK ==
438          GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-sysmon",
439                              gettext_noop ("GNUnet system monitoring and information daemon"), options, &run,
440                              NULL)) ? ret : 1;
441   GNUNET_free ((void*) argv);
442   return ret;
443 }
444
445 /* end of gnunet-daemon-sysmon.c */