Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fdtput.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
17  * MA 02111-1307 USA
18  */
19 
20 #include <assert.h>
21 #include <ctype.h>
22 #include <getopt.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <libfdt.h>
28 
29 #include "util.h"
30 
31 /* These are the operations we support */
32 enum oper_type {
33  OPER_WRITE_PROP, /* Write a property in a node */
34  OPER_CREATE_NODE, /* Create a new node */
35 };
36 
37 struct display_info {
38  enum oper_type oper; /* operation to perform */
39  int type; /* data type (s/i/u/x or 0 for default) */
40  int size; /* data size (1/2/4) */
41  int verbose; /* verbose output */
42  int auto_path; /* automatically create all path components */
43 };
44 
45 
53 static void report_error(const char *name, int namelen, int err)
54 {
55  if (namelen == -1)
56  namelen = strlen(name);
57  fprintf(stderr, "Error at '%1.*s': %s\n", namelen, name,
58  fdt_strerror(err));
59 }
60 
70 static int encode_value(struct display_info *disp, char **arg, int arg_count,
71  char **valuep, int *value_len)
72 {
73  char *value = NULL; /* holding area for value */
74  int value_size = 0; /* size of holding area */
75  char *ptr; /* pointer to current value position */
76  int len; /* length of this cell/string/byte */
77  int ival;
78  int upto; /* the number of bytes we have written to buf */
79  char fmt[3];
80 
81  upto = 0;
82 
83  if (disp->verbose)
84  fprintf(stderr, "Decoding value:\n");
85 
86  fmt[0] = '%';
87  fmt[1] = disp->type ? disp->type : 'd';
88  fmt[2] = '\0';
89  for (; arg_count > 0; arg++, arg_count--, upto += len) {
90  /* assume integer unless told otherwise */
91  if (disp->type == 's')
92  len = strlen(*arg) + 1;
93  else
94  len = disp->size == -1 ? 4 : disp->size;
95 
96  /* enlarge our value buffer by a suitable margin if needed */
97  if (upto + len > value_size) {
98  value_size = (upto + len) + 500;
99  value = realloc(value, value_size);
100  if (!value) {
101  fprintf(stderr, "Out of mmory: cannot alloc "
102  "%d bytes\n", value_size);
103  return -1;
104  }
105  }
106 
107  ptr = value + upto;
108  if (disp->type == 's') {
109  memcpy(ptr, *arg, len);
110  if (disp->verbose)
111  fprintf(stderr, "\tstring: '%s'\n", ptr);
112  } else {
113  int *iptr = (int *)ptr;
114  sscanf(*arg, fmt, &ival);
115  if (len == 4)
116  *iptr = cpu_to_fdt32(ival);
117  else
118  *ptr = (uint8_t)ival;
119  if (disp->verbose) {
120  fprintf(stderr, "\t%s: %d\n",
121  disp->size == 1 ? "byte" :
122  disp->size == 2 ? "short" : "int",
123  ival);
124  }
125  }
126  }
127  *value_len = upto;
128  *valuep = value;
129  if (disp->verbose)
130  fprintf(stderr, "Value size %d\n", upto);
131  return 0;
132 }
133 
134 static int store_key_value(void *blob, const char *node_name,
135  const char *property, const char *buf, int len)
136 {
137  int node;
138  int err;
139 
140  node = fdt_path_offset(blob, node_name);
141  if (node < 0) {
142  report_error(node_name, -1, node);
143  return -1;
144  }
145 
146  err = fdt_setprop(blob, node, property, buf, len);
147  if (err) {
148  report_error(property, -1, err);
149  return -1;
150  }
151  return 0;
152 }
153 
164 static int create_paths(void *blob, const char *in_path)
165 {
166  const char *path = in_path;
167  const char *sep;
168  int node, offset = 0;
169 
170  /* skip leading '/' */
171  while (*path == '/')
172  path++;
173 
174  for (sep = path; *sep; path = sep + 1, offset = node) {
175  /* equivalent to strchrnul(), but it requires _GNU_SOURCE */
176  sep = strchr(path, '/');
177  if (!sep)
178  sep = path + strlen(path);
179 
180  node = fdt_subnode_offset_namelen(blob, offset, path,
181  sep - path);
182  if (node == -FDT_ERR_NOTFOUND) {
183  node = fdt_add_subnode_namelen(blob, offset, path,
184  sep - path);
185  }
186  if (node < 0) {
187  report_error(path, sep - path, node);
188  return -1;
189  }
190  }
191 
192  return 0;
193 }
194 
206 static int create_node(void *blob, const char *node_name)
207 {
208  int node = 0;
209  char *p;
210 
211  p = strrchr(node_name, '/');
212  if (!p) {
213  report_error(node_name, -1, -FDT_ERR_BADPATH);
214  return -1;
215  }
216  *p = '\0';
217 
218  if (p > node_name) {
219  node = fdt_path_offset(blob, node_name);
220  if (node < 0) {
221  report_error(node_name, -1, node);
222  return -1;
223  }
224  }
225 
226  node = fdt_add_subnode(blob, node, p + 1);
227  if (node < 0) {
228  report_error(p + 1, -1, node);
229  return -1;
230  }
231 
232  return 0;
233 }
234 
235 static int do_fdtput(struct display_info *disp, const char *filename,
236  char **arg, int arg_count)
237 {
238  char *value;
239  char *blob;
240  int len, ret = 0;
241 
242  blob = utilfdt_read(filename);
243  if (!blob)
244  return -1;
245 
246  switch (disp->oper) {
247  case OPER_WRITE_PROP:
248  /*
249  * Convert the arguments into a single binary value, then
250  * store them into the property.
251  */
252  assert(arg_count >= 2);
253  if (disp->auto_path && create_paths(blob, *arg))
254  return -1;
255  if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) ||
256  store_key_value(blob, *arg, arg[1], value, len))
257  ret = -1;
258  break;
259  case OPER_CREATE_NODE:
260  for (; ret >= 0 && arg_count--; arg++) {
261  if (disp->auto_path)
262  ret = create_paths(blob, *arg);
263  else
264  ret = create_node(blob, *arg);
265  }
266  break;
267  }
268  if (ret >= 0)
269  ret = utilfdt_write(filename, blob);
270 
271  free(blob);
272  return ret;
273 }
274 
275 static const char *usage_msg =
276  "fdtput - write a property value to a device tree\n"
277  "\n"
278  "The command line arguments are joined together into a single value.\n"
279  "\n"
280  "Usage:\n"
281  " fdtput <options> <dt file> <node> <property> [<value>...]\n"
282  " fdtput -c <options> <dt file> [<node>...]\n"
283  "Options:\n"
284  "\t-c\t\tCreate nodes if they don't already exist\n"
285  "\t-p\t\tAutomatically create nodes as needed for the node path\n"
286  "\t-t <type>\tType of data\n"
287  "\t-v\t\tVerbose: display each value decoded from command line\n"
288  "\t-h\t\tPrint this help\n\n"
290 
291 static void usage(const char *msg)
292 {
293  if (msg)
294  fprintf(stderr, "Error: %s\n\n", msg);
295 
296  fprintf(stderr, "%s", usage_msg);
297  exit(2);
298 }
299 
300 int main(int argc, char *argv[])
301 {
302  struct display_info disp;
303  char *filename = NULL;
304 
305  memset(&disp, '\0', sizeof(disp));
306  disp.size = -1;
307  disp.oper = OPER_WRITE_PROP;
308  for (;;) {
309  int c = getopt(argc, argv, "chpt:v");
310  if (c == -1)
311  break;
312 
313  /*
314  * TODO: add options to:
315  * - delete property
316  * - delete node (optionally recursively)
317  * - rename node
318  * - pack fdt before writing
319  * - set amount of free space when writing
320  * - expand fdt if value doesn't fit
321  */
322  switch (c) {
323  case 'c':
324  disp.oper = OPER_CREATE_NODE;
325  break;
326  case 'h':
327  case '?':
328  usage(NULL);
329  case 'p':
330  disp.auto_path = 1;
331  break;
332  case 't':
333  if (utilfdt_decode_type(optarg, &disp.type,
334  &disp.size))
335  usage("Invalid type string");
336  break;
337 
338  case 'v':
339  disp.verbose = 1;
340  break;
341  }
342  }
343 
344  if (optind < argc)
345  filename = argv[optind++];
346  if (!filename)
347  usage("Missing filename");
348 
349  argv += optind;
350  argc -= optind;
351 
352  if (disp.oper == OPER_WRITE_PROP) {
353  if (argc < 1)
354  usage("Missing node");
355  if (argc < 2)
356  usage("Missing property");
357  }
358 
359  if (do_fdtput(&disp, filename, argv, argc))
360  return 1;
361  return 0;
362 }