1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
32enum oper_type {
33 OPER_WRITE_PROP,
34 OPER_CREATE_NODE,
35};
36
37struct display_info {
38 enum oper_type oper;
39 int type;
40 int size;
41 int verbose;
42 int auto_path;
43};
44
45
46
47
48
49
50
51
52
53static 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
61
62
63
64
65
66
67
68
69
70static int encode_value(struct display_info *disp, char **arg, int arg_count,
71 char **valuep, int *value_len)
72{
73 char *value = NULL;
74 int value_size = 0;
75 char *ptr;
76 int len;
77 int ival;
78 int upto;
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
91 if (disp->type == 's')
92 len = strlen(*arg) + 1;
93 else
94 len = disp->size == -1 ? 4 : disp->size;
95
96
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
134static 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
154
155
156
157
158
159
160
161
162
163
164static 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
171 while (*path == '/')
172 path++;
173
174 for (sep = path; *sep; path = sep + 1, offset = node) {
175
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
195
196
197
198
199
200
201
202
203
204
205
206static 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
235static 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
250
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
275static 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"
289 USAGE_TYPE_MSG;
290
291static 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
300int 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
315
316
317
318
319
320
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}
363