Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (c) 2017 Konsulko Group Inc. All rights reserved.
0004  *
0005  * Author:
0006  *   Pantelis Antoniou <pantelis.antoniou@konsulko.com>
0007  */
0008 
0009 #include <assert.h>
0010 #include <ctype.h>
0011 #include <getopt.h>
0012 #include <stdio.h>
0013 #include <stdlib.h>
0014 #include <string.h>
0015 #include <inttypes.h>
0016 
0017 #include <libfdt.h>
0018 
0019 #include "util.h"
0020 
0021 #define BUF_INCREMENT   65536
0022 
0023 /* Usage related data. */
0024 static const char usage_synopsis[] =
0025     "apply a number of overlays to a base blob\n"
0026     "   fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]\n"
0027     "\n"
0028     USAGE_TYPE_MSG;
0029 static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS;
0030 static struct option const usage_long_opts[] = {
0031     {"input",            required_argument, NULL, 'i'},
0032     {"output",       required_argument, NULL, 'o'},
0033     {"verbose",            no_argument, NULL, 'v'},
0034     USAGE_COMMON_LONG_OPTS,
0035 };
0036 static const char * const usage_opts_help[] = {
0037     "Input base DT blob",
0038     "Output DT blob",
0039     "Verbose messages",
0040     USAGE_COMMON_OPTS_HELP
0041 };
0042 
0043 int verbose = 0;
0044 
0045 static void *apply_one(char *base, const char *overlay, size_t *buf_len,
0046                const char *name)
0047 {
0048     char *tmp = NULL;
0049     char *tmpo;
0050     int ret;
0051 
0052     /*
0053      * We take a copies first, because a a failed apply can trash
0054      * both the base blob and the overlay
0055      */
0056     tmpo = xmalloc(fdt_totalsize(overlay));
0057 
0058     do {
0059         tmp = xrealloc(tmp, *buf_len);
0060         ret = fdt_open_into(base, tmp, *buf_len);
0061         if (ret) {
0062             fprintf(stderr,
0063                 "\nFailed to make temporary copy: %s\n",
0064                 fdt_strerror(ret));
0065             goto fail;
0066         }
0067 
0068         memcpy(tmpo, overlay, fdt_totalsize(overlay));
0069 
0070         ret = fdt_overlay_apply(tmp, tmpo);
0071         if (ret == -FDT_ERR_NOSPACE) {
0072             *buf_len += BUF_INCREMENT;
0073         }
0074     } while (ret == -FDT_ERR_NOSPACE);
0075 
0076     if (ret) {
0077         fprintf(stderr, "\nFailed to apply '%s': %s\n",
0078             name, fdt_strerror(ret));
0079         goto fail;
0080     }
0081 
0082     free(base);
0083     free(tmpo);
0084     return tmp;
0085 
0086 fail:
0087     free(tmpo);
0088     if (tmp)
0089         free(tmp);
0090 
0091     return NULL;
0092 }
0093 static int do_fdtoverlay(const char *input_filename,
0094              const char *output_filename,
0095              int argc, char *argv[])
0096 {
0097     char *blob = NULL;
0098     char **ovblob = NULL;
0099     size_t buf_len;
0100     int i, ret = -1;
0101 
0102     blob = utilfdt_read(input_filename, &buf_len);
0103     if (!blob) {
0104         fprintf(stderr, "\nFailed to read '%s'\n", input_filename);
0105         goto out_err;
0106     }
0107     if (fdt_totalsize(blob) > buf_len) {
0108         fprintf(stderr,
0109  "\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n",
0110             (unsigned long)buf_len, fdt_totalsize(blob));
0111         goto out_err;
0112     }
0113 
0114     /* allocate blob pointer array */
0115     ovblob = xmalloc(sizeof(*ovblob) * argc);
0116     memset(ovblob, 0, sizeof(*ovblob) * argc);
0117 
0118     /* read and keep track of the overlay blobs */
0119     for (i = 0; i < argc; i++) {
0120         size_t ov_len;
0121         ovblob[i] = utilfdt_read(argv[i], &ov_len);
0122         if (!ovblob[i]) {
0123             fprintf(stderr, "\nFailed to read '%s'\n", argv[i]);
0124             goto out_err;
0125         }
0126         if (fdt_totalsize(ovblob[i]) > ov_len) {
0127             fprintf(stderr,
0128 "\nOverlay '%s' is incomplete (%lu / %" PRIu32 " bytes read)\n",
0129                 argv[i], (unsigned long)ov_len,
0130                 fdt_totalsize(ovblob[i]));
0131             goto out_err;
0132         }
0133     }
0134 
0135     buf_len = fdt_totalsize(blob);
0136 
0137     /* apply the overlays in sequence */
0138     for (i = 0; i < argc; i++) {
0139         blob = apply_one(blob, ovblob[i], &buf_len, argv[i]);
0140         if (!blob)
0141             goto out_err;
0142     }
0143 
0144     fdt_pack(blob);
0145     ret = utilfdt_write(output_filename, blob);
0146     if (ret)
0147         fprintf(stderr, "\nFailed to write '%s'\n",
0148             output_filename);
0149 
0150 out_err:
0151     if (ovblob) {
0152         for (i = 0; i < argc; i++) {
0153             if (ovblob[i])
0154                 free(ovblob[i]);
0155         }
0156         free(ovblob);
0157     }
0158     free(blob);
0159 
0160     return ret;
0161 }
0162 
0163 int main(int argc, char *argv[])
0164 {
0165     int opt, i;
0166     char *input_filename = NULL;
0167     char *output_filename = NULL;
0168 
0169     while ((opt = util_getopt_long()) != EOF) {
0170         switch (opt) {
0171         case_USAGE_COMMON_FLAGS
0172 
0173         case 'i':
0174             input_filename = optarg;
0175             break;
0176         case 'o':
0177             output_filename = optarg;
0178             break;
0179         case 'v':
0180             verbose = 1;
0181             break;
0182         }
0183     }
0184 
0185     if (!input_filename)
0186         usage("missing input file");
0187 
0188     if (!output_filename)
0189         usage("missing output file");
0190 
0191     argv += optind;
0192     argc -= optind;
0193 
0194     if (argc <= 0)
0195         usage("missing overlay file(s)");
0196 
0197     if (verbose) {
0198         printf("input  = %s\n", input_filename);
0199         printf("output = %s\n", output_filename);
0200         for (i = 0; i < argc; i++)
0201             printf("overlay[%d] = %s\n", i, argv[i]);
0202     }
0203 
0204     if (do_fdtoverlay(input_filename, output_filename, argc, argv))
0205         return 1;
0206 
0207     return 0;
0208 }