Statistics
| Branch: | Revision:

iof-bird-daemon / client / birdcl / client.c @ 568d9c9f

History | View | Annotate | Download (7.09 KB)

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

    
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <fcntl.h>
13
#include <unistd.h>
14
#include <termios.h>
15
#include <errno.h>
16
#include <sys/socket.h>
17
#include <sys/un.h>
18
#include <sys/types.h>
19
#include <sys/ioctl.h>
20
#include <signal.h>
21
#include <ctype.h>
22

    
23
#include "nest/bird.h"
24
#include "lib/resource.h"
25
#include "lib/string.h"
26
#include "client/client.h"
27
#include "sysdep/unix/unix.h"
28

    
29
#define INPUT_BUF_LEN 2048
30

    
31
static char *opt_list = "s:vr";
32
static int verbose;
33
static char *init_cmd;
34
static int once;
35

    
36
extern char *server_path;
37
extern int server_fd;
38

    
39
extern int cstate;
40
extern int num_lines, skip_input, interactive;
41

    
42
static int term_lns=25;
43
static int term_cls=80;
44
struct termios tty_save;
45

    
46
void
47
input_start_list(void)
48
{
49
        /* Empty in non-ncurses version. */
50
}
51

    
52
void
53
input_stop_list(void)
54
{
55
        /* Empty in non-ncurses version. */
56
}
57

    
58
/*** Parsing of arguments ***/
59

    
60
static void
61
usage(void)
62
{
63
  fprintf(stderr, "Usage: birdc [-s <control-socket>] [-v] [-r]\n");
64
  exit(1);
65
}
66

    
67
static void
68
parse_args(int argc, char **argv)
69
{
70
  int c;
71

    
72
  while ((c = getopt(argc, argv, opt_list)) >= 0)
73
    switch (c)
74
      {
75
      case 's':
76
        server_path = optarg;
77
        break;
78
      case 'v':
79
        verbose++;
80
        break;
81
      case 'r':
82
        init_cmd = "restrict";
83
        break;
84
      default:
85
        usage();
86
      }
87

    
88
  /* If some arguments are not options, we take it as commands */
89
  if (optind < argc)
90
    {
91
      char *tmp;
92
      int i;
93
      int len = 0;
94

    
95
      if (init_cmd)
96
        usage();
97

    
98
      for (i = optind; i < argc; i++)
99
        len += strlen(argv[i]) + 1;
100

    
101
      tmp = init_cmd = malloc(len);
102
      for (i = optind; i < argc; i++)
103
        {
104
          strcpy(tmp, argv[i]);
105
          tmp += strlen(tmp);
106
          *tmp++ = ' ';
107
        }
108
      tmp[-1] = 0;
109

    
110
      once = 1;
111
    }
112
}
113

    
114
static void
115
run_init_cmd(void)
116
{
117
  if (init_cmd)
118
    {
119
      /* First transition - client received hello from BIRD
120
         and there is waiting initial command */
121
      submit_server_command(init_cmd);
122
      init_cmd = NULL;
123
      return;
124
    }
125

    
126
  if (!init_cmd && once && (cstate == STATE_PROMPT))
127
    {
128
      /* Initial command is finished and we want to exit */
129
      cleanup();
130
      exit(0);
131
    }
132
}
133

    
134
/*** Input ***/
135

    
136
static void
137
got_line(char *cmd_buffer)
138
{
139
  char *cmd;
140

    
141
  if (!cmd_buffer)
142
    {
143
      cleanup();
144
      exit(0);
145
    }
146
  if (cmd_buffer[0])
147
    {
148
      cmd = cmd_expand(cmd_buffer);
149
      if (cmd)
150
        {
151
          if (!handle_internal_command(cmd))
152
            submit_server_command(cmd);
153

    
154
          free(cmd);
155
        }
156
    }
157
  free(cmd_buffer);
158
}
159

    
160
void
161
cleanup(void)
162
{
163
  /* No ncurses -> restore terminal state. */
164
  if (interactive)
165
    if (tcsetattr (0, TCSANOW, &tty_save) != 0)
166
      {
167
        perror("tcsetattr error");
168
        exit(EXIT_FAILURE);
169
      }
170
}
171

    
172
static void
173
print_prompt(void)
174
{
175
  /* No ncurses -> no status to reveal/hide, print prompt manually. */
176
  printf("bird> ");
177
  fflush(stdout);
178
}
179

    
180

    
181
static int lastnb(char *str)
182
{
183
  int i;
184
  for (i=strlen(str)-1; i>0; i--)
185
    {
186
      if(!isblank(str[i]))
187
        return i;
188
    }
189

    
190
  return 0;
191
}
192

    
193
static void
194
term_read(void)
195
{
196
  char *buf = malloc(INPUT_BUF_LEN);
197

    
198
  if (fgets(buf, INPUT_BUF_LEN, stdin) == NULL) {
199
    free(buf);
200
    exit(0);
201
  }
202

    
203
  if (buf[strlen(buf)-1] != '\n')
204
    {
205
      printf("Input too long.\n");
206
      free(buf);
207
      return;
208
    }
209

    
210
  if (strlen(buf) <= 0)
211
    {
212
      free(buf);
213
      return;
214
    }
215

    
216
  buf[strlen(buf)-1] = '\0';
217

    
218
  if (!interactive)
219
    {
220
      print_prompt();
221
      printf("%s\n",buf);
222
    }
223

    
224
  if (buf[lastnb(buf)] == '?')
225
    {
226
      printf("\n");
227
      cmd_help(buf, strlen(buf));
228
      free(buf);
229
      return;
230
    }
231

    
232
  if (strlen(buf) > 0)
233
    {
234
      got_line(buf); /* buf is free()-ed inside */
235
    }
236
  else
237
    {
238
      free(buf); /* no command, only newline -> no-op */
239
      return;
240
    }
241

    
242
}
243

    
244
/*** Communication with server ***/
245

    
246
void
247
more(void)
248
{
249
  struct termios tty;
250

    
251
  printf("--More--\015");
252
  fflush(stdout);
253

    
254
  if (tcgetattr(0, &tty) != 0)
255
    {
256
      perror("tcgetattr error");
257
      exit(EXIT_FAILURE);
258
    }
259
  tty.c_lflag &= (~ECHO);
260
  tty.c_lflag &= (~ICANON);
261
  if (tcsetattr (0, TCSANOW, &tty) != 0)
262
    {
263
      perror("tcsetattr error");
264
      exit(EXIT_FAILURE);
265
    }
266

    
267
 redo:
268
  switch (getchar())
269
    {
270
    case 32:
271
      num_lines = 2;
272
      break;
273
    case 13:
274
      num_lines--;
275
      break;
276
    case '\n':
277
      num_lines--;
278
      break;
279
    case 'q':
280
      skip_input = 1;
281
      break;
282
    default:
283
      goto redo;
284
    }
285

    
286
  tty.c_lflag |= ECHO;
287
  tty.c_lflag |= ICANON;
288
  if (tcsetattr (0, TCSANOW, &tty) != 0)
289
    {
290
      perror("tcsetattr error");
291
      exit(EXIT_FAILURE);
292
    }
293

    
294
  printf("        \015");
295
  fflush(stdout);
296
}
297

    
298
static void
299
get_term_size(void)
300
{
301
  struct winsize tws;
302
  if (ioctl(0, TIOCGWINSZ, &tws) == 0)
303
    {
304
      term_lns = tws.ws_row;
305
      term_cls = tws.ws_col;
306
    }
307
  else
308
    {
309
       term_lns = 25;
310
       term_cls = 80;
311
    }
312
}
313

    
314
#define PRINTF(LEN, PARGS...) do { if (!skip_input) len = printf(PARGS); } while(0)
315

    
316
void
317
server_got_reply(char *x)
318
{
319
  int code;
320
  int len = 0;
321

    
322
  if (*x == '+')                        /* Async reply */
323
    PRINTF(len, ">>> %s\n", x+1);
324
  else if (x[0] == ' ')                 /* Continuation */
325
    PRINTF(len, "%s%s\n", verbose ? "     " : "", x+1);
326
  else if (strlen(x) > 4 &&
327
           sscanf(x, "%d", &code) == 1 && code >= 0 && code < 10000 &&
328
           (x[4] == ' ' || x[4] == '-'))
329
    {
330
      if (code)
331
        PRINTF(len, "%s\n", verbose ? x : x+5);
332

    
333
      if (x[4] == ' ')
334
      {
335
        cstate = STATE_PROMPT;
336
        skip_input = 0;
337
        return;
338
      }
339
    }
340
  else
341
    PRINTF(len, "??? <%s>\n", x);
342

    
343
  if (skip_input)
344
    return;
345

    
346
  if (interactive && (len > 0))
347
    {
348
      num_lines += (len + term_cls - 1) / term_cls; /* Divide and round up */
349
      if (num_lines >= term_lns)
350
        more();
351
    }
352
}
353

    
354
static fd_set select_fds;
355

    
356
static void
357
select_loop(void)
358
{
359
  int rv;
360

    
361
  while (1)
362
    {
363
      FD_ZERO(&select_fds);
364

    
365
      if (cstate != STATE_CMD_USER)
366
        FD_SET(server_fd, &select_fds);
367

    
368
      if (cstate != STATE_CMD_SERVER)
369
        {
370
          FD_SET(0, &select_fds);
371
          if (interactive)
372
            print_prompt();
373
        }
374

    
375
      rv = select(server_fd+1, &select_fds, NULL, NULL, NULL);
376
      if (rv < 0)
377
        {
378
          if (errno == EINTR)
379
            continue;
380
          else
381
            die("select: %m");
382
        }
383

    
384
      if (FD_ISSET(server_fd, &select_fds))
385
        {
386
          server_read();
387
          run_init_cmd();
388
        }
389

    
390
      if (FD_ISSET(0, &select_fds))
391
        term_read();
392
    }
393
}
394

    
395
static void
396
sig_handler(int signal)
397
{
398
  cleanup();
399
  exit(0);
400
}
401

    
402
int
403
main(int argc, char **argv)
404
{
405
  interactive = isatty(fileno(stdin));
406
  if (interactive)
407
    {
408
      if (signal(SIGINT, sig_handler) == SIG_IGN)
409
        signal(SIGINT, SIG_IGN);
410
      if (signal(SIGHUP, sig_handler) == SIG_IGN)
411
        signal(SIGHUP, SIG_IGN);
412
      if (signal(SIGTERM, sig_handler) == SIG_IGN)
413
        signal(SIGTERM, SIG_IGN);
414

    
415
      get_term_size();
416

    
417
      if (tcgetattr(0, &tty_save) != 0)
418
        {
419
          perror("tcgetattr error");
420
          return(EXIT_FAILURE);
421
        }
422
    }
423

    
424
  parse_args(argc, argv);
425
  cmd_build_tree();
426
  server_connect();
427
  select_loop();
428
  return 0;
429
}