The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
command.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 66b9b26cf82fd2b61cb2d4d7da715937d96243e2 $
19 *
20 * @file command.c
21 * @brief Internal commands for the server
22 *
23 * @copyright 2018 The FreeRADIUS server project
24 * @copyright 2018 Alan DeKok (aland@freeradius.org)
25 */
26RCSID("$Id: 66b9b26cf82fd2b61cb2d4d7da715937d96243e2 $")
27
28#include <freeradius-devel/server/command.h>
29#include <freeradius-devel/server/log.h>
30#include <freeradius-devel/util/debug.h>
31
32#include <freeradius-devel/util/misc.h>
33
34/*
35 * Registration hooks for radmin.
36 */
37static int fr_command_register(UNUSED TALLOC_CTX *talloc_ctx, UNUSED char const *name, UNUSED void *ctx, UNUSED fr_cmd_table_t *table)
38{
39 return 0;
40}
41
43
51
52struct fr_cmd_s {
53 char const *name;
54
55 struct fr_cmd_s *next;
56 struct fr_cmd_s *child; //!< if there are subcommands
57
58 char const *syntax; //!< only for terminal nodes
59 char const *help; //!< @todo - long / short help
60
61 fr_cmd_argv_t *syntax_argv; //!< arguments and types
62
63 void *ctx;
66
68 bool intermediate; //!< intermediate commands can't have callbacks
69 bool live; //!< is this entry live?
70 bool added_name; //!< was this name added?
71};
72
73
74static int fr_command_verify_argv(fr_cmd_info_t *info, int start, int verify, int argc, fr_cmd_argv_t **argv_p, bool optional) CC_HINT(nonnull);
75static bool fr_command_valid_name(char const *name);
76static int split(char **input, char **output, bool syntax_string);
77
78/*
79 * Hacks for simplicity. These data types aren't allowed as
80 * parameters, so we can reuse them for something else.
81 */
82
83// our fixed string. Any data type LESS than this must be a real data type
84#define FR_TYPE_FIXED FR_TYPE_TIME_DELTA
85
86#define FR_TYPE_VARARGS FR_TYPE_TLV
87#define FR_TYPE_OPTIONAL FR_TYPE_STRUCT
88#define FR_TYPE_ALTERNATE FR_TYPE_VSA
89#define FR_TYPE_ALTERNATE_CHOICE FR_TYPE_GROUP
90
91/** Find a command
92 *
93 * @param head the head of the list
94 * @param name of the command to find
95 * @param insert where the new command should be inserted
96 * @return
97 * - NULL for "not found". In which case "head" is the insertion point for the new command
98 * - !NULL for the command which was found.
99 */
100static fr_cmd_t *fr_command_find(fr_cmd_t **head, char const *name, fr_cmd_t ***insert)
101{
102 fr_cmd_t *cmd, **where = head;
103
104 if (!head || !name) {
105 if (insert) *insert = head;
106 return NULL;
107 }
108
109 if (!*head) {
110 if (insert) *insert = head;
111 return NULL;
112 }
113
114 /*
115 * Ensure if we exit int he loop insert is initialised
116 */
117 if (insert) *insert = NULL;
118
119 for (cmd = *head; cmd != NULL; cmd = cmd->next) {
120 int status;
121
122 status = strcmp(cmd->name, name);
123
124 /*
125 * Not found yet.
126 */
127 if (status < 0) {
128 where = &(cmd->next);
129 continue;
130 }
131
132 /*
133 * Not in the list.
134 */
135 if (status > 0) break;
136
137 /*
138 * Was found, return it.
139 */
140 return cmd;
141 }
142
143 if (insert) *insert = where;
144
145 return NULL;
146}
147
148/** Allocate an fr_cmd_t structure
149 *
150 * We presume that this allocation is done after a call to fr_command_find()
151 *
152 * @param ctx talloc ctx for the allocation
153 * @param head of the command list (singly linked)
154 * @param name of the command to allocate
155 * @return
156 * - fr_cmd_t structure which has been allocated. Only "name" is filled in.
157 */
158static fr_cmd_t *fr_command_alloc(TALLOC_CTX *ctx, fr_cmd_t **head, char const *name)
159
160{
161 fr_cmd_t *cmd;
162
163 MEM(cmd = talloc_zero(ctx, fr_cmd_t));
164 cmd->name = talloc_strdup(ctx, name);
165 cmd->intermediate = true;
166 cmd->live = false;
167
168 cmd->next = *head;
169 cmd->read_only = true;
170 *head = cmd;
171
172 return cmd;
173}
174
175
176/*
177 * Validate a name (or syntax)
178 *
179 * We have to be careful here, because some commands are taken
180 * from module names, which can be almost anything.
181 */
182static bool fr_command_valid_name(char const *name)
183{
184 uint8_t const *p;
185
186 for (p = (uint8_t const *) name; *p != '\0'; p++) {
187 if (*p < ' ') {
188 fr_strerror_const("Invalid control character in name");
189 return false;
190 }
191
192 if (((*p >= ' ') && (*p <= ',')) ||
193 ((*p >= ':') && (*p <= '@')) ||
194 ((*p >= '[') && (*p <= '^')) ||
195 ((*p > 'z') && (*p <= 0xf7)) ||
196 (*p == '`')) {
197 fr_strerror_const("Invalid special character");
198 return false;
199 }
200
201 /*
202 * Allow valid UTF-8 characters.
203 */
204 if (fr_utf8_char(p, -1)) continue;
205
206 fr_strerror_const("Invalid non-UTF8 character in name");
207 }
208
209 return true;
210}
211
213{
214 char const *p;
215 bool lowercase = false;
216 bool uppercase = false;
217
218 argv->type = FR_TYPE_FIXED;
219
220 if (!fr_command_valid_name(argv->name)) {
221 return false;
222 }
223
224 for (p = argv->name; *p != '\0'; p++) {
225 if (isupper((uint8_t) *p)) uppercase = true;
226 if (islower((uint8_t) *p)) lowercase = true;
227 }
228
229 /*
230 * No alphabetical characters, that's a
231 * problem.
232 */
233 if (!uppercase && !lowercase) {
234 fr_strerror_printf("Syntax command '%s' has no alphabetical characters", argv->name);
235 return false;
236 }
237
238 /*
239 * Mixed case is not allowed in a syntax.
240 */
241 if (uppercase && lowercase) {
242 fr_strerror_printf("Syntax command '%s' has invalid mixed case", argv->name);
243 return false;
244 }
245
246 /*
247 * All-uppercase words MUST be valid data
248 * types.
249 */
250 if (uppercase) {
252
254 switch (type) {
255 case FR_TYPE_MAX:
256 case FR_TYPE_NULL:
259 case FR_TYPE_VOID:
260 fr_strerror_printf("Syntax command '%s' has unknown data type", argv->name);
261 return false;
262
263 default:
264 break;
265 }
266
267 argv->type = type;
268 }
269
270 return true;
271}
272
273/*
274 * Like split, but is alternation aware.
275 */
276static int split_alternation(char **input, char **output)
277{
278 char quote;
279 char *str = *input;
280 char *word;
281
282 /*
283 * String is empty, we're done.
284 */
285 if (!*str) return 0;
286
287 /*
288 * Skip leading whitespace.
289 */
290 while ((*str == ' ') ||
291 (*str == '\t') ||
292 (*str == '\r') ||
293 (*str == '\n'))
294 *(str++) = '\0';
295
296 /*
297 * String is empty, we're done.
298 */
299 if (!*str) return 0;
300
301 /*
302 * Remember the start of the word.
303 */
304 word = str;
305
306 if ((*str == '[') || (*str == '(')) {
307 char end;
308 int count = 0;
309
310 quote = *(str++);
311
312 if (quote == '[') {
313 end = ']';
314 } else {
315 end = ')';
316 }
317
318 /*
319 * Don't allow backslashes here. This piece is
320 * only for parsing syntax strings, which CANNOT
321 * have quotes in them.
322 */
323 while ((*str != end) || (count > 0)) {
324 if (!*str) {
325 fr_strerror_const("String ends before closing brace.");
326 return -1;
327 }
328
329 if (*str == quote) count++;
330 if (*str == end) count--;
331
332 str++;
333 }
334
335 /*
336 * Skip the final "quotation" mark.
337 */
338 str++;
339
340 /*
341 * [foo bar]baz is invalid.
342 */
343 if ((*str != '\0') &&
344 (*str != ' ') &&
345 (*str != '|') &&
346 (*str != '\t')) {
347 fr_strerror_const("Invalid text after quoted string.");
348 return -1;
349 }
350 } else {
351 int count = 0;
352
353 /*
354 * Skip until we reach the next alternation,
355 * ignoring | in nested alternation.
356 *
357 */
358 while (*str) {
359 if (*str == '(') {
360 count++;
361 } else if (*str == ')') {
362 count--;
363 } else if (count == 0) {
364 if (*str == '|') break;
365 }
366 str++;
367 }
368 }
369
370 /*
371 * One of the above characters is after the word.
372 * Over-write it with NUL. If *str==0, then we leave it
373 * alone, so that the next call to split() discovers it,
374 * and returns NULL.
375 */
376 if (*str) {
377 /*
378 * Skip trailing whitespace so that the caller
379 * can peek at the next argument.
380 */
381 while ((*str == ' ') ||
382 (*str == '|') ||
383 (*str == '\t')) {
384 *(str++) = '\0';
385 }
386 }
387
388 *input = str;
389 *output = word;
390 return 1;
391}
392
393static int split(char **input, char **output, bool syntax_string)
394{
395 char quote;
396 char *str = *input;
397 char *word;
398
399 /*
400 * String is empty, we're done.
401 */
402 if (!*str) return 0;
403
404 /*
405 * Skip leading whitespace.
406 */
407 while ((*str == ' ') ||
408 (*str == '\t') ||
409 (*str == '\r') ||
410 (*str == '\n'))
411 *(str++) = '\0';
412
413 /*
414 * String is empty, we're done.
415 */
416 if (!*str) return 0;
417
418 /*
419 * String is only comments, we're done.
420 */
421 if (*str == '#') {
422 *str = '\0';
423 return 0;
424 }
425
426 /*
427 * Remember the start of the word.
428 */
429 word = str;
430
431 /*
432 * Quoted string? Skip to the trailing quote.
433 *
434 * But only if we're not parsing a syntax string.
435 */
436 if (!syntax_string && ((*str == '"') || (*str == '\''))) {
437 quote = *(str++);
438
439 while (*str != quote) {
440 if (!*str) {
441 fr_strerror_const("String is not terminated with a quotation character.");
442 return -1;
443 }
444
445 /*
446 * Skip backslashes and the following character
447 */
448 if (*str == '\\') {
449 str++;
450 if (!*str) {
451 fr_strerror_const("Invalid backslash at end of string.");
452 return -1;
453 }
454 str++;
455 continue;
456 }
457
458 str++;
459 }
460
461 /*
462 * Skip the final quotation mark.
463 */
464 str++;
465
466 /*
467 * "foo"bar is invalid.
468 */
469 if ((*str != '\0') &&
470 (*str != ' ') &&
471 (*str != '#') &&
472 (*str != '\t') &&
473 (*str != '\r') &&
474 (*str != '\n')) {
475 fr_strerror_const("Invalid text after quoted string.");
476 return -1;
477 }
478
479 } else if (syntax_string && ((*str == '[') || (*str == '('))) {
480 char end;
481 int count = 0;
482
483 quote = *(str++);
484
485 if (quote == '[') {
486 end = ']';
487 } else {
488 end = ')';
489 }
490
491 /*
492 * Don't allow backslashes here. This piece is
493 * only for parsing syntax strings, which CANNOT
494 * have quotes in them.
495 */
496 while ((*str != end) || (count > 0)) {
497 if (!*str) {
498 fr_strerror_const("String ends before closing brace.");
499 return -1;
500 }
501
502 if (*str == quote) count++;
503 if (*str == end) count--;
504
505 str++;
506 }
507
508 /*
509 * Skip the final "quotation" mark.
510 */
511 str++;
512
513 /*
514 * [foo bar]baz is invalid.
515 */
516 if ((*str != '\0') &&
517 (*str != ' ') &&
518 (*str != '#') &&
519 (*str != '\t') &&
520 (*str != '\r') &&
521 (*str != '\n')) {
522 fr_strerror_const("Invalid text after quoted string.");
523 return -1;
524 }
525 } else {
526 /*
527 * Skip the next non-space characters.
528 */
529 while (*str &&
530 (*str != ' ') &&
531 (*str != '#') &&
532 (*str != '\t') &&
533 (*str != '\r') &&
534 (*str != '\n'))
535 str++;
536 }
537
538 /*
539 * One of the above characters is after the word.
540 * Over-write it with NUL. If *str==0, then we leave it
541 * alone, so that the next call to split() discovers it,
542 * and returns NULL.
543 */
544 if (*str) {
545 /*
546 * Skip trailing whitespace so that the caller
547 * can peek at the next argument.
548 */
549 while ((*str == ' ') ||
550 (*str == '\t') ||
551 (*str == '\r') ||
552 (*str == '\n'))
553 *(str++) = '\0';
554 }
555
556 *input = str;
557 *output = word;
558 return 1;
559}
560
561static int fr_command_add_syntax(TALLOC_CTX *ctx, char *syntax, fr_cmd_argv_t **head, bool allow_varargs)
562{
563 int i, ret;
564 char *name, *p;
565 fr_cmd_argv_t **last, *prev;
566
567 p = syntax;
568 *head = NULL;
569 last = head;
570 prev = NULL;
571
572 for (i = 0; i < CMD_MAX_ARGV; i++) {
573 fr_cmd_argv_t *argv;
574
575 ret = split(&p, &name, true);
576 if (ret < 0) return ret;
577
578 if (ret == 0) return i;
579
580 /*
581 * Check for varargs. Which MUST NOT be
582 * the first argument, and MUST be the
583 * last argument, and MUST be preceded by
584 * a known data type.
585 */
586 if (strcmp(name, "...") == 0) {
587 if (!allow_varargs) {
588 fr_strerror_const("Varargs MUST NOT be in an [...] or (...) syntax.");
589 return -1;
590 }
591
592 if (!prev || *p) {
593 fr_strerror_const("Varargs MUST be the last argument in the syntax list.");
594 return -1;
595 }
596
597 /*
598 * The thing BEFORE the varags
599 * MUST be a known data type.
600 */
601 if (prev->type >= FR_TYPE_FIXED) {
602 fr_strerror_const("Varargs MUST be preceded by a data type.");
603 return -1;
604 }
605 argv = talloc_zero(ctx, fr_cmd_argv_t);
606 argv->name = name;
607 argv->type = FR_TYPE_VARARGS;
608 allow_varargs = false;
609
610 } else if (name[0] == '[') {
611 /*
612 * Optional things. e.g. [foo bar]
613 */
614 char *option = talloc_strdup(ctx, name + 1);
615 char *q;
617
618 q = option + strlen(option) - 1;
619 if (*q != ']') {
620 fr_strerror_const("Optional syntax is not properly terminated");
621 return -1;
622 }
623
624 *q = '\0';
625 child = NULL;
626
627 /*
628 * varargs can't be inside an optional block
629 */
630 ret = fr_command_add_syntax(option, option, &child, false);
631 if (ret < 0) return ret;
632
633 argv = talloc_zero(ctx, fr_cmd_argv_t);
634 argv->name = name;
635 argv->type = FR_TYPE_OPTIONAL;
636 argv->child = child;
637
638 } else if (name[0] == '(') {
639 /*
640 * Alternate things. e.g. [foo bar]
641 */
642 char *option = talloc_strdup(ctx, name + 1);
643 char *q, *word;
644 fr_cmd_argv_t *child, **last_child;
645
646 q = option + strlen(option) - 1;
647 if (*q != ')') {
648 fr_strerror_const("Alternate syntax is not properly terminated");
649 return -1;
650 }
651
652 *q = '\0';
653 child = NULL;
654 last_child = &child;
655
656 /*
657 * Walk over the choices, creating
658 * intermediate nodes for each one. Then
659 * placing the actual choices into
660 * child->child.
661 */
662 q = option;
663 while (true) {
664 fr_cmd_argv_t *choice, *sub;
665
666 ret = split_alternation(&q, &word);
667 if (ret < 0) return ret;
668 if (ret == 0) break;
669
670 sub = NULL;
671
672 /*
673 * varargs can't be inside an alternation block
674 */
675 ret = fr_command_add_syntax(option, word, &sub, false);
676 if (ret < 0) return ret;
677
678 choice = talloc_zero(option, fr_cmd_argv_t);
679 choice->name = word;
681 choice->child = sub;
682
683 *last_child = choice;
684 last_child = &(choice->next);
685 }
686
687 argv = talloc_zero(ctx, fr_cmd_argv_t);
688 argv->name = name;
689 argv->type = FR_TYPE_ALTERNATE;
690 argv->child = child;
691
692 } else {
693 argv = talloc_zero(ctx, fr_cmd_argv_t);
694 argv->name = name;
695
696 /*
697 * Validates argv->name and sets argv->type
698 */
699 if (!fr_command_valid_syntax(argv)) {
700 talloc_free(argv);
701 return -1;
702 }
703 }
704
705 *last = argv;
706 last = &(argv->next);
707 prev = argv;
708 }
709
710 if (*p) {
711 fr_strerror_const("Too many arguments passed in syntax string");
712 return -1;
713 }
714
715 return i;
716}
717
718/** Add one command to the global command tree
719 *
720 * We do not do any sanity checks on "name". If it has spaces in it,
721 * or "special" characters, that's up to you. We assume that other
722 * things in the server will sanity check them.
723 *
724 * @param talloc_ctx the talloc context
725 * @param head pointer to the head of the command table.
726 * @param name of the command to allocate. Can be NULL for "top level" commands
727 * @param ctx for any callback function
728 * @param table of information about the current command
729 * @return
730 * - <0 on error
731 * - 0 on success
732 */
733int fr_command_add(TALLOC_CTX *talloc_ctx, fr_cmd_t **head, char const *name, void *ctx, fr_cmd_table_t const *table)
734{
735 fr_cmd_t *cmd, **start;
736 fr_cmd_t **insert;
737 int argc = 0, depth = 0;
739
740 /*
741 * This is a place-holder for tab expansion.
742 */
743 if (!table->name) {
744 fr_strerror_const("A name MUST be specified.");
745 return -1;
746 }
747
748 if (!name && table->add_name) {
749 fr_strerror_const("An additional name must be specified");
750 return -1;
751 }
752
754 return -1;
755 }
756
757 if (!fr_command_valid_name(table->name)) {
758 return -1;
759 }
760
761 start = head;
762 syntax_argv = NULL;
763
764 /*
765 * If there are parent commands, ensure that entries for
766 * them exist in the tree. This check allows a table for
767 * "foo" to add "show module foo", even if "show module"
768 * does not yet exist.
769 */
770 if (table->parent) {
771 int i, ret;
772 char *p;
773 char *parents[CMD_MAX_ARGV];
774
775 p = talloc_strdup(talloc_ctx, table->parent);
776
777 for (i = 0; i < CMD_MAX_ARGV; i++) {
778 ret = split(&p, &parents[i], true);
779 if (ret < 0) return -1;
780 if (ret == 0) break;
781
782 if (!fr_command_valid_name(parents[i])) {
783 fr_strerror_printf("Invalid command name '%s'", parents[i]);
784 return -1;
785 }
786
787 /*
788 * Find the head command. If found,
789 * go downwards into the child command.
790 */
791 cmd = fr_command_find(start, parents[i], &insert);
792 if (!cmd) {
793 cmd = fr_command_alloc(talloc_ctx, insert, parents[i]);
794 cmd->live = true;
795 }
796
797 if (!cmd->intermediate) {
798 fr_strerror_const("Cannot add a subcommand to a pre-existing command.");
799 return -1;
800 }
801
802 fr_assert(cmd->func == NULL);
803 start = &(cmd->child);
804 }
805
806 if (i == CMD_MAX_ARGV) {
807 fr_strerror_printf("Commands are too deep (max is %d)", CMD_MAX_ARGV);
808 return -1;
809 }
810
811 depth = i;
812 }
813
814 /*
815 * Add an intermediate name, e.g. "network X"
816 */
817 if (table->add_name) {
818 fr_cmd_t **added_insert;
819
820 /*
821 * See if we need to create the automatic
822 * place-holder command for help text.
823 */
824 cmd = fr_command_find(start, "STRING", &added_insert);
825 if (!cmd) {
826 cmd = fr_command_alloc(talloc_ctx, added_insert, "STRING");
827 }
828
829 /*
830 * In the place-holders children, see if we need
831 * to add this subcommand.
832 */
833 cmd = fr_command_find(&(cmd->child), table->name, &added_insert);
834 if (!cmd) {
835 cmd = fr_command_alloc(talloc_ctx, added_insert, table->name);
836
837 if (table->syntax) cmd->syntax = talloc_strdup(cmd, table->syntax);
838 if (table->help) cmd->help = talloc_strdup(cmd, table->help);
839 }
840
841 /*
842 * Now insert or add the extended name to the command hierarchy.
843 */
844 cmd = fr_command_find(start, name, &insert);
845 if (!cmd) {
846 cmd = fr_command_alloc(talloc_ctx, insert, name);
847 cmd->added_name = true;
848 cmd->live = true;
849 }
850
851 start = &(cmd->child);
852 depth++;
853 }
854
855 /*
856 * @todo - check syntax, too!
857 *
858 * i.e. we have a command "foo" which accepts syntax "bar
859 * baz" we later try to add a command "foo bar" with
860 * syntax "bad". We don't find "bar" in the command
861 * list, because it's buried inside of the syntax for
862 * command "foo". So we can have duplicate / conflicting
863 * commands.
864 *
865 * The simple answer, of course, is "don't do that". The
866 * harder solution is to check for it and error out. But
867 * we're lazy, so too bad.
868 *
869 * The simple solution is to create a command line from
870 * the parents + name + syntax, and then look it up. If
871 * it's found, that's an error.
872 */
873
874 /*
875 * Sanity check the syntax.
876 */
877 if (table->syntax) {
878 char *syntax = talloc_strdup(talloc_ctx, table->syntax);
879
881 if (argc < 0) return -1;
882
883 /*
884 * Empty syntax should have table.syntax == NULL
885 */
886 if (argc == 0) {
888 fr_strerror_const("Invalid empty string was supplied for syntax");
889 return -1;
890 }
891
892 if ((depth + argc) >= CMD_MAX_ARGV) {
894 fr_strerror_const("Too many arguments were supplied to the command.");
895 return -1;
896 }
897 }
898
899 /*
900 * "head" is now pointing to the list where we insert
901 * this new command. We now see if the "name" currently
902 * exists.
903 */
904 cmd = fr_command_find(start, table->name, &insert);
905
906 /*
907 * The command exists already. We can't have TWO
908 * commands of the same name, so it's likely an error.
909 */
910 if (cmd) {
911 /*
912 * Not a callback, but an intermediary node. We
913 * can probably allow it.
914 */
915 if (!table->func) {
916 fr_assert(table->help != NULL);
917
918 /*
919 * Suppress duplicates.
920 */
921 if (cmd->help == table->help) return 0;
922
923 if (cmd->help != NULL) {
924 fr_strerror_printf("Cannot change help for command %s",
925 cmd->name);
926 return -1;
927 }
929 cmd->help = table->help;
930 cmd->read_only = table->read_only;
931 return 0;
932 }
933
934 /*
935 * Can't add new sub-commands to a
936 * command which already has a
937 * pre-defined syntax.
938 */
939 if (!cmd->intermediate) {
940 fr_strerror_printf("Cannot modify a pre-existing command '%s'", cmd->name);
941 return -1;
942 }
943 } else {
944 /*
945 * Allocate cmd and insert it into the current point.
946 */
947 fr_assert(insert != NULL);
948 cmd = fr_command_alloc(talloc_ctx, insert, table->name);
949 }
950
951 /*
952 * Assume that the commands are loaded from static
953 * structures.
954 *
955 * @todo - add "delete command" for unloading modules?
956 * otherwise after a module is removed, the command
957 * remains, and points to nothing.
958 */
959 cmd->ctx = ctx;
960 cmd->help = table->help;
961 cmd->func = table->func;
962
963 cmd->intermediate = (cmd->func == NULL);
964
965 cmd->tab_expand = table->tab_expand;
966 cmd->read_only = table->read_only;
967
968 if (syntax_argv) {
969 cmd->syntax = table->syntax;
970 cmd->syntax_argv = talloc_steal(cmd, syntax_argv);
971 }
972
973 cmd->live = true;
974
975 return 0;
976}
977
978
979/** Add multiple commands to the global command tree
980 *
981 * e.g. for module "foo", add "show module foo", "set module foo",
982 * etc.
983 *
984 * @param talloc_ctx the talloc context
985 * @param head pointer to the head of the command table.
986 * @param name of the command to allocate
987 * @param ctx for any callback function
988 * @param table array of tables, terminated by "help == NULL"
989 * @return
990 * - <0 on error
991 * - 0 on success
992 */
993int fr_command_add_multi(TALLOC_CTX *talloc_ctx, fr_cmd_t **head, char const *name, void *ctx, fr_cmd_table_t const *table)
994{
995 int i;
996
997 for (i = 0; table[i].help != NULL; i++) {
998 if (fr_command_add(talloc_ctx, head, name, ctx, &table[i]) < 0) return -1;
999 }
1000
1001 return 0;
1002}
1003
1004/** A stack for walking commands.
1005 *
1006 */
1007typedef struct {
1009 char const **parents;
1012
1013
1014/** Walk over a command hierarchy
1015 *
1016 * @param head the head of the hierarchy. Call it with NULL to clean up `walk_ctx`
1017 * @param[in,out] walk_ctx to track across multiple function calls. MUST point to a `void*` when starting
1018 * @param ctx for the callback
1019 * @param callback to call with fr_walk_info_t about each command
1020 * @return
1021 * - <0 on error
1022 * - 0 for nothing more to do.
1023 * - 1 for "please call me again to get the next command".
1024 * and walk_ctx now points to data allocated by, and managed by this function.
1025 * It MUST be cleaned up via another call to this function.
1026 */
1027int fr_command_walk(fr_cmd_t *head, void **walk_ctx, void *ctx, fr_cmd_walk_t callback)
1028{
1029 int ret;
1031 fr_cmd_t *cmd = NULL;
1032 fr_cmd_walk_info_t info;
1033
1034 if (!walk_ctx || !callback) {
1035 fr_strerror_const("No walk_ctx or callback specified");
1036 return -1;
1037 }
1038
1039 /*
1040 * Caller can tell us to stop walking by passing a NULL
1041 * "head" pointer after the first call.
1042 */
1043 if (!head) {
1044 if (*walk_ctx) {
1045 stack = *walk_ctx;
1046 done:
1048 *walk_ctx = NULL;
1049 }
1050
1051 /*
1052 * If there's no "head", we just go "yeah, it's
1053 * fine..."
1054 */
1055 return 0;
1056 }
1057
1058 /*
1059 * Allocate a stack the first time we're called. And
1060 * tell the caller to remember it so that we can keep
1061 * walking down the stack.
1062 */
1063 if (!*walk_ctx) {
1064 stack = talloc_zero(NULL, fr_cmd_stack_t);
1065 stack->entry[0] = head;
1066 stack->depth = 0;
1067 *walk_ctx = stack;
1068
1069 stack->parents = info.parents = talloc_zero_array(stack, char const *, CMD_MAX_ARGV);
1070 } else {
1071 stack = *walk_ctx;
1072 info.parents = stack->parents;
1073 }
1074
1075 /*
1076 * Grab this entry, which MUST exist.
1077 */
1078 cmd = stack->entry[stack->depth];
1079
1080 /*
1081 * Fill in the structure.
1082 */
1083 info.num_parents = stack->depth;
1084 info.name = cmd->name;
1085 info.syntax = cmd->syntax;
1086 info.help = cmd->help;
1087
1088 /*
1089 * Run the callback, but only for user-defined commands.
1090 */
1091 ret = callback(ctx, &info);
1092 if (ret <= 0) {
1094 *walk_ctx = NULL;
1095 return ret;
1096 }
1097
1098 /*
1099 * This command has children. Go do those before running
1100 * the next command at the current level.
1101 */
1102 if (cmd->child) {
1103 fr_assert(stack->depth < CMD_MAX_ARGV);
1104 info.parents[stack->depth] = cmd->name;
1105 stack->depth++;
1106 stack->entry[stack->depth] = cmd->child;
1107 return 1;
1108 }
1109
1110check_next:
1111 /*
1112 * Go to the next user-defined command at this level,
1113 * skipping any auto-allocated ones.
1114 */
1115 cmd = cmd->next;
1116 if (cmd) {
1117 stack->entry[stack->depth] = cmd;
1118 return 1;
1119 }
1120
1121 /*
1122 * At the top of the stack, see if we're done.
1123 */
1124 if (stack->depth == 0) {
1125 if (!cmd) goto done;
1126
1127 fr_assert(0 == 1);
1128 }
1129
1130 /*
1131 * Done all of the commands at this depth, so we go up a
1132 * level and try to grab another command.
1133 */
1134 stack->depth--;
1135 cmd = stack->entry[stack->depth];
1136 goto check_next;
1137}
1138
1139
1140/*
1141 * This MAY be a partial match. In which case walk down
1142 * the current list, looking for commands which MAY
1143 * match.
1144 */
1145static int fr_command_tab_expand_partial(fr_cmd_t *head, char const *partial, int max_expansions, char const **expansions)
1146{
1147 int i;
1148 size_t len;
1149 fr_cmd_t *cmd;
1150
1151 len = strlen(partial);
1152
1153 /*
1154 * We loop over 'cmd', but only increment 'i' if we found a matching command.
1155 */
1156 for (i = 0, cmd = head; (i < max_expansions) && cmd != NULL; cmd = cmd->next) {
1157 if (strncmp(partial, cmd->name, len) != 0) continue;
1158
1159 expansions[i++] = cmd->name;
1160 }
1161
1162 return i;
1163}
1164
1165
1166static int fr_command_tab_expand_argv(TALLOC_CTX *ctx, fr_cmd_t *cmd, fr_cmd_info_t *info, char const *name, fr_cmd_argv_t *argv,
1167 int max_expansions, char const **expansions)
1168{
1169 char const *p, *q;
1170
1171 /*
1172 * If it's a real data type, run the defined callback to
1173 * expand it.
1174 */
1175 if (argv->type < FR_TYPE_FIXED) {
1176 if (!cmd->tab_expand) {
1177 expansions[0] = argv->name;
1178 return 1;
1179 }
1180
1181 return cmd->tab_expand(ctx, cmd->ctx, info, max_expansions, expansions);
1182 }
1183
1184 /*
1185 * Don't expand "[foo]", instead see if we can expand the
1186 * "foo".
1187 */
1188 if (argv->type == FR_TYPE_OPTIONAL) {
1189 return fr_command_tab_expand_argv(ctx, cmd, info, name, argv->child, max_expansions, expansions);
1190 }
1191
1192 /*
1193 * Don't expand (foo|bar), instead see if we can expand
1194 * "foo" and "bar".
1195 */
1196 if (argv->type == FR_TYPE_ALTERNATE) {
1197 int count, ret;
1198 fr_cmd_argv_t *child;
1199
1200 count = 0;
1201 for (child = argv->child; child != NULL; child = child->next) {
1202 if (count >= max_expansions) return count;
1203
1204 ret = fr_command_tab_expand_argv(ctx, cmd, info, name, child, max_expansions - count, &expansions[count]);
1205 if (!ret) continue;
1206
1207 count++;
1208 }
1209
1210 return count;
1211 }
1212
1213 fr_assert(argv->type == FR_TYPE_FIXED);
1214
1215 /*
1216 * Not a full match, but we're at the last
1217 * keyword in the list. Maybe it's a partial
1218 * match?
1219 */
1220 for (p = name, q = argv->name;
1221 (*p != '\0') && (*q != '\0');
1222 p++, q++) {
1223 /*
1224 * Mismatch, can't expand.
1225 */
1226 if (*p != *q) return 0;
1227
1228 /*
1229 * Input is longer than string we're
1230 * trying to match. We can't expand
1231 * that.
1232 */
1233 if (p[1] && !q[1]) return 0;
1234
1235 /*
1236 * Input is shorter than the string we're
1237 * trying to match. Return the syntax
1238 * string as a suggested expansion.
1239 *
1240 * @todo - return a string which is ALL
1241 * of the fixed strings.
1242 *
1243 * e.g. "foo bar IPADDR". If they enter
1244 * "f<tab>", we should likely return "foo
1245 * bar", instead of just "foo".
1246 */
1247 if (!p[1] && q[1]) {
1248 expansions[0] = argv->name;
1249 return 1;
1250 }
1251 }
1252
1253 return 0;
1254}
1255
1256/*
1257 * We're at a leaf command, which has a syntax. Walk down the
1258 * syntax argv checking if it matches. If we get a matching
1259 * command, add that to the expansions array and return. If we
1260 * get a data type instead, do the callback to ask the caller to
1261 * expand it.
1262 */
1263/*
1264 * We're at a leaf command, which has a syntax. Walk down the
1265 * syntax argv checking if it matches. If we get a matching
1266 * command, add that to the expansions array and return. If we
1267 * get a data type instead, do the callback to ask the caller to
1268 * expand it.
1269 */
1270static int fr_command_tab_expand_syntax(TALLOC_CTX *ctx, fr_cmd_t *cmd, int syntax_offset, fr_cmd_info_t *info,
1271 int max_expansions, char const **expansions)
1272{
1273 int ret;
1274 fr_cmd_argv_t *argv = cmd->syntax_argv;
1275
1276 ret = fr_command_verify_argv(info, syntax_offset, info->argc - 1, info->argc - 1, &argv, false);
1277 if (ret < 0) return -1;
1278
1279 /*
1280 * We've found the last argv. See if we need to expand it.
1281 */
1282 return fr_command_tab_expand_argv(ctx, cmd, info, info->argv[syntax_offset + ret], argv, max_expansions, expansions);
1283}
1284
1285
1286/** Get the commands && help at a particular level
1287 *
1288 * @param ctx talloc context for dynamically allocated expansions. The caller should free it to free all expansions it created.
1289 * Expansions added by this function are "const char *", and are managed by the command hierarchy.
1290 * @param head the head of the hierarchy.
1291 * @param info the structure describing the command to expand
1292 * @param max_expansions the maximum number of entries in the expansions array
1293 * @param expansions where the expansions will be stored.
1294 * @return
1295 * - <0 on error
1296 * - number of entries in the expansions array
1297 */
1298int fr_command_tab_expand(TALLOC_CTX *ctx, fr_cmd_t *head, fr_cmd_info_t *info, int max_expansions, char const **expansions)
1299{
1300 int i;
1301 fr_cmd_t *cmd, *start;
1302
1303 if (!head) return 0;
1304
1305 start = head;
1306
1307 /*
1308 * Walk down the children until we find the correct
1309 * location.
1310 */
1311 for (i = 0; i < info->argc; i++) {
1312 cmd = fr_command_find(&start, info->argv[i], NULL);
1313
1314 /*
1315 * The command wasn't found in the list. Walk
1316 * over the list AGAIN, doing tab expansions of
1317 * any partial matches.
1318 */
1319 if (!cmd) {
1320 return fr_command_tab_expand_partial(start, info->argv[i], max_expansions, expansions);
1321 }
1322
1323 if (cmd->intermediate) {
1324 fr_assert(cmd->child != NULL);
1325 start = cmd->child;
1326 continue;
1327 }
1328
1329 if (!cmd->syntax_argv) {
1330 if ((i + 1) == info->argc) return 0;
1331
1332 return -1;
1333 }
1334
1335 if (!cmd->live) return 0;
1336
1337 /*
1338 * If there is a syntax, the command MUST be a
1339 * leaf node.
1340 *
1341 * Skip the name
1342 */
1343 fr_assert(cmd->func != NULL);
1344 return fr_command_tab_expand_syntax(ctx, cmd, i + 1, info, max_expansions, expansions);
1345 }
1346
1347 cmd = start;
1348
1349 /*
1350 * We've looked for "foo bar" and found it. There should
1351 * be child commands under that hierarchy. In which
1352 * case, show them as expansions.
1353 */
1354 fr_assert(i == info->argc);
1355 fr_assert(cmd->child != NULL);
1356
1357 for (i = 0, cmd = cmd->child; (i < max_expansions) && (cmd != NULL); i++, cmd = cmd->next) {
1358 expansions[i] = cmd->name;
1359 }
1360
1361 return i;
1362}
1363
1364
1365/*
1366 * Magic parsing macros
1367 */
1368#define SKIP_NAME(name) do { p = word; q = name; while (*p && *q && (*p == *q)) { \
1369 p++; \
1370 q++; \
1371 } } while (0)
1372#define MATCHED_NAME ((!*p || isspace((uint8_t) *p)) && !*q)
1373#define TOO_FAR (*p && (*q > *p))
1374#define MATCHED_START ((text + start) >= word) && ((text + start) <= p)
1375
1376static int fr_command_run_partial(FILE *fp, FILE *fp_err, fr_cmd_info_t *info, bool read_only, int offset, fr_cmd_t *head)
1377{
1378 int i, ret;
1379 fr_cmd_t *start, *cmd = NULL;
1380 fr_cmd_info_t my_info;
1381
1382 fr_assert(head->intermediate);
1383 fr_assert(head->child != NULL);
1384
1385 start = head->child;
1386
1387 /*
1388 * Wildcard '*' is at 'offset + 1'. Then the command to run is at 'offset + 2'.
1389 */
1390 fr_assert(info->argc >= (offset + 2));
1391
1392 /*
1393 * Loop from "start", trying to find a matching command.
1394 */
1395 for (i = offset + 1; i < info->argc; i++) {
1396 char const *p, *q, *word;
1397
1398 /*
1399 * Re-parse the input because "*" only picked up
1400 * the first command, not the rest of them.
1401 */
1402 for (cmd = start; cmd != NULL; cmd = cmd->next) {
1403 if (!cmd->live) continue;
1404
1405 word = info->argv[i];
1406 SKIP_NAME(cmd->name);
1407
1408 if (!MATCHED_NAME) continue;
1409
1410 if (cmd->intermediate) {
1411 info->cmd[i] = cmd;
1412 start = cmd->child;
1413 break;
1414 }
1415
1416 /*
1417 * Not an intermediate command, we've got
1418 * to run it.
1419 */
1420 break;
1421 }
1422
1423 /*
1424 * Not found, die.
1425 */
1426 if (!cmd) return 0;
1427
1428 /*
1429 * Ignore read-only on intermediate commands.
1430 * Some may have been automatically allocated
1431 */
1432 if (cmd->intermediate) continue;
1433 break;
1434 }
1435
1436 if (!cmd) return 0;
1437
1438 if (!cmd->live) return 0;
1439
1440 if (!cmd->read_only && read_only) {
1441 fprintf(fp_err, "No permissions to run command '%s'\n", cmd->name);
1442 return -1;
1443 }
1444
1445 /*
1446 * Leaf nodes must have a callback.
1447 */
1448 fr_assert(cmd->func != NULL);
1449
1450 // @todo - add cmd->min_argc && cmd->max_argc, to track optional things, varargs, etc.
1451
1452 /*
1453 * The arguments have already been verified by
1454 * fr_command_str_to_argv().
1455 */
1456 my_info.argc = info->argc - i - 1;
1457 my_info.max_argc = info->max_argc - info->argc;
1458 my_info.runnable = true;
1459 my_info.argv = &info->argv[i + 1];
1460 my_info.box = &info->box[i + 1];
1461 ret = cmd->func(fp, fp_err, cmd->ctx, &my_info);
1462
1463 return ret;
1464}
1465
1466
1467/** Run a particular command
1468 *
1469 * info->argc is left alone, as are all other fields.
1470 * If you want to run multiple commands, call fr_command_clear(0, info)
1471 * to zero out the relevant information.
1472 *
1473 * @param fp where the output is sent
1474 * @param fp_err where the error output is sent
1475 * @param info the structure describing the command to expand
1476 * @param read_only whether or not this command should be run in read-only mode.
1477 * @return
1478 * - <0 on error
1479 * - 0 the command was run successfully
1480 */
1481int fr_command_run(FILE *fp, FILE *fp_err, fr_cmd_info_t *info, bool read_only)
1482{
1483 int i, ret;
1484 fr_cmd_t *cmd;
1485 fr_cmd_info_t my_info;
1486
1487 cmd = NULL;
1488
1489 /*
1490 * Asked to do nothing, do nothing.
1491 */
1492 if (info->argc == 0) return 0;
1493
1494 for (i = 0; i < info->argc; i++) {
1495 cmd = info->cmd[i];
1496 fr_assert(cmd != NULL);
1497
1498 if (cmd->added_name && (info->argv[i][0] == '*')) {
1499 fr_assert(i > 0);
1500
1501 for (; cmd != NULL; cmd = cmd->next) {
1502 if (!cmd->live) continue;
1503
1504 fprintf(fp, "%s %s\n", info->argv[i - 1], cmd->name);
1505 info->argv[i] = cmd->name;
1506 ret = fr_command_run_partial(fp, fp_err, info, read_only, i, cmd);
1507 if (ret < 0) return ret;
1508 }
1509
1510 return 0;
1511 }
1512
1513 /*
1514 * Ignore read-only on intermediate commands.
1515 * Some may have been automatically allocated
1516 */
1517 if (cmd->intermediate) continue;
1518 break;
1519 }
1520
1521 if (!cmd) return 0;
1522
1523 if (!cmd->live) return 0;
1524
1525 if (!cmd->read_only && read_only) {
1526 fprintf(fp_err, "No permissions to run command '%s' help %s\n", cmd->name, cmd->help);
1527 return -1;
1528 }
1529
1530 /*
1531 * Leaf nodes must have a callback.
1532 */
1533 fr_assert(cmd->func != NULL);
1534
1535 // @todo - add cmd->min_argc && cmd->max_argc, to track optional things, varargs, etc.
1536
1537 /*
1538 * The arguments have already been verified by
1539 * fr_command_str_to_argv().
1540 */
1541 my_info.argc = info->argc - i - 1;
1542 my_info.max_argc = info->max_argc - info->argc;
1543 my_info.runnable = true;
1544 my_info.argv = &info->argv[i + 1];
1545 my_info.box = &info->box[i + 1];
1546 ret = cmd->func(fp, fp_err, cmd->ctx, &my_info);
1547
1548 return ret;
1549}
1550
1551
1552/** Get help text for a particular command.
1553 *
1554 * @param head the head of the hierarchy.
1555 * @param argc the number of arguments in argv
1556 * @param argv the arguments
1557 * @return
1558 * - NULL on "no help text"
1559 * - !NULL is the help text. Do not free or access it.
1560 */
1561char const *fr_command_help(fr_cmd_t *head, int argc, char *argv[])
1562{
1563 int i;
1564 fr_cmd_t *cmd, *start;
1565
1566 start = head;
1567
1568 for (i = 0; i < argc; i++) {
1569 cmd = fr_command_find(&start, argv[i], NULL);
1570 if (!cmd) return NULL;
1571
1572 if (cmd->intermediate) {
1573 fr_assert(cmd->child != NULL);
1574 start = cmd->child;
1575 continue;
1576 }
1577
1578 return cmd->help;
1579 }
1580
1581 /*
1582 * Return intermediate node help, if that help exists.
1583 */
1584 if (start) return start->help;
1585
1586 return NULL;
1587}
1588
1589static const char *tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
1590
1591static void fr_command_debug_node(FILE *fp, fr_cmd_t *cmd, int depth)
1592{
1593 fprintf(fp, "%.*s%s\n", depth, tabs, cmd->name);
1594 if (cmd->syntax) fprintf(fp, "%.*s -> %s\n", depth, tabs, cmd->syntax);
1595 if (cmd->help) fprintf(fp, "%.*s ? %s\n", depth, tabs, cmd->help);
1596}
1597
1598static void fr_command_debug_internal(FILE *fp, fr_cmd_t *head, int depth)
1599{
1600 fr_cmd_t *cmd;
1601
1602 for (cmd = head; cmd != NULL; cmd = cmd->next) {
1603 fr_command_debug_node(fp, cmd, depth);
1604 if (cmd->child) {
1605 fr_command_debug_internal(fp, cmd->child, depth + 1);
1606 }
1607 }
1608}
1609
1611{
1613}
1614
1615
1616static void fr_command_list_node(FILE *fp, fr_cmd_t *cmd, int depth, char const **argv, int options)
1617{
1618 int i;
1619
1620 for (i = 0; i < depth; i++) {
1621 fprintf(fp, "%s ", argv[i]);
1622 }
1623
1624 if ((options & FR_COMMAND_OPTION_NAME) != 0) {
1625 fprintf(fp, ":");
1626 }
1627
1628 if (!cmd->syntax) {
1629 fprintf(fp, "%s\n", cmd->name);
1630 } else {
1631 fprintf(fp, "%s %s\n", cmd->name, cmd->syntax);
1632 }
1633
1634 if (cmd->help && ((options & FR_COMMAND_OPTION_HELP) != 0)) {
1635 fprintf(fp, "\t%s\n", cmd->help);
1636 }
1637}
1638
1639static void fr_command_list_internal(FILE *fp, fr_cmd_t *head, int depth, int max_depth, char const **argv, int options)
1640{
1641 fr_cmd_t *cmd;
1642
1643 for (cmd = head; cmd != NULL; cmd = cmd->next) {
1644 if (cmd->added_name) continue;
1645
1646 // We DO print out commands are !cmd->live
1647
1648 if (cmd->child && ((depth + 1) < max_depth)) {
1649 argv[depth] = cmd->name;
1650 fr_command_list_internal(fp, cmd->child, depth + 1, max_depth, argv, options);
1651 } else {
1652 fr_command_list_node(fp, cmd, depth, argv, options);
1653 }
1654 }
1655}
1656
1657void fr_command_list(FILE *fp, int max_depth, fr_cmd_t *head, int options)
1658{
1659 char const *argv[CMD_MAX_ARGV];
1660
1661 if ((max_depth <= 0) || !head) return;
1662 if (max_depth > CMD_MAX_ARGV) max_depth = CMD_MAX_ARGV;
1663
1664 argv[0] = NULL; /* not sure what argv is doing here... */
1665
1666 if ((options & FR_COMMAND_OPTION_LIST_CHILD) != 0) {
1667 if (!head->child) {
1668 fr_assert(head->func != NULL);
1669 // @todo - skip syntax_argv as necessary
1670 fr_command_list_node(fp, head, 0, argv, options);
1671 return;
1672 }
1673 head = head->child;
1674 }
1675
1676 fr_command_list_internal(fp, head, 0, max_depth, argv, options);
1677}
1678
1679
1680static int fr_command_verify_argv(fr_cmd_info_t *info, int start, int verify, int argc, fr_cmd_argv_t **argv_p, bool optional)
1681{
1682 char quote;
1683 int used = 0, ret;
1685 fr_value_box_t *box, my_box;
1686 char const *name;
1687 fr_cmd_argv_t *argv = *argv_p;
1688 fr_cmd_argv_t *child;
1689 TALLOC_CTX *ctx = NULL;
1690
1691redo:
1693
1694 /*
1695 * Don't eat too many arguments.
1696 */
1697 if ((start + used) >= argc) {
1698 fr_assert(argv != NULL);
1699
1700 /*
1701 * Skip trailing optional pieces.
1702 */
1703 while (argv && (argv->type == FR_TYPE_OPTIONAL)) {
1704 argv = argv->next;
1705 }
1706
1707 *argv_p = argv;
1708 return used;
1709 }
1710
1711 /*
1712 * May be written to for things like
1713 * "combo_ipaddr".
1714 */
1715 type = argv->type;
1716 name = info->argv[start + used];
1717
1718 /*
1719 * Fixed strings.
1720 *
1721 * Note that for optional parameters, we assume that they
1722 * always begin with fixed strings.
1723 */
1724 if (type == FR_TYPE_FIXED) {
1725 if (strcmp(argv->name, info->argv[start + used]) != 0) {
1726
1727 /*
1728 * This one didn't match, so we return
1729 * "no match", even if we consumed many
1730 * inputs.
1731 */
1732 if (optional) return 0;
1733
1734 return -1;
1735 }
1736
1737 used++;
1738 goto next;
1739 }
1740
1741 /*
1742 * Optional. It's OK if there's no match.
1743 */
1744 if (type == FR_TYPE_OPTIONAL) {
1745 child = argv->child;
1746
1747 ret = fr_command_verify_argv(info, start + used, verify, argc, &child, true);
1748 if (ret < 0) return ret;
1749
1750 /*
1751 * No match, that's OK. Skip it.
1752 */
1753 if (ret == 0) {
1754 goto next;
1755 }
1756
1757 /*
1758 * We've used SOME of the input.
1759 */
1760 used += ret;
1761
1762 /*
1763 * But perhaps not all of it. If so, remember
1764 * how much we've used, and return that.
1765 */
1766 if (child) {
1767 *argv_p = argv;
1768 return used;
1769 }
1770
1771 /*
1772 * If we have used all of the optional thing, keep going.
1773 */
1774 goto next;
1775 }
1776
1777 /*
1778 * Try the alternates until we find a match.
1779 */
1780 if (type == FR_TYPE_ALTERNATE) {
1781 child = NULL;
1782
1783 for (child = argv->child; child != NULL; child = child->next) {
1784 fr_cmd_argv_t *sub;
1785
1787 fr_assert(child->child != NULL);
1788 sub = child->child;
1789
1790 ret = fr_command_verify_argv(info, start + used, verify, argc, &sub, true);
1791 if (ret <= 0) continue;
1792
1793 /*
1794 * Only a partial match. Return that.
1795 */
1796 if (sub) {
1797 *argv_p = argv;
1798 return used + ret;
1799 }
1800
1801 used += ret;
1802 goto next;
1803 }
1804
1805 /*
1806 * We've gone through all of the alternates
1807 * without a match, that's an error.
1808 */
1809 goto no_match;
1810 }
1811
1813
1814 /*
1815 * Don't re-verify things we've already verified.
1816 */
1817 if ((start + used) < verify) {
1818 used++;
1819 goto next;
1820 }
1821
1822 quote = '\0';
1823 if (type == FR_TYPE_STRING) {
1824 if ((name[0] == '"') ||
1825 (name[0] == '\'')) {
1826 quote = name[0];
1827 }
1828 }
1829
1830 /*
1831 * Set up and/or cache value boxes
1832 */
1833 if (info->box) {
1834 ctx = info->box;
1835 if (!info->box[start + used]) {
1836 info->box[start + used] = talloc_zero(ctx, fr_value_box_t);
1837 }
1838
1839 box = info->box[start + used];
1840 } else {
1841 box = &my_box;
1842 }
1843
1844 /*
1845 * Parse the data to be sure it's well formed.
1846 */
1847 if (fr_value_box_from_str(ctx, box, type,
1848 NULL,
1849 name, strlen(name),
1850 fr_value_unescape_by_char[(uint8_t)quote]) < 0) {
1851 fr_strerror_printf_push("Failed parsing argument '%s'", name);
1852 return -1;
1853 }
1854
1855 if (box == &my_box) fr_value_box_clear(box);
1856 used++;
1857
1858next:
1859 /*
1860 * Go to the next one, but only if we don't have varargs.
1861 */
1862 if (!argv->next || (argv->next->type != FR_TYPE_VARARGS)) {
1863 argv = argv->next;
1864 }
1865
1866 if (argv) {
1867 goto redo;
1868 }
1869
1870 if ((start + used) < argc) {
1871no_match:
1872 fr_strerror_printf("No match for command %s", info->argv[start + used]);
1873 return -1;
1874 }
1875
1876 *argv_p = NULL;
1877 return used;
1878}
1879
1880static char const *skip_word(char const *text)
1881{
1882 char quote;
1883 char const *word = text;
1884
1885 if ((*word != '"') && (*word != '\'')) {
1887 return word;
1888 }
1889
1890 quote = *word;
1891 word++;
1892 while (*word && (*word != quote)) {
1893 if (*word != '\\') {
1894 word++;
1895 continue;
1896 }
1897
1898 word++;
1899 if (!*word) return NULL;
1900 word++;
1901 }
1902
1903 return word;
1904}
1905
1906
1907/** Check the syntax of a command, starting at `*text`
1908 *
1909 * Note that we don't keep a stack of where we are for partial
1910 * commands. So we MUST re-parse the ENTIRE input every time.
1911 */
1912static int syntax_str_to_argv(int start_argc, fr_cmd_argv_t *start, fr_cmd_info_t *info,
1913 char const **text, bool *runnable)
1914{
1915 int argc = start_argc;
1916 int ret;
1917 bool child_done;
1918 char const *word, *my_word, *p, *q;
1919 fr_cmd_argv_t *argv = start;
1920 fr_cmd_argv_t *child;
1921
1922 word = *text;
1923 *runnable = false;
1924
1925 while (argv) {
1926 fr_skip_whitespace(word);
1927
1928 if (!*word) goto done;
1929
1930 /*
1931 * Parse / check data types.
1932 */
1933 if (argv->type < FR_TYPE_FIXED) {
1934 size_t len, offset;
1935 char quote, *str;
1937
1938 p = skip_word(word);
1939 if (!p) {
1940 fr_strerror_const("Invalid string");
1941 return -1;
1942 }
1943
1944 /*
1945 * An already-parsed data type. Skip it.
1946 */
1947 if (argc < info->argc) {
1948 fr_assert(info->box[argc] != NULL);
1949 word = p;
1950 argc++;
1951 goto next;
1952 }
1953
1954 /*
1955 * Non-strings MUST not be quoted.
1956 */
1957 if ((argv->type != FR_TYPE_STRING) &&
1958 ((*word == '"') || (*word == '\''))) {
1959 fr_strerror_printf("Invalid quoted string at %s", word);
1960 return -1;
1961 }
1962
1963 len = p - word;
1964 if ((*word == '"') || (*word == '\'')) {
1965 quote = *word;
1966 offset = 1;
1967 } else {
1968 quote = 0;
1969 offset = 0;
1970 }
1971
1972 type = argv->type;
1973 if (!info->box) {
1974 fr_strerror_const("No array defined for values");
1975 return -1;
1976 }
1977
1978 if (!info->box[argc]) {
1979 info->box[argc] = talloc_zero(info->box, fr_value_box_t);
1980 }
1981
1982 ret = fr_value_box_from_str(info->box[argc], info->box[argc],
1983 type, NULL,
1984 word + offset, len - (offset << 1),
1986 if (ret < 0) return -1;
1987
1988 /*
1989 * Note that argv[i] is the *input* string.
1990 *
1991 * The called function MUST check box[i]
1992 * for the actual value.
1993 */
1994 info->argv[argc] = str = talloc_memdup(info->argv, word + offset, len + 1);
1995 str[len] = '\0';
1996
1997 word = p;
1998 argc++;
1999 goto next;
2000 }
2001
2002 /*
2003 * Fixed strings. We re-validate these for the
2004 * heck of it.
2005 */
2006 if (argv->type == FR_TYPE_FIXED) {
2007 SKIP_NAME(argv->name);
2008
2009 /*
2010 * End of input text before we matched
2011 * the whole command.
2012 */
2013 if (!*p && *q) {
2014 fr_strerror_printf("Input is too short for command: %s", argv->name);
2015 return -1;
2016 }
2017
2018 /*
2019 * The only matching exit condition is *p is a
2020 * space, and *q is the NUL character.
2021 */
2022 if (!MATCHED_NAME) {
2023 fr_strerror_printf("Unknown command at: %s", p);
2024 return -1;
2025 }
2026
2027 /*
2028 * Otherwise keep looking for the next option.
2029 */
2030 info->argv[argc] = argv->name;
2031 info->cmd[argc] = NULL;
2032 // assume that the value box has already been cleared
2033
2034 word = p;
2035 argc++;
2036 goto next;
2037 }
2038
2039 /*
2040 * Evaluate alternates in sequence until one
2041 * matches. If none match, that's an error.
2042 */
2043 if (argv->type == FR_TYPE_ALTERNATE) {
2044 my_word = word;
2045
2046 for (child = argv->child; child != NULL; child = child->next) {
2047 fr_cmd_argv_t *sub;
2048
2050 fr_assert(child->child != NULL);
2051 sub = child->child;
2052
2053 /*
2054 * This can fail on things like
2055 * "(INTEGER|IPADDR)" where
2056 * "192.168.0.1" is not a valid
2057 * INTEGER, but it is a valid IPADDR.
2058 */
2059 ret = syntax_str_to_argv(argc, sub, info, &my_word, &child_done);
2060 if (ret <= 0) continue;
2061
2062 goto skip_child;
2063 }
2064
2065 /*
2066 * We've gone through all of the alternates
2067 * without a match, that's an error.
2068 */
2069 fr_strerror_printf("No matching command for input string %s", word);
2070 return -1;
2071 }
2072
2073 /*
2074 * Evaluate an optional argument. If nothing
2075 * matches, that's OK.
2076 */
2077 if (argv->type == FR_TYPE_OPTIONAL) {
2078 child = argv->child;
2079 my_word = word;
2080
2081 ret = syntax_str_to_argv(argc, child, info, &my_word, &child_done);
2082 if (ret < 0) return ret;
2083
2084 /*
2085 * Didn't match anything, skip it.
2086 */
2087 if (ret == 0) goto next;
2088
2089 skip_child:
2090 /*
2091 * We've eaten more input, remember that,
2092 */
2093 argc += ret;
2094 word = my_word;
2095
2096 /*
2097 * We used only *part* of it. We're done here.
2098 */
2099 if (!child_done) {
2100 word = my_word;
2101 goto done;
2102 }
2103
2104 goto next;
2105 }
2106
2107 /*
2108 * Not done yet!
2109 */
2110 fr_strerror_printf("%s: Internal sanity check failed", __FUNCTION__);
2111 return -1;
2112
2113 next:
2114 /*
2115 * Go to the next one, but only if we don't have varargs.
2116 */
2117 if (!argv->next || (argv->next->type != FR_TYPE_VARARGS)) {
2118 argv = argv->next;
2119 }
2120 }
2121
2122done:
2123 /*
2124 * End of input. Skip any trailing optional pieces.
2125 */
2126 if (!*word) {
2127 while (argv && (argv->type == FR_TYPE_OPTIONAL)) argv = argv->next;
2128 }
2129
2130 if (!argv) *runnable = true;
2131 *text = word;
2132 return (argc - start_argc);
2133}
2134
2135/** Split a string in-place, updating argv[]
2136 *
2137 * This function also respects the various data types (mostly).
2138 * Strings can have quotes. Nothing else can have quotes.
2139 * Non-string data types are skipped and only parsed to data types by
2140 * fr_command_run().
2141 *
2142 * @param head the head of the hierarchy.
2143 * @param info the structure describing the command to expand
2144 * @param text the string to split
2145 * @return
2146 * - <0 on error.
2147 * - total number of arguments in the argv[] array. Always >= argc.
2148 */
2150{
2151 int argc, ret;
2152 char const *word, *p, *q;
2153 fr_cmd_t *cmd;
2154
2155 if ((info->argc < 0) || (info->max_argc <= 0)) {
2156 fr_strerror_const("argc / max_argc must be greater than zero");
2157 return -1;
2158 }
2159
2160 if (!text) {
2161 fr_strerror_const("No string to split.");
2162 return -1;
2163 }
2164
2165 /*
2166 * Must have something to check.
2167 */
2168 if (!head) {
2169 fr_strerror_const("No commands to parse.");
2170 return -1;
2171 }
2172
2173 info->runnable = false;
2174 cmd = head;
2175 word = text;
2176
2177 /*
2178 * Double-check the commands we may have already parsed.
2179 */
2180 for (argc = 0; argc < info->argc; argc++) {
2181 cmd = info->cmd[argc];
2182 fr_assert(cmd != NULL);
2183
2184 fr_skip_whitespace(word);
2185
2186 if ((word[0] == '*') && isspace(word[1]) && cmd->added_name) {
2187 p = word + 1;
2188 goto skip_matched;
2189 }
2190
2191 SKIP_NAME(cmd->name);
2192
2193 /*
2194 * The only matching exit condition is *p is a
2195 * space, and *q is the NUL character.
2196 */
2197 if (!MATCHED_NAME) {
2198 goto invalid;
2199 }
2200
2201skip_matched:
2202 word = p;
2203
2204 if (!cmd->intermediate) {
2205 argc++;
2206 goto check_syntax;
2207 }
2208 }
2209
2210 /*
2211 * If we've found a cached command, go parse it's
2212 * children.
2213 */
2214 if ((argc > 0) && cmd->intermediate) {
2215 cmd = cmd->child;
2216 }
2217
2218 /*
2219 * Search the remaining text for matching commands.
2220 */
2221 while (cmd) {
2222 fr_skip_whitespace(word);
2223
2224 /*
2225 * Skip commands which we shouldn't know about...
2226 */
2227 if (!cmd->live) {
2228 cmd = cmd->next;
2229 continue;
2230 }
2231
2232 /*
2233 * End of the input. Tab expand everything here.
2234 */
2235 if (!*word) {
2236 info->argc = argc;
2237 return argc;
2238 }
2239
2240 /*
2241 * Double-check using the cached cmd.
2242 */
2243 if (argc < info->argc) {
2244 cmd = info->cmd[argc];
2245 if (!cmd) {
2246 fr_strerror_printf("No cmd at offset %d", argc);
2247 goto invalid;
2248 }
2249 }
2250
2251 /*
2252 * Allow wildcards as a primitive "for" loop in
2253 * some special circumstances.
2254 */
2255 if ((word[0] == '*') && isspace(word[1]) && cmd->added_name) {
2256 fr_assert(cmd->intermediate);
2257 fr_assert(cmd->child != NULL);
2258
2259 info->argv[argc] = "*";
2260 info->cmd[argc] = cmd;
2261 word++;
2262 cmd = cmd->child;
2263 argc++;
2264 continue;
2265 }
2266
2267 SKIP_NAME(cmd->name);
2268
2269 /*
2270 * The only matching exit condition is *p is a
2271 * space, and *q is the NUL character.
2272 */
2273 if (!MATCHED_NAME) {
2274 if (argc < info->argc) {
2275 invalid:
2276 fr_strerror_const("Invalid internal state");
2277 return -1;
2278 }
2279
2280 /*
2281 * We're looking for "abc" and we found
2282 * "def". We know that "abc" can't occur
2283 * any more, so stop.
2284 */
2285 if (TOO_FAR) {
2286 cmd = NULL;
2287 break;
2288 }
2289
2290 /*
2291 * Otherwise keep searching for it.
2292 */
2293 cmd = cmd->next;
2294 continue;
2295 }
2296
2297 if (cmd->intermediate) {
2298 fr_assert(cmd->child != NULL);
2299 info->argv[argc] = cmd->name;
2300 info->cmd[argc] = cmd;
2301 word = p;
2302 cmd = cmd->child;
2303 argc++;
2304 continue;
2305 }
2306
2307 /*
2308 * Skip the command name we matched.
2309 */
2310 word = p;
2311 info->argv[argc] = cmd->name;
2312 info->cmd[argc] = cmd;
2313 argc++;
2314 break;
2315 }
2316
2317 if (argc == info->max_argc) {
2318 too_many:
2319 fr_strerror_const("Too many arguments for command.");
2320 return -1;
2321 }
2322
2323 /*
2324 * We've walked off of the end of the list without
2325 * finding anything.
2326 */
2327 if (!cmd) {
2328 fr_strerror_printf("No such command: %s", word);
2329 return -1;
2330 }
2331
2332 fr_assert(cmd->func != NULL);
2333 fr_assert(cmd->child == NULL);
2334
2335check_syntax:
2336 /*
2337 * The command doesn't take any arguments. Error out if
2338 * there are any. Otherwise, return that the command is
2339 * runnable.
2340 */
2341 if (!cmd->syntax_argv) {
2342 fr_skip_whitespace(word);
2343
2344 if (*word > 0) goto too_many;
2345
2346 info->runnable = true;
2347 info->argc = argc;
2348 return argc;
2349 }
2350
2351 /*
2352 * Do recursive checks on the input string.
2353 */
2354 ret = syntax_str_to_argv(argc, cmd->syntax_argv, info, &word, &info->runnable);
2355 if (ret < 0) return ret;
2356
2357 argc += ret;
2358
2359 /*
2360 * Run out of options to parse, but there's still more
2361 * input.
2362 */
2363 if (!info->runnable && *word) {
2364 fr_skip_whitespace(word);
2365 if (*word) goto too_many;
2366 }
2367
2368 info->argc = argc;
2369 return argc;
2370}
2371
2372/** Clear out any value boxes etc.
2373 *
2374 * @param new_argc the argc to set inside of info
2375 * @param info the information with the current argc
2376 */
2377int fr_command_clear(int new_argc, fr_cmd_info_t *info)
2378{
2379 int i;
2380
2381 if ((new_argc < 0) || (new_argc >= CMD_MAX_ARGV) ||
2382 (new_argc > info->argc)) {
2383 fr_strerror_const("Invalid argument");
2384 return -1;
2385 }
2386
2387 if (new_argc == info->argc) return 0;
2388
2389 for (i = new_argc; i < info->argc; i++) {
2390 if (info->box && info->box[i]) {
2391 fr_value_box_clear(info->box[i]);
2392 talloc_const_free(info->argv[i]);
2393 }
2394 if (info->cmd && info->cmd[i]) info->cmd[i] = NULL;
2395 info->argv[i] = NULL;
2396 }
2397
2398 info->argc = new_argc;
2399 return 0;
2400}
2401
2402/** Initialize an fr_cmd_info_t structure.
2403 *
2404 */
2405void fr_command_info_init(TALLOC_CTX *ctx, fr_cmd_info_t *info)
2406{
2407 memset(info, 0, sizeof(*info));
2408
2409 info->argc = 0;
2410 info->max_argc = CMD_MAX_ARGV;
2411 MEM(info->argv = talloc_zero_array(ctx, char const *, CMD_MAX_ARGV));
2412 MEM(info->box = talloc_zero_array(ctx, fr_value_box_t *, CMD_MAX_ARGV));
2413 MEM(info->cmd = talloc_zero_array(ctx, fr_cmd_t *, CMD_MAX_ARGV));
2414}
2415
2416
2417static int expand_all(fr_cmd_t *cmd, fr_cmd_info_t *info, fr_cmd_argv_t *argv, int count, int max_expansions, char const **expansions)
2418{
2419 fr_cmd_argv_t *child;
2420
2421 if (count >= max_expansions) return count;
2422
2423 if (argv->type == FR_TYPE_ALTERNATE) {
2424 child = NULL;
2425
2426 for (child = argv->child; child != NULL; child = child->next) {
2427 fr_cmd_argv_t *sub;
2428
2430 fr_assert(child->child != NULL);
2431 sub = child->child;
2432
2433 count = expand_all(cmd, info, sub, count, max_expansions, expansions);
2434 }
2435
2436 return count;
2437 }
2438
2439 if (argv->type == FR_TYPE_ALTERNATE) {
2440 for (child = argv->child; child != NULL; child = child->next) {
2441 fr_cmd_argv_t *sub;
2442
2444 fr_assert(child->child != NULL);
2445 sub = child->child;
2446
2447 count = expand_all(cmd, info, sub, count, max_expansions, expansions);
2448 }
2449
2450 return count;
2451 }
2452
2453 /*
2454 * @todo - might want to do something smarter here?
2455 */
2456 if (argv->type == FR_TYPE_OPTIONAL) {
2457 return expand_all(cmd, info, argv->child, count, max_expansions, expansions);
2458 }
2459
2460 if ((argv->type < FR_TYPE_FIXED) && cmd->tab_expand) {
2461 int ret;
2462
2463 info->argv[info->argc] = "";
2464 info->box[info->argc] = NULL;
2465 info->argc++;
2466
2467 fr_assert(count == 0);
2468 ret = cmd->tab_expand(NULL, cmd->ctx, info, max_expansions - count, expansions + count);
2469 if (ret < 0) return ret;
2470
2471 return count + ret;
2472 }
2473
2474 expansions[count] = strdup(argv->name);
2475 return count + 1;
2476}
2477
2478static int expand_syntax(fr_cmd_t *cmd, fr_cmd_info_t *info, fr_cmd_argv_t *argv, char const *text, int start,
2479 char const **word_p, int count, int max_expansions, char const **expansions)
2480{
2481 char const *p, *q;
2482 char const *word = *word_p;
2483
2484 /*
2485 * Loop over syntax_argv, looking for matches.
2486 */
2487 for (/* nothing */ ; argv != NULL; argv = argv->next) {
2488 fr_skip_whitespace(word);
2489
2490 if (!*word) {
2491 return expand_all(cmd, info, argv, count, max_expansions, expansions);
2492 }
2493
2494 if (argv->type == FR_TYPE_VARARGS) return count;
2495
2496 if (count >= max_expansions) return count;
2497
2498 /*
2499 * Optional gets expanded, too.
2500 */
2501 if (argv->type == FR_TYPE_OPTIONAL) {
2502 char const *my_word;
2503
2504 my_word = word;
2505
2506 count = expand_syntax(cmd, info, argv->child, text, start, &my_word, count, max_expansions, expansions);
2507
2508 if (word != my_word) *word_p = word;
2509 continue;
2510 }
2511
2512 if (argv->type == FR_TYPE_ALTERNATE) {
2513 fr_cmd_argv_t *child;
2514
2515 for (child = argv->child; child != NULL; child = child->next) {
2516 fr_cmd_argv_t *sub;
2517 char const *my_word = word;
2518
2520 fr_assert(child->child != NULL);
2521 sub = child->child;
2522
2523 /*
2524 * See if the child eats any of
2525 * the input. If so, use it.
2526 */
2527 count = expand_syntax(cmd, info, sub, text, start, &my_word, count, max_expansions, expansions);
2528 if (my_word != word) {
2529 *word_p = word;
2530 break;
2531 }
2532 }
2533
2534 continue;
2535 }
2536
2537 /*
2538 * Check data types.
2539 */
2540 if (argv->type < FR_TYPE_FIXED) {
2541 int ret;
2542 size_t len, offset;
2543 char quote, *my_word;
2544 fr_type_t type = argv->type;
2545
2546 p = skip_word(word);
2547
2548 if (!p) return count;
2549
2550 if (MATCHED_START) {
2551 if (!cmd->tab_expand) {
2552 /*
2553 * Partial word on input.
2554 * Tell the caller the
2555 * full name.
2556 */
2557 if (!*p || (isspace((uint8_t) *p))) {
2558 expand_name:
2559 expansions[count] = strdup(argv->name);
2560 count++;
2561 }
2562
2563 return count;
2564 }
2565
2566 /*
2567 * Give the function the partial
2568 * text which should be expanded.
2569 */
2570 info->argv[info->argc] = word;
2571 info->box[info->argc] = NULL;
2572 info->argc++;
2573
2574 /*
2575 * Expand this thing.
2576 */
2577 fr_assert(count == 0);
2578 ret = cmd->tab_expand(NULL, cmd->ctx, info, max_expansions - count, expansions + count);
2579 if (ret < 0) return ret;
2580 return count + ret;
2581 }
2582
2583 len = p - word;
2584
2585 info->argv[info->argc] = my_word = talloc_zero_array(info->argv, char, len + 1);
2586 memcpy(my_word, word, len);
2587 my_word[len] = '\0';
2588
2589 if (!info->box[info->argc]) {
2590 info->box[info->argc] = talloc_zero(info->box, fr_value_box_t);
2591 }
2592
2593 if ((*word == '"') || (*word == '\'')) {
2594 quote = *word;
2595 offset = 1;
2596 } else {
2597 quote = 0;
2598 offset = 0;
2599 }
2600
2601 ret = fr_value_box_from_str(info->box[info->argc], info->box[info->argc],
2602 type, NULL,
2603 word + offset, len - (offset << 1),
2605 if (ret < 0) return -1;
2606 info->argc++;
2607 *word_p = word = p;
2608 continue;
2609 }
2610
2611 /*
2612 * This should be the only remaining data type.
2613 */
2614 fr_assert(argv->type == FR_TYPE_FIXED);
2615
2616 SKIP_NAME(argv->name);
2617
2618 /*
2619 * The only matching exit condition is *p is a
2620 * space, and *q is the NUL character.
2621 */
2622 if (MATCHED_NAME) {
2623 *word_p = word = p;
2624 info->argv[info->argc] = word;
2625 info->box[info->argc] = NULL;
2626 info->argc++;
2627 continue;
2628 }
2629
2630 /*
2631 * Ran off of the end of the input before
2632 * matching all of the name. The input is a
2633 * PARTIAL match. Go fill it in.
2634 */
2635 if (!*p || isspace((uint8_t) *p)) {
2636 goto expand_name;
2637 }
2638
2639 /*
2640 * No match, stop here.
2641 */
2642 break;
2643 }
2644
2645 /*
2646 * Ran out of words to match.
2647 */
2648 *word_p = word;
2649 return count;
2650}
2651
2652
2653/** Do readline-style command completions
2654 *
2655 * Most useful as part of readline tab expansions. The expansions
2656 * are strdup() strings, and MUST be free'd by the caller.
2657 *
2658 * @param head of the command tree
2659 * @param text the text to check
2660 * @param start offset in the text where the completions should start
2661 * @param max_expansions how many entries in the "expansions" array.
2662 * @param[in,out] expansions where the expansions are stored.
2663 * @return
2664 * - <0 on error
2665 * - >= 0 number of expansions in the array
2666 */
2667int fr_command_complete(fr_cmd_t *head, char const *text, int start,
2668 int max_expansions, char const **expansions)
2669{
2670 char const *word, *p, *q;
2671 fr_cmd_t *cmd;
2672 int count;
2673 fr_cmd_info_t *info;
2674
2675 cmd = head;
2676 word = text;
2677 count = 0;
2678
2679 info = talloc_zero(head, fr_cmd_info_t);
2681
2682 /*
2683 * Try to do this without mangling "text".
2684 */
2685 while (cmd) {
2686 fr_skip_whitespace(word);
2687
2688 /*
2689 * Skip commands which we shouldn't know about...
2690 */
2691 if (!cmd->live) {
2692 cmd = cmd->next;
2693 continue;
2694 }
2695
2696 /*
2697 * End of the input. Tab expand everything here.
2698 */
2699 if (!*word) {
2700 expand:
2701 while (cmd && (count < max_expansions)) {
2702 if (!cmd->live) goto next;
2703
2704 SKIP_NAME(cmd->name);
2705
2706 /*
2707 * Matched all of the input to
2708 * part of cmd->name.
2709 */
2710 if (!*p || isspace((uint8_t) *p)) {
2711 expansions[count] = strdup(cmd->name);
2712 count++;
2713 }
2714
2715 next:
2716 cmd = cmd->next;
2717 }
2718
2719 talloc_free(info);
2720 return count;
2721 }
2722
2723 SKIP_NAME(cmd->name);
2724
2725 /*
2726 * We're supposed to expand the text at this
2727 * location, go do so. Even if it doesn't match.
2728 */
2729 if (MATCHED_START) {
2730 goto expand;
2731 }
2732
2733 /*
2734 * We've run off of the end of the input, and
2735 * found a partially matching command. Return
2736 * all of the commands which match this
2737 * expansion.
2738 */
2739 if (!*p && *q) {
2740 goto expand;
2741 }
2742
2743 /*
2744 * The only matching exit condition is *p is a
2745 * space, and *q is the NUL character.
2746 */
2747 if (!MATCHED_NAME) {
2748 if (TOO_FAR) return count;
2749
2750 cmd = cmd->next;
2751 continue;
2752 }
2753
2754 if (cmd->intermediate) {
2755 fr_assert(cmd->child != NULL);
2756 word = p;
2757 cmd = cmd->child;
2758
2759 info->argv[info->argc] = cmd->name;
2760 info->argc++;
2761 continue;
2762 }
2763
2764 /*
2765 * Skip the command name we matched.
2766 */
2767 word = p;
2768 break;
2769 }
2770
2771 /*
2772 * No match, can't do anything.
2773 */
2774 if (!cmd) {
2775 talloc_free(info);
2776 return count;
2777 }
2778
2779 /*
2780 * No syntax, can't do anything.
2781 */
2782 if (!cmd->syntax_argv) {
2783 talloc_free(info);
2784 return count;
2785 }
2786
2787 count = expand_syntax(cmd, info, cmd->syntax_argv, text, start, &word, count, max_expansions, expansions);
2788 fr_command_clear(0, info);
2789 talloc_free(info);
2790 return count;
2791}
2792
2793static void print_help(FILE *fp, fr_cmd_t *cmd)
2794{
2795 if (!cmd->help) {
2796 fprintf(fp, "%s\n", cmd->name);
2797 } else {
2798 fprintf(fp, "%-30s%s\n", cmd->name, cmd->help);
2799 }
2800}
2801
2802/** Do readline-style help completions
2803 *
2804 * Most useful as part of readline.
2805 *
2806 * @param fp where the help is printed
2807 * @param head of the command tree
2808 * @param text the text to check
2809 */
2810int fr_command_print_help(FILE *fp, fr_cmd_t *head, char const *text)
2811{
2812 char const *word, *p, *q;
2813 fr_cmd_t *cmd;
2814
2815 cmd = head;
2816 word = text;
2817
2818 /*
2819 * Try to do this without mangling "text".
2820 */
2821 while (cmd) {
2822 fr_skip_whitespace(word);
2823
2824 /*
2825 * End of the input. Tab expand everything here.
2826 */
2827 if (!*word) {
2828 while (cmd) {
2829 print_help(fp, cmd);
2830 cmd = cmd->next;
2831 }
2832 return 0;
2833 }
2834
2835 /*
2836 * Try to find a matching cmd->name
2837 */
2838 SKIP_NAME(cmd->name);
2839
2840 /*
2841 * Matched part of the name. Print out help for this one.
2842 */
2843 if (!*p && *q) {
2844 print_help(fp, cmd);
2845 }
2846
2847 /*
2848 * The only matching exit condition is *p is a
2849 * space, and *q is the NUL character.
2850 */
2851 if (!MATCHED_NAME) {
2852 if (TOO_FAR) return 0;
2853
2854 cmd = cmd->next;
2855 continue;
2856 }
2857
2858 /*
2859 * Done the input, but not the commands.
2860 */
2861 if (!*p) {
2862 /*
2863 * If we've ALSO matched this complete
2864 * command, AND it has children, then
2865 * print help about the children.
2866 */
2867 if (!*q && cmd->intermediate) goto intermediate;
2868 break;
2869 }
2870
2871 if (cmd->intermediate) {
2872 intermediate:
2873 fr_assert(cmd->child != NULL);
2874 word = p;
2875 cmd = cmd->child;
2876 continue;
2877 }
2878
2879 /*
2880 * Skip the command name we matched.
2881 */
2882 break;
2883 }
2884
2885 /*
2886 * No match, can't do anything.
2887 */
2888 if (!cmd) {
2889 return 0;
2890 }
2891
2892 /*
2893 * For one command, try to print out the syntax, as it's
2894 * generally more useful than the help.
2895 */
2896 if (!cmd->syntax) {
2897 print_help(fp, cmd);
2898 } else {
2899 fprintf(fp, "%-30s%s\n", cmd->name, cmd->syntax);
2900 }
2901
2902 return 0;
2903}
2904
2905/* See if partial string matches a full string.
2906 *
2907 * @param word the partial word to match
2908 * @param name the name which "word" might match
2909 * @return
2910 * - false if they do not match
2911 * - true if "word" is a prefix of "name"
2912 *
2913 */
2914bool fr_command_strncmp(const char *word, const char *name)
2915{
2916 char const *p, *q;
2917
2918 if (!*word) return true;
2919
2920 SKIP_NAME(name);
2921
2922 /*
2923 * If we're done P (partial or full), that's a match.
2924 */
2925 return (*p == '\0');
2926}
#define CMD_MAX_ARGV
Definition radmin.c:150
#define RCSID(id)
Definition build.h:485
#define UNUSED
Definition build.h:317
static int split_alternation(char **input, char **output)
Definition command.c:276
static char const * skip_word(char const *text)
Definition command.c:1880
bool read_only
Definition command.c:67
#define MATCHED_NAME
Definition command.c:1372
int fr_command_clear(int new_argc, fr_cmd_info_t *info)
Clear out any value boxes etc.
Definition command.c:2377
static int expand_all(fr_cmd_t *cmd, fr_cmd_info_t *info, fr_cmd_argv_t *argv, int count, int max_expansions, char const **expansions)
Definition command.c:2417
void fr_command_list(FILE *fp, int max_depth, fr_cmd_t *head, int options)
Definition command.c:1657
void * ctx
Definition command.c:63
int fr_command_walk(fr_cmd_t *head, void **walk_ctx, void *ctx, fr_cmd_walk_t callback)
Walk over a command hierarchy.
Definition command.c:1027
char const * name
Definition command.c:46
bool added_name
was this name added?
Definition command.c:70
int fr_command_str_to_argv(fr_cmd_t *head, fr_cmd_info_t *info, char const *text)
Split a string in-place, updating argv[].
Definition command.c:2149
int fr_command_run(FILE *fp, FILE *fp_err, fr_cmd_info_t *info, bool read_only)
Run a particular command.
Definition command.c:1481
static fr_cmd_t * fr_command_alloc(TALLOC_CTX *ctx, fr_cmd_t **head, char const *name)
Allocate an fr_cmd_t structure.
Definition command.c:158
static int syntax_str_to_argv(int start_argc, fr_cmd_argv_t *start, fr_cmd_info_t *info, char const **text, bool *runnable)
Check the syntax of a command, starting at *text
Definition command.c:1912
static int fr_command_add_syntax(TALLOC_CTX *ctx, char *syntax, fr_cmd_argv_t **head, bool allow_varargs)
Definition command.c:561
static void fr_command_list_node(FILE *fp, fr_cmd_t *cmd, int depth, char const **argv, int options)
Definition command.c:1616
struct fr_cmd_s * child
if there are subcommands
Definition command.c:56
void fr_command_info_init(TALLOC_CTX *ctx, fr_cmd_info_t *info)
Initialize an fr_cmd_info_t structure.
Definition command.c:2405
fr_cmd_func_t func
Definition command.c:64
fr_cmd_argv_t * syntax_argv
arguments and types
Definition command.c:61
static void fr_command_debug_node(FILE *fp, fr_cmd_t *cmd, int depth)
Definition command.c:1591
int fr_command_print_help(FILE *fp, fr_cmd_t *head, char const *text)
Do readline-style help completions.
Definition command.c:2810
fr_command_register_hook_t fr_command_register_hook
Definition command.c:42
void fr_command_debug(FILE *fp, fr_cmd_t *head)
Definition command.c:1610
char const ** parents
Definition command.c:1009
char const * fr_command_help(fr_cmd_t *head, int argc, char *argv[])
Get help text for a particular command.
Definition command.c:1561
static void fr_command_list_internal(FILE *fp, fr_cmd_t *head, int depth, int max_depth, char const **argv, int options)
Definition command.c:1639
#define FR_TYPE_OPTIONAL
Definition command.c:87
int fr_command_complete(fr_cmd_t *head, char const *text, int start, int max_expansions, char const **expansions)
Do readline-style command completions.
Definition command.c:2667
static void fr_command_debug_internal(FILE *fp, fr_cmd_t *head, int depth)
Definition command.c:1598
static int fr_command_register(UNUSED TALLOC_CTX *talloc_ctx, UNUSED char const *name, UNUSED void *ctx, UNUSED fr_cmd_table_t *table)
Definition command.c:37
static int fr_command_tab_expand_partial(fr_cmd_t *head, char const *partial, int max_expansions, char const **expansions)
Definition command.c:1145
struct fr_cmd_s * next
Definition command.c:55
char const * name
Definition command.c:53
static int fr_command_verify_argv(fr_cmd_info_t *info, int start, int verify, int argc, fr_cmd_argv_t **argv_p, bool optional)
Definition command.c:1680
static int fr_command_run_partial(FILE *fp, FILE *fp_err, fr_cmd_info_t *info, bool read_only, int offset, fr_cmd_t *head)
Definition command.c:1376
bool fr_command_strncmp(const char *word, const char *name)
Definition command.c:2914
#define FR_TYPE_FIXED
Definition command.c:84
#define FR_TYPE_ALTERNATE
Definition command.c:88
int fr_command_add(TALLOC_CTX *talloc_ctx, fr_cmd_t **head, char const *name, void *ctx, fr_cmd_table_t const *table)
Add one command to the global command tree.
Definition command.c:733
int fr_command_add_multi(TALLOC_CTX *talloc_ctx, fr_cmd_t **head, char const *name, void *ctx, fr_cmd_table_t const *table)
Add multiple commands to the global command tree.
Definition command.c:993
static const char * tabs
Definition command.c:1589
#define TOO_FAR
Definition command.c:1373
bool intermediate
intermediate commands can't have callbacks
Definition command.c:68
#define MATCHED_START
Definition command.c:1374
#define SKIP_NAME(name)
Definition command.c:1368
#define FR_TYPE_ALTERNATE_CHOICE
Definition command.c:89
static bool fr_command_valid_syntax(fr_cmd_argv_t *argv)
Definition command.c:212
fr_type_t type
Definition command.c:47
static int expand_syntax(fr_cmd_t *cmd, fr_cmd_info_t *info, fr_cmd_argv_t *argv, char const *text, int start, char const **word_p, int count, int max_expansions, char const **expansions)
Definition command.c:2478
char const * syntax
only for terminal nodes
Definition command.c:58
bool live
is this entry live?
Definition command.c:69
static int split(char **input, char **output, bool syntax_string)
Definition command.c:393
#define FR_TYPE_VARARGS
Definition command.c:86
char const * help
Definition command.c:59
int fr_command_tab_expand(TALLOC_CTX *ctx, fr_cmd_t *head, fr_cmd_info_t *info, int max_expansions, char const **expansions)
Get the commands && help at a particular level.
Definition command.c:1298
static fr_cmd_t * fr_command_find(fr_cmd_t **head, char const *name, fr_cmd_t ***insert)
Find a command.
Definition command.c:100
fr_cmd_tab_t tab_expand
Definition command.c:65
static bool fr_command_valid_name(char const *name)
Definition command.c:182
fr_cmd_argv_t * next
Definition command.c:48
static int fr_command_tab_expand_syntax(TALLOC_CTX *ctx, fr_cmd_t *cmd, int syntax_offset, fr_cmd_info_t *info, int max_expansions, char const **expansions)
Definition command.c:1270
static void print_help(FILE *fp, fr_cmd_t *cmd)
Definition command.c:2793
fr_cmd_argv_t * child
Definition command.c:49
static int fr_command_tab_expand_argv(TALLOC_CTX *ctx, fr_cmd_t *cmd, fr_cmd_info_t *info, char const *name, fr_cmd_argv_t *argv, int max_expansions, char const **expansions)
Definition command.c:1166
A stack for walking commands.
Definition command.c:1007
int(* fr_cmd_walk_t)(void *ctx, fr_cmd_walk_info_t *)
Definition command.h:72
char const ** parents
Definition command.h:66
bool add_name
do we add a name here?
Definition command.h:59
char const * help
help text
Definition command.h:55
int argc
current argument count
Definition command.h:39
int(* fr_cmd_func_t)(FILE *fp, FILE *fp_err, void *ctx, fr_cmd_info_t const *info)
Definition command.h:47
fr_cmd_func_t func
function to process this command
Definition command.h:56
char const * syntax
Definition command.h:68
char const * syntax
e.g. "STRING"
Definition command.h:54
fr_value_box_t ** box
value_box version of commands.
Definition command.h:43
bool read_only
Definition command.h:58
char const * parent
e.g. "show module"
Definition command.h:52
#define FR_COMMAND_OPTION_NAME
Definition command.h:89
#define FR_COMMAND_OPTION_LIST_CHILD
Definition command.h:88
fr_cmd_tab_t tab_expand
tab expand things in the syntax string
Definition command.h:57
bool runnable
is the command runnable?
Definition command.h:41
int(* fr_command_register_hook_t)(TALLOC_CTX *talloc_ctx, char const *name, void *ctx, fr_cmd_table_t *table)
Definition command.h:73
#define FR_COMMAND_OPTION_HELP
Definition command.h:90
int max_argc
maximum number of arguments
Definition command.h:40
char const * name
e.g. "stats"
Definition command.h:53
char const * help
Definition command.h:69
char const ** argv
text version of commands
Definition command.h:42
int(* fr_cmd_tab_t)(TALLOC_CTX *talloc_ctx, void *ctx, fr_cmd_info_t *info, int max_expansions, char const **expansions)
Definition command.h:49
char const * name
Definition command.h:67
fr_cmd_t ** cmd
cached commands at each offset
Definition command.h:44
#define MEM(x)
Definition debug.h:36
talloc_free(reap)
static char * stack[MAX_STACK]
Definition radmin.c:158
fr_type_t
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_MAX
Number of defined data types.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_VALUE_BOX
A boxed value.
@ FR_TYPE_VOID
User data.
unsigned char uint8_t
static size_t used
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
#define fr_skip_not_whitespace(_p)
Skip everything that's not whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition misc.h:72
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition misc.h:59
size_t fr_utf8_char(uint8_t const *str, ssize_t inlen)
Checks for utf-8, taken from http://www.w3.org/International/questions/qa-forms-utf-8.
Definition print.c:39
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:81
static char const * name
return count
Definition module.c:155
fr_aka_sim_id_type_t type
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:224
static fr_slen_t head
Definition xlat.h:416
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition strerror.h:84
#define fr_strerror_const(_msg)
Definition strerror.h:223
fr_table_num_ordered_t const fr_type_table[]
Map data types to names representing those types.
Definition types.c:31
#define FR_TYPE_STRUCTURAL
Definition types.h:296
fr_sbuff_unescape_rules_t * fr_value_unescape_by_char[UINT8_MAX+1]
Definition value.c:342
ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules)
Definition value.c:5450
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:3946
int nonnull(2, 5))