Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fdtget.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
3  *
4  * Portions from U-Boot cmd_fdt.c (C) Copyright 2007
5  * Gerald Van Baren, Custom IDEAS, [email protected]
6  * Based on code written by:
7  * Pantelis Antoniou <[email protected]> and
8  * Matthew McClintock <[email protected]>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23  * MA 02111-1307 USA
24  */
25 
26 #include <assert.h>
27 #include <ctype.h>
28 #include <getopt.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include <libfdt.h>
34 
35 #include "util.h"
36 
38  MODE_SHOW_VALUE, /* show values for node properties */
39  MODE_LIST_PROPS, /* list the properties for a node */
40  MODE_LIST_SUBNODES, /* list the subnodes of a node */
41 };
42 
43 /* Holds information which controls our output and options */
44 struct display_info {
45  int type; /* data type (s/i/u/x or 0 for default) */
46  int size; /* data size (1/2/4) */
47  enum display_mode mode; /* display mode that we are using */
48  const char *default_val; /* default value if node/property not found */
49 };
50 
51 static void report_error(const char *where, int err)
52 {
53  fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
54 }
55 
67 static int show_data(struct display_info *disp, const char *data, int len)
68 {
69  int i, size;
70  const uint8_t *p = (const uint8_t *)data;
71  const char *s;
72  int value;
73  int is_string;
74  char fmt[3];
75 
76  /* no data, don't print */
77  if (len == 0)
78  return 0;
79 
80  is_string = (disp->type) == 's' ||
81  (!disp->type && util_is_printable_string(data, len));
82  if (is_string) {
83  if (data[len - 1] != '\0') {
84  fprintf(stderr, "Unterminated string\n");
85  return -1;
86  }
87  for (s = data; s - data < len; s += strlen(s) + 1) {
88  if (s != data)
89  printf(" ");
90  printf("%s", (const char *)s);
91  }
92  return 0;
93  }
94  size = disp->size;
95  if (size == -1) {
96  size = (len % 4) == 0 ? 4 : 1;
97  } else if (len % size) {
98  fprintf(stderr, "Property length must be a multiple of "
99  "selected data size\n");
100  return -1;
101  }
102  fmt[0] = '%';
103  fmt[1] = disp->type ? disp->type : 'd';
104  fmt[2] = '\0';
105  for (i = 0; i < len; i += size, p += size) {
106  if (i)
107  printf(" ");
108  value = size == 4 ? fdt32_to_cpu(*(const uint32_t *)p) :
109  size == 2 ? (*p << 8) | p[1] : *p;
110  printf(fmt, value);
111  }
112  return 0;
113 }
114 
122 static int list_properties(const void *blob, int node)
123 {
124  const struct fdt_property *data;
125  const char *name;
126  int prop;
127 
128  prop = fdt_first_property_offset(blob, node);
129  do {
130  /* Stop silently when there are no more properties */
131  if (prop < 0)
132  return prop == -FDT_ERR_NOTFOUND ? 0 : prop;
133  data = fdt_get_property_by_offset(blob, prop, NULL);
134  name = fdt_string(blob, fdt32_to_cpu(data->nameoff));
135  if (name)
136  puts(name);
137  prop = fdt_next_property_offset(blob, prop);
138  } while (1);
139 }
140 
141 #define MAX_LEVEL 32 /* how deeply nested we will go */
142 
150 static int list_subnodes(const void *blob, int node)
151 {
152  int nextoffset; /* next node offset from libfdt */
153  uint32_t tag; /* current tag */
154  int level = 0; /* keep track of nesting level */
155  const char *pathp;
156  int depth = 1; /* the assumed depth of this node */
157 
158  while (level >= 0) {
159  tag = fdt_next_tag(blob, node, &nextoffset);
160  switch (tag) {
161  case FDT_BEGIN_NODE:
162  pathp = fdt_get_name(blob, node, NULL);
163  if (level <= depth) {
164  if (pathp == NULL)
165  pathp = "/* NULL pointer error */";
166  if (*pathp == '\0')
167  pathp = "/"; /* root is nameless */
168  if (level == 1)
169  puts(pathp);
170  }
171  level++;
172  if (level >= MAX_LEVEL) {
173  printf("Nested too deep, aborting.\n");
174  return 1;
175  }
176  break;
177  case FDT_END_NODE:
178  level--;
179  if (level == 0)
180  level = -1; /* exit the loop */
181  break;
182  case FDT_END:
183  return 1;
184  case FDT_PROP:
185  break;
186  default:
187  if (level <= depth)
188  printf("Unknown tag 0x%08X\n", tag);
189  return 1;
190  }
191  node = nextoffset;
192  }
193  return 0;
194 }
195 
206 static int show_data_for_item(const void *blob, struct display_info *disp,
207  int node, const char *property)
208 {
209  const void *value = NULL;
210  int len, err = 0;
211 
212  switch (disp->mode) {
213  case MODE_LIST_PROPS:
214  err = list_properties(blob, node);
215  break;
216 
217  case MODE_LIST_SUBNODES:
218  err = list_subnodes(blob, node);
219  break;
220 
221  default:
222  assert(property);
223  value = fdt_getprop(blob, node, property, &len);
224  if (value) {
225  if (show_data(disp, value, len))
226  err = -1;
227  else
228  printf("\n");
229  } else if (disp->default_val) {
230  puts(disp->default_val);
231  } else {
232  report_error(property, len);
233  err = -1;
234  }
235  break;
236  }
237 
238  return err;
239 }
240 
250 static int do_fdtget(struct display_info *disp, const char *filename,
251  char **arg, int arg_count, int args_per_step)
252 {
253  char *blob;
254  const char *prop;
255  int i, node;
256 
257  blob = utilfdt_read(filename);
258  if (!blob)
259  return -1;
260 
261  for (i = 0; i + args_per_step <= arg_count; i += args_per_step) {
262  node = fdt_path_offset(blob, arg[i]);
263  if (node < 0) {
264  if (disp->default_val) {
265  puts(disp->default_val);
266  continue;
267  } else {
268  report_error(arg[i], node);
269  return -1;
270  }
271  }
272  prop = args_per_step == 1 ? NULL : arg[i + 1];
273 
274  if (show_data_for_item(blob, disp, node, prop))
275  return -1;
276  }
277  return 0;
278 }
279 
280 static const char *usage_msg =
281  "fdtget - read values from device tree\n"
282  "\n"
283  "Each value is printed on a new line.\n\n"
284  "Usage:\n"
285  " fdtget <options> <dt file> [<node> <property>]...\n"
286  " fdtget -p <options> <dt file> [<node> ]...\n"
287  "Options:\n"
288  "\t-t <type>\tType of data\n"
289  "\t-p\t\tList properties for each node\n"
290  "\t-l\t\tList subnodes for each node\n"
291  "\t-d\t\tDefault value to display when the property is "
292  "missing\n"
293  "\t-h\t\tPrint this help\n\n"
295 
296 static void usage(const char *msg)
297 {
298  if (msg)
299  fprintf(stderr, "Error: %s\n\n", msg);
300 
301  fprintf(stderr, "%s", usage_msg);
302  exit(2);
303 }
304 
305 int main(int argc, char *argv[])
306 {
307  char *filename = NULL;
308  struct display_info disp;
309  int args_per_step = 2;
310 
311  /* set defaults */
312  memset(&disp, '\0', sizeof(disp));
313  disp.size = -1;
314  disp.mode = MODE_SHOW_VALUE;
315  for (;;) {
316  int c = getopt(argc, argv, "d:hlpt:");
317  if (c == -1)
318  break;
319 
320  switch (c) {
321  case 'h':
322  case '?':
323  usage(NULL);
324 
325  case 't':
326  if (utilfdt_decode_type(optarg, &disp.type,
327  &disp.size))
328  usage("Invalid type string");
329  break;
330 
331  case 'p':
332  disp.mode = MODE_LIST_PROPS;
333  args_per_step = 1;
334  break;
335 
336  case 'l':
337  disp.mode = MODE_LIST_SUBNODES;
338  args_per_step = 1;
339  break;
340 
341  case 'd':
342  disp.default_val = optarg;
343  break;
344  }
345  }
346 
347  if (optind < argc)
348  filename = argv[optind++];
349  if (!filename)
350  usage("Missing filename");
351 
352  argv += optind;
353  argc -= optind;
354 
355  /* Allow no arguments, and silently succeed */
356  if (!argc)
357  return 0;
358 
359  /* Check for node, property arguments */
360  if (args_per_step == 2 && (argc % 2))
361  usage("Must have an even number of arguments");
362 
363  if (do_fdtget(&disp, filename, argv, argc, args_per_step))
364  return 1;
365  return 0;
366 }