]>
Commit | Line | Data |
---|---|---|
7d3aab1c MM |
1 | /* |
2 | * BIRD Internet Routing Daemon -- Command-Line Interface | |
3 | * | |
4 | * (c) 1999 Martin Mares <mj@ucw.cz> | |
5 | * | |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
7 | */ | |
8 | ||
1d2664a4 MM |
9 | #include <string.h> |
10 | ||
7d3aab1c | 11 | #include "nest/bird.h" |
7d3aab1c | 12 | #include "nest/cli.h" |
bc2fb680 MM |
13 | #include "conf/conf.h" |
14 | #include "lib/string.h" | |
7d3aab1c MM |
15 | |
16 | pool *cli_pool; | |
17 | ||
18 | void | |
19 | cli_printf(cli *c, int code, char *msg, ...) | |
20 | { | |
21 | va_list args; | |
22 | byte buf[1024]; | |
b9672a84 MM |
23 | int cd = code; |
24 | int size, cnt; | |
7d3aab1c MM |
25 | struct cli_out *o; |
26 | ||
27 | va_start(args, msg); | |
b9672a84 MM |
28 | if (cd < 0) |
29 | { | |
30 | cd = -cd; | |
10b5baae | 31 | #if 0 /* FIXME: Enable */ |
b9672a84 MM |
32 | if (cd == c->last_reply) |
33 | size = bsprintf(buf, " "); | |
34 | else | |
10b5baae | 35 | #endif |
b9672a84 MM |
36 | size = bsprintf(buf, "%04d-", cd); |
37 | } | |
7d3aab1c | 38 | else |
b9672a84 MM |
39 | size = bsprintf(buf, "%04d ", cd); |
40 | c->last_reply = cd; | |
41 | cnt = bvsnprintf(buf+size, sizeof(buf)-size-1, msg, args); | |
42 | if (cnt < 0) | |
43 | { | |
44 | cli_printf(c, code < 0 ? -8000 : 8000, "<line overflow>"); | |
45 | return; | |
46 | } | |
47 | size += cnt; | |
7d3aab1c MM |
48 | buf[size++] = '\n'; |
49 | if (!(o = c->tx_write) || o->wpos + size > o->end) | |
50 | { | |
b9672a84 MM |
51 | if (!o && c->tx_buf) |
52 | o = c->tx_buf; | |
7d3aab1c | 53 | else |
b9672a84 MM |
54 | { |
55 | o = mb_alloc(c->pool, sizeof(struct cli_out) + CLI_TX_BUF_SIZE); | |
56 | if (c->tx_write) | |
57 | c->tx_write->next = o; | |
58 | else | |
59 | c->tx_buf = o; | |
60 | o->next = NULL; | |
61 | o->wpos = o->outpos = o->buf; | |
62 | o->end = o->buf + CLI_TX_BUF_SIZE; | |
63 | } | |
7d3aab1c | 64 | c->tx_write = o; |
b9672a84 MM |
65 | if (!c->tx_pos) |
66 | c->tx_pos = o; | |
7d3aab1c MM |
67 | } |
68 | memcpy(o->wpos, buf, size); | |
69 | o->wpos += size; | |
70 | } | |
71 | ||
b9672a84 MM |
72 | static void |
73 | cli_hello(cli *c) | |
74 | { | |
75 | cli_printf(c, 1, "BIRD " BIRD_VERSION " ready."); | |
76 | c->cont = NULL; | |
77 | } | |
78 | ||
7d3aab1c MM |
79 | static void |
80 | cli_free_out(cli *c) | |
81 | { | |
82 | struct cli_out *o, *p; | |
83 | ||
84 | if (o = c->tx_buf) | |
85 | { | |
b9672a84 | 86 | c->tx_write = NULL; |
7d3aab1c MM |
87 | o->wpos = o->outpos = o->buf; |
88 | while (p = o->next) | |
89 | { | |
90 | o->next = p->next; | |
91 | mb_free(p); | |
92 | } | |
93 | } | |
94 | } | |
95 | ||
bc2fb680 MM |
96 | static byte *cli_rh_pos; |
97 | static unsigned int cli_rh_len; | |
98 | static int cli_rh_trick_flag; | |
99 | struct cli *this_cli; | |
100 | ||
101 | static int | |
102 | cli_cmd_read_hook(byte *buf, unsigned int max) | |
103 | { | |
104 | if (!cli_rh_trick_flag) | |
105 | { | |
106 | cli_rh_trick_flag = 1; | |
107 | buf[0] = '!'; | |
108 | return 1; | |
109 | } | |
110 | if (max > cli_rh_len) | |
111 | max = cli_rh_len; | |
112 | memcpy(buf, cli_rh_pos, max); | |
113 | cli_rh_pos += max; | |
114 | cli_rh_len -= max; | |
115 | return max; | |
116 | } | |
117 | ||
118 | static void | |
119 | cli_command(struct cli *c) | |
120 | { | |
121 | struct config f; | |
122 | int res; | |
123 | ||
1d2664a4 | 124 | bzero(&f, sizeof(f)); |
bc2fb680 MM |
125 | f.mem = c->parser_pool; |
126 | cf_read_hook = cli_cmd_read_hook; | |
127 | cli_rh_pos = c->rx_buf; | |
128 | cli_rh_len = strlen(c->rx_buf); | |
129 | cli_rh_trick_flag = 0; | |
130 | this_cli = c; | |
131 | res = cli_parse(&f); | |
132 | lp_flush(c->parser_pool); | |
133 | if (!res) | |
134 | cli_printf(c, 9001, f.err_msg); | |
135 | } | |
136 | ||
7d3aab1c MM |
137 | static int |
138 | cli_event(void *data) | |
139 | { | |
140 | cli *c = data; | |
141 | int err; | |
142 | ||
b9672a84 MM |
143 | if (c->tx_pos) |
144 | ; | |
145 | else if (c->cont) | |
146 | c->cont(c); | |
147 | else | |
7d3aab1c | 148 | { |
b9672a84 MM |
149 | err = cli_get_command(c); |
150 | if (!err) | |
151 | return 0; | |
152 | if (err < 0) | |
153 | cli_printf(c, 9000, "Command too long"); | |
154 | else | |
bc2fb680 | 155 | cli_command(c); |
7d3aab1c | 156 | } |
b9672a84 MM |
157 | if (cli_write(c)) |
158 | { | |
159 | cli_free_out(c); | |
160 | return 1; | |
161 | } | |
162 | return 0; | |
7d3aab1c MM |
163 | } |
164 | ||
165 | cli * | |
166 | cli_new(void *priv) | |
167 | { | |
168 | pool *p = rp_new(cli_pool, "CLI"); | |
169 | cli *c = mb_alloc(p, sizeof(cli)); | |
170 | ||
171 | c->pool = p; | |
172 | c->priv = priv; | |
173 | c->event = ev_new(p); | |
174 | c->event->hook = cli_event; | |
175 | c->event->data = c; | |
176 | c->tx_buf = c->tx_pos = c->tx_write = NULL; | |
b9672a84 | 177 | c->cont = cli_hello; |
ffb59d24 | 178 | c->cleanup = NULL; |
b9672a84 | 179 | c->last_reply = 0; |
bc2fb680 | 180 | c->parser_pool = lp_new(c->pool, 4096); |
b9672a84 | 181 | ev_schedule(c->event); |
7d3aab1c MM |
182 | return c; |
183 | } | |
184 | ||
185 | void | |
186 | cli_kick(cli *c) | |
187 | { | |
b9672a84 MM |
188 | if (!c->cont && !c->tx_pos) |
189 | ev_schedule(c->event); | |
7d3aab1c MM |
190 | } |
191 | ||
192 | void | |
193 | cli_written(cli *c) | |
194 | { | |
7d3aab1c | 195 | cli_free_out(c); |
b9672a84 | 196 | ev_schedule(c->event); |
7d3aab1c MM |
197 | } |
198 | ||
199 | void | |
200 | cli_free(cli *c) | |
201 | { | |
ffb59d24 MM |
202 | if (c->cleanup) |
203 | c->cleanup(c); | |
7d3aab1c MM |
204 | rfree(c->pool); |
205 | } | |
206 | ||
207 | void | |
208 | cli_init(void) | |
209 | { | |
210 | cli_pool = rp_new(&root_pool, "CLI"); | |
211 | } |