26 RCSID(
"$Id: 98890f987989f0a9ed7705ab1055515f56f5a968 $")
28 #include <freeradius-devel/server/command.h>
29 #include <freeradius-devel/server/log.h>
30 #include <freeradius-devel/util/debug.h>
32 #include <freeradius-devel/util/misc.h>
76 static int split(
char **input,
char **output,
bool syntax_string);
84 #define FR_TYPE_FIXED FR_TYPE_TIME_DELTA
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
107 if (insert) *insert =
head;
111 for (cmd = *
head; cmd != NULL; cmd = cmd->
next) {
120 where = &(cmd->
next);
127 if (status > 0)
break;
135 if (insert) *insert = where;
178 for (p = (
uint8_t const *)
name; *p !=
'\0'; p++) {
184 if (((*p >=
' ') && (*p <=
',')) ||
185 ((*p >=
':') && (*p <=
'@')) ||
186 ((*p >=
'[') && (*p <=
'^')) ||
187 ((*p >
'z') && (*p <= 0xf7)) ||
207 bool lowercase =
false;
208 bool uppercase =
false;
216 for (p = argv->
name; *p !=
'\0'; p++) {
217 if (isupper((
uint8_t) *p)) uppercase =
true;
218 if (islower((
uint8_t) *p)) lowercase =
true;
225 if (!uppercase && !lowercase) {
233 if (uppercase && lowercase) {
282 while ((*str ==
' ') ||
298 if ((*str ==
'[') || (*str ==
'(')) {
315 while ((*str != end) || (
count > 0)) {
321 if (*str == quote)
count++;
322 if (*str == end)
count--;
335 if ((*str !=
'\0') &&
353 }
else if (*str ==
')') {
355 }
else if (
count == 0) {
356 if (*str ==
'|')
break;
373 while ((*str ==
' ') ||
385 static int split(
char **input,
char **output,
bool syntax_string)
399 while ((*str ==
' ') ||
428 if (!syntax_string && ((*str ==
'"') || (*str ==
'\''))) {
431 while (*str != quote) {
461 if ((*str !=
'\0') &&
471 }
else if (syntax_string && ((*str ==
'[') || (*str ==
'('))) {
488 while ((*str != end) || (
count > 0)) {
494 if (*str == quote)
count++;
495 if (*str == end)
count--;
508 if ((*str !=
'\0') &&
541 while ((*str ==
' ') ||
568 if (ret < 0)
return ret;
570 if (ret == 0)
return i;
578 if (strcmp(
name,
"...") == 0) {
579 if (!allow_varargs) {
600 allow_varargs =
false;
602 }
else if (
name[0] ==
'[') {
606 char *option = talloc_strdup(
ctx,
name + 1);
610 q = option + strlen(option) - 1;
623 if (ret < 0)
return ret;
630 }
else if (
name[0] ==
'(') {
634 char *option = talloc_strdup(
ctx,
name + 1);
638 q = option + strlen(option) - 1;
659 if (ret < 0)
return ret;
668 if (ret < 0)
return ret;
675 *last_child = choice;
676 last_child = &(choice->
next);
698 last = &(argv->
next);
729 int argc = 0,
depth = 0;
767 p = talloc_strdup(talloc_ctx, table->
parent);
770 ret =
split(&p, &parents[i],
true);
771 if (ret < 0)
return -1;
795 start = &(cmd->
child);
830 if (table->
help) cmd->
help = talloc_strdup(cmd, table->
help);
843 start = &(cmd->
child);
870 char *
syntax = talloc_strdup(talloc_ctx, table->
syntax);
873 if (argc < 0)
return -1;
913 if (cmd->
help == table->
help)
return 0;
915 if (cmd->
help != NULL) {
989 for (i = 0; table[i].
help != NULL; i++) {
1026 if (!walk_ctx || !callback) {
1083 ret = callback(ctx, &info);
1116 if (
stack->depth == 0) {
1117 if (!cmd)
goto done;
1143 len = strlen(partial);
1148 for (i = 0, cmd =
head; (i < max_expansions) && cmd != NULL; cmd = cmd->
next) {
1149 if (strncmp(partial, cmd->
name, len) != 0)
continue;
1151 expansions[i++] = cmd->
name;
1159 int max_expansions,
char const **expansions)
1169 expansions[0] = argv->
name;
1173 return cmd->
tab_expand(ctx, cmd->
ctx, info, max_expansions, expansions);
1193 for (child = argv->
child; child != NULL; child = child->
next) {
1213 (*p !=
'\0') && (*q !=
'\0');
1218 if (*p != *q)
return 0;
1225 if (p[1] && !q[1])
return 0;
1239 if (!p[1] && q[1]) {
1240 expansions[0] = argv->
name;
1263 int max_expansions,
char const **expansions)
1269 if (ret < 0)
return -1;
1295 if (!
head)
return 0;
1303 for (i = 0; i < info->
argc; i++) {
1322 if ((i + 1) == info->
argc)
return 0;
1327 if (!cmd->
live)
return 0;
1349 for (i = 0, cmd = cmd->
child; (i < max_expansions) && (cmd != NULL); i++, cmd = cmd->
next) {
1350 expansions[i] = cmd->
name;
1360 #define SKIP_NAME(name) do { p = word; q = name; while (*p && *q && (*p == *q)) { \
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)
1377 start =
head->child;
1387 for (i = offset + 1; i < info->
argc; i++) {
1388 char const *p, *q, *word;
1394 for (cmd = start; cmd != NULL; cmd = cmd->
next) {
1395 if (!cmd->
live)
continue;
1397 word = info->
argv[i];
1430 if (!cmd->
live)
return 0;
1433 fprintf(fp_err,
"No permissions to run command '%s'\n", cmd->
name);
1452 my_info.
box = &info->
box[i + 1];
1453 ret = cmd->
func(fp, fp_err, cmd->
ctx, &my_info);
1484 if (info->
argc == 0)
return 0;
1486 for (i = 0; i < info->
argc; i++) {
1493 for (; cmd != NULL; cmd = cmd->
next) {
1494 if (!cmd->
live)
continue;
1496 fprintf(fp,
"%s %s\n", info->
argv[i - 1], cmd->
name);
1499 if (ret < 0)
return ret;
1515 if (!cmd->
live)
return 0;
1518 fprintf(fp_err,
"No permissions to run command '%s' help %s\n", cmd->
name, cmd->
help);
1537 my_info.
box = &info->
box[i + 1];
1538 ret = cmd->
func(fp, fp_err, cmd->
ctx, &my_info);
1560 for (i = 0; i < argc; i++) {
1562 if (!cmd)
return NULL;
1576 if (start)
return start->
help;
1581 static const char *
tabs =
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
1594 for (cmd =
head; cmd != NULL; cmd = cmd->
next) {
1612 for (i = 0; i <
depth; i++) {
1613 fprintf(fp,
"%s ", argv[i]);
1621 fprintf(fp,
"%s\n", cmd->
name);
1623 fprintf(fp,
"%s %s\n", cmd->
name, cmd->
syntax);
1627 fprintf(fp,
"\t%s\n", cmd->
help);
1635 for (cmd =
head; cmd != NULL; cmd = cmd->
next) {
1640 if (cmd->
child && ((
depth + 1) < max_depth)) {
1653 if ((max_depth <= 0) || !
head)
return;
1681 TALLOC_CTX *ctx = NULL;
1689 if ((start +
used) >= argc) {
1717 if (strcmp(argv->
name, info->
argv[start +
used]) != 0) {
1724 if (optional)
return 0;
1737 child = argv->
child;
1740 if (ret < 0)
return ret;
1775 for (child = argv->
child; child != NULL; child = child->
next) {
1783 if (ret <= 0)
continue;
1809 if ((start +
used) < verify) {
1816 if ((
name[0] ==
'"') ||
1817 (
name[0] ==
'\'')) {
1827 if (!info->
box[start +
used]) {
1831 box = info->
box[start +
used];
1862 if ((start +
used) < argc) {
1875 char const *word = text;
1877 if ((*word !=
'"') && (*word !=
'\'')) {
1884 while (*word && (*word != quote)) {
1885 if (*word !=
'\\') {
1891 if (!*word)
return NULL;
1905 char const **text,
bool *runnable)
1907 int argc = start_argc;
1910 char const *word, *my_word, *p, *q;
1920 if (!*word)
goto done;
1939 if (argc < info->argc) {
1950 ((*word ==
'"') || (*word ==
'\''))) {
1956 if ((*word ==
'"') || (*word ==
'\'')) {
1970 if (!info->
box[argc]) {
1976 word + offset, len - (offset << 1),
1978 if (ret < 0)
return -1;
1986 info->
argv[argc] = str = talloc_memdup(info->
argv, word + offset, len + 1);
2023 info->
cmd[argc] = NULL;
2038 for (child = argv->
child; child != NULL; child = child->
next) {
2052 if (ret <= 0)
continue;
2070 child = argv->
child;
2074 if (ret < 0)
return ret;
2079 if (ret == 0)
goto next;
2122 if (!argv) *runnable =
true;
2124 return (argc - start_argc);
2144 char const *word, *p, *q;
2172 for (argc = 0; argc < info->
argc; argc++) {
2173 cmd = info->
cmd[argc];
2178 if ((word[0] ==
'*') && isspace(word[1]) && cmd->
added_name) {
2235 if (argc < info->argc) {
2236 cmd = info->
cmd[argc];
2247 if ((word[0] ==
'*') && isspace(word[1]) && cmd->
added_name) {
2251 info->
argv[argc] =
"*";
2252 info->
cmd[argc] = cmd;
2266 if (argc < info->argc) {
2292 info->
cmd[argc] = cmd;
2304 info->
cmd[argc] = cmd;
2336 if (*word > 0)
goto too_many;
2347 if (ret < 0)
return ret;
2357 if (*word)
goto too_many;
2374 (new_argc > info->
argc)) {
2379 if (new_argc == info->
argc)
return 0;
2381 for (i = new_argc; i < info->
argc; i++) {
2382 if (info->
box && info->
box[i]) {
2386 if (info->
cmd && info->
cmd[i]) info->
cmd[i] = NULL;
2387 info->
argv[i] = NULL;
2390 info->
argc = new_argc;
2399 memset(info, 0,
sizeof(*info));
2418 for (child = argv->
child; child != NULL; child = child->
next) {
2432 for (child = argv->
child; child != NULL; child = child->
next) {
2461 if (ret < 0)
return ret;
2471 char const **word_p,
int count,
int max_expansions,
char const **expansions)
2474 char const *word = *word_p;
2479 for ( ; argv != NULL; argv = argv->
next) {
2483 return expand_all(cmd, info, argv,
count, max_expansions, expansions);
2494 char const *my_word;
2500 if (word != my_word) *word_p = word;
2507 for (child = argv->
child; child != NULL; child = child->
next) {
2509 char const *my_word = word;
2520 if (my_word != word) {
2535 char quote, *my_word;
2540 if (!p)
return count;
2549 if (!*p || (isspace((
uint8_t) *p))) {
2571 if (ret < 0)
return ret;
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';
2585 if ((*word ==
'"') || (*word ==
'\'')) {
2595 word + offset, len - (offset << 1),
2597 if (ret < 0)
return -1;
2627 if (!*p || isspace((
uint8_t) *p)) {
2660 int max_expansions,
char const **expansions)
2662 char const *word, *p, *q;
2693 while (cmd && (
count < max_expansions)) {
2702 if (!*p || isspace((
uint8_t) *p)) {
2788 fprintf(fp,
"%s\n", cmd->
name);
2790 fprintf(fp,
"%-30s%s\n", cmd->
name, cmd->
help);
2804 char const *word, *p, *q;
2891 fprintf(fp,
"%-30s%s\n", cmd->
name, cmd->
syntax);
2910 if (!*word)
return true;
2917 return (*p ==
'\0');
static int split_alternation(char **input, char **output)
int fr_command_clear(int new_argc, fr_cmd_info_t *info)
Clear out any value boxes etc.
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)
void fr_command_list(FILE *fp, int max_depth, fr_cmd_t *head, int options)
int fr_command_walk(fr_cmd_t *head, void **walk_ctx, void *ctx, fr_cmd_walk_t callback)
Walk over a command hierarchy.
bool added_name
was this name added?
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[].
int fr_command_run(FILE *fp, FILE *fp_err, fr_cmd_info_t *info, bool read_only)
Run a particular command.
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
static int fr_command_add_syntax(TALLOC_CTX *ctx, char *syntax, fr_cmd_argv_t **head, bool allow_varargs)
static void fr_command_list_node(FILE *fp, fr_cmd_t *cmd, int depth, char const **argv, int options)
struct fr_cmd_s * child
if there are subcommands
void fr_command_info_init(TALLOC_CTX *ctx, fr_cmd_info_t *info)
Initialize an fr_cmd_info_t structure.
static fr_cmd_t * fr_command_find(fr_cmd_t **head, char const *name, fr_cmd_t ***insert)
Find a command.
fr_cmd_argv_t * syntax_argv
arguments and types
static void fr_command_debug_node(FILE *fp, fr_cmd_t *cmd, int depth)
int fr_command_print_help(FILE *fp, fr_cmd_t *head, char const *text)
Do readline-style help completions.
fr_command_register_hook_t fr_command_register_hook
void fr_command_debug(FILE *fp, fr_cmd_t *head)
static void fr_command_list_internal(FILE *fp, fr_cmd_t *head, int depth, int max_depth, char const **argv, int options)
static char const * skip_word(char const *text)
int fr_command_complete(fr_cmd_t *head, char const *text, int start, int max_expansions, char const **expansions)
Do readline-style command completions.
static void fr_command_debug_internal(FILE *fp, fr_cmd_t *head, int depth)
static int fr_command_register(UNUSED TALLOC_CTX *talloc_ctx, UNUSED char const *name, UNUSED void *ctx, UNUSED fr_cmd_table_t *table)
static int fr_command_tab_expand_partial(fr_cmd_t *head, char const *partial, int max_expansions, char const **expansions)
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)
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)
bool fr_command_strncmp(const char *word, const char *name)
#define FR_TYPE_ALTERNATE
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.
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.
char const * fr_command_help(fr_cmd_t *head, int argc, char *argv[])
Get help text for a particular command.
bool intermediate
intermediate commands can't have callbacks
#define FR_TYPE_ALTERNATE_CHOICE
static bool fr_command_valid_syntax(fr_cmd_argv_t *argv)
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)
char const * syntax
only for terminal nodes
bool live
is this entry live?
static int split(char **input, char **output, bool syntax_string)
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.
static bool fr_command_valid_name(char const *name)
static fr_cmd_t * fr_command_alloc(TALLOC_CTX *ctx, fr_cmd_t **head, char const *name)
Allocate an fr_cmd_t structure.
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)
static void print_help(FILE *fp, fr_cmd_t *cmd)
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)
A stack for walking commands.
int(* fr_cmd_walk_t)(void *ctx, fr_cmd_walk_info_t *)
bool add_name
do we add a name here?
char const * help
help text
int argc
current argument count
int(* fr_cmd_func_t)(FILE *fp, FILE *fp_err, void *ctx, fr_cmd_info_t const *info)
fr_cmd_func_t func
function to process this command
char const * syntax
e.g. "STRING"
fr_value_box_t ** box
value_box version of commands.
char const * parent
e.g. "show module"
#define FR_COMMAND_OPTION_NAME
#define FR_COMMAND_OPTION_LIST_CHILD
fr_cmd_tab_t tab_expand
tab expand things in the syntax string
bool runnable
is the command runnable?
int(* fr_command_register_hook_t)(TALLOC_CTX *talloc_ctx, char const *name, void *ctx, fr_cmd_table_t *table)
#define FR_COMMAND_OPTION_HELP
int max_argc
maximum number of arguments
char const * name
e.g. "stats"
char const ** argv
text version of commands
int(* fr_cmd_tab_t)(TALLOC_CTX *talloc_ctx, void *ctx, fr_cmd_info_t *info, int max_expansions, char const **expansions)
fr_cmd_t ** cmd
cached commands at each offset
static char * stack[MAX_STACK]
@ 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.
static uint8_t depth(fr_minmax_heap_index_t i)
#define fr_skip_not_whitespace(_p)
Skip everything that's not whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
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.
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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.
static int talloc_const_free(void const *ptr)
Free const'd memory.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
#define fr_strerror_const(_msg)
fr_table_num_ordered_t const fr_type_table[]
Map data types to names representing those types.
#define FR_TYPE_STRUCTURAL
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)
fr_sbuff_unescape_rules_t * fr_value_unescape_by_char[UINT8_MAX+1]
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.