root/scripts/dtc/fdtput.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. report_error
  2. encode_value
  3. store_key_value
  4. create_paths
  5. create_node
  6. do_fdtput
  7. usage
  8. main

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
   4  */
   5 
   6 #include <assert.h>
   7 #include <ctype.h>
   8 #include <getopt.h>
   9 #include <stdio.h>
  10 #include <stdlib.h>
  11 #include <string.h>
  12 
  13 #include <libfdt.h>
  14 
  15 #include "util.h"
  16 
  17 /* These are the operations we support */
  18 enum oper_type {
  19         OPER_WRITE_PROP,                /* Write a property in a node */
  20         OPER_CREATE_NODE,               /* Create a new node */
  21 };
  22 
  23 struct display_info {
  24         enum oper_type oper;    /* operation to perform */
  25         int type;               /* data type (s/i/u/x or 0 for default) */
  26         int size;               /* data size (1/2/4) */
  27         int verbose;            /* verbose output */
  28         int auto_path;          /* automatically create all path components */
  29 };
  30 
  31 
  32 /**
  33  * Report an error with a particular node.
  34  *
  35  * @param name          Node name to report error on
  36  * @param namelen       Length of node name, or -1 to use entire string
  37  * @param err           Error number to report (-FDT_ERR_...)
  38  */
  39 static void report_error(const char *name, int namelen, int err)
  40 {
  41         if (namelen == -1)
  42                 namelen = strlen(name);
  43         fprintf(stderr, "Error at '%1.*s': %s\n", namelen, name,
  44                 fdt_strerror(err));
  45 }
  46 
  47 /**
  48  * Encode a series of arguments in a property value.
  49  *
  50  * @param disp          Display information / options
  51  * @param arg           List of arguments from command line
  52  * @param arg_count     Number of arguments (may be 0)
  53  * @param valuep        Returns buffer containing value
  54  * @param *value_len    Returns length of value encoded
  55  */
  56 static int encode_value(struct display_info *disp, char **arg, int arg_count,
  57                         char **valuep, int *value_len)
  58 {
  59         char *value = NULL;     /* holding area for value */
  60         int value_size = 0;     /* size of holding area */
  61         char *ptr;              /* pointer to current value position */
  62         int len;                /* length of this cell/string/byte */
  63         int ival;
  64         int upto;       /* the number of bytes we have written to buf */
  65         char fmt[3];
  66 
  67         upto = 0;
  68 
  69         if (disp->verbose)
  70                 fprintf(stderr, "Decoding value:\n");
  71 
  72         fmt[0] = '%';
  73         fmt[1] = disp->type ? disp->type : 'd';
  74         fmt[2] = '\0';
  75         for (; arg_count > 0; arg++, arg_count--, upto += len) {
  76                 /* assume integer unless told otherwise */
  77                 if (disp->type == 's')
  78                         len = strlen(*arg) + 1;
  79                 else
  80                         len = disp->size == -1 ? 4 : disp->size;
  81 
  82                 /* enlarge our value buffer by a suitable margin if needed */
  83                 if (upto + len > value_size) {
  84                         value_size = (upto + len) + 500;
  85                         value = realloc(value, value_size);
  86                         if (!value) {
  87                                 fprintf(stderr, "Out of mmory: cannot alloc "
  88                                         "%d bytes\n", value_size);
  89                                 return -1;
  90                         }
  91                 }
  92 
  93                 ptr = value + upto;
  94                 if (disp->type == 's') {
  95                         memcpy(ptr, *arg, len);
  96                         if (disp->verbose)
  97                                 fprintf(stderr, "\tstring: '%s'\n", ptr);
  98                 } else {
  99                         int *iptr = (int *)ptr;
 100                         sscanf(*arg, fmt, &ival);
 101                         if (len == 4)
 102                                 *iptr = cpu_to_fdt32(ival);
 103                         else
 104                                 *ptr = (uint8_t)ival;
 105                         if (disp->verbose) {
 106                                 fprintf(stderr, "\t%s: %d\n",
 107                                         disp->size == 1 ? "byte" :
 108                                         disp->size == 2 ? "short" : "int",
 109                                         ival);
 110                         }
 111                 }
 112         }
 113         *value_len = upto;
 114         *valuep = value;
 115         if (disp->verbose)
 116                 fprintf(stderr, "Value size %d\n", upto);
 117         return 0;
 118 }
 119 
 120 static int store_key_value(void *blob, const char *node_name,
 121                 const char *property, const char *buf, int len)
 122 {
 123         int node;
 124         int err;
 125 
 126         node = fdt_path_offset(blob, node_name);
 127         if (node < 0) {
 128                 report_error(node_name, -1, node);
 129                 return -1;
 130         }
 131 
 132         err = fdt_setprop(blob, node, property, buf, len);
 133         if (err) {
 134                 report_error(property, -1, err);
 135                 return -1;
 136         }
 137         return 0;
 138 }
 139 
 140 /**
 141  * Create paths as needed for all components of a path
 142  *
 143  * Any components of the path that do not exist are created. Errors are
 144  * reported.
 145  *
 146  * @param blob          FDT blob to write into
 147  * @param in_path       Path to process
 148  * @return 0 if ok, -1 on error
 149  */
 150 static int create_paths(void *blob, const char *in_path)
 151 {
 152         const char *path = in_path;
 153         const char *sep;
 154         int node, offset = 0;
 155 
 156         /* skip leading '/' */
 157         while (*path == '/')
 158                 path++;
 159 
 160         for (sep = path; *sep; path = sep + 1, offset = node) {
 161                 /* equivalent to strchrnul(), but it requires _GNU_SOURCE */
 162                 sep = strchr(path, '/');
 163                 if (!sep)
 164                         sep = path + strlen(path);
 165 
 166                 node = fdt_subnode_offset_namelen(blob, offset, path,
 167                                 sep - path);
 168                 if (node == -FDT_ERR_NOTFOUND) {
 169                         node = fdt_add_subnode_namelen(blob, offset, path,
 170                                                        sep - path);
 171                 }
 172                 if (node < 0) {
 173                         report_error(path, sep - path, node);
 174                         return -1;
 175                 }
 176         }
 177 
 178         return 0;
 179 }
 180 
 181 /**
 182  * Create a new node in the fdt.
 183  *
 184  * This will overwrite the node_name string. Any error is reported.
 185  *
 186  * TODO: Perhaps create fdt_path_offset_namelen() so we don't need to do this.
 187  *
 188  * @param blob          FDT blob to write into
 189  * @param node_name     Name of node to create
 190  * @return new node offset if found, or -1 on failure
 191  */
 192 static int create_node(void *blob, const char *node_name)
 193 {
 194         int node = 0;
 195         char *p;
 196 
 197         p = strrchr(node_name, '/');
 198         if (!p) {
 199                 report_error(node_name, -1, -FDT_ERR_BADPATH);
 200                 return -1;
 201         }
 202         *p = '\0';
 203 
 204         if (p > node_name) {
 205                 node = fdt_path_offset(blob, node_name);
 206                 if (node < 0) {
 207                         report_error(node_name, -1, node);
 208                         return -1;
 209                 }
 210         }
 211 
 212         node = fdt_add_subnode(blob, node, p + 1);
 213         if (node < 0) {
 214                 report_error(p + 1, -1, node);
 215                 return -1;
 216         }
 217 
 218         return 0;
 219 }
 220 
 221 static int do_fdtput(struct display_info *disp, const char *filename,
 222                     char **arg, int arg_count)
 223 {
 224         char *value;
 225         char *blob;
 226         int len, ret = 0;
 227 
 228         blob = utilfdt_read(filename);
 229         if (!blob)
 230                 return -1;
 231 
 232         switch (disp->oper) {
 233         case OPER_WRITE_PROP:
 234                 /*
 235                  * Convert the arguments into a single binary value, then
 236                  * store them into the property.
 237                  */
 238                 assert(arg_count >= 2);
 239                 if (disp->auto_path && create_paths(blob, *arg))
 240                         return -1;
 241                 if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) ||
 242                         store_key_value(blob, *arg, arg[1], value, len))
 243                         ret = -1;
 244                 break;
 245         case OPER_CREATE_NODE:
 246                 for (; ret >= 0 && arg_count--; arg++) {
 247                         if (disp->auto_path)
 248                                 ret = create_paths(blob, *arg);
 249                         else
 250                                 ret = create_node(blob, *arg);
 251                 }
 252                 break;
 253         }
 254         if (ret >= 0)
 255                 ret = utilfdt_write(filename, blob);
 256 
 257         free(blob);
 258         return ret;
 259 }
 260 
 261 static const char *usage_msg =
 262         "fdtput - write a property value to a device tree\n"
 263         "\n"
 264         "The command line arguments are joined together into a single value.\n"
 265         "\n"
 266         "Usage:\n"
 267         "       fdtput <options> <dt file> <node> <property> [<value>...]\n"
 268         "       fdtput -c <options> <dt file> [<node>...]\n"
 269         "Options:\n"
 270         "\t-c\t\tCreate nodes if they don't already exist\n"
 271         "\t-p\t\tAutomatically create nodes as needed for the node path\n"
 272         "\t-t <type>\tType of data\n"
 273         "\t-v\t\tVerbose: display each value decoded from command line\n"
 274         "\t-h\t\tPrint this help\n\n"
 275         USAGE_TYPE_MSG;
 276 
 277 static void usage(const char *msg)
 278 {
 279         if (msg)
 280                 fprintf(stderr, "Error: %s\n\n", msg);
 281 
 282         fprintf(stderr, "%s", usage_msg);
 283         exit(2);
 284 }
 285 
 286 int main(int argc, char *argv[])
 287 {
 288         struct display_info disp;
 289         char *filename = NULL;
 290 
 291         memset(&disp, '\0', sizeof(disp));
 292         disp.size = -1;
 293         disp.oper = OPER_WRITE_PROP;
 294         for (;;) {
 295                 int c = getopt(argc, argv, "chpt:v");
 296                 if (c == -1)
 297                         break;
 298 
 299                 /*
 300                  * TODO: add options to:
 301                  * - delete property
 302                  * - delete node (optionally recursively)
 303                  * - rename node
 304                  * - pack fdt before writing
 305                  * - set amount of free space when writing
 306                  * - expand fdt if value doesn't fit
 307                  */
 308                 switch (c) {
 309                 case 'c':
 310                         disp.oper = OPER_CREATE_NODE;
 311                         break;
 312                 case 'h':
 313                 case '?':
 314                         usage(NULL);
 315                 case 'p':
 316                         disp.auto_path = 1;
 317                         break;
 318                 case 't':
 319                         if (utilfdt_decode_type(optarg, &disp.type,
 320                                         &disp.size))
 321                                 usage("Invalid type string");
 322                         break;
 323 
 324                 case 'v':
 325                         disp.verbose = 1;
 326                         break;
 327                 }
 328         }
 329 
 330         if (optind < argc)
 331                 filename = argv[optind++];
 332         if (!filename)
 333                 usage("Missing filename");
 334 
 335         argv += optind;
 336         argc -= optind;
 337 
 338         if (disp.oper == OPER_WRITE_PROP) {
 339                 if (argc < 1)
 340                         usage("Missing node");
 341                 if (argc < 2)
 342                         usage("Missing property");
 343         }
 344 
 345         if (do_fdtput(&disp, filename, argv, argc))
 346                 return 1;
 347         return 0;
 348 }

/* [<][>][^][v][top][bottom][index][help] */