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