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>