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