Add cleanup code for html/telnet server
[olsrd.git] / src / olsr_comport_txt.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41 #include <string.h>
42
43 #include "olsr_cfg.h"
44 #include "olsr_logging.h"
45 #include "olsr_cookie.h"
46 #include "olsr_ip_acl.h"
47 #include "olsr.h"
48 #include "scheduler.h"
49 #include "olsr_comport.h"
50 #include "olsr_comport_txt.h"
51 #include "plugin_loader.h"
52
53 struct txt_repeat_data {
54   struct timer_entry *timer;
55   struct autobuf *buf;
56   char *cmd;
57   char *param;
58   bool csv;
59 };
60
61 static struct avl_tree txt_normal_tree, txt_csv_tree, txt_help_tree;
62 static struct olsr_cookie_info *txtcommand_cookie, *txt_repeattimer_cookie;
63
64 static enum olsr_txtcommand_result olsr_txtcmd_quit(
65     struct comport_connection *con, char *cmd, char *param);
66 static enum olsr_txtcommand_result olsr_txtcmd_help(
67     struct comport_connection *con, char *cmd, char *param);
68 static enum olsr_txtcommand_result olsr_txtcmd_csv(
69     struct comport_connection *con, char *cmd, char *param);
70 static enum olsr_txtcommand_result olsr_txtcmd_csvoff(
71     struct comport_connection *con, char *cmd, char *param);
72 static enum olsr_txtcommand_result olsr_txtcmd_repeat(
73     struct comport_connection *con, char *cmd, char *param);
74 static enum olsr_txtcommand_result olsr_txtcmd_timeout(
75     struct comport_connection *con, char *cmd, char *param);
76 static enum olsr_txtcommand_result olsr_txtcmd_version(
77     struct comport_connection *con, char *cmd, char *param);
78 static enum olsr_txtcommand_result olsr_txtcmd_plugin(
79     struct comport_connection *con, char *cmd, char *param);
80 static enum olsr_txtcommand_result olsr_txtcmd_displayhelp(
81     struct comport_connection *con, char *cmd, char *param);
82
83
84 static const char *txt_internal_names[] = {
85   "quit",
86   "exit",
87   "help",
88   "csv",
89   "csvoff",
90   "repeat",
91   "timeout",
92   "version",
93   "plugin"
94 };
95
96 static const char *txt_internal_help[] = {
97   "shuts down the terminal connection\n",
98   "shuts down the terminal connection\n",
99   "display the online help text\n",
100   "activates the csv (comma separated value) flag\n",
101   "deactivates the csv (comma separated value) flag\n",
102   "repeat <interval> <command>: repeats a command every <interval> seconds\n",
103   "timeout <interval>: set the timeout interval to <interval> seconds, 0 means no timeout\n"
104   "displays the version of the olsrd\n"
105   "control olsr plugins dynamically, parameters are 'list', 'activate <plugin>', 'deactivate <plugin>', "
106     "'load <plugin>' and 'unload <plugin>'"
107 };
108
109 static olsr_txthandler txt_internal_handlers[] = {
110   olsr_txtcmd_quit,
111   olsr_txtcmd_quit,
112   olsr_txtcmd_help,
113   olsr_txtcmd_csv,
114   olsr_txtcmd_csvoff,
115   olsr_txtcmd_repeat,
116   olsr_txtcmd_timeout,
117   olsr_txtcmd_version,
118   olsr_txtcmd_plugin
119 };
120
121 void
122 olsr_com_init_txt(void) {
123   size_t i;
124
125   avl_init(&txt_normal_tree, &avl_comp_strcasecmp);
126   avl_init(&txt_csv_tree, &avl_comp_strcasecmp);
127   avl_init(&txt_help_tree, &avl_comp_strcasecmp);
128
129   txtcommand_cookie = olsr_alloc_cookie("comport txt commands", OLSR_COOKIE_TYPE_MEMORY);
130   olsr_cookie_set_memory_size(txtcommand_cookie, sizeof(struct olsr_txtcommand));
131
132   txt_repeattimer_cookie = olsr_alloc_cookie("txt repeat timer", OLSR_COOKIE_TYPE_TIMER);
133
134   for (i=0; i < ARRAYSIZE(txt_internal_names); i++) {
135     olsr_com_add_normal_txtcommand(txt_internal_names[i], txt_internal_handlers[i]);
136     olsr_com_add_csv_txtcommand(txt_internal_names[i], txt_internal_handlers[i]);
137     olsr_com_add_help_txtcommand(txt_internal_names[i], olsr_txtcmd_displayhelp);
138   }
139 }
140
141 void
142 olsr_com_destroy_txt(void) {
143   struct olsr_txtcommand *cmd;
144   struct avl_node *node;
145
146   while ((node = avl_walk_first(&txt_normal_tree)) != NULL) {
147     cmd = txt_tree2cmd(node);
148     olsr_com_remove_normal_txtcommand(cmd);
149   }
150   while ((node = avl_walk_first(&txt_csv_tree)) != NULL) {
151     cmd = txt_tree2cmd(node);
152     olsr_com_remove_csv_txtcommand(cmd);
153   }
154   while ((node = avl_walk_first(&txt_help_tree)) != NULL) {
155     cmd = txt_tree2cmd(node);
156     olsr_com_remove_help_txtcommand(cmd);
157   }
158 }
159 struct olsr_txtcommand *
160 olsr_com_add_normal_txtcommand (const char *command, olsr_txthandler handler) {
161   struct olsr_txtcommand *txt;
162
163   txt = olsr_cookie_malloc(txtcommand_cookie);
164   txt->node.key = strdup(command);
165   txt->handler = handler;
166
167   avl_insert(&txt_normal_tree, &txt->node, AVL_DUP_NO);
168   return txt;
169 }
170
171 struct olsr_txtcommand *
172 olsr_com_add_csv_txtcommand (const char *command, olsr_txthandler handler) {
173   struct olsr_txtcommand *txt;
174
175   txt = olsr_cookie_malloc(txtcommand_cookie);
176   txt->node.key = strdup(command);
177   txt->handler = handler;
178
179   avl_insert(&txt_csv_tree, &txt->node, AVL_DUP_NO);
180   return txt;
181 }
182
183 struct olsr_txtcommand *
184 olsr_com_add_help_txtcommand (const char *command, olsr_txthandler handler) {
185   struct olsr_txtcommand *txt;
186
187   txt = olsr_cookie_malloc(txtcommand_cookie);
188   txt->node.key = strdup(command);
189   txt->handler = handler;
190
191   avl_insert(&txt_help_tree, &txt->node, AVL_DUP_NO);
192   return txt;
193 }
194
195 void olsr_com_remove_normal_txtcommand (struct olsr_txtcommand *cmd) {
196   avl_delete(&txt_normal_tree, &cmd->node);
197   free(cmd->node.key);
198   olsr_cookie_free(txtcommand_cookie, cmd);
199 }
200
201 void olsr_com_remove_csv_txtcommand (struct olsr_txtcommand *cmd) {
202   avl_delete(&txt_csv_tree, &cmd->node);
203   free(cmd->node.key);
204   olsr_cookie_free(txtcommand_cookie, cmd);
205 }
206
207 void olsr_com_remove_help_txtcommand (struct olsr_txtcommand *cmd) {
208   avl_delete(&txt_help_tree, &cmd->node);
209   free(cmd->node.key);
210   olsr_cookie_free(txtcommand_cookie, cmd);
211 }
212
213 enum olsr_txtcommand_result
214 olsr_com_handle_txtcommand(struct comport_connection *con, char *cmd, char *param) {
215   struct olsr_txtcommand *ptr;
216
217   ptr = (struct olsr_txtcommand *) avl_find(con->is_csv ? (&txt_csv_tree) : (&txt_normal_tree), cmd);
218
219   OLSR_DEBUG(LOG_COMPORT, "Looking for command '%s' (%s): %s\n",
220     cmd, con->is_csv ? "csv" : "normal", ptr ? "unknown" : "available");
221   if (ptr == NULL) {
222     return UNKNOWN;
223   }
224
225   if (ptr->acl) {
226     if (!ip_acl_acceptable(ptr->acl, &con->addr, olsr_cnf->ip_version)) {
227       return UNKNOWN;
228     }
229   }
230
231   return ptr->handler(con, cmd, param);
232 }
233
234 static enum olsr_txtcommand_result
235 olsr_txtcmd_quit(struct comport_connection *con __attribute__ ((unused)),
236     char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused))) {
237   return QUIT;
238 }
239
240 static enum olsr_txtcommand_result
241 olsr_txtcmd_displayhelp(struct comport_connection *con,
242     char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused))) {
243   size_t i;
244
245   for (i=0; i<ARRAYSIZE(txt_internal_names); i++) {
246     if (strcasecmp(txt_internal_names[i], cmd) == 0) {
247       abuf_puts(&con->out, txt_internal_help[i]);
248       return CONTINUE;
249     }
250   }
251   return UNKNOWN;
252 }
253
254 static enum olsr_txtcommand_result
255 olsr_txtcmd_help(struct comport_connection *con,
256     char *cmd __attribute__ ((unused)), char *param) {
257   struct olsr_txtcommand *ptr;
258
259   if (param != NULL) {
260     ptr = (struct olsr_txtcommand *)avl_find(&txt_help_tree, cmd);
261     if (ptr != NULL) {
262       return ptr->handler(con, param, NULL);
263     }
264     return UNKNOWN;
265   }
266
267   if (!con->is_csv) {
268     abuf_puts(&con->out, "Known commands:\n");
269   }
270
271   ptr = (struct olsr_txtcommand *)avl_walk_first(con->is_csv ? (&txt_csv_tree) : (&txt_normal_tree));
272   while (ptr) {
273     abuf_appendf(&con->out, con->is_csv ? ",%s" : "  %s\n", (char *)ptr->node.key);
274     ptr = (struct olsr_txtcommand *)avl_walk_next(&ptr->node);
275   }
276
277   abuf_puts(&con->out, con->is_csv ? "\n" : "Use 'help <command> to see a help text for a certain command\n");
278   return CONTINUE;
279 }
280
281 static enum olsr_txtcommand_result
282 olsr_txtcmd_csv(struct comport_connection *con,
283     char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused))) {
284   con->is_csv = true;
285   return CONTINUE;
286 }
287
288 static enum olsr_txtcommand_result
289 olsr_txtcmd_csvoff(struct comport_connection *con,
290     char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused))) {
291   con->is_csv = false;
292   return CONTINUE;
293 }
294
295 static enum olsr_txtcommand_result
296 olsr_txtcmd_timeout(struct comport_connection *con,
297     char *cmd __attribute__ ((unused)), char *param) {
298   con->timeout_value = (uint32_t)strtoul(param, NULL, 10);
299   return CONTINUE;
300 }
301
302 static void olsr_txt_repeat_stophandler(struct comport_connection *con) {
303   olsr_stop_timer((struct timer_entry *)con->stop_data[0]);
304   free(con->stop_data[1]);
305
306   con->stop_handler = NULL;
307   con->stop_data[0] = NULL;
308   con->stop_data[1] = NULL;
309   con->stop_data[2] = NULL;
310 }
311
312 static void olsr_txt_repeat_timer(void *data) {
313   struct comport_connection *con = data;
314
315   if (olsr_com_handle_txtcommand(con, con->stop_data[1], con->stop_data[2]) != CONTINUE) {
316     con->stop_handler(con);
317   }
318   olsr_com_activate_output(con);
319 }
320
321 static enum olsr_txtcommand_result
322 olsr_txtcmd_repeat(struct comport_connection *con, char *cmd __attribute__ ((unused)), char *param) {
323   int interval = 0;
324   char *ptr;
325   struct timer_entry *timer;
326
327   if (con->stop_handler) {
328     abuf_puts(&con->out, "Error, you cannot stack continous output commands\n");
329     return CONTINUE;
330   }
331
332   if (param == NULL || (ptr = strchr(param, ' ')) == NULL) {
333     abuf_puts(&con->out, "Missing parameters for repeat\n");
334     return CONTINUE;
335   }
336
337   ptr++;
338
339   interval = atoi(param);
340
341   timer = olsr_start_timer(interval * 1000, 0, true, &olsr_txt_repeat_timer, con, txt_repeattimer_cookie);
342   con->stop_handler = olsr_txt_repeat_stophandler;
343   con->stop_data[0] = timer;
344   con->stop_data[1] = strdup(ptr);
345   con->stop_data[2] = NULL;
346
347   /* split command/parameter and remember it */
348   ptr = strchr(con->stop_data[1], ' ');
349   if (ptr != NULL) {
350     /* found a parameter */
351     *ptr++ = 0;
352     con->stop_data[2] = ptr;
353   }
354
355   /* start command the first time */
356   if (olsr_com_handle_txtcommand(con, con->stop_data[1], con->stop_data[2]) != CONTINUE) {
357     con->stop_handler(con);
358   }
359   return CONTINOUS;
360 }
361
362 static enum olsr_txtcommand_result
363 olsr_txtcmd_version(struct comport_connection *con, char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused))) {
364   abuf_appendf(&con->out,
365       con->is_csv ? "version,%s,%s,%s\n" : " *** %s ***\n Build date: %s on %s\n http://www.olsr.org\n\n",
366       olsrd_version, build_date, build_host);
367   return CONTINUE;
368 }
369
370 static enum olsr_txtcommand_result
371 olsr_txtcmd_plugin(struct comport_connection *con, char *cmd, char *param) {
372   struct olsr_plugin *plugin;
373   char *para2 = NULL;
374   if (param == NULL || strcasecmp(param, "list") == 0) {
375     if (!con->is_csv && abuf_puts(&con->out, "Table:\n") < 0) {
376       return ABUF_ERROR;
377     }
378     OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin) {
379       if (abuf_appendf(&con->out, con->is_csv ? "%s,%s,%s": " %-30s\t%s\t%s\n",
380           plugin->p_name, plugin->active ? "active" : "", plugin->dlhandle == NULL ? "static" : "") < 0) {
381         return ABUF_ERROR;
382       }
383     } OLSR_FOR_ALL_PLUGIN_ENTRIES_END(plugin)
384     return CONTINUE;
385   }
386
387   para2 = strchr(param, ' ');
388   if (para2 == NULL) {
389     if (con->is_csv) {
390       abuf_appendf(&con->out, "Error, missing or unknown parameter\n");
391     }
392     return CONTINUE;
393   }
394   *para2++ = 0;
395
396   plugin = olsr_get_plugin(para2);
397   if (strcasecmp(param, "load") == 0) {
398     if (plugin != NULL) {
399       abuf_appendf(&con->out, "Plugin %s already loaded\n", para2);
400       return CONTINUE;
401     }
402     plugin = olsr_load_plugin(para2);
403     if (plugin != NULL) {
404       abuf_appendf(&con->out, "Plugin %s successfully loaded\n", para2);
405     }
406     else {
407       abuf_appendf(&con->out, "Could not load plugin %s\n", para2);
408     }
409     return CONTINUE;
410   }
411
412   if (plugin == NULL) {
413     if (con->is_csv) {
414       abuf_appendf(&con->out, "Error, could not find plugin '%s'.\n", para2);
415     }
416     return CONTINUE;
417   }
418   if (strcasecmp(param, "activate") == 0) {
419     if (plugin->active) {
420       abuf_appendf(&con->out, "Plugin %s already active\n", para2);
421     }
422     else if (olsr_activate_plugin(plugin)) {
423       abuf_appendf(&con->out, "Could not activate plugin %s\n", para2);
424     }
425     else {
426       abuf_appendf(&con->out, "Plugin %s successfully activated\n", para2);
427     }
428   }
429   else if (strcasecmp(param, "deactivate") == 0) {
430     if (!plugin->active) {
431       abuf_appendf(&con->out, "Plugin %s is not active\n", para2);
432     }
433     else if (olsr_deactivate_plugin(plugin)) {
434       abuf_appendf(&con->out, "Could not deactivate plugin %s\n", para2);
435     }
436     else {
437       abuf_appendf(&con->out, "Plugin %s successfully deactivated\n", para2);
438     }
439   }
440   else if (strcasecmp(param, "unload") == 0) {
441     if (plugin->dlhandle == NULL) {
442       abuf_appendf(&con->out, "Plugin %s is static and cannot be unloaded\n", para2);
443     }
444     else if (olsr_unload_plugin(plugin)) {
445       abuf_appendf(&con->out, "Could not unload plugin %s\n", para2);
446     }
447     else {
448       abuf_appendf(&con->out, "Plugin %s successfully unloaded\n", para2);
449     }
450   }
451   else {
452     abuf_appendf(&con->out, "Unknown command '%s %s %s'.\n", cmd, param, para2);
453   }
454   return CONTINUE;
455 }