+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2013, Google Inc.
*
- * SPDX-License-Identifier: GPL-2.0+
- *
* Perform a grep of an FDT either displaying the source subset or producing
* a new .dtb subset which can be used as required.
*/
#include <assert.h>
#include <ctype.h>
+#include <errno.h>
#include <getopt.h>
+#include <fcntl.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <fdt_region.h>
-#include <../include/libfdt.h>
-#include <libfdt_internal.h>
+#include "fdt_host.h"
+#include "libfdt_internal.h"
/* Define DEBUG to get some debugging output on stderr */
#ifdef DEBUG
}
str = strdup(str);
+ if (!str)
+ goto err_mem;
node = malloc(sizeof(*node));
- if (!str || !node) {
- fprintf(stderr, "Out of memory\n");
- return -1;
- }
+ if (!node)
+ goto err_mem;
node->next = *headp;
node->type = type;
node->include = include;
*headp = node;
return 0;
+err_mem:
+ fprintf(stderr, "Out of memory\n");
+ return -1;
}
static bool util_is_printable_string(const void *data, int len)
} else {
printf(" = [");
for (i = 0; i < len; i++)
- printf("%02x%s", *p++, i < len - 1 ? " " : "");
+ printf("%02x%s", (unsigned char)*p++, i < len - 1 ? " " : "");
printf("]");
}
}
* The output of this function may or may not be a valid FDT. To ensure it
* is, these disp->flags must be set:
*
- * FDT_REG_SUPERNODES: ensures that subnodes are preceeded by their
+ * FDT_REG_SUPERNODES: ensures that subnodes are preceded by their
* parents. Without this option, fragments of subnode data may be
* output without the supernodes above them. This is useful for
* hashing but cannot produce a valid FDT.
* return 1 at the first match. For exclusive conditions, we must
* check that there are no matches.
*/
- for (val = disp->value_head; val; val = val->next) {
- if (!(type & val->type))
- continue;
- match = fdt_stringlist_contains(data, size, val->string);
- debug(" - val->type=%x, str='%s', match=%d\n",
- val->type, val->string, match);
- if (match && val->include) {
- debug(" - match inc %s\n", val->string);
- return 1;
+ if (data) {
+ for (val = disp->value_head; val; val = val->next) {
+ if (!(type & val->type))
+ continue;
+ match = fdt_stringlist_contains(data, size,
+ val->string);
+ debug(" - val->type=%x, str='%s', match=%d\n",
+ val->type, val->string, match);
+ if (match && val->include) {
+ debug(" - match inc %s\n", val->string);
+ return 1;
+ }
+ if (match)
+ none_match &= ~val->type;
}
- if (match)
- none_match &= ~val->type;
}
/*
if (!ret)
count++;
}
+ if (ret && ret != -FDT_ERR_NOTFOUND)
+ return ret;
/* Find all the aliases and add those regions back in */
if (disp->add_aliases && count < max_regions) {
new_count = fdt_add_alias_regions(fdt, region, count,
max_regions, &state);
- if (new_count <= max_regions) {
+ if (new_count == -FDT_ERR_NOTFOUND) {
+ /* No alias node found */
+ } else if (new_count < 0) {
+ return new_count;
+ } else if (new_count <= max_regions) {
/*
* The alias regions will now be at the end of the list.
* Sort the regions by offset to get things into the
}
}
- if (ret != -FDT_ERR_NOTFOUND)
- return ret;
-
return count;
}
*/
static int do_fdtgrep(struct display_info *disp, const char *filename)
{
- struct fdt_region *region;
+ struct fdt_region *region = NULL;
int max_regions;
int count = 100;
char path[1024];
* The first pass will count the regions, but if it is too many,
* we do another pass to actually record them.
*/
- for (i = 0; i < 3; i++) {
- region = malloc(count * sizeof(struct fdt_region));
+ for (i = 0; i < 2; i++) {
+ region = realloc(region, count * sizeof(struct fdt_region));
if (!region) {
fprintf(stderr, "Out of memory for %d regions\n",
count);
disp->flags);
if (count < 0) {
report_error("fdt_find_regions", count);
+ free(region);
return -1;
}
if (count <= max_regions)
break;
+ }
+ if (count > max_regions) {
free(region);
+ fprintf(stderr, "Internal error with fdtgrep_find_region()\n");
+ return -1;
}
/* Optionally print a list of regions */
/* Helper for getopt case statements */
#define case_USAGE_COMMON_FLAGS \
case 'h': usage(NULL); \
+ /* fallthrough */ \
case 'V': util_version(); \
+ /* fallthrough */ \
case '?': usage("unknown option");
static const char usage_short_opts[] =
switch (opt) {
case_USAGE_COMMON_FLAGS
+ /* fallthrough */
case 'a':
disp->show_addr = 1;
break;
break;
case 'C':
inc = 0;
- /* no break */
+ /* fallthrough */
case 'c':
type = FDT_IS_COMPAT;
break;
break;
case 'G':
inc = 0;
- /* no break */
+ /* fallthrough */
case 'g':
type = FDT_ANY_GLOBAL;
break;
break;
case 'N':
inc = 0;
- /* no break */
+ /* fallthrough */
case 'n':
type = FDT_IS_NODE;
break;
break;
case 'P':
inc = 0;
- /* no break */
+ /* fallthrough */
case 'p':
type = FDT_IS_PROP;
break;