48cf0426488a609bdf8a6f581c05951a3bed0317
[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   if (result)
337     vec_sort_with_function (result, vlib_cli_cmp_strings);
338   return result;
339 }
340
341 static u8 *
342 format_vlib_cli_command_help (u8 * s, va_list * args)
343 {
344   vlib_cli_command_t *c = va_arg (*args, vlib_cli_command_t *);
345   int is_long = va_arg (*args, int);
346   if (is_long && c->long_help)
347     s = format (s, "%s", c->long_help);
348   else if (c->short_help)
349     s = format (s, "%s", c->short_help);
350   else
351     s = format (s, "%v commands", c->path);
352   return s;
353 }
354
355 static u8 *
356 format_vlib_cli_parse_rule_name (u8 * s, va_list * args)
357 {
358   vlib_cli_parse_rule_t *r = va_arg (*args, vlib_cli_parse_rule_t *);
359   return format (s, "<%U>", format_c_identifier, r->name);
360 }
361
362 static u8 *
363 format_vlib_cli_path (u8 * s, va_list * args)
364 {
365   u8 *path = va_arg (*args, u8 *);
366   int i, in_rule;
367   in_rule = 0;
368   for (i = 0; i < vec_len (path); i++)
369     {
370       switch (path[i])
371         {
372         case '%':
373           in_rule = 1;
374           vec_add1 (s, '<');    /* start of <RULE> */
375           break;
376
377         case '_':
378           /* _ -> space in rules. */
379           vec_add1 (s, in_rule ? ' ' : '_');
380           break;
381
382         case ' ':
383           if (in_rule)
384             {
385               vec_add1 (s, '>');        /* end of <RULE> */
386               in_rule = 0;
387             }
388           vec_add1 (s, ' ');
389           break;
390
391         default:
392           vec_add1 (s, path[i]);
393           break;
394         }
395     }
396
397   if (in_rule)
398     vec_add1 (s, '>');          /* terminate <RULE> */
399
400   return s;
401 }
402
403 static vlib_cli_command_t *
404 all_subs (vlib_cli_main_t * cm, vlib_cli_command_t * subs, u32 command_index)
405 {
406   vlib_cli_command_t *c = vec_elt_at_index (cm->commands, command_index);
407   vlib_cli_sub_command_t *sc;
408   vlib_cli_sub_rule_t *sr;
409
410   if (c->function)
411     vec_add1 (subs, c[0]);
412
413   vec_foreach (sr, c->sub_rules)
414     subs = all_subs (cm, subs, sr->command_index);
415   vec_foreach (sc, c->sub_commands) subs = all_subs (cm, subs, sc->index);
416
417   return subs;
418 }
419
420 static int
421 vlib_cli_cmp_rule (void *a1, void *a2)
422 {
423   vlib_cli_sub_rule_t *r1 = a1;
424   vlib_cli_sub_rule_t *r2 = a2;
425
426   return vec_cmp (r1->name, r2->name);
427 }
428
429 static int
430 vlib_cli_cmp_command (void *a1, void *a2)
431 {
432   vlib_cli_command_t *c1 = a1;
433   vlib_cli_command_t *c2 = a2;
434
435   return vec_cmp (c1->path, c2->path);
436 }
437
438 static clib_error_t *
439 vlib_cli_dispatch_sub_commands (vlib_main_t * vm,
440                                 vlib_cli_main_t * cm,
441                                 unformat_input_t * input,
442                                 uword parent_command_index)
443 {
444   vlib_cli_command_t *parent, *c;
445   clib_error_t *error = 0;
446   unformat_input_t sub_input;
447   u8 *string;
448   uword is_main_dispatch = cm == &vm->cli_main;
449
450   parent = vec_elt_at_index (cm->commands, parent_command_index);
451   if (is_main_dispatch && unformat (input, "help"))
452     {
453       uword help_at_end_of_line, i;
454
455       help_at_end_of_line =
456         unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
457       while (1)
458         {
459           c = parent;
460           if (unformat_user
461               (input, unformat_vlib_cli_sub_command, vm, c, &parent))
462             ;
463
464           else if (!(unformat_check_input (input) == UNFORMAT_END_OF_INPUT))
465             goto unknown;
466
467           else
468             break;
469         }
470
471       /* help SUB-COMMAND => long format help.
472          "help" at end of line: show all commands. */
473       if (!help_at_end_of_line)
474         vlib_cli_output (vm, "%U", format_vlib_cli_command_help, c,
475                          /* is_long */ 1);
476
477       else if (vec_len (c->sub_commands) + vec_len (c->sub_rules) == 0)
478         vlib_cli_output (vm, "%v: no sub-commands", c->path);
479
480       else
481         {
482           vlib_cli_sub_command_t *sc;
483           vlib_cli_sub_rule_t *sr, *subs;
484
485           subs = vec_dup (c->sub_rules);
486
487           /* Add in rules if any. */
488           vec_foreach (sc, c->sub_commands)
489           {
490             vec_add2 (subs, sr, 1);
491             sr->name = sc->name;
492             sr->command_index = sc->index;
493             sr->rule_index = ~0;
494           }
495
496           vec_sort_with_function (subs, vlib_cli_cmp_rule);
497
498           for (i = 0; i < vec_len (subs); i++)
499             {
500               vlib_cli_command_t *d;
501               vlib_cli_parse_rule_t *r;
502
503               d = vec_elt_at_index (cm->commands, subs[i].command_index);
504               r =
505                 subs[i].rule_index != ~0 ? vec_elt_at_index (cm->parse_rules,
506                                                              subs
507                                                              [i].rule_index) :
508                 0;
509
510               if (r)
511                 vlib_cli_output
512                   (vm, "  %-30U %U",
513                    format_vlib_cli_parse_rule_name, r,
514                    format_vlib_cli_command_help, d, /* is_long */ 0);
515               else
516                 vlib_cli_output
517                   (vm, "  %-30v %U",
518                    subs[i].name,
519                    format_vlib_cli_command_help, d, /* is_long */ 0);
520             }
521
522           vec_free (subs);
523         }
524     }
525
526   else if (is_main_dispatch
527            && (unformat (input, "choices") || unformat (input, "?")))
528     {
529       vlib_cli_command_t *sub, *subs;
530
531       subs = all_subs (cm, 0, parent_command_index);
532       vec_sort_with_function (subs, vlib_cli_cmp_command);
533       vec_foreach (sub, subs)
534         vlib_cli_output (vm, "  %-40U %U",
535                          format_vlib_cli_path, sub->path,
536                          format_vlib_cli_command_help, sub, /* is_long */ 0);
537       vec_free (subs);
538     }
539
540   else if (unformat (input, "comment %v", &string))
541     {
542       vec_free (string);
543     }
544
545   else if (unformat (input, "uncomment %U",
546                      unformat_vlib_cli_sub_input, &sub_input))
547     {
548       error =
549         vlib_cli_dispatch_sub_commands (vm, cm, &sub_input,
550                                         parent_command_index);
551       unformat_free (&sub_input);
552     }
553
554   else
555     if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c))
556     {
557       unformat_input_t *si;
558       uword has_sub_commands =
559         vec_len (c->sub_commands) + vec_len (c->sub_rules) > 0;
560
561       si = input;
562       if (unformat_user (input, unformat_vlib_cli_sub_input, &sub_input))
563         si = &sub_input;
564
565       if (has_sub_commands)
566         error = vlib_cli_dispatch_sub_commands (vm, cm, si, c - cm->commands);
567
568       if (has_sub_commands && !error)
569         /* Found valid sub-command. */ ;
570
571       else if (c->function)
572         {
573           clib_error_t *c_error;
574
575           /* Skip white space for benefit of called function. */
576           unformat_skip_white_space (si);
577
578           if (unformat (si, "?"))
579             {
580               vlib_cli_output (vm, "  %-40U %U", format_vlib_cli_path, c->path, format_vlib_cli_command_help, c,        /* is_long */
581                                0);
582             }
583           else
584             {
585               if (!c->is_mp_safe)
586                 vlib_worker_thread_barrier_sync (vm);
587
588               c_error = c->function (vm, si, c);
589
590               if (!c->is_mp_safe)
591                 vlib_worker_thread_barrier_release (vm);
592
593               if (c_error)
594                 {
595                   error =
596                     clib_error_return (0, "%v: %v", c->path, c_error->what);
597                   clib_error_free (c_error);
598                   /* Free sub input. */
599                   if (si != input)
600                     unformat_free (si);
601
602                   return error;
603                 }
604             }
605
606           /* Free any previous error. */
607           clib_error_free (error);
608         }
609
610       else if (!error)
611         error = clib_error_return (0, "%v: no sub-commands", c->path);
612
613       /* Free sub input. */
614       if (si != input)
615         unformat_free (si);
616     }
617
618   else
619     goto unknown;
620
621   return error;
622
623 unknown:
624   if (parent->path)
625     return clib_error_return (0, "%v: unknown input `%U'", parent->path,
626                               format_unformat_error, input);
627   else
628     return clib_error_return (0, "unknown input `%U'", format_unformat_error,
629                               input);
630 }
631
632
633 void vlib_unix_error_report (vlib_main_t *, clib_error_t *)
634   __attribute__ ((weak));
635
636 void
637 vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error)
638 {
639 }
640
641 /* Process CLI input. */
642 void
643 vlib_cli_input (vlib_main_t * vm,
644                 unformat_input_t * input,
645                 vlib_cli_output_function_t * function, uword function_arg)
646 {
647   vlib_process_t *cp = vlib_get_current_process (vm);
648   vlib_cli_main_t *cm = &vm->cli_main;
649   clib_error_t *error;
650   vlib_cli_output_function_t *save_function;
651   uword save_function_arg;
652
653   save_function = cp->output_function;
654   save_function_arg = cp->output_function_arg;
655
656   cp->output_function = function;
657   cp->output_function_arg = function_arg;
658
659   do
660     {
661       vec_reset_length (cm->parse_rule_data);
662       error = vlib_cli_dispatch_sub_commands (vm, &vm->cli_main, input, /* parent */
663                                               0);
664     }
665   while (!error && !unformat (input, "%U", unformat_eof));
666
667   if (error)
668     {
669       vlib_cli_output (vm, "%v", error->what);
670       vlib_unix_error_report (vm, error);
671       clib_error_free (error);
672     }
673
674   cp->output_function = save_function;
675   cp->output_function_arg = save_function_arg;
676 }
677
678 /* Output to current CLI connection. */
679 void
680 vlib_cli_output (vlib_main_t * vm, char *fmt, ...)
681 {
682   vlib_process_t *cp = vlib_get_current_process (vm);
683   va_list va;
684   u8 *s;
685
686   va_start (va, fmt);
687   s = va_format (0, fmt, &va);
688   va_end (va);
689
690   /* Terminate with \n if not present. */
691   if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
692     vec_add1 (s, '\n');
693
694   if ((!cp) || (!cp->output_function))
695     fformat (stdout, "%v", s);
696   else
697     cp->output_function (cp->output_function_arg, s, vec_len (s));
698
699   vec_free (s);
700 }
701
702 static clib_error_t *
703 show_memory_usage (vlib_main_t * vm,
704                    unformat_input_t * input, vlib_cli_command_t * cmd)
705 {
706   int verbose = 0;
707   clib_error_t *error;
708   u32 index = 0;
709
710   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
711     {
712       if (unformat (input, "verbose"))
713         verbose = 1;
714       else
715         {
716           error = clib_error_return (0, "unknown input `%U'",
717                                      format_unformat_error, input);
718           return error;
719         }
720     }
721
722   /* *INDENT-OFF* */
723   foreach_vlib_main (
724   ({
725       vlib_cli_output (vm, "Thread %d %v\n", index, vlib_worker_threads[index].name);
726       vlib_cli_output (vm, "%U\n", format_mheap, clib_per_cpu_mheaps[index], verbose);
727       index++;
728   }));
729   /* *INDENT-ON* */
730   return 0;
731 }
732
733 /* *INDENT-OFF* */
734 VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
735   .path = "show memory",
736   .short_help = "Show current memory usage",
737   .function = show_memory_usage,
738 };
739 /* *INDENT-ON* */
740
741 static clib_error_t *
742 show_cpu (vlib_main_t * vm, unformat_input_t * input,
743           vlib_cli_command_t * cmd)
744 {
745 #define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
746   _("Model name", "%U", format_cpu_model_name);
747   _("Microarchitecture", "%U", format_cpu_uarch);
748   _("Flags", "%U", format_cpu_flags);
749   _("Base frequency", "%.2f GHz",
750     ((f64) vm->clib_time.clocks_per_second) * 1e-9);
751 #undef _
752   return 0;
753 }
754
755 /*?
756  * Displays various information about the CPU.
757  *
758  * @cliexpar
759  * @cliexstart{show cpu}
760  * Model name:               Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz
761  * Microarchitecture:        Broadwell (Broadwell-EP/EX)
762  * Flags:                    sse3 ssse3 sse41 sse42 avx avx2 aes
763  * Base Frequency:           3.20 GHz
764  * @cliexend
765 ?*/
766 /* *INDENT-OFF* */
767 VLIB_CLI_COMMAND (show_cpu_command, static) = {
768   .path = "show cpu",
769   .short_help = "Show cpu information",
770   .function = show_cpu,
771 };
772
773 /* *INDENT-ON* */
774 static clib_error_t *
775 enable_disable_memory_trace (vlib_main_t * vm,
776                              unformat_input_t * input,
777                              vlib_cli_command_t * cmd)
778 {
779   clib_error_t *error = 0;
780   int enable;
781
782   if (!unformat_user (input, unformat_vlib_enable_disable, &enable))
783     {
784       error = clib_error_return (0, "expecting enable/on or disable/off");
785       goto done;
786     }
787
788   clib_mem_trace (enable);
789
790 done:
791   return error;
792 }
793
794 /* *INDENT-OFF* */
795 VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
796   .path = "memory-trace",
797   .short_help = "Enable/disable memory allocation trace",
798   .function = enable_disable_memory_trace,
799 };
800 /* *INDENT-ON* */
801
802
803 static clib_error_t *
804 test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
805                     vlib_cli_command_t * cmd)
806 {
807   clib_error_t *error = 0;
808   void *heap;
809   mheap_t *mheap;
810
811   if (unformat (input, "on"))
812     {
813         /* *INDENT-OFF* */
814         foreach_vlib_main({
815           heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
816           mheap = mheap_header(heap);
817           mheap->flags |= MHEAP_FLAG_VALIDATE;
818           // Turn off small object cache because it delays detection of errors
819           mheap->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
820         });
821         /* *INDENT-ON* */
822
823     }
824   else if (unformat (input, "off"))
825     {
826         /* *INDENT-OFF* */
827         foreach_vlib_main({
828           heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
829           mheap = mheap_header(heap);
830           mheap->flags &= ~MHEAP_FLAG_VALIDATE;
831           mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
832         });
833         /* *INDENT-ON* */
834     }
835   else if (unformat (input, "now"))
836     {
837         /* *INDENT-OFF* */
838         foreach_vlib_main({
839           heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
840           mheap = mheap_header(heap);
841           mheap_validate(heap);
842         });
843         /* *INDENT-ON* */
844       vlib_cli_output (vm, "heap validation complete");
845
846     }
847   else
848     {
849       return clib_error_return (0, "unknown input `%U'",
850                                 format_unformat_error, input);
851     }
852
853   return error;
854 }
855
856 /* *INDENT-OFF* */
857 VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
858     .path = "test heap-validate",
859     .short_help = "<on/off/now> validate heap on future allocs/frees or right now",
860     .function = test_heap_validate,
861 };
862 /* *INDENT-ON* */
863
864 static clib_error_t *
865 restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
866                 vlib_cli_command_t * cmd)
867 {
868   char *newenviron[] = { NULL };
869
870   execve (vm->name, (char **) vm->argv, newenviron);
871
872   return 0;
873 }
874
875 /* *INDENT-OFF* */
876 VLIB_CLI_COMMAND (restart_cmd,static) = {
877     .path = "restart",
878     .short_help = "restart process",
879     .function = restart_cmd_fn,
880 };
881 /* *INDENT-ON* */
882
883 #ifdef TEST_CODE
884 /*
885  * A trivial test harness to verify the per-process output_function
886  * is working correcty.
887  */
888
889 static clib_error_t *
890 sleep_ten_seconds (vlib_main_t * vm,
891                    unformat_input_t * input, vlib_cli_command_t * cmd)
892 {
893   u16 i;
894   u16 my_id = rand ();
895
896   vlib_cli_output (vm, "Starting 10 seconds sleep with id %u\n", my_id);
897
898   for (i = 0; i < 10; i++)
899     {
900       vlib_process_wait_for_event_or_clock (vm, 1.0);
901       vlib_cli_output (vm, "Iteration number %u, my id: %u\n", i, my_id);
902     }
903   vlib_cli_output (vm, "Done with sleep with id %u\n", my_id);
904   return 0;
905 }
906
907 /* *INDENT-OFF* */
908 VLIB_CLI_COMMAND (ping_command, static) = {
909   .path = "test sleep",
910   .function = sleep_ten_seconds,
911   .short_help = "Sleep for 10 seconds",
912 };
913 /* *INDENT-ON* */
914 #endif /* ifdef TEST_CODE */
915
916 static uword
917 vlib_cli_normalize_path (char *input, char **result)
918 {
919   char *i = input;
920   char *s = 0;
921   uword l = 0;
922   uword index_of_last_space = ~0;
923
924   while (*i != 0)
925     {
926       u8 c = *i++;
927       /* Multiple white space -> single space. */
928       switch (c)
929         {
930         case ' ':
931         case '\t':
932         case '\n':
933         case '\r':
934           if (l > 0 && s[l - 1] != ' ')
935             {
936               vec_add1 (s, ' ');
937               l++;
938             }
939           break;
940
941         default:
942           if (l > 0 && s[l - 1] == ' ')
943             index_of_last_space = vec_len (s);
944           vec_add1 (s, c);
945           l++;
946           break;
947         }
948     }
949
950   /* Remove any extra space at end. */
951   if (l > 0 && s[l - 1] == ' ')
952     _vec_len (s) -= 1;
953
954   *result = s;
955   return index_of_last_space;
956 }
957
958 always_inline uword
959 parent_path_len (char *path)
960 {
961   word i;
962   for (i = vec_len (path) - 1; i >= 0; i--)
963     {
964       if (path[i] == ' ')
965         return i;
966     }
967   return ~0;
968 }
969
970 static void
971 add_sub_command (vlib_cli_main_t * cm, uword parent_index, uword child_index)
972 {
973   vlib_cli_command_t *p, *c;
974   vlib_cli_sub_command_t *sub_c;
975   u8 *sub_name;
976   word i, l;
977
978   p = vec_elt_at_index (cm->commands, parent_index);
979   c = vec_elt_at_index (cm->commands, child_index);
980
981   l = parent_path_len (c->path);
982   if (l == ~0)
983     sub_name = vec_dup ((u8 *) c->path);
984   else
985     {
986       ASSERT (l + 1 < vec_len (c->path));
987       sub_name = 0;
988       vec_add (sub_name, c->path + l + 1, vec_len (c->path) - (l + 1));
989     }
990
991   if (sub_name[0] == '%')
992     {
993       uword *q;
994       vlib_cli_sub_rule_t *sr;
995
996       /* Remove %. */
997       vec_delete (sub_name, 1, 0);
998
999       if (!p->sub_rule_index_by_name)
1000         p->sub_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1001                                                      sizeof (sub_name[0]),
1002                                                      sizeof (uword));
1003       q = hash_get_mem (p->sub_rule_index_by_name, sub_name);
1004       if (q)
1005         {
1006           sr = vec_elt_at_index (p->sub_rules, q[0]);
1007           ASSERT (sr->command_index == child_index);
1008           return;
1009         }
1010
1011       q = hash_get_mem (cm->parse_rule_index_by_name, sub_name);
1012       if (!q)
1013         {
1014           clib_error ("reference to unknown rule `%%%v' in path `%v'",
1015                       sub_name, c->path);
1016           return;
1017         }
1018
1019       hash_set_mem (p->sub_rule_index_by_name, sub_name,
1020                     vec_len (p->sub_rules));
1021       vec_add2 (p->sub_rules, sr, 1);
1022       sr->name = sub_name;
1023       sr->rule_index = q[0];
1024       sr->command_index = child_index;
1025       return;
1026     }
1027
1028   if (!p->sub_command_index_by_name)
1029     p->sub_command_index_by_name = hash_create_vec ( /* initial length */ 32,
1030                                                     sizeof (c->path[0]),
1031                                                     sizeof (uword));
1032
1033   /* Check if sub-command has already been created. */
1034   if (hash_get_mem (p->sub_command_index_by_name, sub_name))
1035     {
1036       vec_free (sub_name);
1037       return;
1038     }
1039
1040   vec_add2 (p->sub_commands, sub_c, 1);
1041   sub_c->index = child_index;
1042   sub_c->name = sub_name;
1043   hash_set_mem (p->sub_command_index_by_name, sub_c->name,
1044                 sub_c - p->sub_commands);
1045
1046   vec_validate (p->sub_command_positions, vec_len (sub_c->name) - 1);
1047   for (i = 0; i < vec_len (sub_c->name); i++)
1048     {
1049       int n;
1050       vlib_cli_parse_position_t *pos;
1051
1052       pos = vec_elt_at_index (p->sub_command_positions, i);
1053
1054       if (!pos->bitmaps)
1055         pos->min_char = sub_c->name[i];
1056
1057       n = sub_c->name[i] - pos->min_char;
1058       if (n < 0)
1059         {
1060           pos->min_char = sub_c->name[i];
1061           vec_insert (pos->bitmaps, -n, 0);
1062           n = 0;
1063         }
1064
1065       vec_validate (pos->bitmaps, n);
1066       pos->bitmaps[n] =
1067         clib_bitmap_ori (pos->bitmaps[n], sub_c - p->sub_commands);
1068     }
1069 }
1070
1071 static void
1072 vlib_cli_make_parent (vlib_cli_main_t * cm, uword ci)
1073 {
1074   uword p_len, pi, *p;
1075   char *p_path;
1076   vlib_cli_command_t *c, *parent;
1077
1078   /* Root command (index 0) should have already been added. */
1079   ASSERT (vec_len (cm->commands) > 0);
1080
1081   c = vec_elt_at_index (cm->commands, ci);
1082   p_len = parent_path_len (c->path);
1083
1084   /* No space?  Parent is root command. */
1085   if (p_len == ~0)
1086     {
1087       add_sub_command (cm, 0, ci);
1088       return;
1089     }
1090
1091   p_path = 0;
1092   vec_add (p_path, c->path, p_len);
1093
1094   p = hash_get_mem (cm->command_index_by_path, p_path);
1095
1096   /* Parent exists? */
1097   if (!p)
1098     {
1099       /* Parent does not exist; create it. */
1100       vec_add2 (cm->commands, parent, 1);
1101       parent->path = p_path;
1102       hash_set_mem (cm->command_index_by_path, parent->path,
1103                     parent - cm->commands);
1104       pi = parent - cm->commands;
1105     }
1106   else
1107     {
1108       pi = p[0];
1109       vec_free (p_path);
1110     }
1111
1112   add_sub_command (cm, pi, ci);
1113
1114   /* Create parent's parent. */
1115   if (!p)
1116     vlib_cli_make_parent (cm, pi);
1117 }
1118
1119 always_inline uword
1120 vlib_cli_command_is_empty (vlib_cli_command_t * c)
1121 {
1122   return (c->long_help == 0 && c->short_help == 0 && c->function == 0);
1123 }
1124
1125 clib_error_t *
1126 vlib_cli_register (vlib_main_t * vm, vlib_cli_command_t * c)
1127 {
1128   vlib_cli_main_t *cm = &vm->cli_main;
1129   clib_error_t *error = 0;
1130   uword ci, *p;
1131   char *normalized_path;
1132
1133   if ((error = vlib_call_init_function (vm, vlib_cli_init)))
1134     return error;
1135
1136   (void) vlib_cli_normalize_path (c->path, &normalized_path);
1137
1138   if (!cm->command_index_by_path)
1139     cm->command_index_by_path = hash_create_vec ( /* initial length */ 32,
1140                                                  sizeof (c->path[0]),
1141                                                  sizeof (uword));
1142
1143   /* See if command already exists with given path. */
1144   p = hash_get_mem (cm->command_index_by_path, normalized_path);
1145   if (p)
1146     {
1147       vlib_cli_command_t *d;
1148
1149       ci = p[0];
1150       d = vec_elt_at_index (cm->commands, ci);
1151
1152       /* If existing command was created via vlib_cli_make_parent
1153          replaced it with callers data. */
1154       if (vlib_cli_command_is_empty (d))
1155         {
1156           vlib_cli_command_t save = d[0];
1157
1158           ASSERT (!vlib_cli_command_is_empty (c));
1159
1160           /* Copy callers fields. */
1161           d[0] = c[0];
1162
1163           /* Save internal fields. */
1164           d->path = save.path;
1165           d->sub_commands = save.sub_commands;
1166           d->sub_command_index_by_name = save.sub_command_index_by_name;
1167           d->sub_command_positions = save.sub_command_positions;
1168           d->sub_rules = save.sub_rules;
1169         }
1170       else
1171         error =
1172           clib_error_return (0, "duplicate command name with path %v",
1173                              normalized_path);
1174
1175       vec_free (normalized_path);
1176       if (error)
1177         return error;
1178     }
1179   else
1180     {
1181       /* Command does not exist: create it. */
1182
1183       /* Add root command (index 0). */
1184       if (vec_len (cm->commands) == 0)
1185         {
1186           /* Create command with index 0; path is empty string. */
1187           vec_resize (cm->commands, 1);
1188         }
1189
1190       ci = vec_len (cm->commands);
1191       hash_set_mem (cm->command_index_by_path, normalized_path, ci);
1192       vec_add1 (cm->commands, c[0]);
1193
1194       c = vec_elt_at_index (cm->commands, ci);
1195       c->path = normalized_path;
1196
1197       /* Don't inherit from registration. */
1198       c->sub_commands = 0;
1199       c->sub_command_index_by_name = 0;
1200       c->sub_command_positions = 0;
1201     }
1202
1203   vlib_cli_make_parent (cm, ci);
1204   return 0;
1205 }
1206
1207 clib_error_t *
1208 vlib_cli_register_parse_rule (vlib_main_t * vm, vlib_cli_parse_rule_t * r_reg)
1209 {
1210   vlib_cli_main_t *cm = &vm->cli_main;
1211   vlib_cli_parse_rule_t *r;
1212   clib_error_t *error = 0;
1213   u8 *r_name;
1214   uword *p;
1215
1216   if (!cm->parse_rule_index_by_name)
1217     cm->parse_rule_index_by_name = hash_create_vec ( /* initial length */ 32,
1218                                                     sizeof (r->name[0]),
1219                                                     sizeof (uword));
1220
1221   /* Make vector copy of name. */
1222   r_name = format (0, "%s", r_reg->name);
1223
1224   if ((p = hash_get_mem (cm->parse_rule_index_by_name, r_name)))
1225     {
1226       vec_free (r_name);
1227       return clib_error_return (0, "duplicate parse rule name `%s'",
1228                                 r_reg->name);
1229     }
1230
1231   vec_add2 (cm->parse_rules, r, 1);
1232   r[0] = r_reg[0];
1233   r->name = (char *) r_name;
1234   hash_set_mem (cm->parse_rule_index_by_name, r->name, r - cm->parse_rules);
1235
1236   return error;
1237 }
1238
1239 #if 0
1240 /* $$$ turn back on again someday, maybe */
1241 static clib_error_t *vlib_cli_register_parse_rules (vlib_main_t * vm,
1242                                                     vlib_cli_parse_rule_t *
1243                                                     lo,
1244                                                     vlib_cli_parse_rule_t *
1245                                                     hi)
1246   __attribute__ ((unused))
1247 {
1248   clib_error_t *error = 0;
1249   vlib_cli_parse_rule_t *r;
1250
1251   for (r = lo; r < hi; r = clib_elf_section_data_next (r, 0))
1252     {
1253       if (!r->name || strlen (r->name) == 0)
1254         {
1255           error = clib_error_return (0, "parse rule with no name");
1256           goto done;
1257         }
1258
1259       error = vlib_cli_register_parse_rule (vm, r);
1260       if (error)
1261         goto done;
1262     }
1263
1264 done:
1265   return error;
1266 }
1267 #endif
1268
1269 static int
1270 cli_path_compare (void *a1, void *a2)
1271 {
1272   u8 **s1 = a1;
1273   u8 **s2 = a2;
1274
1275   if ((vec_len (*s1) < vec_len (*s2)) &&
1276       memcmp ((char *) *s1, (char *) *s2, vec_len (*s1)) == 0)
1277     return -1;
1278
1279
1280   if ((vec_len (*s1) > vec_len (*s2)) &&
1281       memcmp ((char *) *s1, (char *) *s2, vec_len (*s2)) == 0)
1282     return 1;
1283
1284   return vec_cmp (*s1, *s2);
1285 }
1286
1287 static clib_error_t *
1288 show_cli_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
1289                  vlib_cli_command_t * cmd)
1290 {
1291   vlib_cli_main_t *cm = &vm->cli_main;
1292   vlib_cli_command_t *cli;
1293   u8 **paths = 0, **s;
1294
1295   /* *INDENT-OFF* */
1296   vec_foreach (cli, cm->commands)
1297     if (vec_len (cli->path) > 0)
1298       vec_add1 (paths, (u8 *) cli->path);
1299
1300   vec_sort_with_function (paths, cli_path_compare);
1301
1302   vec_foreach (s, paths)
1303     vlib_cli_output (vm, "%v", *s);
1304   /* *INDENT-ON* */
1305
1306   vec_free (paths);
1307   return 0;
1308 }
1309
1310 /* *INDENT-OFF* */
1311 VLIB_CLI_COMMAND (show_cli_command, static) = {
1312   .path = "show cli",
1313   .short_help = "Show cli commands",
1314   .function = show_cli_cmd_fn,
1315 };
1316 /* *INDENT-ON* */
1317
1318 static clib_error_t *
1319 vlib_cli_init (vlib_main_t * vm)
1320 {
1321   vlib_cli_main_t *cm = &vm->cli_main;
1322   clib_error_t *error = 0;
1323   vlib_cli_command_t *cmd;
1324
1325   cmd = cm->cli_command_registrations;
1326
1327   while (cmd)
1328     {
1329       error = vlib_cli_register (vm, cmd);
1330       if (error)
1331         return error;
1332       cmd = cmd->next_cli_command;
1333     }
1334   return error;
1335 }
1336
1337 VLIB_INIT_FUNCTION (vlib_cli_init);
1338
1339 /*
1340  * fd.io coding-style-patch-verification: ON
1341  *
1342  * Local Variables:
1343  * eval: (c-set-style "gnu")
1344  * End:
1345  */