xref: /OK3568_Linux_fs/u-boot/tools/fdtgrep.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2013, Google Inc.
3*4882a593Smuzhiyun  * Written by Simon Glass <sjg@chromium.org>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Perform a grep of an FDT either displaying the source subset or producing
8*4882a593Smuzhiyun  * a new .dtb subset which can be used as required.
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <assert.h>
12*4882a593Smuzhiyun #include <ctype.h>
13*4882a593Smuzhiyun #include <errno.h>
14*4882a593Smuzhiyun #include <getopt.h>
15*4882a593Smuzhiyun #include <fcntl.h>
16*4882a593Smuzhiyun #include <stdbool.h>
17*4882a593Smuzhiyun #include <stdio.h>
18*4882a593Smuzhiyun #include <stdlib.h>
19*4882a593Smuzhiyun #include <string.h>
20*4882a593Smuzhiyun #include <unistd.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include "fdt_host.h"
23*4882a593Smuzhiyun #include "libfdt_internal.h"
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* Define DEBUG to get some debugging output on stderr */
26*4882a593Smuzhiyun #ifdef DEBUG
27*4882a593Smuzhiyun #define debug(a, b...) fprintf(stderr, a, ## b)
28*4882a593Smuzhiyun #else
29*4882a593Smuzhiyun #define debug(a, b...)
30*4882a593Smuzhiyun #endif
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /* A linked list of values we are grepping for */
33*4882a593Smuzhiyun struct value_node {
34*4882a593Smuzhiyun 	int type;		/* Types this value matches (FDT_IS... mask) */
35*4882a593Smuzhiyun 	int include;		/* 1 to include matches, 0 to exclude */
36*4882a593Smuzhiyun 	const char *string;	/* String to match */
37*4882a593Smuzhiyun 	struct value_node *next;	/* Pointer to next node, or NULL */
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /* Output formats we support */
41*4882a593Smuzhiyun enum output_t {
42*4882a593Smuzhiyun 	OUT_DTS,		/* Device tree source */
43*4882a593Smuzhiyun 	OUT_DTB,		/* Valid device tree binary */
44*4882a593Smuzhiyun 	OUT_BIN,		/* Fragment of .dtb, for hashing */
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /* Holds information which controls our output and options */
48*4882a593Smuzhiyun struct display_info {
49*4882a593Smuzhiyun 	enum output_t output;	/* Output format */
50*4882a593Smuzhiyun 	int add_aliases;	/* Add aliases node to output */
51*4882a593Smuzhiyun 	int all;		/* Display all properties/nodes */
52*4882a593Smuzhiyun 	int colour;		/* Display output in ANSI colour */
53*4882a593Smuzhiyun 	int region_list;	/* Output a region list */
54*4882a593Smuzhiyun 	int flags;		/* Flags (FDT_REG_...) */
55*4882a593Smuzhiyun 	int list_strings;	/* List strings in string table */
56*4882a593Smuzhiyun 	int show_offset;	/* Show offset */
57*4882a593Smuzhiyun 	int show_addr;		/* Show address */
58*4882a593Smuzhiyun 	int header;		/* Output an FDT header */
59*4882a593Smuzhiyun 	int diff;		/* Show +/- diff markers */
60*4882a593Smuzhiyun 	int include_root;	/* Include the root node and all properties */
61*4882a593Smuzhiyun 	int remove_strings;	/* Remove unused strings */
62*4882a593Smuzhiyun 	int show_dts_version;	/* Put '/dts-v1/;' on the first line */
63*4882a593Smuzhiyun 	int types_inc;		/* Mask of types that we include (FDT_IS...) */
64*4882a593Smuzhiyun 	int types_exc;		/* Mask of types that we exclude (FDT_IS...) */
65*4882a593Smuzhiyun 	int invert;		/* Invert polarity of match */
66*4882a593Smuzhiyun 	struct value_node *value_head;	/* List of values to match */
67*4882a593Smuzhiyun 	const char *output_fname;	/* Output filename */
68*4882a593Smuzhiyun 	FILE *fout;		/* File to write dts/dtb output */
69*4882a593Smuzhiyun };
70*4882a593Smuzhiyun 
report_error(const char * where,int err)71*4882a593Smuzhiyun static void report_error(const char *where, int err)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun /* Supported ANSI colours */
77*4882a593Smuzhiyun enum {
78*4882a593Smuzhiyun 	COL_BLACK,
79*4882a593Smuzhiyun 	COL_RED,
80*4882a593Smuzhiyun 	COL_GREEN,
81*4882a593Smuzhiyun 	COL_YELLOW,
82*4882a593Smuzhiyun 	COL_BLUE,
83*4882a593Smuzhiyun 	COL_MAGENTA,
84*4882a593Smuzhiyun 	COL_CYAN,
85*4882a593Smuzhiyun 	COL_WHITE,
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	COL_NONE = -1,
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun /**
91*4882a593Smuzhiyun  * print_ansi_colour() - Print out the ANSI sequence for a colour
92*4882a593Smuzhiyun  *
93*4882a593Smuzhiyun  * @fout:	Output file
94*4882a593Smuzhiyun  * @col:	Colour to output (COL_...), or COL_NONE to reset colour
95*4882a593Smuzhiyun  */
print_ansi_colour(FILE * fout,int col)96*4882a593Smuzhiyun static void print_ansi_colour(FILE *fout, int col)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	if (col == COL_NONE)
99*4882a593Smuzhiyun 		fprintf(fout, "\033[0m");
100*4882a593Smuzhiyun 	else
101*4882a593Smuzhiyun 		fprintf(fout, "\033[1;%dm", col + 30);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun /**
106*4882a593Smuzhiyun  * value_add() - Add a new value to our list of things to grep for
107*4882a593Smuzhiyun  *
108*4882a593Smuzhiyun  * @disp:	Display structure, holding info about our options
109*4882a593Smuzhiyun  * @headp:	Pointer to header pointer of list
110*4882a593Smuzhiyun  * @type:	Type of this value (FDT_IS_...)
111*4882a593Smuzhiyun  * @include:	1 if we want to include matches, 0 to exclude
112*4882a593Smuzhiyun  * @str:	String value to match
113*4882a593Smuzhiyun  */
value_add(struct display_info * disp,struct value_node ** headp,int type,int include,const char * str)114*4882a593Smuzhiyun static int value_add(struct display_info *disp, struct value_node **headp,
115*4882a593Smuzhiyun 		     int type, int include, const char *str)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	struct value_node *node;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	/*
120*4882a593Smuzhiyun 	 * Keep track of which types we are excluding/including. We don't
121*4882a593Smuzhiyun 	 * allow both including and excluding things, because it doesn't make
122*4882a593Smuzhiyun 	 * sense. 'Including' means that everything not mentioned is
123*4882a593Smuzhiyun 	 * excluded. 'Excluding' means that everything not mentioned is
124*4882a593Smuzhiyun 	 * included. So using the two together would be meaningless.
125*4882a593Smuzhiyun 	 */
126*4882a593Smuzhiyun 	if (include)
127*4882a593Smuzhiyun 		disp->types_inc |= type;
128*4882a593Smuzhiyun 	else
129*4882a593Smuzhiyun 		disp->types_exc |= type;
130*4882a593Smuzhiyun 	if (disp->types_inc & disp->types_exc & type) {
131*4882a593Smuzhiyun 		fprintf(stderr,
132*4882a593Smuzhiyun 			"Cannot use both include and exclude for '%s'\n", str);
133*4882a593Smuzhiyun 		return -1;
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	str = strdup(str);
137*4882a593Smuzhiyun 	node = malloc(sizeof(*node));
138*4882a593Smuzhiyun 	if (!str || !node) {
139*4882a593Smuzhiyun 		fprintf(stderr, "Out of memory\n");
140*4882a593Smuzhiyun 		return -1;
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun 	node->next = *headp;
143*4882a593Smuzhiyun 	node->type = type;
144*4882a593Smuzhiyun 	node->include = include;
145*4882a593Smuzhiyun 	node->string = str;
146*4882a593Smuzhiyun 	*headp = node;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	return 0;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
util_is_printable_string(const void * data,int len)151*4882a593Smuzhiyun static bool util_is_printable_string(const void *data, int len)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	const char *s = data;
154*4882a593Smuzhiyun 	const char *ss, *se;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	/* zero length is not */
157*4882a593Smuzhiyun 	if (len == 0)
158*4882a593Smuzhiyun 		return 0;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	/* must terminate with zero */
161*4882a593Smuzhiyun 	if (s[len - 1] != '\0')
162*4882a593Smuzhiyun 		return 0;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	se = s + len;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	while (s < se) {
167*4882a593Smuzhiyun 		ss = s;
168*4882a593Smuzhiyun 		while (s < se && *s && isprint((unsigned char)*s))
169*4882a593Smuzhiyun 			s++;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 		/* not zero, or not done yet */
172*4882a593Smuzhiyun 		if (*s != '\0' || s == ss)
173*4882a593Smuzhiyun 			return 0;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 		s++;
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	return 1;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
utilfdt_print_data(const char * data,int len)181*4882a593Smuzhiyun static void utilfdt_print_data(const char *data, int len)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	int i;
184*4882a593Smuzhiyun 	const char *p = data;
185*4882a593Smuzhiyun 	const char *s;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	/* no data, don't print */
188*4882a593Smuzhiyun 	if (len == 0)
189*4882a593Smuzhiyun 		return;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	if (util_is_printable_string(data, len)) {
192*4882a593Smuzhiyun 		printf(" = ");
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 		s = data;
195*4882a593Smuzhiyun 		do {
196*4882a593Smuzhiyun 			printf("\"%s\"", s);
197*4882a593Smuzhiyun 			s += strlen(s) + 1;
198*4882a593Smuzhiyun 			if (s < data + len)
199*4882a593Smuzhiyun 				printf(", ");
200*4882a593Smuzhiyun 		} while (s < data + len);
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	} else if ((len % 4) == 0) {
203*4882a593Smuzhiyun 		const uint32_t *cell = (const uint32_t *)data;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 		printf(" = <");
206*4882a593Smuzhiyun 		for (i = 0, len /= 4; i < len; i++)
207*4882a593Smuzhiyun 			printf("0x%08x%s", fdt32_to_cpu(cell[i]),
208*4882a593Smuzhiyun 			       i < (len - 1) ? " " : "");
209*4882a593Smuzhiyun 		printf(">");
210*4882a593Smuzhiyun 	} else {
211*4882a593Smuzhiyun 		printf(" = [");
212*4882a593Smuzhiyun 		for (i = 0; i < len; i++)
213*4882a593Smuzhiyun 			printf("%02x%s", *p++, i < len - 1 ? " " : "");
214*4882a593Smuzhiyun 		printf("]");
215*4882a593Smuzhiyun 	}
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun /**
219*4882a593Smuzhiyun  * display_fdt_by_regions() - Display regions of an FDT source
220*4882a593Smuzhiyun  *
221*4882a593Smuzhiyun  * This dumps an FDT as source, but only certain regions of it. This is the
222*4882a593Smuzhiyun  * final stage of the grep - we have a list of regions we want to display,
223*4882a593Smuzhiyun  * and this function displays them.
224*4882a593Smuzhiyun  *
225*4882a593Smuzhiyun  * @disp:	Display structure, holding info about our options
226*4882a593Smuzhiyun  * @blob:	FDT blob to display
227*4882a593Smuzhiyun  * @region:	List of regions to display
228*4882a593Smuzhiyun  * @count:	Number of regions
229*4882a593Smuzhiyun  */
display_fdt_by_regions(struct display_info * disp,const void * blob,struct fdt_region region[],int count)230*4882a593Smuzhiyun static int display_fdt_by_regions(struct display_info *disp, const void *blob,
231*4882a593Smuzhiyun 		struct fdt_region region[], int count)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	struct fdt_region *reg = region, *reg_end = region + count;
234*4882a593Smuzhiyun 	uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(blob);
235*4882a593Smuzhiyun 	int base = fdt_off_dt_struct(blob);
236*4882a593Smuzhiyun 	int version = fdt_version(blob);
237*4882a593Smuzhiyun 	int offset, nextoffset;
238*4882a593Smuzhiyun 	int tag, depth, shift;
239*4882a593Smuzhiyun 	FILE *f = disp->fout;
240*4882a593Smuzhiyun 	uint64_t addr, size;
241*4882a593Smuzhiyun 	int in_region;
242*4882a593Smuzhiyun 	int file_ofs;
243*4882a593Smuzhiyun 	int i;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	if (disp->show_dts_version)
246*4882a593Smuzhiyun 		fprintf(f, "/dts-v1/;\n");
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	if (disp->header) {
249*4882a593Smuzhiyun 		fprintf(f, "// magic:\t\t0x%x\n", fdt_magic(blob));
250*4882a593Smuzhiyun 		fprintf(f, "// totalsize:\t\t0x%x (%d)\n", fdt_totalsize(blob),
251*4882a593Smuzhiyun 			fdt_totalsize(blob));
252*4882a593Smuzhiyun 		fprintf(f, "// off_dt_struct:\t0x%x\n",
253*4882a593Smuzhiyun 			fdt_off_dt_struct(blob));
254*4882a593Smuzhiyun 		fprintf(f, "// off_dt_strings:\t0x%x\n",
255*4882a593Smuzhiyun 			fdt_off_dt_strings(blob));
256*4882a593Smuzhiyun 		fprintf(f, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
257*4882a593Smuzhiyun 		fprintf(f, "// version:\t\t%d\n", version);
258*4882a593Smuzhiyun 		fprintf(f, "// last_comp_version:\t%d\n",
259*4882a593Smuzhiyun 			fdt_last_comp_version(blob));
260*4882a593Smuzhiyun 		if (version >= 2) {
261*4882a593Smuzhiyun 			fprintf(f, "// boot_cpuid_phys:\t0x%x\n",
262*4882a593Smuzhiyun 				fdt_boot_cpuid_phys(blob));
263*4882a593Smuzhiyun 		}
264*4882a593Smuzhiyun 		if (version >= 3) {
265*4882a593Smuzhiyun 			fprintf(f, "// size_dt_strings:\t0x%x\n",
266*4882a593Smuzhiyun 				fdt_size_dt_strings(blob));
267*4882a593Smuzhiyun 		}
268*4882a593Smuzhiyun 		if (version >= 17) {
269*4882a593Smuzhiyun 			fprintf(f, "// size_dt_struct:\t0x%x\n",
270*4882a593Smuzhiyun 				fdt_size_dt_struct(blob));
271*4882a593Smuzhiyun 		}
272*4882a593Smuzhiyun 		fprintf(f, "\n");
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	if (disp->flags & FDT_REG_ADD_MEM_RSVMAP) {
276*4882a593Smuzhiyun 		const struct fdt_reserve_entry *p_rsvmap;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 		p_rsvmap = (const struct fdt_reserve_entry *)
279*4882a593Smuzhiyun 				((const char *)blob + off_mem_rsvmap);
280*4882a593Smuzhiyun 		for (i = 0; ; i++) {
281*4882a593Smuzhiyun 			addr = fdt64_to_cpu(p_rsvmap[i].address);
282*4882a593Smuzhiyun 			size = fdt64_to_cpu(p_rsvmap[i].size);
283*4882a593Smuzhiyun 			if (addr == 0 && size == 0)
284*4882a593Smuzhiyun 				break;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 			fprintf(f, "/memreserve/ %llx %llx;\n",
287*4882a593Smuzhiyun 				(unsigned long long)addr,
288*4882a593Smuzhiyun 				(unsigned long long)size);
289*4882a593Smuzhiyun 		}
290*4882a593Smuzhiyun 	}
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	depth = 0;
293*4882a593Smuzhiyun 	nextoffset = 0;
294*4882a593Smuzhiyun 	shift = 4;	/* 4 spaces per indent */
295*4882a593Smuzhiyun 	do {
296*4882a593Smuzhiyun 		const struct fdt_property *prop;
297*4882a593Smuzhiyun 		const char *name;
298*4882a593Smuzhiyun 		int show;
299*4882a593Smuzhiyun 		int len;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 		offset = nextoffset;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 		/*
304*4882a593Smuzhiyun 		 * Work out the file offset of this offset, and decide
305*4882a593Smuzhiyun 		 * whether it is in the region list or not
306*4882a593Smuzhiyun 		 */
307*4882a593Smuzhiyun 		file_ofs = base + offset;
308*4882a593Smuzhiyun 		if (reg < reg_end && file_ofs >= reg->offset + reg->size)
309*4882a593Smuzhiyun 			reg++;
310*4882a593Smuzhiyun 		in_region = reg < reg_end && file_ofs >= reg->offset &&
311*4882a593Smuzhiyun 				file_ofs < reg->offset + reg->size;
312*4882a593Smuzhiyun 		tag = fdt_next_tag(blob, offset, &nextoffset);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 		if (tag == FDT_END)
315*4882a593Smuzhiyun 			break;
316*4882a593Smuzhiyun 		show = in_region || disp->all;
317*4882a593Smuzhiyun 		if (show && disp->diff)
318*4882a593Smuzhiyun 			fprintf(f, "%c", in_region ? '+' : '-');
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 		if (!show) {
321*4882a593Smuzhiyun 			/* Do this here to avoid 'if (show)' in every 'case' */
322*4882a593Smuzhiyun 			if (tag == FDT_BEGIN_NODE)
323*4882a593Smuzhiyun 				depth++;
324*4882a593Smuzhiyun 			else if (tag == FDT_END_NODE)
325*4882a593Smuzhiyun 				depth--;
326*4882a593Smuzhiyun 			continue;
327*4882a593Smuzhiyun 		}
328*4882a593Smuzhiyun 		if (tag != FDT_END) {
329*4882a593Smuzhiyun 			if (disp->show_addr)
330*4882a593Smuzhiyun 				fprintf(f, "%4x: ", file_ofs);
331*4882a593Smuzhiyun 			if (disp->show_offset)
332*4882a593Smuzhiyun 				fprintf(f, "%4x: ", file_ofs - base);
333*4882a593Smuzhiyun 		}
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 		/* Green means included, red means excluded */
336*4882a593Smuzhiyun 		if (disp->colour)
337*4882a593Smuzhiyun 			print_ansi_colour(f, in_region ? COL_GREEN : COL_RED);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 		switch (tag) {
340*4882a593Smuzhiyun 		case FDT_PROP:
341*4882a593Smuzhiyun 			prop = fdt_get_property_by_offset(blob, offset, NULL);
342*4882a593Smuzhiyun 			name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
343*4882a593Smuzhiyun 			fprintf(f, "%*s%s", depth * shift, "", name);
344*4882a593Smuzhiyun 			utilfdt_print_data(prop->data,
345*4882a593Smuzhiyun 					   fdt32_to_cpu(prop->len));
346*4882a593Smuzhiyun 			fprintf(f, ";");
347*4882a593Smuzhiyun 			break;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 		case FDT_NOP:
350*4882a593Smuzhiyun 			fprintf(f, "%*s// [NOP]", depth * shift, "");
351*4882a593Smuzhiyun 			break;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 		case FDT_BEGIN_NODE:
354*4882a593Smuzhiyun 			name = fdt_get_name(blob, offset, &len);
355*4882a593Smuzhiyun 			fprintf(f, "%*s%s {", depth++ * shift, "",
356*4882a593Smuzhiyun 				*name ? name : "/");
357*4882a593Smuzhiyun 			break;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 		case FDT_END_NODE:
360*4882a593Smuzhiyun 			fprintf(f, "%*s};", --depth * shift, "");
361*4882a593Smuzhiyun 			break;
362*4882a593Smuzhiyun 		}
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 		/* Reset colour back to normal before end of line */
365*4882a593Smuzhiyun 		if (disp->colour)
366*4882a593Smuzhiyun 			print_ansi_colour(f, COL_NONE);
367*4882a593Smuzhiyun 		fprintf(f, "\n");
368*4882a593Smuzhiyun 	} while (1);
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	/* Print a list of strings if requested */
371*4882a593Smuzhiyun 	if (disp->list_strings) {
372*4882a593Smuzhiyun 		const char *str;
373*4882a593Smuzhiyun 		int str_base = fdt_off_dt_strings(blob);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 		for (offset = 0; offset < fdt_size_dt_strings(blob);
376*4882a593Smuzhiyun 				offset += strlen(str) + 1) {
377*4882a593Smuzhiyun 			str = fdt_string(blob, offset);
378*4882a593Smuzhiyun 			int len = strlen(str) + 1;
379*4882a593Smuzhiyun 			int show;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 			/* Only print strings that are in the region */
382*4882a593Smuzhiyun 			file_ofs = str_base + offset;
383*4882a593Smuzhiyun 			in_region = reg < reg_end &&
384*4882a593Smuzhiyun 					file_ofs >= reg->offset &&
385*4882a593Smuzhiyun 					file_ofs + len < reg->offset +
386*4882a593Smuzhiyun 						reg->size;
387*4882a593Smuzhiyun 			show = in_region || disp->all;
388*4882a593Smuzhiyun 			if (show && disp->diff)
389*4882a593Smuzhiyun 				printf("%c", in_region ? '+' : '-');
390*4882a593Smuzhiyun 			if (disp->show_addr)
391*4882a593Smuzhiyun 				printf("%4x: ", file_ofs);
392*4882a593Smuzhiyun 			if (disp->show_offset)
393*4882a593Smuzhiyun 				printf("%4x: ", offset);
394*4882a593Smuzhiyun 			printf("%s\n", str);
395*4882a593Smuzhiyun 		}
396*4882a593Smuzhiyun 	}
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	return 0;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun /**
402*4882a593Smuzhiyun  * dump_fdt_regions() - Dump regions of an FDT as binary data
403*4882a593Smuzhiyun  *
404*4882a593Smuzhiyun  * This dumps an FDT as binary, but only certain regions of it. This is the
405*4882a593Smuzhiyun  * final stage of the grep - we have a list of regions we want to dump,
406*4882a593Smuzhiyun  * and this function dumps them.
407*4882a593Smuzhiyun  *
408*4882a593Smuzhiyun  * The output of this function may or may not be a valid FDT. To ensure it
409*4882a593Smuzhiyun  * is, these disp->flags must be set:
410*4882a593Smuzhiyun  *
411*4882a593Smuzhiyun  *   FDT_REG_SUPERNODES: ensures that subnodes are preceded by their
412*4882a593Smuzhiyun  *		parents. Without this option, fragments of subnode data may be
413*4882a593Smuzhiyun  *		output without the supernodes above them. This is useful for
414*4882a593Smuzhiyun  *		hashing but cannot produce a valid FDT.
415*4882a593Smuzhiyun  *   FDT_REG_ADD_STRING_TAB: Adds a string table to the end of the FDT.
416*4882a593Smuzhiyun  *		Without this none of the properties will have names
417*4882a593Smuzhiyun  *   FDT_REG_ADD_MEM_RSVMAP: Adds a mem_rsvmap table - an FDT is invalid
418*4882a593Smuzhiyun  *		without this.
419*4882a593Smuzhiyun  *
420*4882a593Smuzhiyun  * @disp:	Display structure, holding info about our options
421*4882a593Smuzhiyun  * @blob:	FDT blob to display
422*4882a593Smuzhiyun  * @region:	List of regions to display
423*4882a593Smuzhiyun  * @count:	Number of regions
424*4882a593Smuzhiyun  * @out:	Output destination
425*4882a593Smuzhiyun  */
dump_fdt_regions(struct display_info * disp,const void * blob,struct fdt_region region[],int count,char * out)426*4882a593Smuzhiyun static int dump_fdt_regions(struct display_info *disp, const void *blob,
427*4882a593Smuzhiyun 		struct fdt_region region[], int count, char *out)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun 	struct fdt_header *fdt;
430*4882a593Smuzhiyun 	int size, struct_start;
431*4882a593Smuzhiyun 	int ptr;
432*4882a593Smuzhiyun 	int i;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	/* Set up a basic header (even if we don't actually write it) */
435*4882a593Smuzhiyun 	fdt = (struct fdt_header *)out;
436*4882a593Smuzhiyun 	memset(fdt, '\0', sizeof(*fdt));
437*4882a593Smuzhiyun 	fdt_set_magic(fdt, FDT_MAGIC);
438*4882a593Smuzhiyun 	struct_start = FDT_ALIGN(sizeof(struct fdt_header),
439*4882a593Smuzhiyun 					sizeof(struct fdt_reserve_entry));
440*4882a593Smuzhiyun 	fdt_set_off_mem_rsvmap(fdt, struct_start);
441*4882a593Smuzhiyun 	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
442*4882a593Smuzhiyun 	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	/*
445*4882a593Smuzhiyun 	 * Calculate the total size of the regions we are writing out. The
446*4882a593Smuzhiyun 	 * first will be the mem_rsvmap if the FDT_REG_ADD_MEM_RSVMAP flag
447*4882a593Smuzhiyun 	 * is set. The last will be the string table if FDT_REG_ADD_STRING_TAB
448*4882a593Smuzhiyun 	 * is set.
449*4882a593Smuzhiyun 	 */
450*4882a593Smuzhiyun 	for (i = size = 0; i < count; i++)
451*4882a593Smuzhiyun 		size += region[i].size;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	/* Bring in the mem_rsvmap section from the old file if requested */
454*4882a593Smuzhiyun 	if (count > 0 && (disp->flags & FDT_REG_ADD_MEM_RSVMAP)) {
455*4882a593Smuzhiyun 		struct_start += region[0].size;
456*4882a593Smuzhiyun 		size -= region[0].size;
457*4882a593Smuzhiyun 	}
458*4882a593Smuzhiyun 	fdt_set_off_dt_struct(fdt, struct_start);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	/* Update the header to have the correct offsets/sizes */
461*4882a593Smuzhiyun 	if (count >= 2 && (disp->flags & FDT_REG_ADD_STRING_TAB)) {
462*4882a593Smuzhiyun 		int str_size;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 		str_size = region[count - 1].size;
465*4882a593Smuzhiyun 		fdt_set_size_dt_struct(fdt, size - str_size);
466*4882a593Smuzhiyun 		fdt_set_off_dt_strings(fdt, struct_start + size - str_size);
467*4882a593Smuzhiyun 		fdt_set_size_dt_strings(fdt, str_size);
468*4882a593Smuzhiyun 		fdt_set_totalsize(fdt, struct_start + size);
469*4882a593Smuzhiyun 	}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	/* Write the header if required */
472*4882a593Smuzhiyun 	ptr = 0;
473*4882a593Smuzhiyun 	if (disp->header) {
474*4882a593Smuzhiyun 		ptr = sizeof(*fdt);
475*4882a593Smuzhiyun 		while (ptr < fdt_off_mem_rsvmap(fdt))
476*4882a593Smuzhiyun 			out[ptr++] = '\0';
477*4882a593Smuzhiyun 	}
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	/* Output all the nodes including any mem_rsvmap/string table */
480*4882a593Smuzhiyun 	for (i = 0; i < count; i++) {
481*4882a593Smuzhiyun 		struct fdt_region *reg = &region[i];
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 		memcpy(out + ptr, (const char *)blob + reg->offset, reg->size);
484*4882a593Smuzhiyun 		ptr += reg->size;
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	return ptr;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun /**
491*4882a593Smuzhiyun  * show_region_list() - Print out a list of regions
492*4882a593Smuzhiyun  *
493*4882a593Smuzhiyun  * The list includes the region offset (absolute offset from start of FDT
494*4882a593Smuzhiyun  * blob in bytes) and size
495*4882a593Smuzhiyun  *
496*4882a593Smuzhiyun  * @reg:	List of regions to print
497*4882a593Smuzhiyun  * @count:	Number of regions
498*4882a593Smuzhiyun  */
show_region_list(struct fdt_region * reg,int count)499*4882a593Smuzhiyun static void show_region_list(struct fdt_region *reg, int count)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun 	int i;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	printf("Regions: %d\n", count);
504*4882a593Smuzhiyun 	for (i = 0; i < count; i++, reg++) {
505*4882a593Smuzhiyun 		printf("%d:  %-10x  %-10x\n", i, reg->offset,
506*4882a593Smuzhiyun 		       reg->offset + reg->size);
507*4882a593Smuzhiyun 	}
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun 
check_type_include(void * priv,int type,const char * data,int size)510*4882a593Smuzhiyun static int check_type_include(void *priv, int type, const char *data, int size)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun 	struct display_info *disp = priv;
513*4882a593Smuzhiyun 	struct value_node *val;
514*4882a593Smuzhiyun 	int match, none_match = FDT_IS_ANY;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	/* If none of our conditions mention this type, we know nothing */
517*4882a593Smuzhiyun 	debug("type=%x, data=%s\n", type, data ? data : "(null)");
518*4882a593Smuzhiyun 	if (!((disp->types_inc | disp->types_exc) & type)) {
519*4882a593Smuzhiyun 		debug("   - not in any condition\n");
520*4882a593Smuzhiyun 		return -1;
521*4882a593Smuzhiyun 	}
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	/*
524*4882a593Smuzhiyun 	 * Go through the list of conditions. For inclusive conditions, we
525*4882a593Smuzhiyun 	 * return 1 at the first match. For exclusive conditions, we must
526*4882a593Smuzhiyun 	 * check that there are no matches.
527*4882a593Smuzhiyun 	 */
528*4882a593Smuzhiyun 	if (data) {
529*4882a593Smuzhiyun 		for (val = disp->value_head; val; val = val->next) {
530*4882a593Smuzhiyun 			if (!(type & val->type))
531*4882a593Smuzhiyun 				continue;
532*4882a593Smuzhiyun 			match = fdt_stringlist_contains(data, size,
533*4882a593Smuzhiyun 							val->string);
534*4882a593Smuzhiyun 			debug("      - val->type=%x, str='%s', match=%d\n",
535*4882a593Smuzhiyun 			      val->type, val->string, match);
536*4882a593Smuzhiyun 			if (match && val->include) {
537*4882a593Smuzhiyun 				debug("   - match inc %s\n", val->string);
538*4882a593Smuzhiyun 				return 1;
539*4882a593Smuzhiyun 			}
540*4882a593Smuzhiyun 			if (match)
541*4882a593Smuzhiyun 				none_match &= ~val->type;
542*4882a593Smuzhiyun 		}
543*4882a593Smuzhiyun 	}
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	/*
546*4882a593Smuzhiyun 	 * If this is an exclusive condition, and nothing matches, then we
547*4882a593Smuzhiyun 	 * should return 1.
548*4882a593Smuzhiyun 	 */
549*4882a593Smuzhiyun 	if ((type & disp->types_exc) && (none_match & type)) {
550*4882a593Smuzhiyun 		debug("   - match exc\n");
551*4882a593Smuzhiyun 		/*
552*4882a593Smuzhiyun 		 * Allow FDT_IS_COMPAT to make the final decision in the
553*4882a593Smuzhiyun 		 * case where there is no specific type
554*4882a593Smuzhiyun 		 */
555*4882a593Smuzhiyun 		if (type == FDT_IS_NODE && disp->types_exc == FDT_ANY_GLOBAL) {
556*4882a593Smuzhiyun 			debug("   - supressed exc node\n");
557*4882a593Smuzhiyun 			return -1;
558*4882a593Smuzhiyun 		}
559*4882a593Smuzhiyun 		return 1;
560*4882a593Smuzhiyun 	}
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	/*
563*4882a593Smuzhiyun 	 * Allow FDT_IS_COMPAT to make the final decision in the
564*4882a593Smuzhiyun 	 * case where there is no specific type (inclusive)
565*4882a593Smuzhiyun 	 */
566*4882a593Smuzhiyun 	if (type == FDT_IS_NODE && disp->types_inc == FDT_ANY_GLOBAL)
567*4882a593Smuzhiyun 		return -1;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	debug("   - no match, types_inc=%x, types_exc=%x, none_match=%x\n",
570*4882a593Smuzhiyun 	      disp->types_inc, disp->types_exc, none_match);
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	return 0;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun /**
576*4882a593Smuzhiyun  * h_include() - Include handler function for fdt_find_regions()
577*4882a593Smuzhiyun  *
578*4882a593Smuzhiyun  * This function decides whether to include or exclude a node, property or
579*4882a593Smuzhiyun  * compatible string. The function is defined by fdt_find_regions().
580*4882a593Smuzhiyun  *
581*4882a593Smuzhiyun  * The algorithm is documented in the code - disp->invert is 0 for normal
582*4882a593Smuzhiyun  * operation, and 1 to invert the sense of all matches.
583*4882a593Smuzhiyun  *
584*4882a593Smuzhiyun  * See
585*4882a593Smuzhiyun  */
h_include(void * priv,const void * fdt,int offset,int type,const char * data,int size)586*4882a593Smuzhiyun static int h_include(void *priv, const void *fdt, int offset, int type,
587*4882a593Smuzhiyun 		     const char *data, int size)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun 	struct display_info *disp = priv;
590*4882a593Smuzhiyun 	int inc, len;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	inc = check_type_include(priv, type, data, size);
593*4882a593Smuzhiyun 	if (disp->include_root && type == FDT_IS_PROP && offset == 0 && inc)
594*4882a593Smuzhiyun 		return 1;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	/*
597*4882a593Smuzhiyun 	 * If the node name does not tell us anything, check the
598*4882a593Smuzhiyun 	 * compatible string
599*4882a593Smuzhiyun 	 */
600*4882a593Smuzhiyun 	if (inc == -1 && type == FDT_IS_NODE) {
601*4882a593Smuzhiyun 		debug("   - checking compatible2\n");
602*4882a593Smuzhiyun 		data = fdt_getprop(fdt, offset, "compatible", &len);
603*4882a593Smuzhiyun 		inc = check_type_include(priv, FDT_IS_COMPAT, data, len);
604*4882a593Smuzhiyun 	}
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	/* If we still have no idea, check for properties in the node */
607*4882a593Smuzhiyun 	if (inc != 1 && type == FDT_IS_NODE &&
608*4882a593Smuzhiyun 	    (disp->types_inc & FDT_NODE_HAS_PROP)) {
609*4882a593Smuzhiyun 		debug("   - checking node '%s'\n",
610*4882a593Smuzhiyun 		      fdt_get_name(fdt, offset, NULL));
611*4882a593Smuzhiyun 		for (offset = fdt_first_property_offset(fdt, offset);
612*4882a593Smuzhiyun 		     offset > 0 && inc != 1;
613*4882a593Smuzhiyun 		     offset = fdt_next_property_offset(fdt, offset)) {
614*4882a593Smuzhiyun 			const struct fdt_property *prop;
615*4882a593Smuzhiyun 			const char *str;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 			prop = fdt_get_property_by_offset(fdt, offset, NULL);
618*4882a593Smuzhiyun 			if (!prop)
619*4882a593Smuzhiyun 				continue;
620*4882a593Smuzhiyun 			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
621*4882a593Smuzhiyun 			inc = check_type_include(priv, FDT_NODE_HAS_PROP, str,
622*4882a593Smuzhiyun 						 strlen(str));
623*4882a593Smuzhiyun 		}
624*4882a593Smuzhiyun 		if (inc == -1)
625*4882a593Smuzhiyun 			inc = 0;
626*4882a593Smuzhiyun 	}
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	switch (inc) {
629*4882a593Smuzhiyun 	case 1:
630*4882a593Smuzhiyun 		inc = !disp->invert;
631*4882a593Smuzhiyun 		break;
632*4882a593Smuzhiyun 	case 0:
633*4882a593Smuzhiyun 		inc = disp->invert;
634*4882a593Smuzhiyun 		break;
635*4882a593Smuzhiyun 	}
636*4882a593Smuzhiyun 	debug("   - returning %d\n", inc);
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	return inc;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun 
h_cmp_region(const void * v1,const void * v2)641*4882a593Smuzhiyun static int h_cmp_region(const void *v1, const void *v2)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun 	const struct fdt_region *region1 = v1, *region2 = v2;
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	return region1->offset - region2->offset;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun 
fdtgrep_find_regions(const void * fdt,int (* include_func)(void * priv,const void * fdt,int offset,int type,const char * data,int size),struct display_info * disp,struct fdt_region * region,int max_regions,char * path,int path_len,int flags)648*4882a593Smuzhiyun static int fdtgrep_find_regions(const void *fdt,
649*4882a593Smuzhiyun 		int (*include_func)(void *priv, const void *fdt, int offset,
650*4882a593Smuzhiyun 				 int type, const char *data, int size),
651*4882a593Smuzhiyun 		struct display_info *disp, struct fdt_region *region,
652*4882a593Smuzhiyun 		int max_regions, char *path, int path_len, int flags)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun 	struct fdt_region_state state;
655*4882a593Smuzhiyun 	int count;
656*4882a593Smuzhiyun 	int ret;
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	count = 0;
659*4882a593Smuzhiyun 	ret = fdt_first_region(fdt, include_func, disp,
660*4882a593Smuzhiyun 			&region[count++], path, path_len,
661*4882a593Smuzhiyun 			disp->flags, &state);
662*4882a593Smuzhiyun 	while (ret == 0) {
663*4882a593Smuzhiyun 		ret = fdt_next_region(fdt, include_func, disp,
664*4882a593Smuzhiyun 				count < max_regions ? &region[count] : NULL,
665*4882a593Smuzhiyun 				path, path_len, disp->flags, &state);
666*4882a593Smuzhiyun 		if (!ret)
667*4882a593Smuzhiyun 			count++;
668*4882a593Smuzhiyun 	}
669*4882a593Smuzhiyun 	if (ret && ret != -FDT_ERR_NOTFOUND)
670*4882a593Smuzhiyun 		return ret;
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	/* Find all the aliases and add those regions back in */
673*4882a593Smuzhiyun 	if (disp->add_aliases && count < max_regions) {
674*4882a593Smuzhiyun 		int new_count;
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 		new_count = fdt_add_alias_regions(fdt, region, count,
677*4882a593Smuzhiyun 						  max_regions, &state);
678*4882a593Smuzhiyun 		if (new_count == -FDT_ERR_NOTFOUND) {
679*4882a593Smuzhiyun 			/* No alias node found */
680*4882a593Smuzhiyun 		} else if (new_count < 0) {
681*4882a593Smuzhiyun 			return new_count;
682*4882a593Smuzhiyun 		} else if (new_count <= max_regions) {
683*4882a593Smuzhiyun 			/*
684*4882a593Smuzhiyun 			* The alias regions will now be at the end of the list.
685*4882a593Smuzhiyun 			* Sort the regions by offset to get things into the
686*4882a593Smuzhiyun 			* right order
687*4882a593Smuzhiyun 			*/
688*4882a593Smuzhiyun 			count = new_count;
689*4882a593Smuzhiyun 			qsort(region, count, sizeof(struct fdt_region),
690*4882a593Smuzhiyun 			      h_cmp_region);
691*4882a593Smuzhiyun 		}
692*4882a593Smuzhiyun 	}
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	return count;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun 
utilfdt_read_err_len(const char * filename,char ** buffp,off_t * len)697*4882a593Smuzhiyun int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
698*4882a593Smuzhiyun {
699*4882a593Smuzhiyun 	int fd = 0;	/* assume stdin */
700*4882a593Smuzhiyun 	char *buf = NULL;
701*4882a593Smuzhiyun 	off_t bufsize = 1024, offset = 0;
702*4882a593Smuzhiyun 	int ret = 0;
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 	*buffp = NULL;
705*4882a593Smuzhiyun 	if (strcmp(filename, "-") != 0) {
706*4882a593Smuzhiyun 		fd = open(filename, O_RDONLY);
707*4882a593Smuzhiyun 		if (fd < 0)
708*4882a593Smuzhiyun 			return errno;
709*4882a593Smuzhiyun 	}
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	/* Loop until we have read everything */
712*4882a593Smuzhiyun 	buf = malloc(bufsize);
713*4882a593Smuzhiyun 	if (!buf)
714*4882a593Smuzhiyun 		return -ENOMEM;
715*4882a593Smuzhiyun 	do {
716*4882a593Smuzhiyun 		/* Expand the buffer to hold the next chunk */
717*4882a593Smuzhiyun 		if (offset == bufsize) {
718*4882a593Smuzhiyun 			bufsize *= 2;
719*4882a593Smuzhiyun 			buf = realloc(buf, bufsize);
720*4882a593Smuzhiyun 			if (!buf)
721*4882a593Smuzhiyun 				return -ENOMEM;
722*4882a593Smuzhiyun 		}
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 		ret = read(fd, &buf[offset], bufsize - offset);
725*4882a593Smuzhiyun 		if (ret < 0) {
726*4882a593Smuzhiyun 			ret = errno;
727*4882a593Smuzhiyun 			break;
728*4882a593Smuzhiyun 		}
729*4882a593Smuzhiyun 		offset += ret;
730*4882a593Smuzhiyun 	} while (ret != 0);
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	/* Clean up, including closing stdin; return errno on error */
733*4882a593Smuzhiyun 	close(fd);
734*4882a593Smuzhiyun 	if (ret)
735*4882a593Smuzhiyun 		free(buf);
736*4882a593Smuzhiyun 	else
737*4882a593Smuzhiyun 		*buffp = buf;
738*4882a593Smuzhiyun 	*len = bufsize;
739*4882a593Smuzhiyun 	return ret;
740*4882a593Smuzhiyun }
741*4882a593Smuzhiyun 
utilfdt_read_err(const char * filename,char ** buffp)742*4882a593Smuzhiyun int utilfdt_read_err(const char *filename, char **buffp)
743*4882a593Smuzhiyun {
744*4882a593Smuzhiyun 	off_t len;
745*4882a593Smuzhiyun 	return utilfdt_read_err_len(filename, buffp, &len);
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun 
utilfdt_read_len(const char * filename,off_t * len)748*4882a593Smuzhiyun char *utilfdt_read_len(const char *filename, off_t *len)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun 	char *buff;
751*4882a593Smuzhiyun 	int ret = utilfdt_read_err_len(filename, &buff, len);
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	if (ret) {
754*4882a593Smuzhiyun 		fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
755*4882a593Smuzhiyun 			strerror(ret));
756*4882a593Smuzhiyun 		return NULL;
757*4882a593Smuzhiyun 	}
758*4882a593Smuzhiyun 	/* Successful read */
759*4882a593Smuzhiyun 	return buff;
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun 
utilfdt_read(const char * filename)762*4882a593Smuzhiyun char *utilfdt_read(const char *filename)
763*4882a593Smuzhiyun {
764*4882a593Smuzhiyun 	off_t len;
765*4882a593Smuzhiyun 	return utilfdt_read_len(filename, &len);
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun /**
769*4882a593Smuzhiyun  * Run the main fdtgrep operation, given a filename and valid arguments
770*4882a593Smuzhiyun  *
771*4882a593Smuzhiyun  * @param disp		Display information / options
772*4882a593Smuzhiyun  * @param filename	Filename of blob file
773*4882a593Smuzhiyun  * @param return 0 if ok, -ve on error
774*4882a593Smuzhiyun  */
do_fdtgrep(struct display_info * disp,const char * filename)775*4882a593Smuzhiyun static int do_fdtgrep(struct display_info *disp, const char *filename)
776*4882a593Smuzhiyun {
777*4882a593Smuzhiyun 	struct fdt_region *region;
778*4882a593Smuzhiyun 	int max_regions;
779*4882a593Smuzhiyun 	int count = 100;
780*4882a593Smuzhiyun 	char path[1024];
781*4882a593Smuzhiyun 	char *blob;
782*4882a593Smuzhiyun 	int i, ret;
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	blob = utilfdt_read(filename);
785*4882a593Smuzhiyun 	if (!blob)
786*4882a593Smuzhiyun 		return -1;
787*4882a593Smuzhiyun 	ret = fdt_check_header(blob);
788*4882a593Smuzhiyun 	if (ret) {
789*4882a593Smuzhiyun 		fprintf(stderr, "Error: %s\n", fdt_strerror(ret));
790*4882a593Smuzhiyun 		return ret;
791*4882a593Smuzhiyun 	}
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	/* Allow old files, but they are untested */
794*4882a593Smuzhiyun 	if (fdt_version(blob) < 17 && disp->value_head) {
795*4882a593Smuzhiyun 		fprintf(stderr,
796*4882a593Smuzhiyun 			"Warning: fdtgrep does not fully support version %d files\n",
797*4882a593Smuzhiyun 			fdt_version(blob));
798*4882a593Smuzhiyun 	}
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	/*
801*4882a593Smuzhiyun 	 * We do two passes, since we don't know how many regions we need.
802*4882a593Smuzhiyun 	 * The first pass will count the regions, but if it is too many,
803*4882a593Smuzhiyun 	 * we do another pass to actually record them.
804*4882a593Smuzhiyun 	 */
805*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
806*4882a593Smuzhiyun 		region = malloc(count * sizeof(struct fdt_region));
807*4882a593Smuzhiyun 		if (!region) {
808*4882a593Smuzhiyun 			fprintf(stderr, "Out of memory for %d regions\n",
809*4882a593Smuzhiyun 				count);
810*4882a593Smuzhiyun 			return -1;
811*4882a593Smuzhiyun 		}
812*4882a593Smuzhiyun 		max_regions = count;
813*4882a593Smuzhiyun 		count = fdtgrep_find_regions(blob,
814*4882a593Smuzhiyun 				h_include, disp,
815*4882a593Smuzhiyun 				region, max_regions, path, sizeof(path),
816*4882a593Smuzhiyun 				disp->flags);
817*4882a593Smuzhiyun 		if (count < 0) {
818*4882a593Smuzhiyun 			report_error("fdt_find_regions", count);
819*4882a593Smuzhiyun 			return -1;
820*4882a593Smuzhiyun 		}
821*4882a593Smuzhiyun 		if (count <= max_regions)
822*4882a593Smuzhiyun 			break;
823*4882a593Smuzhiyun 		free(region);
824*4882a593Smuzhiyun 	}
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 	/* Optionally print a list of regions */
827*4882a593Smuzhiyun 	if (disp->region_list)
828*4882a593Smuzhiyun 		show_region_list(region, count);
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	/* Output either source .dts or binary .dtb */
831*4882a593Smuzhiyun 	if (disp->output == OUT_DTS) {
832*4882a593Smuzhiyun 		ret = display_fdt_by_regions(disp, blob, region, count);
833*4882a593Smuzhiyun 	} else {
834*4882a593Smuzhiyun 		void *fdt;
835*4882a593Smuzhiyun 		/* Allow reserved memory section to expand slightly */
836*4882a593Smuzhiyun 		int size = fdt_totalsize(blob) + 16;
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun 		fdt = malloc(size);
839*4882a593Smuzhiyun 		if (!fdt) {
840*4882a593Smuzhiyun 			fprintf(stderr, "Out_of_memory\n");
841*4882a593Smuzhiyun 			ret = -1;
842*4882a593Smuzhiyun 			goto err;
843*4882a593Smuzhiyun 		}
844*4882a593Smuzhiyun 		size = dump_fdt_regions(disp, blob, region, count, fdt);
845*4882a593Smuzhiyun 		if (disp->remove_strings) {
846*4882a593Smuzhiyun 			void *out;
847*4882a593Smuzhiyun 
848*4882a593Smuzhiyun 			out = malloc(size);
849*4882a593Smuzhiyun 			if (!out) {
850*4882a593Smuzhiyun 				fprintf(stderr, "Out_of_memory\n");
851*4882a593Smuzhiyun 				ret = -1;
852*4882a593Smuzhiyun 				goto err;
853*4882a593Smuzhiyun 			}
854*4882a593Smuzhiyun 			ret = fdt_remove_unused_strings(fdt, out);
855*4882a593Smuzhiyun 			if (ret < 0) {
856*4882a593Smuzhiyun 				fprintf(stderr,
857*4882a593Smuzhiyun 					"Failed to remove unused strings: err=%d\n",
858*4882a593Smuzhiyun 					ret);
859*4882a593Smuzhiyun 				goto err;
860*4882a593Smuzhiyun 			}
861*4882a593Smuzhiyun 			free(fdt);
862*4882a593Smuzhiyun 			fdt = out;
863*4882a593Smuzhiyun 			ret = fdt_pack(fdt);
864*4882a593Smuzhiyun 			if (ret < 0) {
865*4882a593Smuzhiyun 				fprintf(stderr, "Failed to pack: err=%d\n",
866*4882a593Smuzhiyun 					ret);
867*4882a593Smuzhiyun 				goto err;
868*4882a593Smuzhiyun 			}
869*4882a593Smuzhiyun 			size = fdt_totalsize(fdt);
870*4882a593Smuzhiyun 		}
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun 		if (size != fwrite(fdt, 1, size, disp->fout)) {
873*4882a593Smuzhiyun 			fprintf(stderr, "Write failure, %d bytes\n", size);
874*4882a593Smuzhiyun 			free(fdt);
875*4882a593Smuzhiyun 			ret = 1;
876*4882a593Smuzhiyun 			goto err;
877*4882a593Smuzhiyun 		}
878*4882a593Smuzhiyun 		free(fdt);
879*4882a593Smuzhiyun 	}
880*4882a593Smuzhiyun err:
881*4882a593Smuzhiyun 	free(blob);
882*4882a593Smuzhiyun 	free(region);
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 	return ret;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun static const char usage_synopsis[] =
888*4882a593Smuzhiyun 	"fdtgrep - extract portions from device tree\n"
889*4882a593Smuzhiyun 	"\n"
890*4882a593Smuzhiyun 	"Usage:\n"
891*4882a593Smuzhiyun 	"	fdtgrep <options> <dt file>|-\n\n"
892*4882a593Smuzhiyun 	"Output formats are:\n"
893*4882a593Smuzhiyun 	"\tdts - device tree soure text\n"
894*4882a593Smuzhiyun 	"\tdtb - device tree blob (sets -Hmt automatically)\n"
895*4882a593Smuzhiyun 	"\tbin - device tree fragment (may not be a valid .dtb)";
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun /* Helper for usage_short_opts string constant */
898*4882a593Smuzhiyun #define USAGE_COMMON_SHORT_OPTS "hV"
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun /* Helper for aligning long_opts array */
901*4882a593Smuzhiyun #define a_argument required_argument
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun /* Helper for usage_long_opts option array */
904*4882a593Smuzhiyun #define USAGE_COMMON_LONG_OPTS \
905*4882a593Smuzhiyun 	{"help",      no_argument, NULL, 'h'}, \
906*4882a593Smuzhiyun 	{"version",   no_argument, NULL, 'V'}, \
907*4882a593Smuzhiyun 	{NULL,        no_argument, NULL, 0x0}
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun /* Helper for usage_opts_help array */
910*4882a593Smuzhiyun #define USAGE_COMMON_OPTS_HELP \
911*4882a593Smuzhiyun 	"Print this help and exit", \
912*4882a593Smuzhiyun 	"Print version and exit", \
913*4882a593Smuzhiyun 	NULL
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun /* Helper for getopt case statements */
916*4882a593Smuzhiyun #define case_USAGE_COMMON_FLAGS \
917*4882a593Smuzhiyun 	case 'h': usage(NULL); \
918*4882a593Smuzhiyun 	case 'V': util_version(); \
919*4882a593Smuzhiyun 	case '?': usage("unknown option");
920*4882a593Smuzhiyun 
921*4882a593Smuzhiyun static const char usage_short_opts[] =
922*4882a593Smuzhiyun 		"haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTv"
923*4882a593Smuzhiyun 		USAGE_COMMON_SHORT_OPTS;
924*4882a593Smuzhiyun static struct option const usage_long_opts[] = {
925*4882a593Smuzhiyun 	{"show-address",	no_argument, NULL, 'a'},
926*4882a593Smuzhiyun 	{"colour",		no_argument, NULL, 'A'},
927*4882a593Smuzhiyun 	{"include-node-with-prop", a_argument, NULL, 'b'},
928*4882a593Smuzhiyun 	{"include-compat",	a_argument, NULL, 'c'},
929*4882a593Smuzhiyun 	{"exclude-compat",	a_argument, NULL, 'C'},
930*4882a593Smuzhiyun 	{"diff",		no_argument, NULL, 'd'},
931*4882a593Smuzhiyun 	{"enter-node",		no_argument, NULL, 'e'},
932*4882a593Smuzhiyun 	{"show-offset",		no_argument, NULL, 'f'},
933*4882a593Smuzhiyun 	{"include-match",	a_argument, NULL, 'g'},
934*4882a593Smuzhiyun 	{"exclude-match",	a_argument, NULL, 'G'},
935*4882a593Smuzhiyun 	{"show-header",		no_argument, NULL, 'H'},
936*4882a593Smuzhiyun 	{"show-version",	no_argument, NULL, 'I'},
937*4882a593Smuzhiyun 	{"list-regions",	no_argument, NULL, 'l'},
938*4882a593Smuzhiyun 	{"list-strings",	no_argument, NULL, 'L'},
939*4882a593Smuzhiyun 	{"include-mem",		no_argument, NULL, 'm'},
940*4882a593Smuzhiyun 	{"include-node",	a_argument, NULL, 'n'},
941*4882a593Smuzhiyun 	{"exclude-node",	a_argument, NULL, 'N'},
942*4882a593Smuzhiyun 	{"include-prop",	a_argument, NULL, 'p'},
943*4882a593Smuzhiyun 	{"exclude-prop",	a_argument, NULL, 'P'},
944*4882a593Smuzhiyun 	{"remove-strings",	no_argument, NULL, 'r'},
945*4882a593Smuzhiyun 	{"include-root",	no_argument, NULL, 'R'},
946*4882a593Smuzhiyun 	{"show-subnodes",	no_argument, NULL, 's'},
947*4882a593Smuzhiyun 	{"skip-supernodes",	no_argument, NULL, 'S'},
948*4882a593Smuzhiyun 	{"show-stringtab",	no_argument, NULL, 't'},
949*4882a593Smuzhiyun 	{"show-aliases",	no_argument, NULL, 'T'},
950*4882a593Smuzhiyun 	{"out",			a_argument, NULL, 'o'},
951*4882a593Smuzhiyun 	{"out-format",		a_argument, NULL, 'O'},
952*4882a593Smuzhiyun 	{"invert-match",	no_argument, NULL, 'v'},
953*4882a593Smuzhiyun 	USAGE_COMMON_LONG_OPTS,
954*4882a593Smuzhiyun };
955*4882a593Smuzhiyun static const char * const usage_opts_help[] = {
956*4882a593Smuzhiyun 	"Display address",
957*4882a593Smuzhiyun 	"Show all nodes/tags, colour those that match",
958*4882a593Smuzhiyun 	"Include contains containing property",
959*4882a593Smuzhiyun 	"Compatible nodes to include in grep",
960*4882a593Smuzhiyun 	"Compatible nodes to exclude in grep",
961*4882a593Smuzhiyun 	"Diff: Mark matching nodes with +, others with -",
962*4882a593Smuzhiyun 	"Enter direct subnode names of matching nodes",
963*4882a593Smuzhiyun 	"Display offset",
964*4882a593Smuzhiyun 	"Node/property/compatible string to include in grep",
965*4882a593Smuzhiyun 	"Node/property/compatible string to exclude in grep",
966*4882a593Smuzhiyun 	"Output a header",
967*4882a593Smuzhiyun 	"Put \"/dts-v1/;\" on first line of dts output",
968*4882a593Smuzhiyun 	"Output a region list",
969*4882a593Smuzhiyun 	"List strings in string table",
970*4882a593Smuzhiyun 	"Include mem_rsvmap section in binary output",
971*4882a593Smuzhiyun 	"Node to include in grep",
972*4882a593Smuzhiyun 	"Node to exclude in grep",
973*4882a593Smuzhiyun 	"Property to include in grep",
974*4882a593Smuzhiyun 	"Property to exclude in grep",
975*4882a593Smuzhiyun 	"Remove unused strings from string table",
976*4882a593Smuzhiyun 	"Include root node and all properties",
977*4882a593Smuzhiyun 	"Show all subnodes matching nodes",
978*4882a593Smuzhiyun 	"Don't include supernodes of matching nodes",
979*4882a593Smuzhiyun 	"Include string table in binary output",
980*4882a593Smuzhiyun 	"Include matching aliases in output",
981*4882a593Smuzhiyun 	"-o <output file>",
982*4882a593Smuzhiyun 	"-O <output format>",
983*4882a593Smuzhiyun 	"Invert the sense of matching (select non-matching lines)",
984*4882a593Smuzhiyun 	USAGE_COMMON_OPTS_HELP
985*4882a593Smuzhiyun };
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun /**
988*4882a593Smuzhiyun  * Call getopt_long() with standard options
989*4882a593Smuzhiyun  *
990*4882a593Smuzhiyun  * Since all util code runs getopt in the same way, provide a helper.
991*4882a593Smuzhiyun  */
992*4882a593Smuzhiyun #define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
993*4882a593Smuzhiyun 				       usage_long_opts, NULL)
994*4882a593Smuzhiyun 
util_usage(const char * errmsg,const char * synopsis,const char * short_opts,struct option const long_opts[],const char * const opts_help[])995*4882a593Smuzhiyun void util_usage(const char *errmsg, const char *synopsis,
996*4882a593Smuzhiyun 		const char *short_opts, struct option const long_opts[],
997*4882a593Smuzhiyun 		const char * const opts_help[])
998*4882a593Smuzhiyun {
999*4882a593Smuzhiyun 	FILE *fp = errmsg ? stderr : stdout;
1000*4882a593Smuzhiyun 	const char a_arg[] = "<arg>";
1001*4882a593Smuzhiyun 	size_t a_arg_len = strlen(a_arg) + 1;
1002*4882a593Smuzhiyun 	size_t i;
1003*4882a593Smuzhiyun 	int optlen;
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun 	fprintf(fp,
1006*4882a593Smuzhiyun 		"Usage: %s\n"
1007*4882a593Smuzhiyun 		"\n"
1008*4882a593Smuzhiyun 		"Options: -[%s]\n", synopsis, short_opts);
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 	/* prescan the --long opt length to auto-align */
1011*4882a593Smuzhiyun 	optlen = 0;
1012*4882a593Smuzhiyun 	for (i = 0; long_opts[i].name; ++i) {
1013*4882a593Smuzhiyun 		/* +1 is for space between --opt and help text */
1014*4882a593Smuzhiyun 		int l = strlen(long_opts[i].name) + 1;
1015*4882a593Smuzhiyun 		if (long_opts[i].has_arg == a_argument)
1016*4882a593Smuzhiyun 			l += a_arg_len;
1017*4882a593Smuzhiyun 		if (optlen < l)
1018*4882a593Smuzhiyun 			optlen = l;
1019*4882a593Smuzhiyun 	}
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun 	for (i = 0; long_opts[i].name; ++i) {
1022*4882a593Smuzhiyun 		/* helps when adding new applets or options */
1023*4882a593Smuzhiyun 		assert(opts_help[i] != NULL);
1024*4882a593Smuzhiyun 
1025*4882a593Smuzhiyun 		/* first output the short flag if it has one */
1026*4882a593Smuzhiyun 		if (long_opts[i].val > '~')
1027*4882a593Smuzhiyun 			fprintf(fp, "      ");
1028*4882a593Smuzhiyun 		else
1029*4882a593Smuzhiyun 			fprintf(fp, "  -%c, ", long_opts[i].val);
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 		/* then the long flag */
1032*4882a593Smuzhiyun 		if (long_opts[i].has_arg == no_argument) {
1033*4882a593Smuzhiyun 			fprintf(fp, "--%-*s", optlen, long_opts[i].name);
1034*4882a593Smuzhiyun 		} else {
1035*4882a593Smuzhiyun 			fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
1036*4882a593Smuzhiyun 				(int)(optlen - strlen(long_opts[i].name) -
1037*4882a593Smuzhiyun 				a_arg_len), "");
1038*4882a593Smuzhiyun 		}
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun 		/* finally the help text */
1041*4882a593Smuzhiyun 		fprintf(fp, "%s\n", opts_help[i]);
1042*4882a593Smuzhiyun 	}
1043*4882a593Smuzhiyun 
1044*4882a593Smuzhiyun 	if (errmsg) {
1045*4882a593Smuzhiyun 		fprintf(fp, "\nError: %s\n", errmsg);
1046*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
1047*4882a593Smuzhiyun 	} else {
1048*4882a593Smuzhiyun 		exit(EXIT_SUCCESS);
1049*4882a593Smuzhiyun 	}
1050*4882a593Smuzhiyun }
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun /**
1053*4882a593Smuzhiyun  * Show usage and exit
1054*4882a593Smuzhiyun  *
1055*4882a593Smuzhiyun  * If you name all your usage variables with usage_xxx, then you can call this
1056*4882a593Smuzhiyun  * help macro rather than expanding all arguments yourself.
1057*4882a593Smuzhiyun  *
1058*4882a593Smuzhiyun  * @param errmsg	If non-NULL, an error message to display
1059*4882a593Smuzhiyun  */
1060*4882a593Smuzhiyun #define usage(errmsg) \
1061*4882a593Smuzhiyun 	util_usage(errmsg, usage_synopsis, usage_short_opts, \
1062*4882a593Smuzhiyun 		   usage_long_opts, usage_opts_help)
1063*4882a593Smuzhiyun 
util_version(void)1064*4882a593Smuzhiyun void util_version(void)
1065*4882a593Smuzhiyun {
1066*4882a593Smuzhiyun 	printf("Version: %s\n", "(U-Boot)");
1067*4882a593Smuzhiyun 	exit(0);
1068*4882a593Smuzhiyun }
1069*4882a593Smuzhiyun 
scan_args(struct display_info * disp,int argc,char * argv[])1070*4882a593Smuzhiyun static void scan_args(struct display_info *disp, int argc, char *argv[])
1071*4882a593Smuzhiyun {
1072*4882a593Smuzhiyun 	int opt;
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 	while ((opt = util_getopt_long()) != EOF) {
1075*4882a593Smuzhiyun 		int type = 0;
1076*4882a593Smuzhiyun 		int inc = 1;
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun 		switch (opt) {
1079*4882a593Smuzhiyun 		case_USAGE_COMMON_FLAGS
1080*4882a593Smuzhiyun 		case 'a':
1081*4882a593Smuzhiyun 			disp->show_addr = 1;
1082*4882a593Smuzhiyun 			break;
1083*4882a593Smuzhiyun 		case 'A':
1084*4882a593Smuzhiyun 			disp->all = 1;
1085*4882a593Smuzhiyun 			break;
1086*4882a593Smuzhiyun 		case 'b':
1087*4882a593Smuzhiyun 			type = FDT_NODE_HAS_PROP;
1088*4882a593Smuzhiyun 			break;
1089*4882a593Smuzhiyun 		case 'C':
1090*4882a593Smuzhiyun 			inc = 0;
1091*4882a593Smuzhiyun 			/* no break */
1092*4882a593Smuzhiyun 		case 'c':
1093*4882a593Smuzhiyun 			type = FDT_IS_COMPAT;
1094*4882a593Smuzhiyun 			break;
1095*4882a593Smuzhiyun 		case 'd':
1096*4882a593Smuzhiyun 			disp->diff = 1;
1097*4882a593Smuzhiyun 			break;
1098*4882a593Smuzhiyun 		case 'e':
1099*4882a593Smuzhiyun 			disp->flags |= FDT_REG_DIRECT_SUBNODES;
1100*4882a593Smuzhiyun 			break;
1101*4882a593Smuzhiyun 		case 'f':
1102*4882a593Smuzhiyun 			disp->show_offset = 1;
1103*4882a593Smuzhiyun 			break;
1104*4882a593Smuzhiyun 		case 'G':
1105*4882a593Smuzhiyun 			inc = 0;
1106*4882a593Smuzhiyun 			/* no break */
1107*4882a593Smuzhiyun 		case 'g':
1108*4882a593Smuzhiyun 			type = FDT_ANY_GLOBAL;
1109*4882a593Smuzhiyun 			break;
1110*4882a593Smuzhiyun 		case 'H':
1111*4882a593Smuzhiyun 			disp->header = 1;
1112*4882a593Smuzhiyun 			break;
1113*4882a593Smuzhiyun 		case 'l':
1114*4882a593Smuzhiyun 			disp->region_list = 1;
1115*4882a593Smuzhiyun 			break;
1116*4882a593Smuzhiyun 		case 'L':
1117*4882a593Smuzhiyun 			disp->list_strings = 1;
1118*4882a593Smuzhiyun 			break;
1119*4882a593Smuzhiyun 		case 'm':
1120*4882a593Smuzhiyun 			disp->flags |= FDT_REG_ADD_MEM_RSVMAP;
1121*4882a593Smuzhiyun 			break;
1122*4882a593Smuzhiyun 		case 'N':
1123*4882a593Smuzhiyun 			inc = 0;
1124*4882a593Smuzhiyun 			/* no break */
1125*4882a593Smuzhiyun 		case 'n':
1126*4882a593Smuzhiyun 			type = FDT_IS_NODE;
1127*4882a593Smuzhiyun 			break;
1128*4882a593Smuzhiyun 		case 'o':
1129*4882a593Smuzhiyun 			disp->output_fname = optarg;
1130*4882a593Smuzhiyun 			break;
1131*4882a593Smuzhiyun 		case 'O':
1132*4882a593Smuzhiyun 			if (!strcmp(optarg, "dtb"))
1133*4882a593Smuzhiyun 				disp->output = OUT_DTB;
1134*4882a593Smuzhiyun 			else if (!strcmp(optarg, "dts"))
1135*4882a593Smuzhiyun 				disp->output = OUT_DTS;
1136*4882a593Smuzhiyun 			else if (!strcmp(optarg, "bin"))
1137*4882a593Smuzhiyun 				disp->output = OUT_BIN;
1138*4882a593Smuzhiyun 			else
1139*4882a593Smuzhiyun 				usage("Unknown output format");
1140*4882a593Smuzhiyun 			break;
1141*4882a593Smuzhiyun 		case 'P':
1142*4882a593Smuzhiyun 			inc = 0;
1143*4882a593Smuzhiyun 			/* no break */
1144*4882a593Smuzhiyun 		case 'p':
1145*4882a593Smuzhiyun 			type = FDT_IS_PROP;
1146*4882a593Smuzhiyun 			break;
1147*4882a593Smuzhiyun 		case 'r':
1148*4882a593Smuzhiyun 			disp->remove_strings = 1;
1149*4882a593Smuzhiyun 			break;
1150*4882a593Smuzhiyun 		case 'R':
1151*4882a593Smuzhiyun 			disp->include_root = 1;
1152*4882a593Smuzhiyun 			break;
1153*4882a593Smuzhiyun 		case 's':
1154*4882a593Smuzhiyun 			disp->flags |= FDT_REG_ALL_SUBNODES;
1155*4882a593Smuzhiyun 			break;
1156*4882a593Smuzhiyun 		case 'S':
1157*4882a593Smuzhiyun 			disp->flags &= ~FDT_REG_SUPERNODES;
1158*4882a593Smuzhiyun 			break;
1159*4882a593Smuzhiyun 		case 't':
1160*4882a593Smuzhiyun 			disp->flags |= FDT_REG_ADD_STRING_TAB;
1161*4882a593Smuzhiyun 			break;
1162*4882a593Smuzhiyun 		case 'T':
1163*4882a593Smuzhiyun 			disp->add_aliases = 1;
1164*4882a593Smuzhiyun 			break;
1165*4882a593Smuzhiyun 		case 'v':
1166*4882a593Smuzhiyun 			disp->invert = 1;
1167*4882a593Smuzhiyun 			break;
1168*4882a593Smuzhiyun 		case 'I':
1169*4882a593Smuzhiyun 			disp->show_dts_version = 1;
1170*4882a593Smuzhiyun 			break;
1171*4882a593Smuzhiyun 		}
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun 		if (type && value_add(disp, &disp->value_head, type, inc,
1174*4882a593Smuzhiyun 				      optarg))
1175*4882a593Smuzhiyun 			usage("Cannot add value");
1176*4882a593Smuzhiyun 	}
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 	if (disp->invert && disp->types_exc)
1179*4882a593Smuzhiyun 		usage("-v has no meaning when used with 'exclude' conditions");
1180*4882a593Smuzhiyun }
1181*4882a593Smuzhiyun 
main(int argc,char * argv[])1182*4882a593Smuzhiyun int main(int argc, char *argv[])
1183*4882a593Smuzhiyun {
1184*4882a593Smuzhiyun 	char *filename = NULL;
1185*4882a593Smuzhiyun 	struct display_info disp;
1186*4882a593Smuzhiyun 	int ret;
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun 	/* set defaults */
1189*4882a593Smuzhiyun 	memset(&disp, '\0', sizeof(disp));
1190*4882a593Smuzhiyun 	disp.flags = FDT_REG_SUPERNODES;	/* Default flags */
1191*4882a593Smuzhiyun 
1192*4882a593Smuzhiyun 	scan_args(&disp, argc, argv);
1193*4882a593Smuzhiyun 
1194*4882a593Smuzhiyun 	/* Show matched lines in colour if we can */
1195*4882a593Smuzhiyun 	disp.colour = disp.all && isatty(0);
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun 	/* Any additional arguments can match anything, just like -g */
1198*4882a593Smuzhiyun 	while (optind < argc - 1) {
1199*4882a593Smuzhiyun 		if (value_add(&disp, &disp.value_head, FDT_IS_ANY, 1,
1200*4882a593Smuzhiyun 			      argv[optind++]))
1201*4882a593Smuzhiyun 			usage("Cannot add value");
1202*4882a593Smuzhiyun 	}
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 	if (optind < argc)
1205*4882a593Smuzhiyun 		filename = argv[optind++];
1206*4882a593Smuzhiyun 	if (!filename)
1207*4882a593Smuzhiyun 		usage("Missing filename");
1208*4882a593Smuzhiyun 
1209*4882a593Smuzhiyun 	/* If a valid .dtb is required, set flags to ensure we get one */
1210*4882a593Smuzhiyun 	if (disp.output == OUT_DTB) {
1211*4882a593Smuzhiyun 		disp.header = 1;
1212*4882a593Smuzhiyun 		disp.flags |= FDT_REG_ADD_MEM_RSVMAP | FDT_REG_ADD_STRING_TAB;
1213*4882a593Smuzhiyun 	}
1214*4882a593Smuzhiyun 
1215*4882a593Smuzhiyun 	if (disp.output_fname) {
1216*4882a593Smuzhiyun 		disp.fout = fopen(disp.output_fname, "w");
1217*4882a593Smuzhiyun 		if (!disp.fout)
1218*4882a593Smuzhiyun 			usage("Cannot open output file");
1219*4882a593Smuzhiyun 	} else {
1220*4882a593Smuzhiyun 		disp.fout = stdout;
1221*4882a593Smuzhiyun 	}
1222*4882a593Smuzhiyun 
1223*4882a593Smuzhiyun 	/* Run the grep and output the results */
1224*4882a593Smuzhiyun 	ret = do_fdtgrep(&disp, filename);
1225*4882a593Smuzhiyun 	if (disp.output_fname)
1226*4882a593Smuzhiyun 		fclose(disp.fout);
1227*4882a593Smuzhiyun 	if (ret)
1228*4882a593Smuzhiyun 		return 1;
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 	return 0;
1231*4882a593Smuzhiyun }
1232