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
33using 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 */
97void
98PluginTool::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 */
117void
118PluginTool::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 */
129void
130PluginTool::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 */
139void
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 */
148void
150{
151 opmode = M_LIST_LOADED;
152}
153
154/** Handle signals.
155 * @param signum signal number of received signal
156 */
157void
159{
160 c->wake(FAWKES_CID_PLUGINMANAGER);
161 quit = true;
162}
163
164/** Execute load operation. */
165void
166PluginTool::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,
173 MSG_PLUGIN_LOAD,
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. */
184void
185PluginTool::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,
192 MSG_PLUGIN_UNLOAD,
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. */
203void
204PluginTool::list_avail()
205{
206 printf("Request the list of all available plugins\n");
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. */
217void
218PluginTool::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");
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. */
232void
233PluginTool::watch()
234{
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 */
251void
252PluginTool::deregistered(unsigned int id) noexcept
253{
254 quit = true;
255}
256
257/** Inbound message received.
258 * @param msg message.
259 */
260void
261PluginTool::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
365void
366PluginTool::connection_established(unsigned int id) noexcept
367{
368 // ignored, client has to be connected already
369}
370
371void
372PluginTool::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. */
379void
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
void wake(unsigned int component_id)
Wake a waiting thread.
Definition: client.cpp:814
void register_handler(FawkesNetworkClientHandler *handler, unsigned int component_id)
Register handler.
Definition: client.cpp:658
void wait(unsigned int component_id, unsigned int timeout_sec=15)
Wait for messages for component ID.
Definition: client.cpp:785
void deregister_handler(unsigned int component_id)
Deregister handler.
Definition: client.cpp:676
void enqueue(FawkesNetworkMessage *message)
Enqueue message to send.
Definition: client.cpp:596
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.
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