Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  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. */
 24static const char usage_synopsis[] =
 25	"apply a number of overlays to a base blob\n"
 26	"	fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]";
 27static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS;
 28static 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};
 34static 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
 41int verbose = 0;
 42
 43static 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 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
 84fail:
 85	free(tmpo);
 86	if (tmp)
 87		free(tmp);
 88
 89	return NULL;
 90}
 91static 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
148out_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
161int 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}