]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add recursive option for printing dictionary entries
authorAlan T. DeKok <aland@freeradius.org>
Wed, 26 Nov 2025 20:06:25 +0000 (15:06 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 26 Nov 2025 20:06:25 +0000 (15:06 -0500)
src/bin/radict.c

index 03a0fca1a53a56bfd5b36448d3ca76c1f6f4a43c..e44d2b7d15bfd17a97c91d85190eafb8607997ef 100644 (file)
@@ -45,6 +45,7 @@ typedef enum {
 static fr_dict_t *dicts[255];
 static bool print_values = false;
 static bool print_headers = false;
+static bool print_recursive = false;
 static radict_out_t output_format = RADICT_OUT_FANCY;
 static fr_dict_t **dict_end = dicts;
 
@@ -65,6 +66,7 @@ static void usage(void)
        fprintf(stderr, "  -h               Print help text.\n");
        fprintf(stderr, "  -H               Show the headers of each field.\n");
        fprintf(stderr, "  -p <protocol>    Set protocol by name\n");
+       fprintf(stderr, "  -r               Write out attributes recursively.\n");
        fprintf(stderr, "  -V               Write out all attribute values.\n");
        fprintf(stderr, "  -x               Debugging mode.\n");
        fprintf(stderr, "\n");
@@ -162,15 +164,21 @@ static int load_dicts(char const *dict_dir, char const *protocol)
        return 0;
 }
 
-static void da_print_info_td(fr_dict_t const *dict, fr_dict_attr_t const *da)
+static const char *spaces = "                                                                                ";
+
+static void da_print_info_td(fr_dict_t const *dict, fr_dict_attr_t const *da, int depth)
 {
        char                    oid_str[512];
        char                    flags[256];
        fr_hash_iter_t          iter;
-       fr_dict_enum_value_t            *enumv;
+       fr_dict_enum_value_t    *enumv;
        fr_sbuff_t              old_str_sbuff = FR_SBUFF_OUT(oid_str, sizeof(oid_str));
        fr_sbuff_t              flags_sbuff = FR_SBUFF_OUT(flags, sizeof(flags));
 
+       char const              *type;
+       fr_dict_attr_t const    *child;
+       fr_hash_table_t         *namespace;
+
        if (fr_dict_attr_oid_print(&old_str_sbuff, NULL, da, false) <= 0) {
                fr_strerror_printf("OID string too long");
                fr_exit(EXIT_FAILURE);
@@ -178,6 +186,15 @@ static void da_print_info_td(fr_dict_t const *dict, fr_dict_attr_t const *da)
 
        fr_dict_attr_flags_print(&flags_sbuff, dict, da->type, &da->flags);
 
+       if (!da->flags.is_alias) {
+               type = fr_type_to_str(da->type);
+       } else {
+               fr_assert(da->type == FR_TYPE_VOID);
+               type = "ALIAS";
+       }
+
+       printf("%.*s", depth, spaces);
+
        /* Protocol Name Type */
 
        switch(output_format) {
@@ -187,7 +204,7 @@ static void da_print_info_td(fr_dict_t const *dict, fr_dict_attr_t const *da)
                               fr_sbuff_start(&old_str_sbuff),
                               da->name,
                               da->attr,
-                              fr_type_to_str(da->type),
+                              type,
                               fr_sbuff_start(&flags_sbuff));
                        break;
 
@@ -198,7 +215,7 @@ static void da_print_info_td(fr_dict_t const *dict, fr_dict_attr_t const *da)
                               fr_sbuff_start(&old_str_sbuff),
                               da->name,
                               da->attr,
-                              fr_type_to_str(da->type),
+                              type,
                               fr_sbuff_start(&flags_sbuff));
        }
 
@@ -213,7 +230,6 @@ static void da_print_info_td(fr_dict_t const *dict, fr_dict_attr_t const *da)
                     enumv = fr_hash_table_iter_next(ext->value_by_name, &iter)) {
                        char *str;
 
-
                        switch(output_format) {
                                case RADICT_OUT_CSV:
                                        str = fr_asprintf(NULL, "%s,%s,%s,%d,%s,%s,%s,%pV",
@@ -221,7 +237,7 @@ static void da_print_info_td(fr_dict_t const *dict, fr_dict_attr_t const *da)
                                                                fr_sbuff_start(&old_str_sbuff),
                                                                da->name,
                                                                da->attr,
-                                                               fr_type_to_str(da->type),
+                                                               type,
                                                                fr_sbuff_start(&flags_sbuff),
                                                                enumv->name,
                                                                enumv->value);
@@ -234,16 +250,30 @@ static void da_print_info_td(fr_dict_t const *dict, fr_dict_attr_t const *da)
                                                                fr_sbuff_start(&old_str_sbuff),
                                                                da->name,
                                                                da->attr,
-                                                               fr_type_to_str(da->type),
+                                                               type,
                                                                fr_sbuff_start(&flags_sbuff),
                                                                enumv->name,
                                                                enumv->value);
                        }
 
-                       printf("%s\n", str);
+                       printf("%.*s%s\n", depth, spaces, str);
                        talloc_free(str);
                }
        }
+
+       /*
+        *      Print definitions recursively.
+        */
+       if (!print_recursive || !fr_type_is_structural(da->type)) return;
+
+       namespace = dict_attr_namespace(da);
+       fr_assert(namespace != NULL);
+
+       for (child = fr_hash_table_iter_init(namespace, &iter);
+            child != NULL;
+            child = fr_hash_table_iter_next(namespace, &iter)) {
+               da_print_info_td(dict, child, depth + 1);
+       }
 }
 
 static void _raddict_export(fr_dict_t const *dict, uint64_t *count, uintptr_t *low, uintptr_t *high, fr_dict_attr_t const *da, unsigned int lvl)
@@ -268,7 +298,7 @@ static void _raddict_export(fr_dict_t const *dict, uint64_t *count, uintptr_t *l
                        *high = (uintptr_t)da;
                }
 
-               da_print_info_td(fr_dict_by_da(da), da);
+               da_print_info_td(fr_dict_by_da(da), da, 0);
        }
 
        if (count) (*count)++;
@@ -332,7 +362,7 @@ int main(int argc, char *argv[])
        fr_debug_lvl = 1;
        fr_log_fp = stdout;
 
-       while ((c = getopt(argc, argv, "AcfED:p:VxhH")) != -1) switch (c) {
+       while ((c = getopt(argc, argv, "AcfED:p:rVxhH")) != -1) switch (c) {
                case 'A':
                        alias = true;
                        break;
@@ -361,6 +391,10 @@ int main(int argc, char *argv[])
                        protocol = optarg;
                        break;
 
+               case 'r':
+                       print_recursive = true;
+                       break;
+
                case 'V':
                        print_values = true;
                        break;
@@ -449,6 +483,8 @@ int main(int argc, char *argv[])
                        DEBUG2("Memory allocd %zu (bytes)", talloc_total_size(*dict_p));
                        DEBUG2("Memory spread %zu (bytes)", (size_t) (high - low));
                } while (++dict_p < dict_end);
+
+               goto finish;
        }
 
        if (alias) {
@@ -459,6 +495,8 @@ int main(int argc, char *argv[])
                                fr_dict_alias_export(fr_log_fp, fr_dict_root(*dict_p));
                        }
                } while (++dict_p < dict_end);
+
+               goto finish;
        }
 
        if (argc == 0) {
@@ -482,7 +520,7 @@ int main(int argc, char *argv[])
 
                        da = fr_dict_attr_by_oid(NULL, fr_dict_root(*dict_p), attr);
                        if (da) {
-                               da_print_info_td(*dict_p, da);
+                               da_print_info_td(*dict_p, da, 0);
                                found = true;
                        } else {
                                fprintf(stderr, "Dictionary %s does not contain attribute %s\n",