Annotation of embedaddon/bird2/client/client.c, revision 1.1
1.1 ! misho 1: /*
! 2: * BIRD Client
! 3: *
! 4: * (c) 1999--2004 Martin Mares <mj@ucw.cz>
! 5: * (c) 2013 Tomas Hlavacek <tmshlvck@gmail.com>
! 6: *
! 7: * Can be freely distributed and used under the terms of the GNU GPL.
! 8: */
! 9:
! 10: /**
! 11: * DOC: BIRD client
! 12: *
! 13: * There are two variants of BIRD client: regular and light. regular
! 14: * variant depends on readline and ncurses libraries, while light
! 15: * variant uses just libc. Most of the code and the main() is common
! 16: * for both variants (in client.c file) and just a few functions are
! 17: * different (in birdc.c for regular and birdcl.c for light). Two
! 18: * binaries are generated by linking common object files like client.o
! 19: * (which is compiled from client.c just once) with either birdc.o or
! 20: * birdcl.o for each variant.
! 21: */
! 22:
! 23: #include <stdio.h>
! 24: #include <stdlib.h>
! 25: #include <fcntl.h>
! 26: #include <unistd.h>
! 27: #include <errno.h>
! 28: #include <sys/select.h>
! 29: #include <sys/socket.h>
! 30: #include <sys/types.h>
! 31: #include <sys/un.h>
! 32:
! 33: #include "nest/bird.h"
! 34: #include "lib/resource.h"
! 35: #include "lib/string.h"
! 36: #include "client/client.h"
! 37: #include "sysdep/unix/unix.h"
! 38:
! 39: #define SERVER_READ_BUF_LEN 4096
! 40:
! 41: static char *opt_list = "s:vrl";
! 42: static int verbose, restricted, once;
! 43: static char *init_cmd;
! 44:
! 45: static char *server_path = PATH_CONTROL_SOCKET;
! 46: static int server_fd;
! 47: static byte server_read_buf[SERVER_READ_BUF_LEN];
! 48: static byte *server_read_pos = server_read_buf;
! 49:
! 50: int init = 1; /* During intial sequence */
! 51: int busy = 1; /* Executing BIRD command */
! 52: int interactive; /* Whether stdin is terminal */
! 53:
! 54: static int num_lines, skip_input;
! 55: int term_lns, term_cls;
! 56:
! 57:
! 58: /*** Parsing of arguments ***/
! 59:
! 60: static void
! 61: usage(char *name)
! 62: {
! 63: fprintf(stderr, "Usage: %s [-s <control-socket>] [-v] [-r] [-l]\n", name);
! 64: exit(1);
! 65: }
! 66:
! 67: static void
! 68: parse_args(int argc, char **argv)
! 69: {
! 70: int server_changed = 0;
! 71: int c;
! 72:
! 73: while ((c = getopt(argc, argv, opt_list)) >= 0)
! 74: switch (c)
! 75: {
! 76: case 's':
! 77: server_path = optarg;
! 78: server_changed = 1;
! 79: break;
! 80: case 'v':
! 81: verbose++;
! 82: break;
! 83: case 'r':
! 84: restricted = 1;
! 85: break;
! 86: case 'l':
! 87: if (!server_changed)
! 88: server_path = xbasename(server_path);
! 89: break;
! 90: default:
! 91: usage(argv[0]);
! 92: }
! 93:
! 94: /* If some arguments are not options, we take it as commands */
! 95: if (optind < argc)
! 96: {
! 97: char *tmp;
! 98: int i;
! 99: int len = 0;
! 100:
! 101: for (i = optind; i < argc; i++)
! 102: len += strlen(argv[i]) + 1;
! 103:
! 104: tmp = init_cmd = malloc(len);
! 105: for (i = optind; i < argc; i++)
! 106: {
! 107: strcpy(tmp, argv[i]);
! 108: tmp += strlen(tmp);
! 109: *tmp++ = ' ';
! 110: }
! 111: tmp[-1] = 0;
! 112:
! 113: once = 1;
! 114: interactive = 0;
! 115: }
! 116: }
! 117:
! 118:
! 119: /*** Input ***/
! 120:
! 121: static void server_send(char *cmd);
! 122:
! 123: static int
! 124: handle_internal_command(char *cmd)
! 125: {
! 126: if (!strncmp(cmd, "exit", 4) || !strncmp(cmd, "quit", 4))
! 127: {
! 128: cleanup();
! 129: exit(0);
! 130: }
! 131: if (!strncmp(cmd, "help", 4))
! 132: {
! 133: puts("Press `?' for context sensitive help.");
! 134: return 1;
! 135: }
! 136: return 0;
! 137: }
! 138:
! 139: static void
! 140: submit_server_command(char *cmd)
! 141: {
! 142: busy = 1;
! 143: num_lines = 2;
! 144: server_send(cmd);
! 145: }
! 146:
! 147: static inline void
! 148: submit_init_command(char *cmd_raw)
! 149: {
! 150: char *cmd = cmd_expand(cmd_raw);
! 151:
! 152: if (!cmd)
! 153: {
! 154: cleanup();
! 155: exit(0);
! 156: }
! 157:
! 158: submit_server_command(cmd);
! 159: free(cmd);
! 160: }
! 161:
! 162: void
! 163: submit_command(char *cmd_raw)
! 164: {
! 165: char *cmd = cmd_expand(cmd_raw);
! 166:
! 167: if (!cmd)
! 168: return;
! 169:
! 170: if (!handle_internal_command(cmd))
! 171: submit_server_command(cmd);
! 172:
! 173: free(cmd);
! 174: }
! 175:
! 176: static void
! 177: init_commands(void)
! 178: {
! 179: if (restricted)
! 180: {
! 181: submit_server_command("restrict");
! 182: restricted = 0;
! 183: return;
! 184: }
! 185:
! 186: if (init_cmd)
! 187: {
! 188: /* First transition - client received hello from BIRD
! 189: and there is waiting initial command */
! 190: submit_init_command(init_cmd);
! 191: init_cmd = NULL;
! 192: return;
! 193: }
! 194:
! 195: if (once)
! 196: {
! 197: /* Initial command is finished and we want to exit */
! 198: cleanup();
! 199: exit(0);
! 200: }
! 201:
! 202: input_init();
! 203:
! 204: term_lns = (term_lns > 0) ? term_lns : 25;
! 205: term_cls = (term_cls > 0) ? term_cls : 80;
! 206:
! 207: init = 0;
! 208: }
! 209:
! 210:
! 211: /*** Output ***/
! 212:
! 213: void
! 214: more(void)
! 215: {
! 216: more_begin();
! 217: printf("--More--\015");
! 218: fflush(stdout);
! 219:
! 220: redo:
! 221: switch (getchar())
! 222: {
! 223: case ' ':
! 224: num_lines = 2;
! 225: break;
! 226: case '\n':
! 227: case '\r':
! 228: num_lines--;
! 229: break;
! 230: case 'q':
! 231: skip_input = 1;
! 232: break;
! 233: default:
! 234: goto redo;
! 235: }
! 236:
! 237: printf(" \015");
! 238: fflush(stdout);
! 239: more_end();
! 240: }
! 241:
! 242:
! 243: /*** Communication with server ***/
! 244:
! 245: static void
! 246: server_connect(void)
! 247: {
! 248: struct sockaddr_un sa;
! 249:
! 250: server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
! 251: if (server_fd < 0)
! 252: DIE("Cannot create socket");
! 253:
! 254: if (strlen(server_path) >= sizeof(sa.sun_path))
! 255: die("server_connect: path too long");
! 256:
! 257: bzero(&sa, sizeof(sa));
! 258: sa.sun_family = AF_UNIX;
! 259: strcpy(sa.sun_path, server_path);
! 260: if (connect(server_fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) < 0)
! 261: DIE("Unable to connect to server control socket (%s)", server_path);
! 262: if (fcntl(server_fd, F_SETFL, O_NONBLOCK) < 0)
! 263: DIE("fcntl");
! 264: }
! 265:
! 266:
! 267: #define PRINTF(LEN, PARGS...) do { if (!skip_input) len = printf(PARGS); } while(0)
! 268:
! 269: static void
! 270: server_got_reply(char *x)
! 271: {
! 272: int code;
! 273: int len = 0;
! 274:
! 275: if (*x == '+') /* Async reply */
! 276: PRINTF(len, ">>> %s\n", x+1);
! 277: else if (x[0] == ' ') /* Continuation */
! 278: PRINTF(len, "%s%s\n", verbose ? " " : "", x+1);
! 279: else if (strlen(x) > 4 &&
! 280: sscanf(x, "%d", &code) == 1 && code >= 0 && code < 10000 &&
! 281: (x[4] == ' ' || x[4] == '-'))
! 282: {
! 283: if (code)
! 284: PRINTF(len, "%s\n", verbose ? x : x+5);
! 285:
! 286: if (x[4] == ' ')
! 287: {
! 288: busy = 0;
! 289: skip_input = 0;
! 290: return;
! 291: }
! 292: }
! 293: else
! 294: PRINTF(len, "??? <%s>\n", x);
! 295:
! 296: if (interactive && busy && !skip_input && !init && (len > 0))
! 297: {
! 298: num_lines += (len + term_cls - 1) / term_cls; /* Divide and round up */
! 299: if (num_lines >= term_lns)
! 300: more();
! 301: }
! 302: }
! 303:
! 304: static void
! 305: server_read(void)
! 306: {
! 307: int c;
! 308: byte *start, *p;
! 309:
! 310: redo:
! 311: c = read(server_fd, server_read_pos, server_read_buf + sizeof(server_read_buf) - server_read_pos);
! 312: if (!c)
! 313: die("Connection closed by server");
! 314: if (c < 0)
! 315: {
! 316: if (errno == EINTR)
! 317: goto redo;
! 318: else
! 319: DIE("Server read error");
! 320: }
! 321:
! 322: start = server_read_buf;
! 323: p = server_read_pos;
! 324: server_read_pos += c;
! 325: while (p < server_read_pos)
! 326: if (*p++ == '\n')
! 327: {
! 328: p[-1] = 0;
! 329: server_got_reply(start);
! 330: start = p;
! 331: }
! 332: if (start != server_read_buf)
! 333: {
! 334: int l = server_read_pos - start;
! 335: memmove(server_read_buf, start, l);
! 336: server_read_pos = server_read_buf + l;
! 337: }
! 338: else if (server_read_pos == server_read_buf + sizeof(server_read_buf))
! 339: {
! 340: strcpy(server_read_buf, "?<too-long>");
! 341: server_read_pos = server_read_buf + 11;
! 342: }
! 343: }
! 344:
! 345: static void
! 346: select_loop(void)
! 347: {
! 348: int rv;
! 349: while (1)
! 350: {
! 351: if (init && !busy)
! 352: init_commands();
! 353:
! 354: if (!init)
! 355: input_notify(!busy);
! 356:
! 357: fd_set select_fds;
! 358: FD_ZERO(&select_fds);
! 359:
! 360: FD_SET(server_fd, &select_fds);
! 361: if (!busy)
! 362: FD_SET(0, &select_fds);
! 363:
! 364: rv = select(server_fd+1, &select_fds, NULL, NULL, NULL);
! 365: if (rv < 0)
! 366: {
! 367: if (errno == EINTR)
! 368: continue;
! 369: else
! 370: DIE("select");
! 371: }
! 372:
! 373: if (FD_ISSET(0, &select_fds))
! 374: {
! 375: input_read();
! 376: continue;
! 377: }
! 378:
! 379: if (FD_ISSET(server_fd, &select_fds))
! 380: {
! 381: server_read();
! 382: continue;
! 383: }
! 384: }
! 385: }
! 386:
! 387: static void
! 388: wait_for_write(int fd)
! 389: {
! 390: while (1)
! 391: {
! 392: int rv;
! 393: fd_set set;
! 394: FD_ZERO(&set);
! 395: FD_SET(fd, &set);
! 396:
! 397: rv = select(fd+1, NULL, &set, NULL, NULL);
! 398: if (rv < 0)
! 399: {
! 400: if (errno == EINTR)
! 401: continue;
! 402: else
! 403: DIE("select");
! 404: }
! 405:
! 406: if (FD_ISSET(server_fd, &set))
! 407: return;
! 408: }
! 409: }
! 410:
! 411: static void
! 412: server_send(char *cmd)
! 413: {
! 414: int l = strlen(cmd);
! 415: byte *z = alloca(l + 1);
! 416:
! 417: memcpy(z, cmd, l);
! 418: z[l++] = '\n';
! 419: while (l)
! 420: {
! 421: int cnt = write(server_fd, z, l);
! 422:
! 423: if (cnt < 0)
! 424: {
! 425: if (errno == EAGAIN)
! 426: wait_for_write(server_fd);
! 427: else if (errno == EINTR)
! 428: continue;
! 429: else
! 430: DIE("Server write error");
! 431: }
! 432: else
! 433: {
! 434: l -= cnt;
! 435: z += cnt;
! 436: }
! 437: }
! 438: }
! 439:
! 440: int
! 441: main(int argc, char **argv)
! 442: {
! 443: interactive = isatty(0);
! 444: parse_args(argc, argv);
! 445: cmd_build_tree();
! 446: server_connect();
! 447: select_loop();
! 448: return 0;
! 449: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>