]>
git.ipfire.org Git - thirdparty/bird.git/blob - nest/cli.c
2 * BIRD Internet Routing Daemon -- Command-Line Interface
4 * (c) 1999--2000 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
10 * DOC: Command line interface
12 * This module takes care of the BIRD's command-line interface (CLI).
13 * The CLI exists to provide a way to control BIRD remotely and to inspect
14 * its status. It uses a very simple textual protocol over a stream
15 * connection provided by the platform dependent code (on UNIX systems,
16 * it's a UNIX domain socket).
18 * Each session of the CLI consists of a sequence of request and replies,
19 * slightly resembling the FTP and SMTP protocols.
20 * Requests are commands encoded as a single line of text, replies are
21 * sequences of lines starting with a four-digit code followed by either
22 * a space (if it's the last line of the reply) or a minus sign (when the
23 * reply is going to continue with the next line), the rest of the line
24 * contains a textual message semantics of which depends on the numeric
25 * code. If a reply line has the same code as the previous one and it's
26 * a continuation line, the whole prefix can be replaced by a single
27 * white space character.
29 * Reply codes starting with 0 stand for `action successfully completed' messages,
30 * 1 means `table entry', 8 `runtime error' and 9 `syntax error'.
32 * Each CLI session is internally represented by a &cli structure and a
33 * resource pool containing all resources associated with the connection,
34 * so that it can be easily freed whenever the connection gets closed, not depending
35 * on the current state of command processing.
37 * The CLI commands are declared as a part of the configuration grammar
38 * by using the |CF_CLI| macro. When a command is received, it is processed
39 * by the same lexical analyzer and parser as used for the configuration, but
40 * it's switched to a special mode by prepending a fake token to the text,
41 * so that it uses only the CLI command rules. Then the parser invokes
42 * an execution routine corresponding to the command, which either constructs
43 * the whole reply and returns it back or (in case it expects the reply will be long)
44 * it prints a partial reply and asks the CLI module (using the @cont hook)
45 * to call it again when the output is transferred to the user.
47 * The @this_cli variable points to a &cli structure of the session being
48 * currently parsed, but it's of course available only in command handlers
49 * not entered using the @cont hook.
51 * TX buffer management works as follows: At cli.tx_buf there is a
52 * list of TX buffers (struct cli_out), cli.tx_write is the buffer
53 * currently used by the producer (cli_printf(), cli_alloc_out()) and
54 * cli.tx_pos is the buffer currently used by the consumer
55 * (cli_write(), in system dependent code). The producer uses
56 * cli_out.wpos ptr as the current write position and the consumer
57 * uses cli_out.outpos ptr as the current read position. When the
58 * producer produces something, it calls cli_write_trigger(). If there
59 * is not enough space in the current buffer, the producer allocates
60 * the new one. When the consumer processes everything in the buffer
61 * queue, it calls cli_written(), tha frees all buffers (except the
62 * first one) and schedules cli.event .
66 #include "nest/bird.h"
68 #include "conf/conf.h"
69 #include "lib/string.h"
74 cli_alloc_out(cli
*c
, int size
)
78 if (!(o
= c
->tx_write
) || o
->wpos
+ size
> o
->end
)
84 o
= mb_alloc(c
->pool
, sizeof(struct cli_out
) + CLI_TX_BUF_SIZE
);
86 c
->tx_write
->next
= o
;
89 o
->wpos
= o
->outpos
= o
->buf
;
90 o
->end
= o
->buf
+ CLI_TX_BUF_SIZE
;
98 return o
->wpos
- size
;
102 * cli_printf - send reply to a CLI connection
104 * @code: numeric code of the reply, negative for continuation lines
105 * @msg: a printf()-like formatting string.
107 * This function send a single line of reply to a given CLI connection.
108 * In works in all aspects like bsprintf() except that it automatically
109 * prepends the reply line prefix.
111 * Please note that if the connection can be already busy sending some
112 * data in which case cli_printf() stores the output to a temporary buffer,
113 * so please avoid sending a large batch of replies without waiting
114 * for the buffers to be flushed.
116 * If you want to write to the current CLI output, you can use the cli_msg()
120 cli_printf(cli
*c
, int code
, char *msg
, ...)
123 byte buf
[CLI_LINE_SIZE
];
131 if (cd
== c
->last_reply
)
132 size
= bsprintf(buf
, " ");
134 size
= bsprintf(buf
, "%04d-", cd
);
137 else if (cd
== CLI_ASYNC_CODE
)
139 size
= 1; buf
[0] = '+';
144 size
= bsprintf(buf
, "%04d ", cd
);
150 cnt
= bvsnprintf(buf
+size
, sizeof(buf
)-size
-1, msg
, args
);
154 cli_printf(c
, errcode
, "<line overflow>");
159 memcpy(cli_alloc_out(c
, size
), buf
, size
);
163 cli_copy_message(cli
*c
)
168 if (c
->ring_overflow
)
171 int n
= bsprintf(buf
, "<%d messages lost>\n", c
->ring_overflow
);
172 c
->ring_overflow
= 0;
173 memcpy(cli_alloc_out(c
, n
), buf
, n
);
180 if (p
== c
->ring_end
)
182 ASSERT(p
!= c
->ring_write
);
184 c
->async_msg_size
+= cnt
;
185 q
= cli_alloc_out(c
, cnt
);
191 if (p
== c
->ring_end
)
202 cli_printf(c
, 1, "BIRD " BIRD_VERSION
" ready.");
209 struct cli_out
*o
, *p
;
213 o
->wpos
= o
->outpos
= o
->buf
;
220 c
->tx_write
= c
->tx_pos
= NULL
;
221 c
->async_msg_size
= 0;
228 ev_schedule(c
->event
);
232 static byte
*cli_rh_pos
;
233 static uint cli_rh_len
;
234 static int cli_rh_trick_flag
;
235 struct cli
*this_cli
;
238 cli_cmd_read_hook(byte
*buf
, uint max
, UNUSED
int fd
)
240 if (!cli_rh_trick_flag
)
242 cli_rh_trick_flag
= 1;
246 if (max
> cli_rh_len
)
248 memcpy(buf
, cli_rh_pos
, max
);
255 cli_command(struct cli
*c
)
260 if (config
->cli_debug
> 1)
261 log(L_TRACE
"CLI: %s", c
->rx_buf
);
262 bzero(&f
, sizeof(f
));
263 f
.mem
= c
->parser_pool
;
264 f
.pool
= rp_new(c
->pool
, "Config");
265 cf_read_hook
= cli_cmd_read_hook
;
266 cli_rh_pos
= c
->rx_buf
;
267 cli_rh_len
= strlen(c
->rx_buf
);
268 cli_rh_trick_flag
= 0;
270 lp_flush(c
->parser_pool
);
273 cli_printf(c
, 9001, f
.err_msg
);
279 cli_event(void *data
)
284 while (c
->ring_read
!= c
->ring_write
&&
285 c
->async_msg_size
< CLI_MAX_ASYNC_QUEUE
)
294 err
= cli_get_command(c
);
298 cli_printf(c
, 9000, "Command too long");
303 cli_write_trigger(c
);
309 pool
*p
= rp_new(cli_pool
, "CLI");
310 cli
*c
= mb_alloc(p
, sizeof(cli
));
312 bzero(c
, sizeof(cli
));
315 c
->event
= ev_new(p
);
316 c
->event
->hook
= cli_event
;
319 c
->parser_pool
= lp_new_default(c
->pool
);
320 c
->show_pool
= lp_new_default(c
->pool
);
321 c
->rx_buf
= mb_alloc(c
->pool
, CLI_RX_BUF_SIZE
);
322 ev_schedule(c
->event
);
329 if (!c
->cont
&& !c
->tx_pos
)
330 ev_schedule(c
->event
);
333 static list cli_log_hooks
;
334 static int cli_log_inited
;
337 cli_set_log_echo(cli
*c
, uint mask
, uint size
)
341 mb_free(c
->ring_buf
);
342 c
->ring_buf
= c
->ring_end
= c
->ring_read
= c
->ring_write
= NULL
;
348 c
->ring_buf
= mb_alloc(c
->pool
, size
);
349 c
->ring_end
= c
->ring_buf
+ size
;
350 c
->ring_read
= c
->ring_write
= c
->ring_buf
;
351 add_tail(&cli_log_hooks
, &c
->n
);
352 c
->log_threshold
= size
/ 8;
354 c
->ring_overflow
= 0;
358 cli_echo(uint
class, byte
*msg
)
360 unsigned len
, free
, i
, l
;
364 if (!cli_log_inited
|| EMPTY_LIST(cli_log_hooks
))
366 len
= strlen(msg
) + 1;
367 WALK_LIST(c
, cli_log_hooks
)
369 if (!(c
->log_mask
& (1 << class)))
371 if (c
->ring_read
<= c
->ring_write
)
372 free
= (c
->ring_end
- c
->ring_buf
) - (c
->ring_write
- c
->ring_read
+ 1);
374 free
= c
->ring_read
- c
->ring_write
- 1;
376 (free
< c
->log_threshold
&& class < (unsigned) L_INFO
[0]))
381 if (c
->ring_read
== c
->ring_write
)
382 ev_schedule(c
->event
);
387 if (c
->ring_read
<= c
->ring_write
)
388 i
= c
->ring_end
- c
->ring_write
;
390 i
= c
->ring_read
- c
->ring_write
;
393 memcpy(c
->ring_write
, m
, i
);
397 if (c
->ring_write
== c
->ring_end
)
398 c
->ring_write
= c
->ring_buf
;
403 /* Hack for scheduled undo notification */
404 extern cli
*cmd_reconfig_stored_cli
;
409 cli_set_log_echo(c
, 0, 0);
412 if (c
== cmd_reconfig_stored_cli
)
413 cmd_reconfig_stored_cli
= NULL
;
418 * cli_init - initialize the CLI module
420 * This function is called during BIRD startup to initialize
421 * the internal data structures of the CLI module.
426 cli_pool
= rp_new(&root_pool
, "CLI");
427 init_list(&cli_log_hooks
);