1 /*
2  * Copyright (c) 2017 Konsulko Group Inc. All rights reserved.
3  *
4  * Author:
5  *	 Pantelis Antoniou <pantelis.antoniou@konsulko.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22 
23 #include <assert.h>
24 #include <ctype.h>
25 #include <getopt.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <inttypes.h>
30 
31 #include <libfdt.h>
32 
33 #include "util.h"
34 
35 /* Usage related data. */
36 static const char usage_synopsis[] =
37 	"apply a number of overlays to a base blob\n"
38 	"	fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]\n"
39 	"\n"
40 	USAGE_TYPE_MSG;
41 static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS;
42 static struct option const usage_long_opts[] = {
43 	{"input",            required_argument, NULL, 'i'},
44 	{"output",	     required_argument, NULL, 'o'},
45 	{"verbose",	           no_argument, NULL, 'v'},
46 	USAGE_COMMON_LONG_OPTS,
47 };
48 static const char * const usage_opts_help[] = {
49 	"Input base DT blob",
50 	"Output DT blob",
51 	"Verbose messages",
52 	USAGE_COMMON_OPTS_HELP
53 };
54 
55 int verbose = 0;
56 
do_fdtoverlay(const char * input_filename,const char * output_filename,int argc,char * argv[])57 static int do_fdtoverlay(const char *input_filename,
58 			 const char *output_filename,
59 			 int argc, char *argv[])
60 {
61 	char *blob = NULL;
62 	char **ovblob = NULL;
63 	size_t blob_len, ov_len, total_len;
64 	int i, ret = -1;
65 
66 	blob = utilfdt_read(input_filename, &blob_len);
67 	if (!blob) {
68 		fprintf(stderr, "\nFailed to read base blob %s\n",
69 				input_filename);
70 		goto out_err;
71 	}
72 	if (fdt_totalsize(blob) > blob_len) {
73 		fprintf(stderr,
74  "\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n",
75 			(unsigned long)blob_len, fdt_totalsize(blob));
76 		goto out_err;
77 	}
78 	ret = 0;
79 
80 	/* allocate blob pointer array */
81 	ovblob = malloc(sizeof(*ovblob) * argc);
82 	memset(ovblob, 0, sizeof(*ovblob) * argc);
83 
84 	/* read and keep track of the overlay blobs */
85 	total_len = 0;
86 	for (i = 0; i < argc; i++) {
87 		ovblob[i] = utilfdt_read(argv[i], &ov_len);
88 		if (!ovblob[i]) {
89 			fprintf(stderr, "\nFailed to read overlay %s\n",
90 					argv[i]);
91 			goto out_err;
92 		}
93 		total_len += ov_len;
94 	}
95 
96 	/* grow the blob to worst case */
97 	blob_len = fdt_totalsize(blob) + total_len;
98 	blob = xrealloc(blob, blob_len);
99 	fdt_open_into(blob, blob, blob_len);
100 
101 	/* apply the overlays in sequence */
102 	for (i = 0; i < argc; i++) {
103 		ret = fdt_overlay_apply(blob, ovblob[i]);
104 		if (ret) {
105 			fprintf(stderr, "\nFailed to apply %s (%d)\n",
106 					argv[i], ret);
107 			goto out_err;
108 		}
109 	}
110 
111 	fdt_pack(blob);
112 	ret = utilfdt_write(output_filename, blob);
113 	if (ret)
114 		fprintf(stderr, "\nFailed to write output blob %s\n",
115 				output_filename);
116 
117 out_err:
118 	if (ovblob) {
119 		for (i = 0; i < argc; i++) {
120 			if (ovblob[i])
121 				free(ovblob[i]);
122 		}
123 		free(ovblob);
124 	}
125 	free(blob);
126 
127 	return ret;
128 }
129 
main(int argc,char * argv[])130 int main(int argc, char *argv[])
131 {
132 	int opt, i;
133 	char *input_filename = NULL;
134 	char *output_filename = NULL;
135 
136 	while ((opt = util_getopt_long()) != EOF) {
137 		switch (opt) {
138 		case_USAGE_COMMON_FLAGS
139 
140 		case 'i':
141 			input_filename = optarg;
142 			break;
143 		case 'o':
144 			output_filename = optarg;
145 			break;
146 		case 'v':
147 			verbose = 1;
148 			break;
149 		}
150 	}
151 
152 	if (!input_filename)
153 		usage("missing input file");
154 
155 	if (!output_filename)
156 		usage("missing output file");
157 
158 	argv += optind;
159 	argc -= optind;
160 
161 	if (argc <= 0)
162 		usage("missing overlay file(s)");
163 
164 	if (verbose) {
165 		printf("input  = %s\n", input_filename);
166 		printf("output = %s\n", output_filename);
167 		for (i = 0; i < argc; i++)
168 			printf("overlay[%d] = %s\n", i, argv[i]);
169 	}
170 
171 	if (do_fdtoverlay(input_filename, output_filename, argc, argv))
172 		return 1;
173 
174 	return 0;
175 }
176