0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <assert.h>
0013 #include <ctype.h>
0014 #include <getopt.h>
0015 #include <stdio.h>
0016 #include <stdlib.h>
0017 #include <string.h>
0018
0019 #include <libfdt.h>
0020
0021 #include "util.h"
0022
0023 enum display_mode {
0024 MODE_SHOW_VALUE,
0025 MODE_LIST_PROPS,
0026 MODE_LIST_SUBNODES,
0027 };
0028
0029
0030 struct display_info {
0031 int type;
0032 int size;
0033 enum display_mode mode;
0034 const char *default_val;
0035 };
0036
0037 static void report_error(const char *where, int err)
0038 {
0039 fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
0040 }
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053 static int show_data(struct display_info *disp, const char *data, int len)
0054 {
0055 int i, size;
0056 const uint8_t *p = (const uint8_t *)data;
0057 const char *s;
0058 int value;
0059 int is_string;
0060 char fmt[3];
0061
0062
0063 if (len == 0)
0064 return 0;
0065
0066 is_string = (disp->type) == 's' ||
0067 (!disp->type && util_is_printable_string(data, len));
0068 if (is_string) {
0069 if (data[len - 1] != '\0') {
0070 fprintf(stderr, "Unterminated string\n");
0071 return -1;
0072 }
0073 for (s = data; s - data < len; s += strlen(s) + 1) {
0074 if (s != data)
0075 printf(" ");
0076 printf("%s", (const char *)s);
0077 }
0078 return 0;
0079 }
0080 size = disp->size;
0081 if (size == -1) {
0082 size = (len % 4) == 0 ? 4 : 1;
0083 } else if (len % size) {
0084 fprintf(stderr, "Property length must be a multiple of "
0085 "selected data size\n");
0086 return -1;
0087 }
0088 fmt[0] = '%';
0089 fmt[1] = disp->type ? disp->type : 'd';
0090 fmt[2] = '\0';
0091 for (i = 0; i < len; i += size, p += size) {
0092 if (i)
0093 printf(" ");
0094 value = size == 4 ? fdt32_to_cpu(*(const uint32_t *)p) :
0095 size == 2 ? (*p << 8) | p[1] : *p;
0096 printf(fmt, value);
0097 }
0098 return 0;
0099 }
0100
0101
0102
0103
0104
0105
0106
0107
0108 static int list_properties(const void *blob, int node)
0109 {
0110 const struct fdt_property *data;
0111 const char *name;
0112 int prop;
0113
0114 prop = fdt_first_property_offset(blob, node);
0115 do {
0116
0117 if (prop < 0)
0118 return prop == -FDT_ERR_NOTFOUND ? 0 : prop;
0119 data = fdt_get_property_by_offset(blob, prop, NULL);
0120 name = fdt_string(blob, fdt32_to_cpu(data->nameoff));
0121 if (name)
0122 puts(name);
0123 prop = fdt_next_property_offset(blob, prop);
0124 } while (1);
0125 }
0126
0127 #define MAX_LEVEL 32
0128
0129
0130
0131
0132
0133
0134
0135
0136 static int list_subnodes(const void *blob, int node)
0137 {
0138 int nextoffset;
0139 uint32_t tag;
0140 int level = 0;
0141 const char *pathp;
0142 int depth = 1;
0143
0144 while (level >= 0) {
0145 tag = fdt_next_tag(blob, node, &nextoffset);
0146 switch (tag) {
0147 case FDT_BEGIN_NODE:
0148 pathp = fdt_get_name(blob, node, NULL);
0149 if (level <= depth) {
0150 if (pathp == NULL)
0151 pathp = "/* NULL pointer error */";
0152 if (*pathp == '\0')
0153 pathp = "/";
0154 if (level == 1)
0155 puts(pathp);
0156 }
0157 level++;
0158 if (level >= MAX_LEVEL) {
0159 printf("Nested too deep, aborting.\n");
0160 return 1;
0161 }
0162 break;
0163 case FDT_END_NODE:
0164 level--;
0165 if (level == 0)
0166 level = -1;
0167 break;
0168 case FDT_END:
0169 return 1;
0170 case FDT_PROP:
0171 break;
0172 default:
0173 if (level <= depth)
0174 printf("Unknown tag 0x%08X\n", tag);
0175 return 1;
0176 }
0177 node = nextoffset;
0178 }
0179 return 0;
0180 }
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192 static int show_data_for_item(const void *blob, struct display_info *disp,
0193 int node, const char *property)
0194 {
0195 const void *value = NULL;
0196 int len, err = 0;
0197
0198 switch (disp->mode) {
0199 case MODE_LIST_PROPS:
0200 err = list_properties(blob, node);
0201 break;
0202
0203 case MODE_LIST_SUBNODES:
0204 err = list_subnodes(blob, node);
0205 break;
0206
0207 default:
0208 assert(property);
0209 value = fdt_getprop(blob, node, property, &len);
0210 if (value) {
0211 if (show_data(disp, value, len))
0212 err = -1;
0213 else
0214 printf("\n");
0215 } else if (disp->default_val) {
0216 puts(disp->default_val);
0217 } else {
0218 report_error(property, len);
0219 err = -1;
0220 }
0221 break;
0222 }
0223
0224 return err;
0225 }
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236 static int do_fdtget(struct display_info *disp, const char *filename,
0237 char **arg, int arg_count, int args_per_step)
0238 {
0239 char *blob;
0240 const char *prop;
0241 int i, node;
0242
0243 blob = utilfdt_read(filename);
0244 if (!blob)
0245 return -1;
0246
0247 for (i = 0; i + args_per_step <= arg_count; i += args_per_step) {
0248 node = fdt_path_offset(blob, arg[i]);
0249 if (node < 0) {
0250 if (disp->default_val) {
0251 puts(disp->default_val);
0252 continue;
0253 } else {
0254 report_error(arg[i], node);
0255 return -1;
0256 }
0257 }
0258 prop = args_per_step == 1 ? NULL : arg[i + 1];
0259
0260 if (show_data_for_item(blob, disp, node, prop))
0261 return -1;
0262 }
0263 return 0;
0264 }
0265
0266 static const char *usage_msg =
0267 "fdtget - read values from device tree\n"
0268 "\n"
0269 "Each value is printed on a new line.\n\n"
0270 "Usage:\n"
0271 " fdtget <options> <dt file> [<node> <property>]...\n"
0272 " fdtget -p <options> <dt file> [<node> ]...\n"
0273 "Options:\n"
0274 "\t-t <type>\tType of data\n"
0275 "\t-p\t\tList properties for each node\n"
0276 "\t-l\t\tList subnodes for each node\n"
0277 "\t-d\t\tDefault value to display when the property is "
0278 "missing\n"
0279 "\t-h\t\tPrint this help\n\n"
0280 USAGE_TYPE_MSG;
0281
0282 static void usage(const char *msg)
0283 {
0284 if (msg)
0285 fprintf(stderr, "Error: %s\n\n", msg);
0286
0287 fprintf(stderr, "%s", usage_msg);
0288 exit(2);
0289 }
0290
0291 int main(int argc, char *argv[])
0292 {
0293 char *filename = NULL;
0294 struct display_info disp;
0295 int args_per_step = 2;
0296
0297
0298 memset(&disp, '\0', sizeof(disp));
0299 disp.size = -1;
0300 disp.mode = MODE_SHOW_VALUE;
0301 for (;;) {
0302 int c = getopt(argc, argv, "d:hlpt:");
0303 if (c == -1)
0304 break;
0305
0306 switch (c) {
0307 case 'h':
0308 case '?':
0309 usage(NULL);
0310
0311 case 't':
0312 if (utilfdt_decode_type(optarg, &disp.type,
0313 &disp.size))
0314 usage("Invalid type string");
0315 break;
0316
0317 case 'p':
0318 disp.mode = MODE_LIST_PROPS;
0319 args_per_step = 1;
0320 break;
0321
0322 case 'l':
0323 disp.mode = MODE_LIST_SUBNODES;
0324 args_per_step = 1;
0325 break;
0326
0327 case 'd':
0328 disp.default_val = optarg;
0329 break;
0330 }
0331 }
0332
0333 if (optind < argc)
0334 filename = argv[optind++];
0335 if (!filename)
0336 usage("Missing filename");
0337
0338 argv += optind;
0339 argc -= optind;
0340
0341
0342 if (!argc)
0343 return 0;
0344
0345
0346 if (args_per_step == 2 && (argc % 2))
0347 usage("Must have an even number of arguments");
0348
0349 if (do_fdtget(&disp, filename, argv, argc, args_per_step))
0350 return 1;
0351 return 0;
0352 }