214 lines · 4.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * Copyright (c) 2017 Konsulko Group Inc. All rights reserved. * * Author: *	 Pantelis Antoniou <pantelis.antoniou@konsulko.com> */ #include <assert.h>#include <ctype.h>#include <getopt.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <inttypes.h> #include <libfdt.h> #include "util.h" #define BUF_INCREMENT	65536 /* Usage related data. */static const char usage_synopsis[] =	"apply a number of overlays to a base blob\n"	"	fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]";static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS;static struct option const usage_long_opts[] = {	{"input",            required_argument, NULL, 'i'},	{"output",	     required_argument, NULL, 'o'},	{"verbose",	           no_argument, NULL, 'v'},	USAGE_COMMON_LONG_OPTS,};static const char * const usage_opts_help[] = {	"Input base DT blob",	"Output DT blob",	"Verbose messages",	USAGE_COMMON_OPTS_HELP}; int verbose = 0; static void *apply_one(char *base, const char *overlay, size_t *buf_len,		       const char *name){	char *tmp = NULL;	char *tmpo;	int ret;	bool has_symbols; 	/*	 * We take copies first, because a failed apply can trash	 * both the base blob and the overlay	 */	tmpo = xmalloc(fdt_totalsize(overlay)); 	do {		tmp = xrealloc(tmp, *buf_len);		ret = fdt_open_into(base, tmp, *buf_len);		if (ret) {			fprintf(stderr,				"\nFailed to make temporary copy: %s\n",				fdt_strerror(ret));			goto fail;		}		ret = fdt_path_offset(tmp, "/__symbols__");		has_symbols = ret >= 0; 		memcpy(tmpo, overlay, fdt_totalsize(overlay)); 		ret = fdt_overlay_apply(tmp, tmpo);		if (ret == -FDT_ERR_NOSPACE) {			*buf_len += BUF_INCREMENT;		}	} while (ret == -FDT_ERR_NOSPACE); 	if (ret) {		fprintf(stderr, "\nFailed to apply '%s': %s\n",			name, fdt_strerror(ret));		if (!has_symbols) {			fprintf(stderr,				"base blob does not have a '/__symbols__' node, "				"make sure you have compiled the base blob with '-@' option\n");		}		goto fail;	} 	free(base);	free(tmpo);	return tmp; fail:	free(tmpo);	if (tmp)		free(tmp); 	return NULL;}static int do_fdtoverlay(const char *input_filename,			 const char *output_filename,			 int argc, char *argv[]){	char *blob = NULL;	char **ovblob = NULL;	size_t buf_len;	int i, ret = -1; 	blob = utilfdt_read(input_filename, &buf_len);	if (!blob) {		fprintf(stderr, "\nFailed to read '%s'\n", input_filename);		goto out_err;	}	if (fdt_totalsize(blob) > buf_len) {		fprintf(stderr, "\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n",			(unsigned long)buf_len, fdt_totalsize(blob));		goto out_err;	} 	/* allocate blob pointer array */	ovblob = xmalloc(sizeof(*ovblob) * argc);	memset(ovblob, 0, sizeof(*ovblob) * argc); 	/* read and keep track of the overlay blobs */	for (i = 0; i < argc; i++) {		size_t ov_len;		ovblob[i] = utilfdt_read(argv[i], &ov_len);		if (!ovblob[i]) {			fprintf(stderr, "\nFailed to read '%s'\n", argv[i]);			goto out_err;		}		if (fdt_totalsize(ovblob[i]) > ov_len) {			fprintf(stderr,"\nOverlay '%s' is incomplete (%lu / %" PRIu32 " bytes read)\n",				argv[i], (unsigned long)ov_len,				fdt_totalsize(ovblob[i]));			goto out_err;		}	} 	buf_len = fdt_totalsize(blob); 	/* apply the overlays in sequence */	for (i = 0; i < argc; i++) {		blob = apply_one(blob, ovblob[i], &buf_len, argv[i]);		if (!blob)			goto out_err;	} 	fdt_pack(blob);	ret = utilfdt_write(output_filename, blob);	if (ret)		fprintf(stderr, "\nFailed to write '%s'\n",			output_filename); out_err:	if (ovblob) {		for (i = 0; i < argc; i++) {			if (ovblob[i])				free(ovblob[i]);		}		free(ovblob);	}	free(blob); 	return ret;} int main(int argc, char *argv[]){	int opt, i;	char *input_filename = NULL;	char *output_filename = NULL; 	while ((opt = util_getopt_long()) != EOF) {		switch (opt) {		case_USAGE_COMMON_FLAGS 		case 'i':			input_filename = optarg;			break;		case 'o':			output_filename = optarg;			break;		case 'v':			verbose = 1;			break;		}	} 	if (!input_filename)		usage("missing input file"); 	if (!output_filename)		usage("missing output file"); 	argv += optind;	argc -= optind; 	if (argc <= 0)		usage("missing overlay file(s)"); 	if (verbose) {		printf("input  = %s\n", input_filename);		printf("output = %s\n", output_filename);		for (i = 0; i < argc; i++)			printf("overlay[%d] = %s\n", i, argv[i]);	} 	if (do_fdtoverlay(input_filename, output_filename, argc, argv))		return 1; 	return 0;}