]> git.ipfire.org Git - thirdparty/bird.git/blame - client/client.c
Fixed display of short continued messages in verbose mode.
[thirdparty/bird.git] / client / client.c
CommitLineData
ed608150
MM
1/*
2 * BIRD Client
3 *
f50b9e48 4 * (c) 1999--2000 Martin Mares <mj@ucw.cz>
ed608150
MM
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9fac310d
MM
9#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
c51f132d 12#include <fcntl.h>
9fac310d 13#include <unistd.h>
c51f132d
MM
14#include <errno.h>
15#include <sys/socket.h>
16#include <sys/un.h>
17#include <sys/time.h>
18#include <sys/types.h>
7211be1c
MM
19#include <readline/readline.h>
20#include <readline/history.h>
9fac310d 21
ed608150 22#include "nest/bird.h"
9fac310d 23#include "lib/resource.h"
ed608150
MM
24#include "client/client.h"
25
c51f132d
MM
26static char *opt_list = "s:v";
27static int verbose;
28
29static char *server_path = PATH_CONTROL_SOCKET_DIR "/bird.ctl";
30static int server_fd;
31static int server_reply;
32static byte server_read_buf[4096];
33static byte *server_read_pos = server_read_buf;
34
35static int input_initialized;
36static int input_hidden;
37static int input_hidden_end;
38
39/*** Parsing of arguments ***/
f50b9e48 40
9fac310d
MM
41static void
42usage(void)
43{
c51f132d 44 fprintf(stderr, "Usage: birdc [-s <control-socket>] [-v]\n");
9fac310d
MM
45 exit(1);
46}
47
48static void
49parse_args(int argc, char **argv)
50{
51 int c;
52
53 while ((c = getopt(argc, argv, opt_list)) >= 0)
54 switch (c)
55 {
c51f132d
MM
56 case 's':
57 server_path = optarg;
58 break;
59 case 'v':
60 verbose++;
61 break;
9fac310d
MM
62 default:
63 usage();
64 }
65 if (optind < argc)
66 usage();
67}
f50b9e48 68
c51f132d
MM
69/*** Input ***/
70
71static void server_send(char *);
72static void io_loop(int);
7211be1c 73
fae0396e
MM
74/* HACK: libreadline internals we need to access */
75extern int _rl_vis_botlin;
76extern void _rl_move_vert(int);
77extern Function *rl_last_func;
78
c51f132d
MM
79static void
80got_line(char *cmd_buffer)
81{
e69e4ed9
MM
82 char *cmd;
83
7211be1c 84 if (!cmd_buffer)
c51f132d
MM
85 {
86 cleanup();
87 exit(0);
88 }
7211be1c 89 if (cmd_buffer[0])
c51f132d 90 {
e69e4ed9
MM
91 cmd = cmd_expand(cmd_buffer);
92 if (cmd)
93 {
94 add_history(cmd);
95 puts(cmd);
96 if (!strcmp(cmd, "exit") || !strcmp(cmd, "quit"))
97 {
98 cleanup();
99 exit(0);
100 }
101 server_send(cmd);
102 input_hidden = -1;
103 io_loop(0);
104 input_hidden = 0;
105 free(cmd);
106 }
c51f132d
MM
107 }
108 free(cmd_buffer);
109}
110
fae0396e
MM
111void
112input_start_list(void) /* Leave the currently edited line and make space for listing */
113{
114 _rl_move_vert(_rl_vis_botlin);
115 crlf();
116}
117
118void
119input_stop_list(void) /* Reprint the currently edited line after listing */
120{
121 rl_on_new_line();
122 rl_redisplay();
123}
124
0223d4ff
MM
125static int
126input_complete(int arg, int key)
127{
fae0396e
MM
128 static int complete_flag;
129 char buf[256];
130
131 if (rl_last_func != input_complete)
132 complete_flag = 0;
133 switch (cmd_complete(rl_line_buffer, rl_point, buf, complete_flag))
134 {
135 case 0:
136 complete_flag = 1;
137 break;
138 case 1:
139 rl_insert_text(buf);
140 break;
141 default:
142 complete_flag = 1;
143 ding();
144 }
0223d4ff
MM
145 return 0;
146}
147
148static int
149input_help(int arg, int key)
150{
151 int i = 0;
152
fae0396e 153 if (arg != 1)
0223d4ff 154 return rl_insert(arg, '?');
fae0396e 155 while (i < rl_point)
0223d4ff
MM
156 {
157 if (rl_line_buffer[i++] == '"')
158 do
159 {
fae0396e 160 if (i >= rl_point) /* `?' inside quoted string -> insert */
0223d4ff
MM
161 return rl_insert(1, '?');
162 }
163 while (rl_line_buffer[i++] != '"');
164 }
fae0396e
MM
165 rl_begin_undo_group(); /* HACK: We want to display `?' at point position */
166 rl_insert_text("?");
0223d4ff 167 rl_redisplay();
fae0396e
MM
168 rl_end_undo_group();
169 input_start_list();
170 cmd_help(rl_line_buffer, rl_point);
171 rl_undo_command(1, 0);
172 input_stop_list();
0223d4ff
MM
173 return 0;
174}
175
c51f132d
MM
176static void
177input_init(void)
178{
179 rl_readline_name = "birdc";
0223d4ff
MM
180 rl_add_defun("bird-complete", input_complete, '\t');
181 rl_add_defun("bird-help", input_help, '?');
c51f132d
MM
182 rl_callback_handler_install("bird> ", got_line);
183 input_initialized = 1;
184 if (fcntl(0, F_SETFL, O_NONBLOCK) < 0)
185 die("fcntl: %m");
186}
187
188static void
189input_hide(void)
190{
191 if (input_hidden)
192 return;
193 if (rl_line_buffer)
194 {
195 input_hidden_end = rl_end;
196 rl_end = 0;
197 rl_expand_prompt("");
198 rl_redisplay();
199 input_hidden = 1;
200 }
201}
202
203static void
204input_reveal(void)
205{
206 if (input_hidden <= 0)
207 return;
208 rl_end = input_hidden_end;
209 rl_expand_prompt("bird> ");
210 rl_forced_update_display();
211 input_hidden = 0;
212}
213
214void
215cleanup(void)
216{
217 if (input_initialized)
218 {
219 input_initialized = 0;
220 input_hide();
221 rl_callback_handler_remove();
222 }
223}
224
225/*** Communication with server ***/
226
227static void
228server_connect(void)
229{
230 struct sockaddr_un sa;
231
232 server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
233 if (server_fd < 0)
234 die("Cannot create socket: %m");
235 bzero(&sa, sizeof(sa));
236 sa.sun_family = AF_UNIX;
237 strcpy(sa.sun_path, server_path);
238 if (connect(server_fd, (struct sockaddr *) &sa, sizeof(struct sockaddr)) < 0)
239 die("Unable to connect to server control socket (%s): %m", server_path);
240 if (fcntl(server_fd, F_SETFL, O_NONBLOCK) < 0)
241 die("fcntl: %m");
242}
243
244static void
245server_got_reply(char *x)
246{
247 int code;
248
249 input_hide();
250 if (*x == '+') /* Async reply */
251 printf(">>> %s\n", x+1);
252 else if (x[0] == ' ') /* Continuation */
54fb7701 253 printf("%s%s\n", verbose ? " " : "", x+1);
c51f132d
MM
254 else if (strlen(x) > 4 &&
255 sscanf(x, "%d", &code) == 1 && code >= 0 && code < 10000 &&
256 (x[4] == ' ' || x[4] == '-'))
257 {
258 if (code)
259 printf("%s\n", verbose ? x : x+5);
260 if (x[4] == ' ')
261 server_reply = code;
262 }
263 else
264 printf("??? <%s>\n", x);
265}
266
267static void
268server_read(void)
269{
270 int c;
271 byte *start, *p;
272
273 c = read(server_fd, server_read_pos, server_read_buf + sizeof(server_read_buf) - server_read_pos);
274 if (!c)
275 die("Connection closed by server.");
276 if (c < 0)
277 die("Server read error: %m");
278 start = server_read_buf;
279 p = server_read_pos;
280 server_read_pos += c;
281 while (p < server_read_pos)
282 if (*p++ == '\n')
283 {
284 p[-1] = 0;
285 server_got_reply(start);
286 start = p;
287 }
288 if (start != server_read_buf)
289 {
290 int l = server_read_pos - start;
291 memmove(server_read_buf, start, l);
292 server_read_pos = server_read_buf + l;
293 }
294 else if (server_read_pos == server_read_buf + sizeof(server_read_buf))
295 {
296 strcpy(server_read_buf, "?<too-long>");
297 server_read_pos = server_read_buf + 11;
298 }
299}
300
301static fd_set select_fds;
302
303static void
304io_loop(int mode)
305{
306 server_reply = -1;
307 while (mode || server_reply < 0)
308 {
309 FD_SET(server_fd, &select_fds);
310 if (mode)
311 FD_SET(0, &select_fds);
312 select(server_fd+1, &select_fds, NULL, NULL, NULL);
313 if (FD_ISSET(server_fd, &select_fds))
314 {
315 server_read();
316 if (mode)
317 input_reveal();
318 }
319 if (FD_ISSET(0, &select_fds))
320 rl_callback_read_char();
321 }
322 input_reveal();
323}
324
325static void
326server_send(char *cmd)
327{
328 int l = strlen(cmd);
329 byte *z = alloca(l + 1);
330
331 memcpy(z, cmd, l);
332 z[l++] = '\n';
333 while (l)
334 {
335 int cnt = write(server_fd, z, l);
336 if (cnt < 0)
337 {
338 if (errno == -EAGAIN)
339 {
340 fd_set set;
341 FD_ZERO(&set);
342 do
343 {
344 FD_SET(server_fd, &set);
345 select(server_fd+1, NULL, &set, NULL, NULL);
346 }
347 while (!FD_ISSET(server_fd, &set));
348 }
349 else
350 die("Server write error: %m");
351 }
352 else
353 {
354 l -= cnt;
355 z += cnt;
356 }
357 }
7211be1c
MM
358}
359
ed608150
MM
360int
361main(int argc, char **argv)
362{
9fac310d
MM
363#ifdef HAVE_LIBDMALLOC
364 if (!getenv("DMALLOC_OPTIONS"))
365 dmalloc_debug(0x2f03d00);
366#endif
367
368 parse_args(argc, argv);
0223d4ff 369 cmd_build_tree();
c51f132d
MM
370 server_connect();
371 io_loop(0);
9fac310d 372
c51f132d
MM
373 input_init();
374
375 io_loop(1);
376 return 0;
ed608150 377}