Statistics
| Branch: | Revision:

iof-bird-daemon / client / client.c @ 2983460b

History | View | Annotate | Download (7.22 KB)

1
/*
2
 *        BIRD Client
3
 *
4
 *        (c) 1999--2000 Martin Mares <mj@ucw.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8

    
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <fcntl.h>
12
#include <unistd.h>
13
#include <errno.h>
14
#include <sys/socket.h>
15
#include <sys/un.h>
16
#include <sys/time.h>
17
#include <sys/types.h>
18
#include <readline/readline.h>
19
#include <readline/history.h>
20

    
21
#include "nest/bird.h"
22
#include "lib/resource.h"
23
#include "lib/string.h"
24
#include "client/client.h"
25

    
26
static char *opt_list = "s:v";
27
static int verbose;
28

    
29
static char *server_path = PATH_CONTROL_SOCKET;
30
static int server_fd;
31
static int server_reply;
32
static byte server_read_buf[4096];
33
static byte *server_read_pos = server_read_buf;
34

    
35
static int input_initialized;
36
static int input_hidden;
37
static int input_hidden_end;
38

    
39
/*** Parsing of arguments ***/
40

    
41
static void
42
usage(void)
43
{
44
  fprintf(stderr, "Usage: birdc [-s <control-socket>] [-v]\n");
45
  exit(1);
46
}
47

    
48
static void
49
parse_args(int argc, char **argv)
50
{
51
  int c;
52

    
53
  while ((c = getopt(argc, argv, opt_list)) >= 0)
54
    switch (c)
55
      {
56
      case 's':
57
        server_path = optarg;
58
        break;
59
      case 'v':
60
        verbose++;
61
        break;
62
      default:
63
        usage();
64
      }
65
  if (optind < argc)
66
    usage();
67
}
68

    
69
/*** Input ***/
70

    
71
static void server_send(char *);
72
static void io_loop(int);
73

    
74
/* HACK: libreadline internals we need to access */
75
extern int _rl_vis_botlin;
76
extern void _rl_move_vert(int);
77
extern Function *rl_last_func;
78

    
79
static int
80
handle_internal_command(char *cmd)
81
{
82
  if (!strncmp(cmd, "exit", 4) || !strncmp(cmd, "quit", 4))
83
    {
84
      cleanup();
85
      exit(0);
86
    }
87
  if (!strncmp(cmd, "help", 4))
88
    {
89
      puts("Press `?' for context sensitive help.");
90
      return 1;
91
    }
92
  return 0;
93
}
94

    
95
static void
96
got_line(char *cmd_buffer)
97
{
98
  char *cmd;
99

    
100
  if (!cmd_buffer)
101
    {
102
      cleanup();
103
      exit(0);
104
    }
105
  if (cmd_buffer[0])
106
    {
107
      cmd = cmd_expand(cmd_buffer);
108
      if (cmd)
109
        {
110
          add_history(cmd);
111
          if (!handle_internal_command(cmd))
112
            {
113
              server_send(cmd);
114
              input_hidden = -1;
115
              io_loop(0);
116
              input_hidden = 0;
117
            }
118
          free(cmd);
119
        }
120
      else
121
        add_history(cmd_buffer);
122
    }
123
  free(cmd_buffer);
124
}
125

    
126
void
127
input_start_list(void)                        /* Leave the currently edited line and make space for listing */
128
{
129
  _rl_move_vert(_rl_vis_botlin);
130
  crlf();
131
}
132

    
133
void
134
input_stop_list(void)                        /* Reprint the currently edited line after listing */
135
{
136
  rl_on_new_line();
137
  rl_redisplay();
138
}
139

    
140
static int
141
input_complete(int arg, int key)
142
{
143
  static int complete_flag;
144
  char buf[256];
145

    
146
  if (rl_last_func != input_complete)
147
    complete_flag = 0;
148
  switch (cmd_complete(rl_line_buffer, rl_point, buf, complete_flag))
149
    {
150
    case 0:
151
      complete_flag = 1;
152
      break;
153
    case 1:
154
      rl_insert_text(buf);
155
      break;
156
    default:
157
      complete_flag = 1;
158
      ding();
159
    }
160
  return 0;
161
}
162

    
163
static int
164
input_help(int arg, int key)
165
{
166
  int i = 0;
167

    
168
  if (arg != 1)
169
    return rl_insert(arg, '?');
170
  while (i < rl_point)
171
    {
172
      if (rl_line_buffer[i++] == '"')
173
        do
174
          {
175
            if (i >= rl_point)                /* `?' inside quoted string -> insert */
176
              return rl_insert(1, '?');
177
          }
178
        while (rl_line_buffer[i++] != '"');
179
    }
180
  rl_begin_undo_group();                /* HACK: We want to display `?' at point position */
181
  rl_insert_text("?");
182
  rl_redisplay();
183
  rl_end_undo_group();
184
  input_start_list();
185
  cmd_help(rl_line_buffer, rl_point);
186
  rl_undo_command(1, 0);
187
  input_stop_list();
188
  return 0;
189
}
190

    
191
static void
192
input_init(void)
193
{
194
  rl_readline_name = "birdc";
195
  rl_add_defun("bird-complete", input_complete, '\t');
196
  rl_add_defun("bird-help", input_help, '?');
197
  rl_callback_handler_install("bird> ", got_line);
198
  input_initialized = 1;
199
  if (fcntl(0, F_SETFL, O_NONBLOCK) < 0)
200
    die("fcntl: %m");
201
}
202

    
203
static void
204
input_hide(void)
205
{
206
  if (input_hidden)
207
    return;
208
  if (rl_line_buffer)
209
    {
210
      input_hidden_end = rl_end;
211
      rl_end = 0;
212
      rl_expand_prompt("");
213
      rl_redisplay();
214
      input_hidden = 1;
215
    }
216
}
217

    
218
static void
219
input_reveal(void)
220
{
221
  if (input_hidden <= 0)
222
    return;
223
  rl_end = input_hidden_end;
224
  rl_expand_prompt("bird> ");
225
  rl_forced_update_display();
226
  input_hidden = 0;
227
}
228

    
229
void
230
cleanup(void)
231
{
232
  if (input_initialized)
233
    {
234
      input_initialized = 0;
235
      input_hide();
236
      rl_callback_handler_remove();
237
    }
238
}
239

    
240
/*** Communication with server ***/
241

    
242
static void
243
server_connect(void)
244
{
245
  struct sockaddr_un sa;
246

    
247
  server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
248
  if (server_fd < 0)
249
    die("Cannot create socket: %m");
250
  bzero(&sa, sizeof(sa));
251
  sa.sun_family = AF_UNIX;
252
  strcpy(sa.sun_path, server_path);
253
  if (connect(server_fd, (struct sockaddr *) &sa, sizeof(struct sockaddr)) < 0)
254
    die("Unable to connect to server control socket (%s): %m", server_path);
255
  if (fcntl(server_fd, F_SETFL, O_NONBLOCK) < 0)
256
    die("fcntl: %m");
257
}
258

    
259
static void
260
server_got_reply(char *x)
261
{
262
  int code;
263

    
264
  input_hide();
265
  if (*x == '+')                        /* Async reply */
266
    printf(">>> %s\n", x+1);
267
  else if (x[0] == ' ')                        /* Continuation */
268
    printf("%s%s\n", verbose ? "     " : "", x+1);
269
  else if (strlen(x) > 4 &&
270
           sscanf(x, "%d", &code) == 1 && code >= 0 && code < 10000 &&
271
           (x[4] == ' ' || x[4] == '-'))
272
    {
273
      if (code)
274
        printf("%s\n", verbose ? x : x+5);
275
      if (x[4] == ' ')
276
        server_reply = code;
277
    }
278
  else
279
    printf("??? <%s>\n", x);
280
}
281

    
282
static void
283
server_read(void)
284
{
285
  int c;
286
  byte *start, *p;
287

    
288
  c = read(server_fd, server_read_pos, server_read_buf + sizeof(server_read_buf) - server_read_pos);
289
  if (!c)
290
    die("Connection closed by server.");
291
  if (c < 0)
292
    die("Server read error: %m");
293
  start = server_read_buf;
294
  p = server_read_pos;
295
  server_read_pos += c;
296
  while (p < server_read_pos)
297
    if (*p++ == '\n')
298
      {
299
        p[-1] = 0;
300
        server_got_reply(start);
301
        start = p;
302
      }
303
  if (start != server_read_buf)
304
    {
305
      int l = server_read_pos - start;
306
      memmove(server_read_buf, start, l);
307
      server_read_pos = server_read_buf + l;
308
    }
309
  else if (server_read_pos == server_read_buf + sizeof(server_read_buf))
310
    {
311
      strcpy(server_read_buf, "?<too-long>");
312
      server_read_pos = server_read_buf + 11;
313
    }
314
}
315

    
316
static fd_set select_fds;
317

    
318
static void
319
io_loop(int mode)
320
{
321
  server_reply = -1;
322
  while (mode || server_reply < 0)
323
    {
324
      FD_ZERO(&select_fds);
325
      FD_SET(server_fd, &select_fds);
326
      if (mode)
327
        FD_SET(0, &select_fds);
328
      select(server_fd+1, &select_fds, NULL, NULL, NULL);
329
      if (FD_ISSET(server_fd, &select_fds))
330
        {
331
          server_read();
332
          if (mode)
333
            input_reveal();
334
        }
335
      if (FD_ISSET(0, &select_fds))
336
        rl_callback_read_char();
337
    }
338
  input_reveal();
339
}
340

    
341
static void
342
server_send(char *cmd)
343
{
344
  int l = strlen(cmd);
345
  byte *z = alloca(l + 1);
346

    
347
  memcpy(z, cmd, l);
348
  z[l++] = '\n';
349
  while (l)
350
    {
351
      int cnt = write(server_fd, z, l);
352
      if (cnt < 0)
353
        {
354
          if (errno == -EAGAIN)
355
            {
356
              fd_set set;
357
              FD_ZERO(&set);
358
              do
359
                {
360
                  FD_SET(server_fd, &set);
361
                  select(server_fd+1, NULL, &set, NULL, NULL);
362
                }
363
              while (!FD_ISSET(server_fd, &set));
364
            }
365
          else
366
            die("Server write error: %m");
367
        }
368
      else
369
        {
370
          l -= cnt;
371
          z += cnt;
372
        }
373
    }
374
}
375

    
376
int
377
main(int argc, char **argv)
378
{
379
#ifdef HAVE_LIBDMALLOC
380
  if (!getenv("DMALLOC_OPTIONS"))
381
    dmalloc_debug(0x2f03d00);
382
#endif
383

    
384
  parse_args(argc, argv);
385
  cmd_build_tree();
386
  server_connect();
387
  io_loop(0);
388

    
389
  input_init();
390

    
391
  io_loop(1);
392
  return 0;
393
}