a1f0304b8d6cd4b9f66d30344912a1c5e9d599e4
[osmocom-bb.git] / src / vty / vty.c
1
2 #include <stdio.h>
3 #include <stdarg.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <errno.h>
8 #include <ctype.h>
9 #include <termios.h>
10
11 #include <sys/utsname.h>
12 #include <sys/param.h>
13
14 #include <arpa/telnet.h>
15
16 #include <osmocom/vty/vty.h>
17 #include <osmocom/vty/command.h>
18 #include <osmocom/vty/buffer.h>
19 #include <osmocom/core/talloc.h>
20
21 #define SYSCONFDIR "/usr/local/etc"
22
23 /* our callback, located in telnet_interface.c */
24 void vty_event(enum event event, int sock, struct vty *vty);
25
26 extern struct host host;
27
28 /* Vector which store each vty structure. */
29 static vector vtyvec;
30
31 vector Vvty_serv_thread;
32
33 char *vty_cwd = NULL;
34
35 /* Configure lock. */
36 static int vty_config;
37
38 static int no_password_check = 1;
39
40 void *tall_vty_ctx;
41
42 static void vty_clear_buf(struct vty *vty)
43 {
44         memset(vty->buf, 0, vty->max);
45 }
46
47 /* Allocate new vty struct. */
48 struct vty *vty_new()
49 {
50         struct vty *new = talloc_zero(tall_vty_ctx, struct vty);
51
52         if (!new)
53                 goto out;
54
55         new->obuf = buffer_new(new, 0); /* Use default buffer size. */
56         if (!new->obuf)
57                 goto out_new;
58         new->buf = _talloc_zero(new, VTY_BUFSIZ, "vty_new->buf");
59         if (!new->buf)
60                 goto out_obuf;
61
62         new->max = VTY_BUFSIZ;
63
64         return new;
65
66 out_obuf:
67         buffer_free(new->obuf);
68 out_new:
69         talloc_free(new);
70         new = NULL;
71 out:
72         return new;
73 }
74
75 /* Authentication of vty */
76 static void vty_auth(struct vty *vty, char *buf)
77 {
78         char *passwd = NULL;
79         enum node_type next_node = 0;
80         int fail;
81         char *crypt(const char *, const char *);
82
83         switch (vty->node) {
84         case AUTH_NODE:
85 #ifdef VTY_CRYPT_PW
86                 if (host.encrypt)
87                         passwd = host.password_encrypt;
88                 else
89 #endif
90                         passwd = host.password;
91                 if (host.advanced)
92                         next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
93                 else
94                         next_node = VIEW_NODE;
95                 break;
96         case AUTH_ENABLE_NODE:
97 #ifdef VTY_CRYPT_PW
98                 if (host.encrypt)
99                         passwd = host.enable_encrypt;
100                 else
101 #endif
102                         passwd = host.enable;
103                 next_node = ENABLE_NODE;
104                 break;
105         }
106
107         if (passwd) {
108 #ifdef VTY_CRYPT_PW
109                 if (host.encrypt)
110                         fail = strcmp(crypt(buf, passwd), passwd);
111                 else
112 #endif
113                         fail = strcmp(buf, passwd);
114         } else
115                 fail = 1;
116
117         if (!fail) {
118                 vty->fail = 0;
119                 vty->node = next_node;  /* Success ! */
120         } else {
121                 vty->fail++;
122                 if (vty->fail >= 3) {
123                         if (vty->node == AUTH_NODE) {
124                                 vty_out(vty,
125                                         "%% Bad passwords, too many failures!%s",
126                                         VTY_NEWLINE);
127                                 vty->status = VTY_CLOSE;
128                         } else {
129                                 /* AUTH_ENABLE_NODE */
130                                 vty->fail = 0;
131                                 vty_out(vty,
132                                         "%% Bad enable passwords, too many failures!%s",
133                                         VTY_NEWLINE);
134                                 vty->node = VIEW_NODE;
135                         }
136                 }
137         }
138 }
139
140 /* Close vty interface. */
141 void vty_close(struct vty *vty)
142 {
143         int i;
144
145         if (vty->obuf)  {
146                 /* Flush buffer. */
147                 buffer_flush_all(vty->obuf, vty->fd);
148
149                 /* Free input buffer. */
150                 buffer_free(vty->obuf);
151                 vty->obuf = NULL;
152         }
153
154         /* Free command history. */
155         for (i = 0; i < VTY_MAXHIST; i++)
156                 if (vty->hist[i])
157                         talloc_free(vty->hist[i]);
158
159         /* Unset vector. */
160         vector_unset(vtyvec, vty->fd);
161
162         /* Close socket. */
163         if (vty->fd > 0)
164                 close(vty->fd);
165
166         if (vty->buf) {
167                 talloc_free(vty->buf);
168                 vty->buf = NULL;
169         }
170
171         /* Check configure. */
172         vty_config_unlock(vty);
173
174         /* VTY_CLOSED is handled by the telnet_interface */
175         vty_event(VTY_CLOSED, vty->fd, vty);
176
177         /* OK free vty. */
178         talloc_free(vty);
179 }
180
181 int vty_shell(struct vty *vty)
182 {
183         return vty->type == VTY_SHELL ? 1 : 0;
184 }
185
186
187 /* VTY standard output function. */
188 int vty_out(struct vty *vty, const char *format, ...)
189 {
190         va_list args;
191         int len = 0;
192         int size = 1024;
193         char buf[1024];
194         char *p = NULL;
195
196         if (vty_shell(vty)) {
197                 va_start(args, format);
198                 vprintf(format, args);
199                 va_end(args);
200         } else {
201                 /* Try to write to initial buffer.  */
202                 va_start(args, format);
203                 len = vsnprintf(buf, sizeof buf, format, args);
204                 va_end(args);
205
206                 /* Initial buffer is not enough.  */
207                 if (len < 0 || len >= size) {
208                         while (1) {
209                                 if (len > -1)
210                                         size = len + 1;
211                                 else
212                                         size = size * 2;
213
214                                 p = talloc_realloc_size(vty, p, size);
215                                 if (!p)
216                                         return -1;
217
218                                 va_start(args, format);
219                                 len = vsnprintf(p, size, format, args);
220                                 va_end(args);
221
222                                 if (len > -1 && len < size)
223                                         break;
224                         }
225                 }
226
227                 /* When initial buffer is enough to store all output.  */
228                 if (!p)
229                         p = buf;
230
231                 /* Pointer p must point out buffer. */
232                 buffer_put(vty->obuf, (u_char *) p, len);
233
234                 /* If p is not different with buf, it is allocated buffer.  */
235                 if (p != buf)
236                         talloc_free(p);
237         }
238
239         vty_event(VTY_WRITE, vty->fd, vty);
240
241         return len;
242 }
243
244 int vty_out_newline(struct vty *vty)
245 {
246         char *p = vty_newline(vty);
247         buffer_put(vty->obuf, p, strlen(p));
248         return 0;
249 }
250
251 void *vty_current_index(struct vty *vty)
252 {
253         return vty->index;
254 }
255 int vty_current_node(struct vty *vty)
256 {
257         return vty->node;
258 }
259
260 int vty_config_lock(struct vty *vty)
261 {
262         if (vty_config == 0) {
263                 vty->config = 1;
264                 vty_config = 1;
265         }
266         return vty->config;
267 }
268
269 int vty_config_unlock(struct vty *vty)
270 {
271         if (vty_config == 1 && vty->config == 1) {
272                 vty->config = 0;
273                 vty_config = 0;
274         }
275         return vty->config;
276 }
277
278 /* Say hello to vty interface. */
279 void vty_hello(struct vty *vty)
280 {
281         if (host.motdfile) {
282                 FILE *f;
283                 char buf[4096];
284
285                 f = fopen(host.motdfile, "r");
286                 if (f) {
287                         while (fgets(buf, sizeof(buf), f)) {
288                                 char *s;
289                                 /* work backwards to ignore trailling isspace() */
290                                 for (s = buf + strlen(buf);
291                                      (s > buf) && isspace(*(s - 1)); s--) ;
292                                 *s = '\0';
293                                 vty_out(vty, "%s%s", buf, VTY_NEWLINE);
294                         }
295                         fclose(f);
296                 } else
297                         vty_out(vty, "MOTD file not found%s", VTY_NEWLINE);
298         } else if (host.motd)
299                 vty_out(vty, "%s", host.motd);
300 }
301
302 /* Put out prompt and wait input from user. */
303 static void vty_prompt(struct vty *vty)
304 {
305         struct utsname names;
306         const char *hostname;
307
308         if (vty->type == VTY_TERM) {
309                 hostname = host.app_info->name;
310                 if (!hostname) {
311                         uname(&names);
312                         hostname = names.nodename;
313                 }
314                 vty_out(vty, cmd_prompt(vty->node), hostname);
315         }
316 }
317
318 /* Command execution over the vty interface. */
319 static int vty_command(struct vty *vty, char *buf)
320 {
321         int ret;
322         vector vline;
323
324         /* Split readline string up into the vector */
325         vline = cmd_make_strvec(buf);
326
327         if (vline == NULL)
328                 return CMD_SUCCESS;
329
330         ret = cmd_execute_command(vline, vty, NULL, 0);
331         if (ret != CMD_SUCCESS)
332                 switch (ret) {
333                 case CMD_WARNING:
334                         if (vty->type == VTY_FILE)
335                                 vty_out(vty, "Warning...%s", VTY_NEWLINE);
336                         break;
337                 case CMD_ERR_AMBIGUOUS:
338                         vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
339                         break;
340                 case CMD_ERR_NO_MATCH:
341                         vty_out(vty, "%% Unknown command.%s", VTY_NEWLINE);
342                         break;
343                 case CMD_ERR_INCOMPLETE:
344                         vty_out(vty, "%% Command incomplete.%s", VTY_NEWLINE);
345                         break;
346                 }
347         cmd_free_strvec(vline);
348
349         return ret;
350 }
351
352 static const char telnet_backward_char = 0x08;
353 static const char telnet_space_char = ' ';
354
355 /* Basic function to write buffer to vty. */
356 static void vty_write(struct vty *vty, const char *buf, size_t nbytes)
357 {
358         if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
359                 return;
360
361         /* Should we do buffering here ?  And make vty_flush (vty) ? */
362         buffer_put(vty->obuf, buf, nbytes);
363 }
364
365 /* Ensure length of input buffer.  Is buffer is short, double it. */
366 static void vty_ensure(struct vty *vty, int length)
367 {
368         if (vty->max <= length) {
369                 vty->max *= 2;
370                 vty->buf = talloc_realloc_size(vty, vty->buf, vty->max);
371                 // FIXME: check return
372         }
373 }
374
375 /* Basic function to insert character into vty. */
376 static void vty_self_insert(struct vty *vty, char c)
377 {
378         int i;
379         int length;
380
381         vty_ensure(vty, vty->length + 1);
382         length = vty->length - vty->cp;
383         memmove(&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
384         vty->buf[vty->cp] = c;
385
386         vty_write(vty, &vty->buf[vty->cp], length + 1);
387         for (i = 0; i < length; i++)
388                 vty_write(vty, &telnet_backward_char, 1);
389
390         vty->cp++;
391         vty->length++;
392 }
393
394 /* Self insert character 'c' in overwrite mode. */
395 static void vty_self_insert_overwrite(struct vty *vty, char c)
396 {
397         vty_ensure(vty, vty->length + 1);
398         vty->buf[vty->cp++] = c;
399
400         if (vty->cp > vty->length)
401                 vty->length++;
402
403         if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
404                 return;
405
406         vty_write(vty, &c, 1);
407 }
408
409 /* Insert a word into vty interface with overwrite mode. */
410 static void vty_insert_word_overwrite(struct vty *vty, char *str)
411 {
412         int len = strlen(str);
413         vty_write(vty, str, len);
414         strcpy(&vty->buf[vty->cp], str);
415         vty->cp += len;
416         vty->length = vty->cp;
417 }
418
419 /* Forward character. */
420 static void vty_forward_char(struct vty *vty)
421 {
422         if (vty->cp < vty->length) {
423                 vty_write(vty, &vty->buf[vty->cp], 1);
424                 vty->cp++;
425         }
426 }
427
428 /* Backward character. */
429 static void vty_backward_char(struct vty *vty)
430 {
431         if (vty->cp > 0) {
432                 vty->cp--;
433                 vty_write(vty, &telnet_backward_char, 1);
434         }
435 }
436
437 /* Move to the beginning of the line. */
438 static void vty_beginning_of_line(struct vty *vty)
439 {
440         while (vty->cp)
441                 vty_backward_char(vty);
442 }
443
444 /* Move to the end of the line. */
445 static void vty_end_of_line(struct vty *vty)
446 {
447         while (vty->cp < vty->length)
448                 vty_forward_char(vty);
449 }
450
451 /* Add current command line to the history buffer. */
452 static void vty_hist_add(struct vty *vty)
453 {
454         int index;
455
456         if (vty->length == 0)
457                 return;
458
459         index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
460
461         /* Ignore the same string as previous one. */
462         if (vty->hist[index])
463                 if (strcmp(vty->buf, vty->hist[index]) == 0) {
464                         vty->hp = vty->hindex;
465                         return;
466                 }
467
468         /* Insert history entry. */
469         if (vty->hist[vty->hindex])
470                 talloc_free(vty->hist[vty->hindex]);
471         vty->hist[vty->hindex] = talloc_strdup(vty, vty->buf);
472
473         /* History index rotation. */
474         vty->hindex++;
475         if (vty->hindex == VTY_MAXHIST)
476                 vty->hindex = 0;
477
478         vty->hp = vty->hindex;
479 }
480
481 /* Get telnet window size. */
482 static int
483 vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
484 {
485 #ifdef TELNET_OPTION_DEBUG
486   int i;
487
488   for (i = 0; i < nbytes; i++)
489     {
490       switch (buf[i])
491         {
492         case IAC:
493           vty_out (vty, "IAC ");
494           break;
495         case WILL:
496           vty_out (vty, "WILL ");
497           break;
498         case WONT:
499           vty_out (vty, "WONT ");
500           break;
501         case DO:
502           vty_out (vty, "DO ");
503           break;
504         case DONT:
505           vty_out (vty, "DONT ");
506           break;
507         case SB:
508           vty_out (vty, "SB ");
509           break;
510         case SE:
511           vty_out (vty, "SE ");
512           break;
513         case TELOPT_ECHO:
514           vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
515           break;
516         case TELOPT_SGA:
517           vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
518           break;
519         case TELOPT_NAWS:
520           vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
521           break;
522         default:
523           vty_out (vty, "%x ", buf[i]);
524           break;
525         }
526     }
527   vty_out (vty, "%s", VTY_NEWLINE);
528
529 #endif /* TELNET_OPTION_DEBUG */
530
531   switch (buf[0])
532     {
533     case SB:
534       vty->sb_len = 0;
535       vty->iac_sb_in_progress = 1;
536       return 0;
537       break;
538     case SE:
539       {
540         if (!vty->iac_sb_in_progress)
541           return 0;
542
543         if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
544           {
545             vty->iac_sb_in_progress = 0;
546             return 0;
547           }
548         switch (vty->sb_buf[0])
549           {
550           case TELOPT_NAWS:
551             if (vty->sb_len != TELNET_NAWS_SB_LEN)
552               vty_out(vty,"RFC 1073 violation detected: telnet NAWS option "
553                         "should send %d characters, but we received %lu",
554                         TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
555             else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
556               vty_out(vty, "Bug detected: sizeof(vty->sb_buf) %lu < %d, "
557                        "too small to handle the telnet NAWS option",
558                        (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
559             else
560               {
561                 vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
562                 vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
563 #ifdef TELNET_OPTION_DEBUG
564                 vty_out(vty, "TELNET NAWS window size negotiation completed: "
565                               "width %d, height %d%s",
566                         vty->width, vty->height, VTY_NEWLINE);
567 #endif
568               }
569             break;
570           }
571         vty->iac_sb_in_progress = 0;
572         return 0;
573         break;
574       }
575     default:
576       break;
577     }
578   return 1;
579 }
580
581 /* Execute current command line. */
582 static int vty_execute(struct vty *vty)
583 {
584         int ret;
585
586         ret = CMD_SUCCESS;
587
588         switch (vty->node) {
589         case AUTH_NODE:
590         case AUTH_ENABLE_NODE:
591                 vty_auth(vty, vty->buf);
592                 break;
593         default:
594                 ret = vty_command(vty, vty->buf);
595                 if (vty->type == VTY_TERM)
596                         vty_hist_add(vty);
597                 break;
598         }
599
600         /* Clear command line buffer. */
601         vty->cp = vty->length = 0;
602         vty_clear_buf(vty);
603
604         if (vty->status != VTY_CLOSE)
605                 vty_prompt(vty);
606
607         return ret;
608 }
609
610 /* Send WILL TELOPT_ECHO to remote server. */
611 static void
612 vty_will_echo (struct vty *vty)
613 {
614         unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
615         vty_out (vty, "%s", cmd);
616 }
617
618 /* Make suppress Go-Ahead telnet option. */
619 static void
620 vty_will_suppress_go_ahead (struct vty *vty)
621 {
622         unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
623         vty_out (vty, "%s", cmd);
624 }
625
626 /* Make don't use linemode over telnet. */
627 static void
628 vty_dont_linemode (struct vty *vty)
629 {
630         unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
631         vty_out (vty, "%s", cmd);
632 }
633
634 /* Use window size. */
635 static void
636 vty_do_window_size (struct vty *vty)
637 {
638         unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
639         vty_out (vty, "%s", cmd);
640 }
641
642 static void vty_kill_line_from_beginning(struct vty *);
643 static void vty_redraw_line(struct vty *);
644
645 /* Print command line history.  This function is called from
646    vty_next_line and vty_previous_line. */
647 static void vty_history_print(struct vty *vty)
648 {
649         int length;
650
651         vty_kill_line_from_beginning(vty);
652
653         /* Get previous line from history buffer */
654         length = strlen(vty->hist[vty->hp]);
655         memcpy(vty->buf, vty->hist[vty->hp], length);
656         vty->cp = vty->length = length;
657
658         /* Redraw current line */
659         vty_redraw_line(vty);
660 }
661
662 /* Show next command line history. */
663 static void vty_next_line(struct vty *vty)
664 {
665         int try_index;
666
667         if (vty->hp == vty->hindex)
668                 return;
669
670         /* Try is there history exist or not. */
671         try_index = vty->hp;
672         if (try_index == (VTY_MAXHIST - 1))
673                 try_index = 0;
674         else
675                 try_index++;
676
677         /* If there is not history return. */
678         if (vty->hist[try_index] == NULL)
679                 return;
680         else
681                 vty->hp = try_index;
682
683         vty_history_print(vty);
684 }
685
686 /* Show previous command line history. */
687 static void vty_previous_line(struct vty *vty)
688 {
689         int try_index;
690
691         try_index = vty->hp;
692         if (try_index == 0)
693                 try_index = VTY_MAXHIST - 1;
694         else
695                 try_index--;
696
697         if (vty->hist[try_index] == NULL)
698                 return;
699         else
700                 vty->hp = try_index;
701
702         vty_history_print(vty);
703 }
704
705 /* This function redraw all of the command line character. */
706 static void vty_redraw_line(struct vty *vty)
707 {
708         vty_write(vty, vty->buf, vty->length);
709         vty->cp = vty->length;
710 }
711
712 /* Forward word. */
713 static void vty_forward_word(struct vty *vty)
714 {
715         while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
716                 vty_forward_char(vty);
717
718         while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
719                 vty_forward_char(vty);
720 }
721
722 /* Backward word without skipping training space. */
723 static void vty_backward_pure_word(struct vty *vty)
724 {
725         while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
726                 vty_backward_char(vty);
727 }
728
729 /* Backward word. */
730 static void vty_backward_word(struct vty *vty)
731 {
732         while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
733                 vty_backward_char(vty);
734
735         while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
736                 vty_backward_char(vty);
737 }
738
739 /* When '^D' is typed at the beginning of the line we move to the down
740    level. */
741 static void vty_down_level(struct vty *vty)
742 {
743         vty_out(vty, "%s", VTY_NEWLINE);
744         /* FIXME: we need to call the exit function of the specific node
745          * in question, not this generic one that doesn't know all nodes */
746         (*config_exit_cmd.func) (NULL, vty, 0, NULL);
747         vty_prompt(vty);
748         vty->cp = 0;
749 }
750
751 /* When '^Z' is received from vty, move down to the enable mode. */
752 static void vty_end_config(struct vty *vty)
753 {
754         vty_out(vty, "%s", VTY_NEWLINE);
755
756         /* FIXME: we need to call the exit function of the specific node
757          * in question, not this generic one that doesn't know all nodes */
758         switch (vty->node) {
759         case VIEW_NODE:
760         case ENABLE_NODE:
761                 /* Nothing to do. */
762                 break;
763         case CONFIG_NODE:
764         case VTY_NODE:
765                 vty_config_unlock(vty);
766                 vty->node = ENABLE_NODE;
767                 break;
768         case CFG_LOG_NODE:
769                 vty->node = CONFIG_NODE;
770                 break;
771         default:
772                 /* Unknown node, we have to ignore it. */
773                 break;
774         }
775
776         vty_prompt(vty);
777         vty->cp = 0;
778 }
779
780 /* Delete a charcter at the current point. */
781 static void vty_delete_char(struct vty *vty)
782 {
783         int i;
784         int size;
785
786         if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
787                 return;
788
789         if (vty->length == 0) {
790                 vty_down_level(vty);
791                 return;
792         }
793
794         if (vty->cp == vty->length)
795                 return;         /* completion need here? */
796
797         size = vty->length - vty->cp;
798
799         vty->length--;
800         memmove(&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
801         vty->buf[vty->length] = '\0';
802
803         vty_write(vty, &vty->buf[vty->cp], size - 1);
804         vty_write(vty, &telnet_space_char, 1);
805
806         for (i = 0; i < size; i++)
807                 vty_write(vty, &telnet_backward_char, 1);
808 }
809
810 /* Delete a character before the point. */
811 static void vty_delete_backward_char(struct vty *vty)
812 {
813         if (vty->cp == 0)
814                 return;
815
816         vty_backward_char(vty);
817         vty_delete_char(vty);
818 }
819
820 /* Kill rest of line from current point. */
821 static void vty_kill_line(struct vty *vty)
822 {
823         int i;
824         int size;
825
826         size = vty->length - vty->cp;
827
828         if (size == 0)
829                 return;
830
831         for (i = 0; i < size; i++)
832                 vty_write(vty, &telnet_space_char, 1);
833         for (i = 0; i < size; i++)
834                 vty_write(vty, &telnet_backward_char, 1);
835
836         memset(&vty->buf[vty->cp], 0, size);
837         vty->length = vty->cp;
838 }
839
840 /* Kill line from the beginning. */
841 static void vty_kill_line_from_beginning(struct vty *vty)
842 {
843         vty_beginning_of_line(vty);
844         vty_kill_line(vty);
845 }
846
847 /* Delete a word before the point. */
848 static void vty_forward_kill_word(struct vty *vty)
849 {
850         while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
851                 vty_delete_char(vty);
852         while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
853                 vty_delete_char(vty);
854 }
855
856 /* Delete a word before the point. */
857 static void vty_backward_kill_word(struct vty *vty)
858 {
859         while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
860                 vty_delete_backward_char(vty);
861         while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
862                 vty_delete_backward_char(vty);
863 }
864
865 /* Transpose chars before or at the point. */
866 static void vty_transpose_chars(struct vty *vty)
867 {
868         char c1, c2;
869
870         /* If length is short or point is near by the beginning of line then
871            return. */
872         if (vty->length < 2 || vty->cp < 1)
873                 return;
874
875         /* In case of point is located at the end of the line. */
876         if (vty->cp == vty->length) {
877                 c1 = vty->buf[vty->cp - 1];
878                 c2 = vty->buf[vty->cp - 2];
879
880                 vty_backward_char(vty);
881                 vty_backward_char(vty);
882                 vty_self_insert_overwrite(vty, c1);
883                 vty_self_insert_overwrite(vty, c2);
884         } else {
885                 c1 = vty->buf[vty->cp];
886                 c2 = vty->buf[vty->cp - 1];
887
888                 vty_backward_char(vty);
889                 vty_self_insert_overwrite(vty, c1);
890                 vty_self_insert_overwrite(vty, c2);
891         }
892 }
893
894 /* Do completion at vty interface. */
895 static void vty_complete_command(struct vty *vty)
896 {
897         int i;
898         int ret;
899         char **matched = NULL;
900         vector vline;
901
902         if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
903                 return;
904
905         vline = cmd_make_strvec(vty->buf);
906         if (vline == NULL)
907                 return;
908
909         /* In case of 'help \t'. */
910         if (isspace((int)vty->buf[vty->length - 1]))
911                 vector_set(vline, '\0');
912
913         matched = cmd_complete_command(vline, vty, &ret);
914
915         cmd_free_strvec(vline);
916
917         vty_out(vty, "%s", VTY_NEWLINE);
918         switch (ret) {
919         case CMD_ERR_AMBIGUOUS:
920                 vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
921                 vty_prompt(vty);
922                 vty_redraw_line(vty);
923                 break;
924         case CMD_ERR_NO_MATCH:
925                 /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
926                 vty_prompt(vty);
927                 vty_redraw_line(vty);
928                 break;
929         case CMD_COMPLETE_FULL_MATCH:
930                 vty_prompt(vty);
931                 vty_redraw_line(vty);
932                 vty_backward_pure_word(vty);
933                 vty_insert_word_overwrite(vty, matched[0]);
934                 vty_self_insert(vty, ' ');
935                 talloc_free(matched[0]);
936                 break;
937         case CMD_COMPLETE_MATCH:
938                 vty_prompt(vty);
939                 vty_redraw_line(vty);
940                 vty_backward_pure_word(vty);
941                 vty_insert_word_overwrite(vty, matched[0]);
942                 talloc_free(matched[0]);
943                 break;
944         case CMD_COMPLETE_LIST_MATCH:
945                 for (i = 0; matched[i] != NULL; i++) {
946                         if (i != 0 && ((i % 6) == 0))
947                                 vty_out(vty, "%s", VTY_NEWLINE);
948                         vty_out(vty, "%-10s ", matched[i]);
949                         talloc_free(matched[i]);
950                 }
951                 vty_out(vty, "%s", VTY_NEWLINE);
952
953                 vty_prompt(vty);
954                 vty_redraw_line(vty);
955                 break;
956         case CMD_ERR_NOTHING_TODO:
957                 vty_prompt(vty);
958                 vty_redraw_line(vty);
959                 break;
960         default:
961                 break;
962         }
963         if (matched)
964                 vector_only_index_free(matched);
965 }
966
967 static void
968 vty_describe_fold(struct vty *vty, int cmd_width,
969                   unsigned int desc_width, struct desc *desc)
970 {
971         char *buf;
972         const char *cmd, *p;
973         int pos;
974
975         cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
976
977         if (desc_width <= 0) {
978                 vty_out(vty, "  %-*s  %s%s", cmd_width, cmd, desc->str,
979                         VTY_NEWLINE);
980                 return;
981         }
982
983         buf = _talloc_zero(vty, strlen(desc->str) + 1, "describe_fold");
984         if (!buf)
985                 return;
986
987         for (p = desc->str; strlen(p) > desc_width; p += pos + 1) {
988                 for (pos = desc_width; pos > 0; pos--)
989                         if (*(p + pos) == ' ')
990                                 break;
991
992                 if (pos == 0)
993                         break;
994
995                 strncpy(buf, p, pos);
996                 buf[pos] = '\0';
997                 vty_out(vty, "  %-*s  %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
998
999                 cmd = "";
1000         }
1001
1002         vty_out(vty, "  %-*s  %s%s", cmd_width, cmd, p, VTY_NEWLINE);
1003
1004         talloc_free(buf);
1005 }
1006
1007 /* Describe matched command function. */
1008 static void vty_describe_command(struct vty *vty)
1009 {
1010         int ret;
1011         vector vline;
1012         vector describe;
1013         unsigned int i, width, desc_width;
1014         struct desc *desc, *desc_cr = NULL;
1015
1016         vline = cmd_make_strvec(vty->buf);
1017
1018         /* In case of '> ?'. */
1019         if (vline == NULL) {
1020                 vline = vector_init(1);
1021                 vector_set(vline, '\0');
1022         } else if (isspace((int)vty->buf[vty->length - 1]))
1023                 vector_set(vline, '\0');
1024
1025         describe = cmd_describe_command(vline, vty, &ret);
1026
1027         vty_out(vty, "%s", VTY_NEWLINE);
1028
1029         /* Ambiguous error. */
1030         switch (ret) {
1031         case CMD_ERR_AMBIGUOUS:
1032                 cmd_free_strvec(vline);
1033                 vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
1034                 vty_prompt(vty);
1035                 vty_redraw_line(vty);
1036                 return;
1037                 break;
1038         case CMD_ERR_NO_MATCH:
1039                 cmd_free_strvec(vline);
1040                 vty_out(vty, "%% There is no matched command.%s", VTY_NEWLINE);
1041                 vty_prompt(vty);
1042                 vty_redraw_line(vty);
1043                 return;
1044                 break;
1045         }
1046
1047         /* Get width of command string. */
1048         width = 0;
1049         for (i = 0; i < vector_active(describe); i++)
1050                 if ((desc = vector_slot(describe, i)) != NULL) {
1051                         unsigned int len;
1052
1053                         if (desc->cmd[0] == '\0')
1054                                 continue;
1055
1056                         len = strlen(desc->cmd);
1057                         if (desc->cmd[0] == '.')
1058                                 len--;
1059
1060                         if (width < len)
1061                                 width = len;
1062                 }
1063
1064         /* Get width of description string. */
1065         desc_width = vty->width - (width + 6);
1066
1067         /* Print out description. */
1068         for (i = 0; i < vector_active(describe); i++)
1069                 if ((desc = vector_slot(describe, i)) != NULL) {
1070                         if (desc->cmd[0] == '\0')
1071                                 continue;
1072
1073                         if (strcmp(desc->cmd, "<cr>") == 0) {
1074                                 desc_cr = desc;
1075                                 continue;
1076                         }
1077
1078                         if (!desc->str)
1079                                 vty_out(vty, "  %-s%s",
1080                                         desc->cmd[0] ==
1081                                         '.' ? desc->cmd + 1 : desc->cmd,
1082                                         VTY_NEWLINE);
1083                         else if (desc_width >= strlen(desc->str))
1084                                 vty_out(vty, "  %-*s  %s%s", width,
1085                                         desc->cmd[0] ==
1086                                         '.' ? desc->cmd + 1 : desc->cmd,
1087                                         desc->str, VTY_NEWLINE);
1088                         else
1089                                 vty_describe_fold(vty, width, desc_width, desc);
1090
1091 #if 0
1092                         vty_out(vty, "  %-*s %s%s", width
1093                                 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1094                                 desc->str ? desc->str : "", VTY_NEWLINE);
1095 #endif                          /* 0 */
1096                 }
1097
1098         if ((desc = desc_cr)) {
1099                 if (!desc->str)
1100                         vty_out(vty, "  %-s%s",
1101                                 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1102                                 VTY_NEWLINE);
1103                 else if (desc_width >= strlen(desc->str))
1104                         vty_out(vty, "  %-*s  %s%s", width,
1105                                 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1106                                 desc->str, VTY_NEWLINE);
1107                 else
1108                         vty_describe_fold(vty, width, desc_width, desc);
1109         }
1110
1111         cmd_free_strvec(vline);
1112         vector_free(describe);
1113
1114         vty_prompt(vty);
1115         vty_redraw_line(vty);
1116 }
1117
1118 /* ^C stop current input and do not add command line to the history. */
1119 static void vty_stop_input(struct vty *vty)
1120 {
1121         vty->cp = vty->length = 0;
1122         vty_clear_buf(vty);
1123         vty_out(vty, "%s", VTY_NEWLINE);
1124
1125         switch (vty->node) {
1126         case VIEW_NODE:
1127         case ENABLE_NODE:
1128                 /* Nothing to do. */
1129                 break;
1130         case CONFIG_NODE:
1131         case VTY_NODE:
1132                 vty_config_unlock(vty);
1133                 vty->node = ENABLE_NODE;
1134                 break;
1135         case CFG_LOG_NODE:
1136                 vty->node = CONFIG_NODE;
1137                 break;
1138         default:
1139                 /* Unknown node, we have to ignore it. */
1140                 break;
1141         }
1142         vty_prompt(vty);
1143
1144         /* Set history pointer to the latest one. */
1145         vty->hp = vty->hindex;
1146 }
1147
1148 #define CONTROL(X)  ((X) - '@')
1149 #define VTY_NORMAL     0
1150 #define VTY_PRE_ESCAPE 1
1151 #define VTY_ESCAPE     2
1152
1153 /* Escape character command map. */
1154 static void vty_escape_map(unsigned char c, struct vty *vty)
1155 {
1156         switch (c) {
1157         case ('A'):
1158                 vty_previous_line(vty);
1159                 break;
1160         case ('B'):
1161                 vty_next_line(vty);
1162                 break;
1163         case ('C'):
1164                 vty_forward_char(vty);
1165                 break;
1166         case ('D'):
1167                 vty_backward_char(vty);
1168                 break;
1169         default:
1170                 break;
1171         }
1172
1173         /* Go back to normal mode. */
1174         vty->escape = VTY_NORMAL;
1175 }
1176
1177 /* Quit print out to the buffer. */
1178 static void vty_buffer_reset(struct vty *vty)
1179 {
1180         buffer_reset(vty->obuf);
1181         vty_prompt(vty);
1182         vty_redraw_line(vty);
1183 }
1184
1185 /* Read data via vty socket. */
1186 int vty_read(struct vty *vty)
1187 {
1188         int i;
1189         int nbytes;
1190         unsigned char buf[VTY_READ_BUFSIZ];
1191
1192         int vty_sock = vty->fd;
1193
1194         /* Read raw data from socket */
1195         if ((nbytes = read(vty->fd, buf, VTY_READ_BUFSIZ)) <= 0) {
1196                 if (nbytes < 0) {
1197                         if (ERRNO_IO_RETRY(errno)) {
1198                                 vty_event(VTY_READ, vty_sock, vty);
1199                                 return 0;
1200                         }
1201                 }
1202                 buffer_reset(vty->obuf);
1203                 vty->status = VTY_CLOSE;
1204         }
1205
1206         for (i = 0; i < nbytes; i++) {
1207                 if (buf[i] == IAC) {
1208                         if (!vty->iac) {
1209                                 vty->iac = 1;
1210                                 continue;
1211                         } else {
1212                                 vty->iac = 0;
1213                         }
1214                 }
1215
1216                 if (vty->iac_sb_in_progress && !vty->iac) {
1217                         if (vty->sb_len < sizeof(vty->sb_buf))
1218                                 vty->sb_buf[vty->sb_len] = buf[i];
1219                         vty->sb_len++;
1220                         continue;
1221                 }
1222
1223                 if (vty->iac) {
1224                         /* In case of telnet command */
1225                         int ret = 0;
1226                         ret = vty_telnet_option(vty, buf + i, nbytes - i);
1227                         vty->iac = 0;
1228                         i += ret;
1229                         continue;
1230                 }
1231
1232                 if (vty->status == VTY_MORE) {
1233                         switch (buf[i]) {
1234                         case CONTROL('C'):
1235                         case 'q':
1236                         case 'Q':
1237                                 vty_buffer_reset(vty);
1238                                 break;
1239 #if 0                           /* More line does not work for "show ip bgp".  */
1240                         case '\n':
1241                         case '\r':
1242                                 vty->status = VTY_MORELINE;
1243                                 break;
1244 #endif
1245                         default:
1246                                 break;
1247                         }
1248                         continue;
1249                 }
1250
1251                 /* Escape character. */
1252                 if (vty->escape == VTY_ESCAPE) {
1253                         vty_escape_map(buf[i], vty);
1254                         continue;
1255                 }
1256
1257                 /* Pre-escape status. */
1258                 if (vty->escape == VTY_PRE_ESCAPE) {
1259                         switch (buf[i]) {
1260                         case '[':
1261                                 vty->escape = VTY_ESCAPE;
1262                                 break;
1263                         case 'b':
1264                                 vty_backward_word(vty);
1265                                 vty->escape = VTY_NORMAL;
1266                                 break;
1267                         case 'f':
1268                                 vty_forward_word(vty);
1269                                 vty->escape = VTY_NORMAL;
1270                                 break;
1271                         case 'd':
1272                                 vty_forward_kill_word(vty);
1273                                 vty->escape = VTY_NORMAL;
1274                                 break;
1275                         case CONTROL('H'):
1276                         case 0x7f:
1277                                 vty_backward_kill_word(vty);
1278                                 vty->escape = VTY_NORMAL;
1279                                 break;
1280                         default:
1281                                 vty->escape = VTY_NORMAL;
1282                                 break;
1283                         }
1284                         continue;
1285                 }
1286
1287                 switch (buf[i]) {
1288                 case CONTROL('A'):
1289                         vty_beginning_of_line(vty);
1290                         break;
1291                 case CONTROL('B'):
1292                         vty_backward_char(vty);
1293                         break;
1294                 case CONTROL('C'):
1295                         vty_stop_input(vty);
1296                         break;
1297                 case CONTROL('D'):
1298                         vty_delete_char(vty);
1299                         break;
1300                 case CONTROL('E'):
1301                         vty_end_of_line(vty);
1302                         break;
1303                 case CONTROL('F'):
1304                         vty_forward_char(vty);
1305                         break;
1306                 case CONTROL('H'):
1307                 case 0x7f:
1308                         vty_delete_backward_char(vty);
1309                         break;
1310                 case CONTROL('K'):
1311                         vty_kill_line(vty);
1312                         break;
1313                 case CONTROL('N'):
1314                         vty_next_line(vty);
1315                         break;
1316                 case CONTROL('P'):
1317                         vty_previous_line(vty);
1318                         break;
1319                 case CONTROL('T'):
1320                         vty_transpose_chars(vty);
1321                         break;
1322                 case CONTROL('U'):
1323                         vty_kill_line_from_beginning(vty);
1324                         break;
1325                 case CONTROL('W'):
1326                         vty_backward_kill_word(vty);
1327                         break;
1328                 case CONTROL('Z'):
1329                         vty_end_config(vty);
1330                         break;
1331                 case '\n':
1332                 case '\r':
1333                         vty_out(vty, "%s", VTY_NEWLINE);
1334                         vty_execute(vty);
1335                         break;
1336                 case '\t':
1337                         vty_complete_command(vty);
1338                         break;
1339                 case '?':
1340                         if (vty->node == AUTH_NODE
1341                             || vty->node == AUTH_ENABLE_NODE)
1342                                 vty_self_insert(vty, buf[i]);
1343                         else
1344                                 vty_describe_command(vty);
1345                         break;
1346                 case '\033':
1347                         if (i + 1 < nbytes && buf[i + 1] == '[') {
1348                                 vty->escape = VTY_ESCAPE;
1349                                 i++;
1350                         } else
1351                                 vty->escape = VTY_PRE_ESCAPE;
1352                         break;
1353                 default:
1354                         if (buf[i] > 31 && buf[i] < 127)
1355                                 vty_self_insert(vty, buf[i]);
1356                         break;
1357                 }
1358         }
1359
1360         /* Check status. */
1361         if (vty->status == VTY_CLOSE)
1362                 vty_close(vty);
1363         else {
1364                 vty_event(VTY_WRITE, vty_sock, vty);
1365                 vty_event(VTY_READ, vty_sock, vty);
1366         }
1367         return 0;
1368 }
1369
1370 /* Read up configuration file */
1371 static int
1372 vty_read_file(FILE *confp, void *priv)
1373 {
1374         int ret;
1375         struct vty *vty;
1376
1377         vty = vty_new();
1378         vty->fd = 0;
1379         vty->type = VTY_FILE;
1380         vty->node = CONFIG_NODE;
1381         vty->priv = priv;
1382
1383         ret = config_from_file(vty, confp);
1384
1385         if (ret != CMD_SUCCESS) {
1386                 switch (ret) {
1387                 case CMD_ERR_AMBIGUOUS:
1388                         fprintf(stderr, "Ambiguous command.\n");
1389                         break;
1390                 case CMD_ERR_NO_MATCH:
1391                         fprintf(stderr, "There is no such command.\n");
1392                         break;
1393                 }
1394                 fprintf(stderr, "Error occurred during reading below "
1395                         "line:\n%s\n", vty->buf);
1396                 vty_close(vty);
1397                 return -EINVAL;
1398         }
1399
1400         vty_close(vty);
1401         return 0;
1402 }
1403
1404 /* Create new vty structure. */
1405 struct vty *
1406 vty_create (int vty_sock, void *priv)
1407 {
1408   struct vty *vty;
1409
1410         struct termios t;
1411
1412         tcgetattr(vty_sock, &t);
1413         cfmakeraw(&t);
1414         tcsetattr(vty_sock, TCSANOW, &t);
1415
1416   /* Allocate new vty structure and set up default values. */
1417   vty = vty_new ();
1418   vty->fd = vty_sock;
1419   vty->priv = priv;
1420   vty->type = VTY_TERM;
1421   if (no_password_check)
1422     {
1423       if (host.advanced)
1424         vty->node = ENABLE_NODE;
1425       else
1426         vty->node = VIEW_NODE;
1427     }
1428   else
1429     vty->node = AUTH_NODE;
1430   vty->fail = 0;
1431   vty->cp = 0;
1432   vty_clear_buf (vty);
1433   vty->length = 0;
1434   memset (vty->hist, 0, sizeof (vty->hist));
1435   vty->hp = 0;
1436   vty->hindex = 0;
1437   vector_set_index (vtyvec, vty_sock, vty);
1438   vty->status = VTY_NORMAL;
1439   if (host.lines >= 0)
1440     vty->lines = host.lines;
1441   else
1442     vty->lines = -1;
1443
1444   if (! no_password_check)
1445     {
1446       /* Vty is not available if password isn't set. */
1447       if (host.password == NULL && host.password_encrypt == NULL)
1448         {
1449           vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1450           vty->status = VTY_CLOSE;
1451           vty_close (vty);
1452           return NULL;
1453         }
1454     }
1455
1456   /* Say hello to the world. */
1457   vty_hello (vty);
1458   if (! no_password_check)
1459     vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1460
1461   /* Setting up terminal. */
1462   vty_will_echo (vty);
1463   vty_will_suppress_go_ahead (vty);
1464
1465   vty_dont_linemode (vty);
1466   vty_do_window_size (vty);
1467   /* vty_dont_lflow_ahead (vty); */
1468
1469   vty_prompt (vty);
1470
1471   /* Add read/write thread. */
1472   vty_event (VTY_WRITE, vty_sock, vty);
1473   vty_event (VTY_READ, vty_sock, vty);
1474
1475   return vty;
1476 }
1477
1478 DEFUN(config_who, config_who_cmd, "who", "Display who is on vty\n")
1479 {
1480         unsigned int i;
1481         struct vty *v;
1482
1483         for (i = 0; i < vector_active(vtyvec); i++)
1484                 if ((v = vector_slot(vtyvec, i)) != NULL)
1485                         vty_out(vty, "%svty[%d] %s",
1486                                 v->config ? "*" : " ", i, VTY_NEWLINE);
1487         return CMD_SUCCESS;
1488 }
1489
1490 /* Move to vty configuration mode. */
1491 DEFUN(line_vty,
1492       line_vty_cmd,
1493       "line vty", "Configure a terminal line\n" "Virtual terminal\n")
1494 {
1495         vty->node = VTY_NODE;
1496         return CMD_SUCCESS;
1497 }
1498
1499 /* vty login. */
1500 DEFUN(vty_login, vty_login_cmd, "login", "Enable password checking\n")
1501 {
1502         no_password_check = 0;
1503         return CMD_SUCCESS;
1504 }
1505
1506 DEFUN(no_vty_login,
1507       no_vty_login_cmd, "no login", NO_STR "Enable password checking\n")
1508 {
1509         no_password_check = 1;
1510         return CMD_SUCCESS;
1511 }
1512
1513 DEFUN(service_advanced_vty,
1514       service_advanced_vty_cmd,
1515       "service advanced-vty",
1516       "Set up miscellaneous service\n" "Enable advanced mode vty interface\n")
1517 {
1518         host.advanced = 1;
1519         return CMD_SUCCESS;
1520 }
1521
1522 DEFUN(no_service_advanced_vty,
1523       no_service_advanced_vty_cmd,
1524       "no service advanced-vty",
1525       NO_STR
1526       "Set up miscellaneous service\n" "Enable advanced mode vty interface\n")
1527 {
1528         host.advanced = 0;
1529         return CMD_SUCCESS;
1530 }
1531
1532 DEFUN(terminal_monitor,
1533       terminal_monitor_cmd,
1534       "terminal monitor",
1535       "Set terminal line parameters\n"
1536       "Copy debug output to the current terminal line\n")
1537 {
1538         vty->monitor = 1;
1539         return CMD_SUCCESS;
1540 }
1541
1542 DEFUN(terminal_no_monitor,
1543       terminal_no_monitor_cmd,
1544       "terminal no monitor",
1545       "Set terminal line parameters\n"
1546       NO_STR "Copy debug output to the current terminal line\n")
1547 {
1548         vty->monitor = 0;
1549         return CMD_SUCCESS;
1550 }
1551
1552 DEFUN(show_history,
1553       show_history_cmd,
1554       "show history", SHOW_STR "Display the session command history\n")
1555 {
1556         int index;
1557
1558         for (index = vty->hindex + 1; index != vty->hindex;) {
1559                 if (index == VTY_MAXHIST) {
1560                         index = 0;
1561                         continue;
1562                 }
1563
1564                 if (vty->hist[index] != NULL)
1565                         vty_out(vty, "  %s%s", vty->hist[index], VTY_NEWLINE);
1566
1567                 index++;
1568         }
1569
1570         return CMD_SUCCESS;
1571 }
1572
1573 /* Display current configuration. */
1574 static int vty_config_write(struct vty *vty)
1575 {
1576         vty_out(vty, "line vty%s", VTY_NEWLINE);
1577
1578         /* login */
1579         if (no_password_check)
1580                 vty_out(vty, " no login%s", VTY_NEWLINE);
1581
1582         vty_out(vty, "!%s", VTY_NEWLINE);
1583
1584         return CMD_SUCCESS;
1585 }
1586
1587 struct cmd_node vty_node = {
1588         VTY_NODE,
1589         "%s(config-line)# ",
1590         1,
1591 };
1592
1593 /* Reset all VTY status. */
1594 void vty_reset()
1595 {
1596         unsigned int i;
1597         struct vty *vty;
1598         struct thread *vty_serv_thread;
1599
1600         for (i = 0; i < vector_active(vtyvec); i++)
1601                 if ((vty = vector_slot(vtyvec, i)) != NULL) {
1602                         buffer_reset(vty->obuf);
1603                         vty->status = VTY_CLOSE;
1604                         vty_close(vty);
1605                 }
1606
1607         for (i = 0; i < vector_active(Vvty_serv_thread); i++)
1608                 if ((vty_serv_thread =
1609                      vector_slot(Vvty_serv_thread, i)) != NULL) {
1610                         //thread_cancel (vty_serv_thread);
1611                         vector_slot(Vvty_serv_thread, i) = NULL;
1612                         close(i);
1613                 }
1614 }
1615
1616 static void vty_save_cwd(void)
1617 {
1618         char cwd[MAXPATHLEN];
1619         char *c ;
1620
1621         c = getcwd(cwd, MAXPATHLEN);
1622
1623         if (!c) {
1624                 if (chdir(SYSCONFDIR) != 0)
1625                     perror("chdir failed");
1626                 if (getcwd(cwd, MAXPATHLEN) == NULL)
1627                     perror("getcwd failed");
1628         }
1629
1630         vty_cwd = _talloc_zero(tall_vty_ctx, strlen(cwd) + 1, "save_cwd");
1631         strcpy(vty_cwd, cwd);
1632 }
1633
1634 char *vty_get_cwd()
1635 {
1636         return vty_cwd;
1637 }
1638
1639 int vty_shell_serv(struct vty *vty)
1640 {
1641         return vty->type == VTY_SHELL_SERV ? 1 : 0;
1642 }
1643
1644 void vty_init_vtysh()
1645 {
1646         vtyvec = vector_init(VECTOR_MIN_SIZE);
1647 }
1648
1649 extern void *tall_bsc_ctx;
1650 /* Install vty's own commands like `who' command. */
1651 void vty_init(struct vty_app_info *app_info)
1652 {
1653         tall_vty_ctx = talloc_named_const(app_info->tall_ctx, 0, "vty");
1654         tall_vty_vec_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_vector");
1655         tall_vty_cmd_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_command");
1656
1657         cmd_init(1);
1658
1659         host.app_info = app_info;
1660
1661         /* For further configuration read, preserve current directory. */
1662         vty_save_cwd();
1663
1664         vtyvec = vector_init(VECTOR_MIN_SIZE);
1665
1666         /* Install bgp top node. */
1667         install_node(&vty_node, vty_config_write);
1668
1669         install_element_ve(&config_who_cmd);
1670         install_element_ve(&show_history_cmd);
1671         install_element(CONFIG_NODE, &line_vty_cmd);
1672         install_element(CONFIG_NODE, &service_advanced_vty_cmd);
1673         install_element(CONFIG_NODE, &no_service_advanced_vty_cmd);
1674         install_element(CONFIG_NODE, &show_history_cmd);
1675         install_element(ENABLE_NODE, &terminal_monitor_cmd);
1676         install_element(ENABLE_NODE, &terminal_no_monitor_cmd);
1677
1678         install_default(VTY_NODE);
1679         install_element(VTY_NODE, &vty_login_cmd);
1680         install_element(VTY_NODE, &no_vty_login_cmd);
1681 }
1682
1683 int vty_read_config_file(const char *file_name, void *priv)
1684 {
1685         FILE *cfile;
1686         int rc;
1687
1688         cfile = fopen(file_name, "r");
1689         if (!cfile)
1690                 return -ENOENT;
1691
1692         rc = vty_read_file(cfile, priv);
1693         fclose(cfile);
1694
1695         host_config_set(file_name);
1696
1697         return rc;
1698 }