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