~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to dtc/fdtput.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        OPER_REMOVE_NODE,               /* Delete a node */
 
36
        OPER_DELETE_PROP,               /* Delete a property in a node */
 
37
};
 
38
 
 
39
struct display_info {
 
40
        enum oper_type oper;    /* operation to perform */
 
41
        int type;               /* data type (s/i/u/x or 0 for default) */
 
42
        int size;               /* data size (1/2/4) */
 
43
        int verbose;            /* verbose output */
 
44
        int auto_path;          /* automatically create all path components */
 
45
};
 
46
 
 
47
 
 
48
/**
 
49
 * Report an error with a particular node.
 
50
 *
 
51
 * @param name          Node name to report error on
 
52
 * @param namelen       Length of node name, or -1 to use entire string
 
53
 * @param err           Error number to report (-FDT_ERR_...)
 
54
 */
 
55
static void report_error(const char *name, int namelen, int err)
 
56
{
 
57
        if (namelen == -1)
 
58
                namelen = strlen(name);
 
59
        fprintf(stderr, "Error at '%1.*s': %s\n", namelen, name,
 
60
                fdt_strerror(err));
 
61
}
 
62
 
 
63
/**
 
64
 * Encode a series of arguments in a property value.
 
65
 *
 
66
 * @param disp          Display information / options
 
67
 * @param arg           List of arguments from command line
 
68
 * @param arg_count     Number of arguments (may be 0)
 
69
 * @param valuep        Returns buffer containing value
 
70
 * @param value_len     Returns length of value encoded
 
71
 */
 
72
static int encode_value(struct display_info *disp, char **arg, int arg_count,
 
73
                        char **valuep, int *value_len)
 
74
{
 
75
        char *value = NULL;     /* holding area for value */
 
76
        int value_size = 0;     /* size of holding area */
 
77
        char *ptr;              /* pointer to current value position */
 
78
        int len;                /* length of this cell/string/byte */
 
79
        int ival;
 
80
        int upto;       /* the number of bytes we have written to buf */
 
81
        char fmt[3];
 
82
 
 
83
        upto = 0;
 
84
 
 
85
        if (disp->verbose)
 
86
                fprintf(stderr, "Decoding value:\n");
 
87
 
 
88
        fmt[0] = '%';
 
89
        fmt[1] = disp->type ? disp->type : 'd';
 
90
        fmt[2] = '\0';
 
91
        for (; arg_count > 0; arg++, arg_count--, upto += len) {
 
92
                /* assume integer unless told otherwise */
 
93
                if (disp->type == 's')
 
94
                        len = strlen(*arg) + 1;
 
95
                else
 
96
                        len = disp->size == -1 ? 4 : disp->size;
 
97
 
 
98
                /* enlarge our value buffer by a suitable margin if needed */
 
99
                if (upto + len > value_size) {
 
100
                        value_size = (upto + len) + 500;
 
101
                        value = xrealloc(value, value_size);
 
102
                }
 
103
 
 
104
                ptr = value + upto;
 
105
                if (disp->type == 's') {
 
106
                        memcpy(ptr, *arg, len);
 
107
                        if (disp->verbose)
 
108
                                fprintf(stderr, "\tstring: '%s'\n", ptr);
 
109
                } else {
 
110
                        fdt32_t *iptr = (fdt32_t *)ptr;
 
111
                        sscanf(*arg, fmt, &ival);
 
112
                        if (len == 4)
 
113
                                *iptr = cpu_to_fdt32(ival);
 
114
                        else
 
115
                                *ptr = (uint8_t)ival;
 
116
                        if (disp->verbose) {
 
117
                                fprintf(stderr, "\t%s: %d\n",
 
118
                                        disp->size == 1 ? "byte" :
 
119
                                        disp->size == 2 ? "short" : "int",
 
120
                                        ival);
 
121
                        }
 
122
                }
 
123
        }
 
124
        *value_len = upto;
 
125
        *valuep = value;
 
126
        if (disp->verbose)
 
127
                fprintf(stderr, "Value size %d\n", upto);
 
128
        return 0;
 
129
}
 
130
 
 
131
#define ALIGN(x)                (((x) + (FDT_TAGSIZE) - 1) & ~((FDT_TAGSIZE) - 1))
 
132
 
 
133
static char *_realloc_fdt(char *fdt, int delta)
 
134
{
 
135
        int new_sz = fdt_totalsize(fdt) + delta;
 
136
        fdt = xrealloc(fdt, new_sz);
 
137
        fdt_open_into(fdt, fdt, new_sz);
 
138
        return fdt;
 
139
}
 
140
 
 
141
static char *realloc_node(char *fdt, const char *name)
 
142
{
 
143
        int delta;
 
144
        /* FDT_BEGIN_NODE, node name in off_struct and FDT_END_NODE */
 
145
        delta = sizeof(struct fdt_node_header) + ALIGN(strlen(name) + 1)
 
146
                        + FDT_TAGSIZE;
 
147
        return _realloc_fdt(fdt, delta);
 
148
}
 
149
 
 
150
static char *realloc_property(char *fdt, int nodeoffset,
 
151
                const char *name, int newlen)
 
152
{
 
153
        int delta = 0;
 
154
        int oldlen = 0;
 
155
 
 
156
        if (!fdt_get_property(fdt, nodeoffset, name, &oldlen))
 
157
                /* strings + property header */
 
158
                delta = sizeof(struct fdt_property) + strlen(name) + 1;
 
159
 
 
160
        if (newlen > oldlen)
 
161
                /* actual value in off_struct */
 
162
                delta += ALIGN(newlen) - ALIGN(oldlen);
 
163
 
 
164
        return _realloc_fdt(fdt, delta);
 
165
}
 
166
 
 
167
static int store_key_value(char **blob, const char *node_name,
 
168
                const char *property, const char *buf, int len)
 
169
{
 
170
        int node;
 
171
        int err;
 
172
 
 
173
        node = fdt_path_offset(*blob, node_name);
 
174
        if (node < 0) {
 
175
                report_error(node_name, -1, node);
 
176
                return -1;
 
177
        }
 
178
 
 
179
        err = fdt_setprop(*blob, node, property, buf, len);
 
180
        if (err == -FDT_ERR_NOSPACE) {
 
181
                *blob = realloc_property(*blob, node, property, len);
 
182
                err = fdt_setprop(*blob, node, property, buf, len);
 
183
        }
 
184
        if (err) {
 
185
                report_error(property, -1, err);
 
186
                return -1;
 
187
        }
 
188
        return 0;
 
189
}
 
190
 
 
191
/**
 
192
 * Create paths as needed for all components of a path
 
193
 *
 
194
 * Any components of the path that do not exist are created. Errors are
 
195
 * reported.
 
196
 *
 
197
 * @param blob          FDT blob to write into
 
198
 * @param in_path       Path to process
 
199
 * @return 0 if ok, -1 on error
 
200
 */
 
201
static int create_paths(char **blob, const char *in_path)
 
202
{
 
203
        const char *path = in_path;
 
204
        const char *sep;
 
205
        int node, offset = 0;
 
206
 
 
207
        /* skip leading '/' */
 
208
        while (*path == '/')
 
209
                path++;
 
210
 
 
211
        for (sep = path; *sep; path = sep + 1, offset = node) {
 
212
                /* equivalent to strchrnul(), but it requires _GNU_SOURCE */
 
213
                sep = strchr(path, '/');
 
214
                if (!sep)
 
215
                        sep = path + strlen(path);
 
216
 
 
217
                node = fdt_subnode_offset_namelen(*blob, offset, path,
 
218
                                sep - path);
 
219
                if (node == -FDT_ERR_NOTFOUND) {
 
220
                        *blob = realloc_node(*blob, path);
 
221
                        node = fdt_add_subnode_namelen(*blob, offset, path,
 
222
                                                       sep - path);
 
223
                }
 
224
                if (node < 0) {
 
225
                        report_error(path, sep - path, node);
 
226
                        return -1;
 
227
                }
 
228
        }
 
229
 
 
230
        return 0;
 
231
}
 
232
 
 
233
/**
 
234
 * Create a new node in the fdt.
 
235
 *
 
236
 * This will overwrite the node_name string. Any error is reported.
 
237
 *
 
238
 * TODO: Perhaps create fdt_path_offset_namelen() so we don't need to do this.
 
239
 *
 
240
 * @param blob          FDT blob to write into
 
241
 * @param node_name     Name of node to create
 
242
 * @return new node offset if found, or -1 on failure
 
243
 */
 
244
static int create_node(char **blob, const char *node_name)
 
245
{
 
246
        int node = 0;
 
247
        char *p;
 
248
 
 
249
        p = strrchr(node_name, '/');
 
250
        if (!p) {
 
251
                report_error(node_name, -1, -FDT_ERR_BADPATH);
 
252
                return -1;
 
253
        }
 
254
        *p = '\0';
 
255
 
 
256
        *blob = realloc_node(*blob, p + 1);
 
257
 
 
258
        if (p > node_name) {
 
259
                node = fdt_path_offset(*blob, node_name);
 
260
                if (node < 0) {
 
261
                        report_error(node_name, -1, node);
 
262
                        return -1;
 
263
                }
 
264
        }
 
265
 
 
266
        node = fdt_add_subnode(*blob, node, p + 1);
 
267
        if (node < 0) {
 
268
                report_error(p + 1, -1, node);
 
269
                return -1;
 
270
        }
 
271
 
 
272
        return 0;
 
273
}
 
274
 
 
275
/**
 
276
 * Delete a property of a node in the fdt.
 
277
 *
 
278
 * @param blob          FDT blob to write into
 
279
 * @param node_name     Path to node containing the property to delete
 
280
 * @param prop_name     Name of property to delete
 
281
 * @return 0 on success, or -1 on failure
 
282
 */
 
283
static int delete_prop(char *blob, const char *node_name, const char *prop_name)
 
284
{
 
285
        int node = 0;
 
286
 
 
287
        node = fdt_path_offset(blob, node_name);
 
288
        if (node < 0) {
 
289
                report_error(node_name, -1, node);
 
290
                return -1;
 
291
        }
 
292
 
 
293
        node = fdt_delprop(blob, node, prop_name);
 
294
        if (node < 0) {
 
295
                report_error(node_name, -1, node);
 
296
                return -1;
 
297
        }
 
298
 
 
299
        return 0;
 
300
}
 
301
 
 
302
/**
 
303
 * Delete a node in the fdt.
 
304
 *
 
305
 * @param blob          FDT blob to write into
 
306
 * @param node_name     Name of node to delete
 
307
 * @return 0 on success, or -1 on failure
 
308
 */
 
309
static int delete_node(char *blob, const char *node_name)
 
310
{
 
311
        int node = 0;
 
312
 
 
313
        node = fdt_path_offset(blob, node_name);
 
314
        if (node < 0) {
 
315
                report_error(node_name, -1, node);
 
316
                return -1;
 
317
        }
 
318
 
 
319
        node = fdt_del_node(blob, node);
 
320
        if (node < 0) {
 
321
                report_error(node_name, -1, node);
 
322
                return -1;
 
323
        }
 
324
 
 
325
        return 0;
 
326
}
 
327
 
 
328
static int do_fdtput(struct display_info *disp, const char *filename,
 
329
                    char **arg, int arg_count)
 
330
{
 
331
        char *value = NULL;
 
332
        char *blob;
 
333
        char *node;
 
334
        int len, ret = 0;
 
335
 
 
336
        blob = utilfdt_read(filename);
 
337
        if (!blob)
 
338
                return -1;
 
339
 
 
340
        switch (disp->oper) {
 
341
        case OPER_WRITE_PROP:
 
342
                /*
 
343
                 * Convert the arguments into a single binary value, then
 
344
                 * store them into the property.
 
345
                 */
 
346
                assert(arg_count >= 2);
 
347
                if (disp->auto_path && create_paths(&blob, *arg))
 
348
                        return -1;
 
349
                if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) ||
 
350
                        store_key_value(&blob, *arg, arg[1], value, len))
 
351
                        ret = -1;
 
352
                break;
 
353
        case OPER_CREATE_NODE:
 
354
                for (; ret >= 0 && arg_count--; arg++) {
 
355
                        if (disp->auto_path)
 
356
                                ret = create_paths(&blob, *arg);
 
357
                        else
 
358
                                ret = create_node(&blob, *arg);
 
359
                }
 
360
                break;
 
361
        case OPER_REMOVE_NODE:
 
362
                for (; ret >= 0 && arg_count--; arg++)
 
363
                        ret = delete_node(blob, *arg);
 
364
                break;
 
365
        case OPER_DELETE_PROP:
 
366
                node = *arg;
 
367
                for (arg++; ret >= 0 && arg_count-- > 1; arg++)
 
368
                        ret = delete_prop(blob, node, *arg);
 
369
                break;
 
370
        }
 
371
        if (ret >= 0) {
 
372
                fdt_pack(blob);
 
373
                ret = utilfdt_write(filename, blob);
 
374
        }
 
375
 
 
376
        free(blob);
 
377
 
 
378
        if (value) {
 
379
                free(value);
 
380
        }
 
381
 
 
382
        return ret;
 
383
}
 
384
 
 
385
/* Usage related data. */
 
386
static const char usage_synopsis[] =
 
387
        "write a property value to a device tree\n"
 
388
        "       fdtput <options> <dt file> <node> <property> [<value>...]\n"
 
389
        "       fdtput -c <options> <dt file> [<node>...]\n"
 
390
        "       fdtput -r <options> <dt file> [<node>...]\n"
 
391
        "       fdtput -d <options> <dt file> <node> [<property>...]\n"
 
392
        "\n"
 
393
        "The command line arguments are joined together into a single value.\n"
 
394
        USAGE_TYPE_MSG;
 
395
static const char usage_short_opts[] = "crdpt:v" USAGE_COMMON_SHORT_OPTS;
 
396
static struct option const usage_long_opts[] = {
 
397
        {"create",           no_argument, NULL, 'c'},
 
398
        {"remove",           no_argument, NULL, 'r'},
 
399
        {"delete",           no_argument, NULL, 'd'},
 
400
        {"auto-path",        no_argument, NULL, 'p'},
 
401
        {"type",              a_argument, NULL, 't'},
 
402
        {"verbose",          no_argument, NULL, 'v'},
 
403
        USAGE_COMMON_LONG_OPTS,
 
404
};
 
405
static const char * const usage_opts_help[] = {
 
406
        "Create nodes if they don't already exist",
 
407
        "Delete nodes (and any subnodes) if they already exist",
 
408
        "Delete properties if they already exist",
 
409
        "Automatically create nodes as needed for the node path",
 
410
        "Type of data",
 
411
        "Display each value decoded from command line",
 
412
        USAGE_COMMON_OPTS_HELP
 
413
};
 
414
 
 
415
int main(int argc, char *argv[])
 
416
{
 
417
        int opt;
 
418
        struct display_info disp;
 
419
        char *filename = NULL;
 
420
 
 
421
        memset(&disp, '\0', sizeof(disp));
 
422
        disp.size = -1;
 
423
        disp.oper = OPER_WRITE_PROP;
 
424
        while ((opt = util_getopt_long()) != EOF) {
 
425
                /*
 
426
                 * TODO: add options to:
 
427
                 * - rename node
 
428
                 * - pack fdt before writing
 
429
                 * - set amount of free space when writing
 
430
                 */
 
431
                switch (opt) {
 
432
                case_USAGE_COMMON_FLAGS
 
433
 
 
434
                case 'c':
 
435
                        disp.oper = OPER_CREATE_NODE;
 
436
                        break;
 
437
                case 'r':
 
438
                        disp.oper = OPER_REMOVE_NODE;
 
439
                        break;
 
440
                case 'd':
 
441
                        disp.oper = OPER_DELETE_PROP;
 
442
                        break;
 
443
                case 'p':
 
444
                        disp.auto_path = 1;
 
445
                        break;
 
446
                case 't':
 
447
                        if (utilfdt_decode_type(optarg, &disp.type,
 
448
                                        &disp.size))
 
449
                                usage("Invalid type string");
 
450
                        break;
 
451
 
 
452
                case 'v':
 
453
                        disp.verbose = 1;
 
454
                        break;
 
455
                }
 
456
        }
 
457
 
 
458
        if (optind < argc)
 
459
                filename = argv[optind++];
 
460
        if (!filename)
 
461
                usage("missing filename");
 
462
 
 
463
        argv += optind;
 
464
        argc -= optind;
 
465
 
 
466
        if (disp.oper == OPER_WRITE_PROP) {
 
467
                if (argc < 1)
 
468
                        usage("missing node");
 
469
                if (argc < 2)
 
470
                        usage("missing property");
 
471
        }
 
472
 
 
473
        if (disp.oper == OPER_DELETE_PROP)
 
474
                if (argc < 1)
 
475
                        usage("missing node");
 
476
 
 
477
        if (do_fdtput(&disp, filename, argv, argc))
 
478
                return 1;
 
479
        return 0;
 
480
}