Fawkes API  Fawkes Development Version
plugin_tool.cpp
1 
2 /***************************************************************************
3  * plugin_tool.cpp - Fawkes plugin tool
4  *
5  * Created: Mon Dec 04 14:43:23 2006
6  * Copyright 2006 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22 
23 #include <tools/plugin/plugin_tool.h>
24 
25 #include <netcomm/fawkes/client.h>
26 #include <plugin/net/messages.h>
27 #include <plugin/net/list_message.h>
28 #include <utils/system/argparser.h>
29 
30 #include <cstdio>
31 #include <cstdlib>
32 #include <cstring>
33 
34 using namespace fawkes;
35 
36 /** @class PluginTool tools/plugin/plugin_tool.h
37  * Program to communicate with plugin manager via Fawkes network.
38  */
39 
40 /** Constructor.
41  * @param argp argument parser, three arguments are handled:
42  * - -l plugin_name load plugin named plugin_name
43  * - -u plugin_name unload plugin named plugin_name
44  * - -w watch for changes
45  * @param c FawkesNetworkClient with established connection
46  */
48 {
49  this->c = c;
50  plugin_name = NULL;
51  quit = false;
52 
53  if ( argp->has_arg("l") ) {
54  opmode = M_LOAD;
55  plugin_name = argp->arg("l");
56  } else if ( argp->has_arg("u") ) {
57  opmode = M_UNLOAD;
58  plugin_name = argp->arg("u");
59  } else if ( argp->has_arg("R") ) {
60  opmode = M_RELOAD;
61  plugin_name = argp->arg("R");
62  } else if ( argp->has_arg("w") ) {
63  opmode = M_WATCH;
64  } else if ( argp->has_arg("a") ) {
65  opmode = M_LIST_AVAIL;
66  } else {
67  opmode = M_LIST_LOADED;
68  }
69 
70  __program_name = argp->program_name();
71 
72  list_found = false;
73 }
74 
75 
76 /** Constructor.
77  * This constructor just set the Fawkes network client. A run() call will
78  * fail if not one of set_load_plugin(), set_unload_plugin(), set_watch_mode()
79  * or set_list_mode() has been called before.
80  * @param c Fawkes network client with established connection
81  */
83 {
84  this->c = c;
85  plugin_name = NULL;
86  quit = false;
87  opmode = M_UNKNOWN;
88  list_found = false;
89 }
90 
91 /** Destructor */
93 {
94 }
95 
96 
97 /** Print usage.
98  * @param program_name program name
99  */
100 void
101 PluginTool::print_usage(const char *program_name)
102 {
103  printf("Usage: %s [-l plugin|-u plugin|-R plugin|-w|-a|-L] [-r host[:port]]\n"
104  " -l plugin Load plugin with given name\n"
105  " -u plugin Unload plugin with given name\n"
106  " -R plugin Reload plugin with given name\n"
107  " -w Watch all load/unload operations\n"
108  " -a List available plugins\n"
109  " -L List loaded plugins (default)\n\n"
110  " -r host[:port] Remote host (and optionally port) to connect to\n\n"
111  " If called without any option list currently loaded plugins\n\n",
112  program_name);
113 }
114 
115 /** Load plugin on next run.
116  * The next time run is called a LOAD_PLUGIN message is sent for the
117  * given plugin name.
118  * @param plugin_name name of the plugin to load
119  */
120 void
121 PluginTool::set_load_plugin(const char *plugin_name)
122 {
123  this->plugin_name = plugin_name;
124  opmode = M_LOAD;
125 }
126 
127 
128 /** Unload plugin on next run.
129  * The next time run is called a UNLOAD_PLUGIN message is sent for the
130  * given plugin name.
131  * @param plugin_name name of the plugin to unload
132  */
133 void
134 PluginTool::set_unload_plugin(const char *plugin_name)
135 {
136  this->plugin_name = plugin_name;
137  opmode = M_UNLOAD;
138 }
139 
140 
141 /** Set watch mode.
142  * On next run() call the client will watch for new events.
143  */
144 void
146 {
147  opmode = M_WATCH;
148 }
149 
150 
151 /** Set list mode.
152  * On next run() call the client will list all loaded plugins once.
153  */
154 void
156 {
157  opmode = M_LIST_LOADED;
158 }
159 
160 
161 /** Handle signals.
162  * @param signum signal number of received signal
163  */
164 void
166 {
167  c->wake(FAWKES_CID_PLUGINMANAGER);
168  quit = true;
169 }
170 
171 
172 /** Execute load operation. */
173 void
174 PluginTool::load()
175 {
176  printf("Requesting loading of plugin %s\n", plugin_name);
177  plugin_load_msg_t *l = (plugin_load_msg_t *)calloc(1, sizeof(plugin_load_msg_t));
178  strncpy(l->name, plugin_name, PLUGIN_MSG_NAME_LENGTH);
179 
180  FawkesNetworkMessage *msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
182  l, sizeof(plugin_load_msg_t));
183  c->enqueue(msg);
184 
185  while ( ! quit ) {
186  c->wait(FAWKES_CID_PLUGINMANAGER);
187  }
188 }
189 
190 
191 /** Execute unload operation. */
192 void
193 PluginTool::unload()
194 {
195  printf("Requesting unloading of plugin %s\n", plugin_name);
197  strncpy(m->name, plugin_name, PLUGIN_MSG_NAME_LENGTH);
198 
199  FawkesNetworkMessage *msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
201  m, sizeof(plugin_unload_msg_t));
202  c->enqueue(msg);
203 
204  while ( ! quit ) {
205  c->wait(FAWKES_CID_PLUGINMANAGER);
206  }
207 }
208 
209 
210 /** Execute list available operation. */
211 void
212 PluginTool::list_avail()
213 {
214  printf("Request the list of all available plugins\n");
215  FawkesNetworkMessage *msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
217  c->enqueue(msg);
218 
219  while ( ! quit ) {
220  c->wait(FAWKES_CID_PLUGINMANAGER);
221  }
222 }
223 
224 
225 /** Execute list operation. */
226 void
227 PluginTool::list_loaded()
228 {
229  // we got a list of loaded messages during startup, show them
230  printf("Request the list of all loaded plugins\n");
231  FawkesNetworkMessage *msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
233  c->enqueue(msg);
234 
235  while ( ! quit ) {
236  c->wait(FAWKES_CID_PLUGINMANAGER);
237  }
238 }
239 
240 
241 /** Watch for plugin manager events. */
242 void
243 PluginTool::watch()
244 {
245  FawkesNetworkMessage *msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
247  c->enqueue(msg);
248  printf("Watching for plugin events\n");
249  printf("%-10s %-40s\n", "Event", "Plugin Name/ID");
250  while ( ! quit ) {
251  c->wait(FAWKES_CID_PLUGINMANAGER);
252  }
253 
254  // unsubscribe
255  msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_UNSUBSCRIBE_WATCH);
256  c->enqueue(msg);
257 }
258 
259 
260 /** Handler has been deregistered.
261  */
262 void
263 PluginTool::deregistered(unsigned int id) throw()
264 {
265  quit = true;
266 }
267 
268 
269 /** Inbound message received.
270  * @param msg message.
271  */
272 void
273 PluginTool::inbound_received(FawkesNetworkMessage *msg,
274  unsigned int id) throw()
275 {
276  if (msg->cid() != FAWKES_CID_PLUGINMANAGER) return;
277 
278  if ( msg->msgid() == MSG_PLUGIN_LOADED ) {
279  if ( msg->payload_size() != sizeof(plugin_loaded_msg_t) ) {
280  printf("Invalid message size (load succeeded)\n");
281  } else {
283  if ( opmode == M_WATCH ) {
284  printf("%-10s %s\n", "loaded", m->name);
285  } else {
286  if ( strncmp(m->name, plugin_name, PLUGIN_MSG_NAME_LENGTH) == 0 ) {
287  printf("Loading of %s succeeded\n", plugin_name);
288  quit = true;
289  }
290  }
291  }
292  } else if ( msg->msgid() == MSG_PLUGIN_LOAD_FAILED) {
293  if ( msg->payload_size() != sizeof(plugin_load_failed_msg_t) ) {
294  printf("Invalid message size (load failed)\n");
295  } else {
297  if ( opmode == M_WATCH ) {
298  printf("%-10s %s\n", "loadfail", m->name);
299  } else {
300  if ( strncmp(m->name, plugin_name, PLUGIN_MSG_NAME_LENGTH) == 0 ) {
301  printf("Loading of %s failed, see log for reason\n", plugin_name);
302  quit = true;
303  }
304  }
305  }
306  } else if ( msg->msgid() == MSG_PLUGIN_UNLOADED ) {
307  if ( msg->payload_size() != sizeof(plugin_unloaded_msg_t) ) {
308  printf("Invalid message size (unload succeeded)\n");
309  } else {
311  if ( opmode == M_WATCH ) {
312  printf("%-10s %s\n", "unloaded", m->name);
313  } else {
314  if ( strncmp(m->name, plugin_name, PLUGIN_MSG_NAME_LENGTH) == 0 ) {
315  printf("Unloading of %s succeeded\n", plugin_name);
316  quit = true;
317  }
318  }
319  }
320  } else if ( msg->msgid() == MSG_PLUGIN_UNLOAD_FAILED) {
321  if ( msg->payload_size() != sizeof(plugin_unload_failed_msg_t) ) {
322  printf("Invalid message size (unload failed)\n");
323  } else {
325  if ( opmode == M_WATCH ) {
326  printf("%-10s %s\n", "unloadfail", m->name);
327  } else {
328  if ( strncmp(m->name, plugin_name, PLUGIN_MSG_NAME_LENGTH) == 0 ) {
329  printf("Unloading of %s failed, see log for reason\n", plugin_name);
330  quit = true;
331  }
332  }
333  }
334  } else if (msg->msgid() == MSG_PLUGIN_AVAIL_LIST ) {
336  if ( plm->has_next() ) {
337  printf("Available plugins:\n");
338  while ( plm->has_next() ) {
339  char *plugin_name = plm->next();
340  char *plugin_desc = NULL;
341  if ( plm->has_next() ) {
342  plugin_desc = plm->next();
343  } else {
344  throw Exception("Invalid plugin list received");
345  }
346  printf(" %-16s (%s)\n", plugin_name, plugin_desc);
347  free(plugin_name);
348  free(plugin_desc);
349  }
350  } else {
351  printf("No plugins available\n");
352  }
353  quit = true;
354  delete plm;
355  } else if (msg->msgid() == MSG_PLUGIN_LOADED_LIST ) {
357  if ( plm->has_next() ) {
358  printf("Loaded plugins:\n");
359  while ( plm->has_next() ) {
360  char *p = plm->next();
361  printf(" %s\n", p);
362  free(p);
363  }
364  } else {
365  printf("No plugins loaded\n");
366  }
367  quit = true;
368  delete plm;
369  } else if ( msg->msgid() == MSG_PLUGIN_AVAIL_LIST_FAILED) {
370  printf("Obtaining list of available plugins failed\n");
371  } else if ( msg->msgid() == MSG_PLUGIN_LOADED_LIST_FAILED) {
372  printf("Obtaining list of loaded plugins failed\n");
373  }
374 }
375 
376 
377 void
378 PluginTool::connection_established(unsigned int id) throw()
379 {
380  // ignored, client has to be connected already
381 }
382 
383 
384 void
385 PluginTool::connection_died(unsigned int id) throw()
386 {
387  printf("Connection died, exiting\n");
388  quit = true;
389 }
390 
391 /** Run opmode as requested determined by the arguments. */
392 void
394 {
395  c->register_handler(this, FAWKES_CID_PLUGINMANAGER);
396 
397  switch (opmode) {
398  case M_LOAD:
399  load();
400  break;
401 
402  case M_UNLOAD:
403  unload();
404  break;
405 
406  case M_RELOAD:
407  unload();
408  quit = false;
409  load();
410  break;
411 
412  case M_LIST_AVAIL:
413  list_avail();
414  break;
415 
416  case M_LIST_LOADED:
417  list_loaded();
418  break;
419 
420  case M_WATCH:
421  watch();
422  break;
423 
424  default:
425  print_usage(__program_name);
426  }
427 
428  c->deregister_handler(FAWKES_CID_PLUGINMANAGER);
429 }
const char * program_name() const
Get name of program.
Definition: argparser.cpp:502
void * payload() const
Get payload buffer.
Definition: message.cpp:321
char * next()
Get next plugin from list.
request list of available plugins
Definition: messages.h:39
plugin unloaded (plugin_unloaded_msg_t)
Definition: messages.h:37
Plugin loaded message.
Definition: messages.h:70
listing available plugins failed
Definition: messages.h:41
Unsubscribe from watching load/unload events.
Definition: messages.h:46
const char * arg(const char *argn)
Get argument value.
Definition: argparser.cpp:182
Simple Fawkes network client.
Definition: client.h:52
unsigned short int cid() const
Get component ID.
Definition: message.cpp:291
char name[PLUGIN_MSG_NAME_LENGTH]
name of the plugin that has been loaded
Definition: messages.h:71
void set_list_mode()
Set list mode.
Fawkes library namespace.
Plugin unloaded message.
Definition: messages.h:87
Representation of a message that is sent over the network.
Definition: message.h:75
Parse command line arguments.
Definition: argparser.h:66
void handle_signal(int signum)
Handle signals.
static void print_usage(const char *program_name)
Print usage.
MT * msgc() const
Get correctly parsed output.
Definition: message.h:154
void set_load_plugin(const char *plugin_name)
Load plugin on next run.
void run()
Run opmode as requested determined by the arguments.
char name[PLUGIN_MSG_NAME_LENGTH]
name of the plugin to load.
Definition: messages.h:57
list of loaded plugins (plugin_list_msg_t)
Definition: messages.h:43
plugin unload failed (plugin_unload_failed_msg_t)
Definition: messages.h:38
char name[PLUGIN_MSG_NAME_LENGTH]
name of plugin that could not be unloaded
Definition: messages.h:76
Plugin unload failed.
Definition: messages.h:80
plugin loaded (plugin_loaded_msg_t)
Definition: messages.h:34
char name[PLUGIN_MSG_NAME_LENGTH]
name of plugin that could not be unloaded
Definition: messages.h:81
request plugin unload (plugin_unload_msg_t)
Definition: messages.h:36
list of available plugins (plugin_list_msg_t)
Definition: messages.h:40
Base class for exceptions in Fawkes.
Definition: exception.h:36
Plugin list message.
Definition: list_message.h:34
void set_unload_plugin(const char *plugin_name)
Unload plugin on next run.
~PluginTool()
Destructor.
Definition: plugin_tool.cpp:92
listing loaded plugins failed
Definition: messages.h:44
char name[PLUGIN_MSG_NAME_LENGTH]
name of the plugin that has been unloaded
Definition: messages.h:88
bool has_next()
Check if more list elements are available.
PluginTool(fawkes::ArgumentParser *argp, fawkes::FawkesNetworkClient *c)
Constructor.
Definition: plugin_tool.cpp:47
Load plugin message.
Definition: messages.h:56
unsigned short int msgid() const
Get message type ID.
Definition: message.cpp:301
request lif of loaded plugins
Definition: messages.h:42
request plugin load (plugin_load_msg_t)
Definition: messages.h:33
Plugin load failed.
Definition: messages.h:75
Subscribe for watching load/unload events.
Definition: messages.h:45
plugin load failed (plugin_load_failed_msg_t)
Definition: messages.h:35
bool has_arg(const char *argn)
Check if argument has been supplied.
Definition: argparser.cpp:169
char name[PLUGIN_MSG_NAME_LENGTH]
name of te plugin to unload.
Definition: messages.h:64
void set_watch_mode()
Set watch mode.
size_t payload_size() const
Get payload size.
Definition: message.cpp:311
Unload plugin message.
Definition: messages.h:63