Add TAB-based auto-completion to the CLI
[vpp.git] / src / vlib / cli.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * cli.c: command line interface
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #include <vlib/vlib.h>
41 #include <vppinfra/cpu.h>
42 #include <unistd.h>
43 #include <ctype.h>
44
45 /* Root of all show commands. */
46 /* *INDENT-OFF* */
47 VLIB_CLI_COMMAND (vlib_cli_show_command, static) = {
48   .path = "show",
49   .short_help = "Show commands",
50 };
51 /* *INDENT-ON* */
52
53 /* Root of all clear commands. */
54 /* *INDENT-OFF* */
55 VLIB_CLI_COMMAND (vlib_cli_clear_command, static) = {
56   .path = "clear",
57   .short_help = "Clear commands",
58 };
59 /* *INDENT-ON* */
60
61 /* Root of all set commands. */
62 /* *INDENT-OFF* */
63 VLIB_CLI_COMMAND (vlib_cli_set_command, static) = {
64   .path = "set",
65   .short_help = "Set commands",
66 };
67 /* *INDENT-ON* */
68
69 /* Root of all test commands. */
70 /* *INDENT-OFF* */
71 VLIB_CLI_COMMAND (vlib_cli_test_command, static) = {
72   .path = "test",
73   .short_help = "Test commands",
74 };
75 /* *INDENT-ON* */
76
77 /* Returns bitmap of commands which match key. */
78 static uword *
79 vlib_cli_sub_command_match (vlib_cli_command_t * c, unformat_input_t * input)
80 {
81   int i, n;
82   uword *match = 0;
83   vlib_cli_parse_position_t *p;
84
85   unformat_skip_white_space (input);
86
87   for (i = 0;; i++)
88     {
89       uword k;
90
91       k = unformat_get_input (input);
92       switch (k)
93         {
94         case 'a' ... 'z':
95         case 'A' ... 'Z':
96         case '0' ... '9':
97         case '-':
98         case '_':
99           break;
100
101         case ' ':
102         case '\t':
103         case '\r':
104         case '\n':
105         case UNFORMAT_END_OF_INPUT:
106           /* White space or end of input removes any non-white
107              matches that were before possible. */
108           if (i < vec_len (c->sub_command_positions)
109               && clib_bitmap_count_set_bits (match) > 1)
110             {
111               p = vec_elt_at_index (c->sub_command_positions, i);
112               for (n = 0; n < vec_len (p->bitmaps); n++)
113                 match = clib_bitmap_andnot (match, p->bitmaps[n]);
114             }
115           goto done;
116
117         default:
118           unformat_put_input (input);
119           goto done;
120         }
121
122       if (i >= vec_len (c->sub_command_positions))
123         {
124         no_match:
125           clib_bitmap_free (match);
126           return 0;
127         }
128
129       p = vec_elt_at_index (c->sub_command_positions, i);
130       if (vec_len (p->bitmaps) == 0)
131         goto no_match;
132
133       n = k - p->min_char;
134       if (n < 0 || n >= vec_len (p->bitmaps))
135         goto no_match;
136
137       if (i == 0)
138         match = clib_bitmap_dup (p->bitmaps[n]);
139       else
140         match = clib_bitmap_and (match, p->bitmaps[n]);
141
142       if (clib_bitmap_is_zero (match))
143         goto no_match;
144     }
145
146 done:
147   return match;
148 }
149
150 /* Looks for string based sub-input formatted { SUB-INPUT }. */
151 uword
152 unformat_vlib_cli_sub_input (unformat_input_t * i, va_list * args)
153 {
154   unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
155   u8 *s;
156   uword c;
157
158   while (1)
159     {
160       c = unformat_get_input (i);
161       switch (c)
162         {
163         case ' ':
164         case '\t':
165         case '\n':
166         case '\r':
167         case '\f':
168           break;
169
170         case '{':
171         default:
172           /* Put back paren. */
173           if (c != UNFORMAT_END_OF_INPUT)
174             unformat_put_input (i);
175
176           if (c == '{' && unformat (i, "%v", &s))
177             {
178               unformat_init_vector (sub_input, s);
179               return 1;
180             }
181           return 0;
182         }
183     }
184   return 0;
185 }
186
187 static vlib_cli_command_t *
188 get_sub_command (vlib_cli_main_t * cm, vlib_cli_command_t * parent, u32 si)
189 {
190   vlib_cli_sub_command_t *s = vec_elt_at_index (parent->sub_commands, si);
191   return vec_elt_at_index (cm->commands, s->index);
192 }
193
194 static uword
195 unformat_vlib_cli_sub_command (unformat_input_t * i, va_list * args)
196 {
197   vlib_main_t *vm = va_arg (*args, vlib_main_t *);
198   vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
199   vlib_cli_command_t **result = va_arg (*args, vlib_cli_command_t **);
200   vlib_cli_main_t *cm = &vm->cli_main;
201   uword *match_bitmap, is_unique, index;
202
203   {
204     vlib_cli_sub_rule_t *sr;
205     vlib_cli_parse_rule_t *r;
206     vec_foreach (sr, c->sub_rules)
207     {
208       void **d;
209       r = vec_elt_at_index (cm->parse_rules, sr->rule_index);
210       vec_add2 (cm->parse_rule_data, d, 1);
211       vec_reset_length (d[0]);
212       if (r->data_size)
213         d[0] = _vec_resize (d[0],
214                             /* length increment */ 1,
215                             r->data_size,
216                             /* header_bytes */ 0,
217                             /* data align */ sizeof (uword));
218       if (unformat_user (i, r->unformat_function, vm, d[0]))
219         {
220           *result = vec_elt_at_index (cm->commands, sr->command_index);
221           return 1;
222         }
223     }
224   }
225
226   match_bitmap = vlib_cli_sub_command_match (c, i);
227   is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
228   index = ~0;
229   if (is_unique)
230     {
231       index = clib_bitmap_first_set (match_bitmap);
232       *result = get_sub_command (cm, c, index);
233     }
234   clib_bitmap_free (match_bitmap);
235
236   return is_unique;
237 }
238
239 static int
240 vlib_cli_cmp_strings (void *a1, void *a2)
241 {
242   u8 *c1 = *(u8 **) a1;
243   u8 *c2 = *(u8 **) a2;
244
245   return vec_cmp (c1, c2);
246 }
247
248 u8 **
249 vlib_cli_get_possible_completions (u8 * str)
250 {
251   vlib_cli_command_t *c;
252   vlib_cli_sub_command_t *sc;
253   vlib_main_t *vm = vlib_get_main ();
254   vlib_cli_main_t *vcm = &vm->cli_main;
255   uword *match_bitmap = 0;
256   uword index, is_unique, help_next_level;
257   u8 **result = 0;
258   unformat_input_t input;
259   unformat_init_vector (&input, vec_dup (str));
260   c = vec_elt_at_index (vcm->commands, 0);
261
262   /* remove trailing whitespace, except for one of them */
263   while (vec_len (input.buffer) >= 2 &&
264          isspace (input.buffer[vec_len (input.buffer) - 1]) &&
265          isspace (input.buffer[vec_len (input.buffer) - 2]))
266     {
267       vec_del1 (input.buffer, vec_len (input.buffer) - 1);
268     }
269
270   /* if input is empty, directly return list of root commands */
271   if (vec_len (input.buffer) == 0 ||
272       (vec_len (input.buffer) == 1 && isspace (input.buffer[0])))
273     {
274       vec_foreach (sc, c->sub_commands)
275       {
276         vec_add1 (result, (u8 *) sc->name);
277       }
278       goto done;
279     }
280
281   /* add a trailing '?' so that vlib_cli_sub_command_match can find
282    * all commands starting with the input string */
283   vec_add1 (input.buffer, '?');
284
285   while (1)
286     {
287       match_bitmap = vlib_cli_sub_command_match (c, &input);
288       /* no match: return no result */
289       if (match_bitmap == 0)
290         {
291           goto done;
292         }
293       is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
294       /* unique match: try to step one subcommand level further */
295       if (is_unique)
296         {
297           /* stop if no more input */
298           if (input.index >= vec_len (input.buffer) - 1)
299             {
300               break;
301             }
302
303           index = clib_bitmap_first_set (match_bitmap);
304           c = get_sub_command (vcm, c, index);
305           clib_bitmap_free (match_bitmap);
306           continue;
307         }
308       /* multiple matches: stop here, return all matches */
309       break;
310     }
311
312   /* remove trailing '?' */
313   vec_del1 (input.buffer, vec_len (input.buffer) - 1);
314
315   /* if we have a space at the end of input, and a unique match,
316    * autocomplete the next level of subcommands */
317   help_next_level = (vec_len (str) == 0) || isspace (str[vec_len (str) - 1]);
318   /* *INDENT-OFF* */
319   clib_bitmap_foreach(index, match_bitmap, {
320     if (help_next_level && is_unique) {
321         c = get_sub_command (vcm, c, index);
322         vec_foreach (sc, c->sub_commands) {
323           vec_add1 (result, (u8*) sc->name);
324         }
325         goto done; /* break doesn't work in this macro-loop */
326     }
327     sc = &c->sub_commands[index];
328     vec_add1(result, (u8*) sc->name);
329   });
330   /* *INDENT-ON* */
331
332 done:
333   clib_bitmap_free (match_bitmap);
334   unformat_free (&input);
335
336   vec_sort_with_function (result, vlib_cli_cmp_strings);
337   return result;
338 }
339
340 static u8 *
341 format_vlib_cli_command_help (u8 * s, va_list * args)
342 {
343   vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
344   int is_long = va_arg (*args, int);
345   if (is_long && c->long_help)
346     s = format (s, "%s", c->long_help);
347   else if (c->short_help)
348     s = format (s, "%s", c->short_help);
349   else
350     s = format (s, "%v commands", c->path);
351   return s;
352 }
353
354 static u8 *
355 format_vlib_cli_parse_rule_name (u8 * s, va_list * args)
356 {
357   vlib_cli_parse_rule_t *r = va_arg (*args, vlib_cli_parse_rule_t *);
358   return format (s, "<%U>", format_c_identifier, r->name);
359 }
360
361 static u8 *
362 format_vlib_cli_path (u8 * s, va_list * args)
363 {
364   u8 *path = va_arg (*args, u8 *);
365   int i, in_rule;
366   in_rule = 0;
367   for (i = 0; i < vec_len (path); i++)
368     {
369       switch (path[i])
370         {
371         case '%':
372           in_rule = 1;
373           vec_add1 (s, '<');    /* start of <RULE> */
374           break;
375
376         case '_':
377           /* _ -> space in rules. */
378           vec_add1 (s, in_rule ? ' ' : '_');
379           break;
380
381         case ' ':
382           if (in_rule)
383             {
384               vec_add1 (s, '>');        /* end of <RULE> */
385               in_rule = 0;
386             }
387           vec_add1 (s, ' ');
388           break;
389
390         default:
391           vec_add1 (s, path[i]);
392           break;
393         }
394     }
395
396   if (in_rule)
397     vec_add1 (s, '>');          /* terminate <RULE> */
398
399   return s;
400 }
401
402 static vlib_cli_command_t *
403 all_subs (vlib_cli_main_t * cm, vlib_cli_command_t * subs, u32 command_index)
404 {
405   vlib_cli_command_t *c = vec_elt_at_index (cm->commands, command_index);
406   vlib_cli_sub_command_t *sc;
407   vlib_cli_sub_rule_t *sr;
408
409   if (c->function)
410     vec_add1 (subs, c[0]);
411
412   vec_foreach (sr, c->sub_rules)
413     subs = all_subs (cm, subs, sr->command_index);
414   vec_foreach (sc, c->sub_commands) subs = all_subs (cm, subs, sc->index);
415
416   return subs;
417 }
418
419 static int
420 vlib_cli_cmp_rule (void *a1, void *a2)
421 {
422   vlib_cli_sub_rule_t *r1 = a1;
423   vlib_cli_sub_rule_t *r2 = a2;
424
425   return vec_cmp (r1->name, r2->name);
426 }
427
428 static int
429 vlib_cli_cmp_command (void *a1, void *a2)
430 {
431   vlib_cli_command_t *c1 = a1;
432   vlib_cli_command_t *c2 = a2;
433
434   return vec_cmp (c1->path, c2->path);
435 }
436
437 static clib_error_t *
438 vlib_cli_dispatch_sub_commands (vlib_main_t * vm,
439                                 vlib_cli_main_t * cm,
440                                 unformat_input_t * input,
441                                 uword parent_command_index)
442 {
443   vlib_cli_command_t *parent, *c;
444   clib_error_t *error = 0;
445   unformat_input_t sub_input;
446   u8 *string;
447   uword is_main_dispatch = cm == &vm->cli_main;
448
449   parent = vec_elt_at_index (cm->commands, parent_command_index);
450   if (is_main_dispatch && unformat (input, "help"))
451     {
452       uword help_at_end_of_line, i;
453
454       help_at_end_of_line =
455         unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
456       while (1)
457         {
458           c = parent;
459           if (unformat_user
460               (input, unformat_vlib_cli_sub_command, vm, c, &parent))
461             ;
462
463           else if (!(unformat_check_input (input) == UNFORMAT_END_OF_INPUT))
464             goto unknown;
465
466           else
467             break;
468         }
469
470       /* help SUB-COMMAND => long format help.
471          "help" at end of line: show all commands. */
472       if (!help_at_end_of_line)
473         vlib_cli_output (vm, "%U", format_vlib_cli_command_help, c,
474                          /* is_long */ 1);
475
476       else if (vec_len (c->sub_commands) + vec_len (c->sub_rules) == 0)
477         vlib_cli_output (vm, "%v: no sub-commands", c->path);
478
479       else
480         {
481           vlib_cli_sub_command_t *sc;
482           vlib_cli_sub_rule_t *sr, *subs;
483
484           subs = vec_dup (c->sub_rules);
485
486           /* Add in rules if any. */
487           vec_foreach (sc, c->sub_commands)
488           {
489             vec_add2 (subs, sr, 1);
490             sr->name = sc->name;
491             sr->command_index = sc->index;
492             sr->rule_index = ~0;
493           }
494
495           vec_sort_with_function (subs, vlib_cli_cmp_rule);
496
497           for (i = 0; i < vec_len (subs); i++)
498             {
499               vlib_cli_command_t *d;
500               vlib_cli_parse_rule_t *r;
501
502               d = vec_elt_at_index (cm->commands, subs[i].command_index);
503               r =
504                 subs[i].rule_index != ~0 ? vec_elt_at_index (cm->parse_rules,
505                                                              subs
506                                                              [i].rule_index) :
507                 0;
508
509               if (r)
510                 vlib_cli_output
511                   (vm, "  %-30U %U",
512                    format_vlib_cli_parse_rule_name, r,
513                    format_vlib_cli_command_help, d, /* is_long */ 0);
514               else
515                 vlib_cli_output
516                   (vm, "  %-30v %U",
517                    subs[i].name,
518                    format_vlib_cli_command_help, d, /* is_long */ 0);
519             }
520
521           vec_free (subs);
522         }
523     }
524
525   else if (is_main_dispatch
526            && (unformat (input, "choices") || unformat (input, "?")))
527     {
528       vlib_cli_command_t *sub, *subs;
529
530       subs = all_subs (cm, 0, parent_command_index);
531       vec_sort_with_function (subs, vlib_cli_cmp_command);
532       vec_foreach (sub, subs)
533         vlib_cli_output (vm, "  %-40U %U",
534                          format_vlib_cli_path, sub->path,
535                          format_vlib_cli_command_help, sub, /* is_long */ 0);
536       vec_free (subs);
537     }
538
539   else if (unformat (input, "comment %v", &string))
540     {
541       vec_free (string);
542     }
543
544   else if (unformat (input, "uncomment %U",
545                      unformat_vlib_cli_sub_input, &sub_input))
546     {
547       error =
548         vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
549                                         parent_command_index);
550       unformat_free (&sub_input);
551     }
552
553   else
554     if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
555     {
556       unformat_input_t *si;
557       uword has_sub_commands =
558         vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
559
560       si = input;
561       if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
562         si = &sub_input;
563
564       if (has_sub_commands)
565         error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
566
567       if (has_sub_commands && !error)
568         /* Found valid sub-command. */ ;
569
570       else if (c->function)
571         {
572           clib_error_t *c_error;
573
574           /* Skip white space for benefit of called function. */
575           unformat_skip_white_space (si);
576
577           if (unformat (si, "?"))
578             {
579               vlib_cli_output (vm, "  %-40U %U", format_vlib_cli_path, c->path, format_vlib_cli_command_help, c,        /* is_long */
580                                0);
581             }
582           else
583             {
584               if (!c->is_mp_safe)
585                 vlib_worker_thread_barrier_sync (vm);
586
587               c_error = c->function (vm, si, c);
588
589               if (!c->is_mp_safe)
590                 vlib_worker_thread_barrier_release (vm);
591
592               if (c_error)
593                 {
594                   error =
595                     clib_error_return (0, "%v: %v", c->path, c_error->what);
596                   clib_error_free (c_error);
597                   /* Free sub input. */
598                   if (si != input)
599                     unformat_free (si);
600
601                   return error;
602                 }
603             }
604
605           /* Free any previous error. */
606           clib_error_free (error);
607         }
608
609       else if (!error)
610         error = clib_error_return (0, "%v: no sub-commands", c->path);
611
612       /* Free sub input. */
613       if (si != input)
614         unformat_free (si);
615     }
616
617   else
618     goto unknown;
619
620   return error;
621
622 unknown:
623   if (parent->path)
624     return clib_error_return (0, "%v: unknown input `%U'", parent->path,
625                               format_unformat_error, input);
626   else
627     return clib_error_return (0, "unknown input `%U'", format_unformat_error,
628                               input);
629 }
630
631
632 void vlib_unix_error_report (vlib_main_t *, clib_error_t *)
633   __attribute__ ((weak));
634
635 void
636 vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error)
637 {
638 }
639
640 /* Process CLI input. */
641 void
642 vlib_cli_input (vlib_main_t * vm,
643                 unformat_input_t * input,
644                 vlib_cli_output_function_t * function, uword function_arg)
645 {
646   vlib_process_t *cp = vlib_get_current_process (vm);
647   vlib_cli_main_t *cm = &vm->cli_main;
648   clib_error_t *error;
649   vlib_cli_output_function_t *save_function;
650   uword save_function_arg;
651
652   save_function = cp->output_function;
653   save_function_arg = cp->output_function_arg;
654
655   cp->output_function = function;
656   cp->output_function_arg = function_arg;
657
658   do
659     {
660       vec_reset_length (cm->parse_rule_data);
661       error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input, /* parent */
662                                               0);
663     }
664   while (!error && !unformat (input, "%U", unformat_eof));
665
666   if (error)
667     {
668       vlib_cli_output (vm, "%v", error->what);
669       vlib_unix_error_report (vm, error);
670       clib_error_free (error);
671     }
672
673   cp->output_function = save_function;
674   cp->output_function_arg = save_function_arg;
675 }
676
677 /* Output to current CLI connection. */
678 void
679 vlib_cli_output (vlib_main_t * vm, char *fmt, ...)
680 {
681   vlib_process_t *cp = vlib_get_current_process (vm);
682   va_list va;
683   u8 *s;
684
685   va_start (va, fmt);
686   s = va_format (0, fmt, &va);
687   va_end (va);
688
689   /* Terminate with \n if not present. */
690   if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
691     vec_add1 (s, '\n');
692
693   if ((!cp) || (!cp->output_function))
694     fformat (stdout, "%v", s);
695   else
696     cp->output_function (cp->output_function_arg, s, vec_len (s));
697
698   vec_free (s);
699 }
700
701 static clib_error_t *
702 show_memory_usage (vlib_main_t * vm,
703                    unformat_input_t * input, vlib_cli_command_t * cmd)
704 {
705   int verbose = 0;
706   clib_error_t *error;
707   u32 index = 0;
708
709   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
710     {
711       if (unformat (input, "verbose"))
712         verbose = 1;
713       else
714         {
715           error = clib_error_return (0, "unknown input `%U'",
716                                      format_unformat_error, input);
717           return error;
718         }
719     }
720
721   /* *INDENT-OFF* */
722   foreach_vlib_main (
723   ({
724       vlib_cli_output (vm, "Thread %d %v\n", index, vlib_worker_threads[index].name);
725       vlib_cli_output (vm, "%U\n", format_mheap, clib_per_cpu_mheaps[index], verbose);
726       index++;
727   }));
728   /* *INDENT-ON* */
729   return 0;
730 }
731
732 /* *INDENT-OFF* */
733 VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
734   .path = "show memory",
735   .short_help = "Show current memory usage",
736   .function = show_memory_usage,
737 };
738 /* *INDENT-ON* */
739
740 static clib_error_t *
741 show_cpu (vlib_main_t * vm, unformat_input_t * input,
742           vlib_cli_command_t * cmd)
743 {
744 #define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
745   _("Model name", "%U", format_cpu_model_name);
746   _("Microarchitecture", "%U", format_cpu_uarch);
747   _("Flags", "%U", format_cpu_flags);
748   _("Base frequency", "%.2f GHz",
749     ((f64) vm->clib_time.clocks_per_second) * 1e-9);
750 #undef _
751   return 0;
752 }
753
754 /*?
755  * Displays various information about the CPU.
756  *
757  * @cliexpar
758  * @cliexstart{show cpu}
759  * Model name:               Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz
760  * Microarchitecture:        Broadwell (Broadwell-EP/EX)
761  * Flags:                    sse3 ssse3 sse41 sse42 avx avx2 aes
762  * Base Frequency:           3.20 GHz
763  * @cliexend
764 ?*/
765 /* *INDENT-OFF* */
766 VLIB_CLI_COMMAND (show_cpu_command, static) = {
767   .path = "show cpu",
768   .short_help = "Show cpu information",
769   .function = show_cpu,
770 };
771
772 /* *INDENT-ON* */
773 static clib_error_t *
774 enable_disable_memory_trace (vlib_main_t * vm,
775                              unformat_input_t * input,
776                              vlib_cli_command_t * cmd)
777 {
778   clib_error_t *error = 0;
779   int enable;
780
781   if (!unformat_user (input, unformat_vlib_enable_disable, &enable))
782     {
783       error = clib_error_return (0, "expecting enable/on or disable/off");
784       goto done;
785     }
786
787   clib_mem_trace (enable);
788
789 done:
790   return error;
791 }
792
793 /* *INDENT-OFF* */
794 VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
795   .path = "memory-trace",
796   .short_help = "Enable/disable memory allocation trace",
797   .function = enable_disable_memory_trace,
798 };
799 /* *INDENT-ON* */
800
801
802 static clib_error_t *
803 test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
804                     vlib_cli_command_t * cmd)
805 {
806   clib_error_t *error = 0;
807   void *heap;
808   mheap_t *mheap;
809
810   if (unformat (input, "on"))
811     {
812         /* *INDENT-OFF* */
813         foreach_vlib_main({
814           heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
815           mheap = mheap_header(heap);
816           mheap->flags |= MHEAP_FLAG_VALIDATE;
817           // Turn off small object cache because it delays detection of errors
818           mheap->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
819         });
820         /* *INDENT-ON* */
821
822     }
823   else if (unformat (input, "off"))
824     {
825         /* *INDENT-OFF* */
826         foreach_vlib_main({
827           heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
828           mheap = mheap_header(heap);
829           mheap->flags &= ~MHEAP_FLAG_VALIDATE;
830           mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
831         });
832         /* *INDENT-ON* */
833     }
834   else if (unformat (input, "now"))
835     {
836         /* *INDENT-OFF* */
837         foreach_vlib_main({
838           heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
839           mheap = mheap_header(heap);
840           mheap_validate(heap);
841         });
842         /* *INDENT-ON* */
843       vlib_cli_output (vm, "heap validation complete");
844
845     }
846   else
847     {
848       return clib_error_return (0, "unknown input `%U'",
849                                 format_unformat_error, input);
850     }
851
852   return error;
853 }
854
855 /* *INDENT-OFF* */
856 VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
857     .path = "test heap-validate",
858     .short_help = "<on/off/now> validate heap on future allocs/frees or right now",
859     .function = test_heap_validate,
860 };
861 /* *INDENT-ON* */
862
863 static clib_error_t *
864 restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
865                 vlib_cli_command_t * cmd)
866 {
867   char *newenviron[] = { NULL };
868
869   execve (vm->name, (char **) vm->argv, newenviron);
870
871   return 0;
872 }
873
874 /* *INDENT-OFF* */
875 VLIB_CLI_COMMAND (restart_cmd,static) = {
876     .path = "restart",
877     .short_help = "restart process",
878     .function = restart_cmd_fn,
879 };
880 /* *INDENT-ON* */
881
882 #ifdef TEST_CODE
883 /*
884  * A trivial test harness to verify the per-process output_function
885  * is working correcty.
886  */
887
888 static clib_error_t *
889 sleep_ten_seconds (vlib_main_t * vm,
890                    unformat_input_t * input, vlib_cli_command_t * cmd)
891 {
892   u16 i;
893   u16 my_id = rand ();
894
895   vlib_cli_output (vm, "Starting 10 seconds sleep with id %u\n", my_id);
896
897   for (i = 0; i < 10; i++)
898     {
899       vlib_process_wait_for_event_or_clock (vm, 1.0);
900       vlib_cli_output (vm, "Iteration number %u, my id: %u\n", i, my_id);
901     }
902   vlib_cli_output (vm, "Done with sleep with id %u\n", my_id);
903   return 0;
904 }
905
906 /* *INDENT-OFF* */
907 VLIB_CLI_COMMAND (ping_command, static) = {
908   .path = "test sleep",
909   .function = sleep_ten_seconds,
910   .short_help = "Sleep for 10 seconds",
911 };
912 /* *INDENT-ON* */
913 #endif /* ifdef TEST_CODE */
914
915 static uword
916 vlib_cli_normalize_path (char *input, char **result)
917 {
918   char *i = input;
919   char *s = 0;
920   uword l = 0;
921   uword index_of_last_space = ~0;
922
923   while (*i != 0)
924     {
925       u8 c = *i++;
926       /* Multiple white space -> single space. */
927       switch (c)
928         {
929         case ' ':
930         case '\t':
931         case '\n':
932         case '\r':
933           if (l > 0 && s[l - 1] != ' ')
934             {
935               vec_add1 (s, ' ');
936               l++;
937             }
938           break;
939
940         default:
941           if (l > 0 && s[l - 1] == ' ')
942             index_of_last_space = vec_len (s);
943           vec_add1 (s, c);
944           l++;
945           break;
946         }
947     }
948
949   /* Remove any extra space at end. */
950   if (l > 0 && s[l - 1] == ' ')
951     _vec_len (s) -= 1;
952
953   *result = s;
954   return index_of_last_space;
955 }
956
957 always_inline uword
958 parent_path_len (char *path)
959 {
960   word i;
961   for (i = vec_len (path) - 1; i >= 0; i--)
962     {
963       if (path[i] == ' ')
964         return i;
965     }
966   return ~0;
967 }
968
969 static void
970 add_sub_command (vlib_cli_main_t * cm, uword parent_index, uword child_index)
971 {
972   vlib_cli_command_t *p, *c;
973   vlib_cli_sub_command_t *sub_c;
974   u8 *sub_name;
975   word i, l;
976
977   p = vec_elt_at_index (cm->commands, parent_index);
978   c = vec_elt_at_index (cm->commands, child_index);
979
980   l = parent_path_len (c->path);
981   if (l == ~0)
982     sub_name = vec_dup ((u8 *) c->path);
983   else
984     {
985       ASSERT (l + 1 < vec_len (c->path));
986       sub_name = 0;
987       vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
988     }
989
990   if (sub_name[0] == '%')
991     {
992       uword *q;
993       vlib_cli_sub_rule_t *sr;
994
995       /* Remove %. */
996       vec_delete (sub_name, 1, 0);
997
998       if (!p->sub_rule_index_by_name)
999         p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1000                                                      sizeof (sub_name[0]),
1001                                                      sizeof (uword));
1002       q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
1003       if (q)
1004         {
1005           sr = vec_elt_at_index (p->sub_rules, q[0]);
1006           ASSERT (sr->command_index == child_index);
1007           return;
1008         }
1009
1010       q = hash_get_mem (cm->parse_rule_index_by_name, sub_name);
1011       if (!q)
1012         {
1013           clib_error ("reference to unknown rule `%%%v' in path `%v'",
1014                       sub_name, c->path);
1015           return;
1016         }
1017
1018       hash_set_mem (p->sub_rule_index_by_name, sub_name,
1019                     vec_len (p->sub_rules));
1020       vec_add2 (p->sub_rules, sr, 1);
1021       sr->name = sub_name;
1022       sr->rule_index = q[0];
1023       sr->command_index = child_index;
1024       return;
1025     }
1026
1027   if (!p->sub_command_index_by_name)
1028     p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32,
1029                                                     sizeof (c->path[0]),
1030                                                     sizeof (uword));
1031
1032   /* Check if sub-command has already been created. */
1033   if (hash_get_mem (p->sub_command_index_by_name, sub_name))
1034     {
1035       vec_free (sub_name);
1036       return;
1037     }
1038
1039   vec_add2 (p->sub_commands, sub_c, 1);
1040   sub_c->index = child_index;
1041   sub_c->name = sub_name;
1042   hash_set_mem (p->sub_command_index_by_name, sub_c->name,
1043                 sub_c - p->sub_commands);
1044
1045   vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
1046   for (i = 0; i < vec_len (sub_c->name); i++)
1047     {
1048       int n;
1049       vlib_cli_parse_position_t *pos;
1050
1051       pos = vec_elt_at_index (p->sub_command_positions, i);
1052
1053       if (!pos->bitmaps)
1054         pos->min_char = sub_c->name[i];
1055
1056       n = sub_c->name[i] - pos->min_char;
1057       if (n < 0)
1058         {
1059           pos->min_char = sub_c->name[i];
1060           vec_insert (pos->bitmaps, -n, 0);
1061           n = 0;
1062         }
1063
1064       vec_validate (pos->bitmaps, n);
1065       pos->bitmaps[n] =
1066         clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
1067     }
1068 }
1069
1070 static void
1071 vlib_cli_make_parent (vlib_cli_main_t * cm, uword ci)
1072 {
1073   uword p_len, pi, *p;
1074   char *p_path;
1075   vlib_cli_command_t *c, *parent;
1076
1077   /* Root command (index 0) should have already been added. */
1078   ASSERT (vec_len (cm->commands) > 0);
1079
1080   c = vec_elt_at_index (cm->commands, ci);
1081   p_len = parent_path_len (c->path);
1082
1083   /* No space?  Parent is root command. */
1084   if (p_len == ~0)
1085     {
1086       add_sub_command (cm, 0, ci);
1087       return;
1088     }
1089
1090   p_path = 0;
1091   vec_add (p_path, c->path, p_len);
1092
1093   p = hash_get_mem (cm->command_index_by_path, p_path);
1094
1095   /* Parent exists? */
1096   if (!p)
1097     {
1098       /* Parent does not exist; create it. */
1099       vec_add2 (cm->commands, parent, 1);
1100       parent->path = p_path;
1101       hash_set_mem (cm->command_index_by_path, parent->path,
1102                     parent - cm->commands);
1103       pi = parent - cm->commands;
1104     }
1105   else
1106     {
1107       pi = p[0];
1108       vec_free (p_path);
1109     }
1110
1111   add_sub_command (cm, pi, ci);
1112
1113   /* Create parent's parent. */
1114   if (!p)
1115     vlib_cli_make_parent (cm, pi);
1116 }
1117
1118 always_inline uword
1119 vlib_cli_command_is_empty (vlib_cli_command_t * c)
1120 {
1121   return (c->long_help == 0 && c->short_help == 0 && c->function == 0);
1122 }
1123
1124 clib_error_t *
1125 vlib_cli_register (vlib_main_t * vm, vlib_cli_command_t * c)
1126 {
1127   vlib_cli_main_t *cm = &vm->cli_main;
1128   clib_error_t *error = 0;
1129   uword ci, *p;
1130   char *normalized_path;
1131
1132   if ((error = vlib_call_init_function (vm, vlib_cli_init)))
1133     return error;
1134
1135   (void) vlib_cli_normalize_path (c->path, &normalized_path);
1136
1137   if (!cm->command_index_by_path)
1138     cm->command_index_by_path = hash_create_vec ( /* initial length */ 32,
1139                                                  sizeof (c->path[0]),
1140                                                  sizeof (uword));
1141
1142   /* See if command already exists with given path. */
1143   p = hash_get_mem (cm->command_index_by_path, normalized_path);
1144   if (p)
1145     {
1146       vlib_cli_command_t *d;
1147
1148       ci = p[0];
1149       d = vec_elt_at_index (cm->commands, ci);
1150
1151       /* If existing command was created via vlib_cli_make_parent
1152          replaced it with callers data. */
1153       if (vlib_cli_command_is_empty (d))
1154         {
1155           vlib_cli_command_t save = d[0];
1156
1157           ASSERT (!vlib_cli_command_is_empty (c));
1158
1159           /* Copy callers fields. */
1160           d[0] = c[0];
1161
1162           /* Save internal fields. */
1163           d->path = save.path;
1164           d->sub_commands = save.sub_commands;
1165           d->sub_command_index_by_name = save.sub_command_index_by_name;
1166           d->sub_command_positions = save.sub_command_positions;
1167           d->sub_rules = save.sub_rules;
1168         }
1169       else
1170         error =
1171           clib_error_return (0, "duplicate command name with path %v",
1172                              normalized_path);
1173
1174       vec_free (normalized_path);
1175       if (error)
1176         return error;
1177     }
1178   else
1179     {
1180       /* Command does not exist: create it. */
1181
1182       /* Add root command (index 0). */
1183       if (vec_len (cm->commands) == 0)
1184         {
1185           /* Create command with index 0; path is empty string. */
1186           vec_resize (cm->commands, 1);
1187         }
1188
1189       ci = vec_len (cm->commands);
1190       hash_set_mem (cm->command_index_by_path, normalized_path, ci);
1191       vec_add1 (cm->commands, c[0]);
1192
1193       c = vec_elt_at_index (cm->commands, ci);
1194       c->path = normalized_path;
1195
1196       /* Don't inherit from registration. */
1197       c->sub_commands = 0;
1198       c->sub_command_index_by_name = 0;
1199       c->sub_command_positions = 0;
1200     }
1201
1202   vlib_cli_make_parent (cm, ci);
1203   return 0;
1204 }
1205
1206 clib_error_t *
1207 vlib_cli_register_parse_rule (vlib_main_t * vm, vlib_cli_parse_rule_t * r_reg)
1208 {
1209   vlib_cli_main_t *cm = &vm->cli_main;
1210   vlib_cli_parse_rule_t *r;
1211   clib_error_t *error = 0;
1212   u8 *r_name;
1213   uword *p;
1214
1215   if (!cm->parse_rule_index_by_name)
1216     cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1217                                                     sizeof (r->name[0]),
1218                                                     sizeof (uword));
1219
1220   /* Make vector copy of name. */
1221   r_name = format (0, "%s", r_reg->name);
1222
1223   if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
1224     {
1225       vec_free (r_name);
1226       return clib_error_return (0, "duplicate parse rule name `%s'",
1227                                 r_reg->name);
1228     }
1229
1230   vec_add2 (cm->parse_rules, r, 1);
1231   r[0] = r_reg[0];
1232   r->name = (char *) r_name;
1233   hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules);
1234
1235   return error;
1236 }
1237
1238 #if 0
1239 /* $$$ turn back on again someday, maybe */
1240 static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm,
1241                                                     vlib_cli_parse_rule_t *
1242                                                     lo,
1243                                                     vlib_cli_parse_rule_t *
1244                                                     hi)
1245   __attribute__ ((unused))
1246 {
1247   clib_error_t *error = 0;
1248   vlib_cli_parse_rule_t *r;
1249
1250   for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
1251     {
1252       if (!r->name || strlen (r->name) == 0)
1253         {
1254           error = clib_error_return (0, "parse rule with no name");
1255           goto done;
1256         }
1257
1258       error = vlib_cli_register_parse_rule (vm, r);
1259       if (error)
1260         goto done;
1261     }
1262
1263 done:
1264   return error;
1265 }
1266 #endif
1267
1268 static int
1269 cli_path_compare (void *a1, void *a2)
1270 {
1271   u8 **s1 = a1;
1272   u8 **s2 = a2;
1273
1274   if ((vec_len (*s1) < vec_len (*s2)) &&
1275       memcmp ((char *) *s1, (char *) *s2, vec_len (*s1)) == 0)
1276     return -1;
1277
1278
1279   if ((vec_len (*s1) > vec_len (*s2)) &&
1280       memcmp ((char *) *s1, (char *) *s2, vec_len (*s2)) == 0)
1281     return 1;
1282
1283   return vec_cmp (*s1, *s2);
1284 }
1285
1286 static clib_error_t *
1287 show_cli_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
1288                  vlib_cli_command_t * cmd)
1289 {
1290   vlib_cli_main_t *cm = &vm->cli_main;
1291   vlib_cli_command_t *cli;
1292   u8 **paths = 0, **s;
1293
1294   /* *INDENT-OFF* */
1295   vec_foreach (cli, cm->commands)
1296     if (vec_len (cli->path) > 0)
1297       vec_add1 (paths, (u8 *) cli->path);
1298
1299   vec_sort_with_function (paths, cli_path_compare);
1300
1301   vec_foreach (s, paths)
1302     vlib_cli_output (vm, "%v", *s);
1303   /* *INDENT-ON* */
1304
1305   vec_free (paths);
1306   return 0;
1307 }
1308
1309 /* *INDENT-OFF* */
1310 VLIB_CLI_COMMAND (show_cli_command, static) = {
1311   .path = "show cli",
1312   .short_help = "Show cli commands",
1313   .function = show_cli_cmd_fn,
1314 };
1315 /* *INDENT-ON* */
1316
1317 static clib_error_t *
1318 vlib_cli_init (vlib_main_t * vm)
1319 {
1320   vlib_cli_main_t *cm = &vm->cli_main;
1321   clib_error_t *error = 0;
1322   vlib_cli_command_t *cmd;
1323
1324   cmd = cm->cli_command_registrations;
1325
1326   while (cmd)
1327     {
1328       error = vlib_cli_register (vm, cmd);
1329       if (error)
1330         return error;
1331       cmd = cmd->next_cli_command;
1332     }
1333   return error;
1334 }
1335
1336 VLIB_INIT_FUNCTION (vlib_cli_init);
1337
1338 /*
1339  * fd.io coding-style-patch-verification: ON
1340  *
1341  * Local Variables:
1342  * eval: (c-set-style "gnu")
1343  * End:
1344  */