1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2017 Konsulko Group Inc. All rights reserved. 4 * 5 * Author: 6 * Pantelis Antoniou <pantelis.antoniou@konsulko.com> 7 */ 8 9 #include <assert.h> 10 #include <ctype.h> 11 #include <getopt.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <inttypes.h> 16 17 #include <libfdt.h> 18 19 #include "util.h" 20 21 #define BUF_INCREMENT 65536 22 23 /* Usage related data. */ 24 static const char usage_synopsis[] = 25 "apply a number of overlays to a base blob\n" 26 " fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]"; 27 static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS; 28 static struct option const usage_long_opts[] = { 29 {"input", required_argument, NULL, 'i'}, 30 {"output", required_argument, NULL, 'o'}, 31 {"verbose", no_argument, NULL, 'v'}, 32 USAGE_COMMON_LONG_OPTS, 33 }; 34 static const char * const usage_opts_help[] = { 35 "Input base DT blob", 36 "Output DT blob", 37 "Verbose messages", 38 USAGE_COMMON_OPTS_HELP 39 }; 40 41 int verbose = 0; 42 43 static void *apply_one(char *base, const char *overlay, size_t *buf_len, 44 const char *name) 45 { 46 char *tmp = NULL; 47 char *tmpo; 48 int ret; 49 50 /* 51 * We take a copies first, because a failed apply can trash 52 * both the base blob and the overlay 53 */ 54 tmpo = xmalloc(fdt_totalsize(overlay)); 55 56 do { 57 tmp = xrealloc(tmp, *buf_len); 58 ret = fdt_open_into(base, tmp, *buf_len); 59 if (ret) { 60 fprintf(stderr, 61 "\nFailed to make temporary copy: %s\n", 62 fdt_strerror(ret)); 63 goto fail; 64 } 65 66 memcpy(tmpo, overlay, fdt_totalsize(overlay)); 67 68 ret = fdt_overlay_apply(tmp, tmpo); 69 if (ret == -FDT_ERR_NOSPACE) { 70 *buf_len += BUF_INCREMENT; 71 } 72 } while (ret == -FDT_ERR_NOSPACE); 73 74 if (ret) { 75 fprintf(stderr, "\nFailed to apply '%s': %s\n", 76 name, fdt_strerror(ret)); 77 goto fail; 78 } 79 80 free(base); 81 free(tmpo); 82 return tmp; 83 84 fail: 85 free(tmpo); 86 if (tmp) 87 free(tmp); 88 89 return NULL; 90 } 91 static int do_fdtoverlay(const char *input_filename, 92 const char *output_filename, 93 int argc, char *argv[]) 94 { 95 char *blob = NULL; 96 char **ovblob = NULL; 97 size_t buf_len; 98 int i, ret = -1; 99 100 blob = utilfdt_read(input_filename, &buf_len); 101 if (!blob) { 102 fprintf(stderr, "\nFailed to read '%s'\n", input_filename); 103 goto out_err; 104 } 105 if (fdt_totalsize(blob) > buf_len) { 106 fprintf(stderr, 107 "\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n", 108 (unsigned long)buf_len, fdt_totalsize(blob)); 109 goto out_err; 110 } 111 112 /* allocate blob pointer array */ 113 ovblob = xmalloc(sizeof(*ovblob) * argc); 114 memset(ovblob, 0, sizeof(*ovblob) * argc); 115 116 /* read and keep track of the overlay blobs */ 117 for (i = 0; i < argc; i++) { 118 size_t ov_len; 119 ovblob[i] = utilfdt_read(argv[i], &ov_len); 120 if (!ovblob[i]) { 121 fprintf(stderr, "\nFailed to read '%s'\n", argv[i]); 122 goto out_err; 123 } 124 if (fdt_totalsize(ovblob[i]) > ov_len) { 125 fprintf(stderr, 126 "\nOverlay '%s' is incomplete (%lu / %" PRIu32 " bytes read)\n", 127 argv[i], (unsigned long)ov_len, 128 fdt_totalsize(ovblob[i])); 129 goto out_err; 130 } 131 } 132 133 buf_len = fdt_totalsize(blob); 134 135 /* apply the overlays in sequence */ 136 for (i = 0; i < argc; i++) { 137 blob = apply_one(blob, ovblob[i], &buf_len, argv[i]); 138 if (!blob) 139 goto out_err; 140 } 141 142 fdt_pack(blob); 143 ret = utilfdt_write(output_filename, blob); 144 if (ret) 145 fprintf(stderr, "\nFailed to write '%s'\n", 146 output_filename); 147 148 out_err: 149 if (ovblob) { 150 for (i = 0; i < argc; i++) { 151 if (ovblob[i]) 152 free(ovblob[i]); 153 } 154 free(ovblob); 155 } 156 free(blob); 157 158 return ret; 159 } 160 161 int main(int argc, char *argv[]) 162 { 163 int opt, i; 164 char *input_filename = NULL; 165 char *output_filename = NULL; 166 167 while ((opt = util_getopt_long()) != EOF) { 168 switch (opt) { 169 case_USAGE_COMMON_FLAGS 170 171 case 'i': 172 input_filename = optarg; 173 break; 174 case 'o': 175 output_filename = optarg; 176 break; 177 case 'v': 178 verbose = 1; 179 break; 180 } 181 } 182 183 if (!input_filename) 184 usage("missing input file"); 185 186 if (!output_filename) 187 usage("missing output file"); 188 189 argv += optind; 190 argc -= optind; 191 192 if (argc <= 0) 193 usage("missing overlay file(s)"); 194 195 if (verbose) { 196 printf("input = %s\n", input_filename); 197 printf("output = %s\n", output_filename); 198 for (i = 0; i < argc; i++) 199 printf("overlay[%d] = %s\n", i, argv[i]); 200 } 201 202 if (do_fdtoverlay(input_filename, output_filename, argc, argv)) 203 return 1; 204 205 return 0; 206 } 207