Blame fdtget.c

Packit Service 87beb7
// SPDX-License-Identifier: GPL-2.0-or-later
Packit Service 87beb7
/*
Packit Service 87beb7
 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
Packit Service 87beb7
 *
Packit Service 87beb7
 * Portions from U-Boot cmd_fdt.c (C) Copyright 2007
Packit Service 87beb7
 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
Packit Service 87beb7
 * Based on code written by:
Packit Service 87beb7
 *   Pantelis Antoniou <pantelis.antoniou@gmail.com> and
Packit Service 87beb7
 *   Matthew McClintock <msm@freescale.com>
Packit Service 87beb7
 */
Packit Service 87beb7
Packit Service 87beb7
#include <assert.h>
Packit Service 87beb7
#include <ctype.h>
Packit Service 87beb7
#include <getopt.h>
Packit Service 87beb7
#include <stdio.h>
Packit Service 87beb7
#include <stdlib.h>
Packit Service 87beb7
#include <string.h>
Packit Service 87beb7
Packit Service 87beb7
#include <libfdt.h>
Packit Service 87beb7
Packit Service 87beb7
#include "util.h"
Packit Service 87beb7
Packit Service 87beb7
enum display_mode {
Packit Service 87beb7
	MODE_SHOW_VALUE,	/* show values for node properties */
Packit Service 87beb7
	MODE_LIST_PROPS,	/* list the properties for a node */
Packit Service 87beb7
	MODE_LIST_SUBNODES,	/* list the subnodes of a node */
Packit Service 87beb7
};
Packit Service 87beb7
Packit Service 87beb7
/* Holds information which controls our output and options */
Packit Service 87beb7
struct display_info {
Packit Service 87beb7
	int type;		/* data type (s/i/u/x or 0 for default) */
Packit Service 87beb7
	int size;		/* data size (1/2/4) */
Packit Service 87beb7
	enum display_mode mode;	/* display mode that we are using */
Packit Service 87beb7
	const char *default_val; /* default value if node/property not found */
Packit Service 87beb7
};
Packit Service 87beb7
Packit Service 87beb7
static void report_error(const char *where, int err)
Packit Service 87beb7
{
Packit Service 87beb7
	fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
Packit Service 87beb7
}
Packit Service 87beb7
Packit Service 87beb7
/**
Packit Service 87beb7
 * Shows a list of cells in the requested format
Packit Service 87beb7
 *
Packit Service 87beb7
 * @param disp		Display information / options
Packit Service 87beb7
 * @param data		Data to display
Packit Service 87beb7
 * @param len		Maximum length of buffer
Packit Service 87beb7
 * @param size		Data size to use for display (e.g. 4 for 32-bit)
Packit Service 87beb7
 * @return 0 if ok, -1 on error
Packit Service 87beb7
 */
Packit Service 87beb7
static int show_cell_list(struct display_info *disp, const char *data, int len,
Packit Service 87beb7
			  int size)
Packit Service 87beb7
{
Packit Service 87beb7
	const uint8_t *p = (const uint8_t *)data;
Packit Service 87beb7
	char fmt[3];
Packit Service 87beb7
	int value;
Packit Service 87beb7
	int i;
Packit Service 87beb7
Packit Service 87beb7
	fmt[0] = '%';
Packit Service 87beb7
	fmt[1] = disp->type ? disp->type : 'd';
Packit Service 87beb7
	fmt[2] = '\0';
Packit Service 87beb7
	for (i = 0; i < len; i += size, p += size) {
Packit Service 87beb7
		if (i)
Packit Service 87beb7
			printf(" ");
Packit Service 87beb7
		value = size == 4 ? fdt32_ld((const fdt32_t *)p) :
Packit Service 87beb7
			size == 2 ? (*p << 8) | p[1] : *p;
Packit Service 87beb7
		printf(fmt, value);
Packit Service 87beb7
	}
Packit Service 87beb7
Packit Service 87beb7
	return 0;
Packit Service 87beb7
}
Packit Service 87beb7
Packit Service 87beb7
/**
Packit Service 87beb7
 * Displays data of a given length according to selected options
Packit Service 87beb7
 *
Packit Service 87beb7
 * If a specific data type is provided in disp, then this is used. Otherwise
Packit Service 87beb7
 * we try to guess the data type / size from the contents.
Packit Service 87beb7
 *
Packit Service 87beb7
 * @param disp		Display information / options
Packit Service 87beb7
 * @param data		Data to display
Packit Service 87beb7
 * @param len		Maximum length of buffer
Packit Service 87beb7
 * @return 0 if ok, -1 if data does not match format
Packit Service 87beb7
 */
Packit Service 87beb7
static int show_data(struct display_info *disp, const char *data, int len)
Packit Service 87beb7
{
Packit Service 87beb7
	int size;
Packit Service 87beb7
	const char *s;
Packit Service 87beb7
	int is_string;
Packit Service 87beb7
Packit Service 87beb7
	/* no data, don't print */
Packit Service 87beb7
	if (len == 0)
Packit Service 87beb7
		return 0;
Packit Service 87beb7
Packit Service 87beb7
	is_string = (disp->type) == 's' ||
Packit Service 87beb7
		(!disp->type && util_is_printable_string(data, len));
Packit Service 87beb7
	if (is_string) {
Packit Service 87beb7
		if (data[len - 1] != '\0') {
Packit Service 87beb7
			fprintf(stderr, "Unterminated string\n");
Packit Service 87beb7
			return -1;
Packit Service 87beb7
		}
Packit Service 87beb7
		for (s = data; s - data < len; s += strlen(s) + 1) {
Packit Service 87beb7
			if (s != data)
Packit Service 87beb7
				printf(" ");
Packit Service 87beb7
			printf("%s", (const char *)s);
Packit Service 87beb7
		}
Packit Service 87beb7
		return 0;
Packit Service 87beb7
	}
Packit Service 87beb7
	size = disp->size;
Packit Service 87beb7
	if (size == -1) {
Packit Service 87beb7
		size = (len % 4) == 0 ? 4 : 1;
Packit Service 87beb7
	} else if (len % size) {
Packit Service 87beb7
		fprintf(stderr, "Property length must be a multiple of "
Packit Service 87beb7
				"selected data size\n");
Packit Service 87beb7
		return -1;
Packit Service 87beb7
	}
Packit Service 87beb7
Packit Service 87beb7
	return show_cell_list(disp, data, len, size);
Packit Service 87beb7
}
Packit Service 87beb7
Packit Service 87beb7
/**
Packit Service 87beb7
 * List all properties in a node, one per line.
Packit Service 87beb7
 *
Packit Service 87beb7
 * @param blob		FDT blob
Packit Service 87beb7
 * @param node		Node to display
Packit Service 87beb7
 * @return 0 if ok, or FDT_ERR... if not.
Packit Service 87beb7
 */
Packit Service 87beb7
static int list_properties(const void *blob, int node)
Packit Service 87beb7
{
Packit Service 87beb7
	const char *name;
Packit Service 87beb7
	int prop;
Packit Service 87beb7
Packit Service 87beb7
	prop = fdt_first_property_offset(blob, node);
Packit Service 87beb7
	do {
Packit Service 87beb7
		/* Stop silently when there are no more properties */
Packit Service 87beb7
		if (prop < 0)
Packit Service 87beb7
			return prop == -FDT_ERR_NOTFOUND ? 0 : prop;
Packit Service 87beb7
		fdt_getprop_by_offset(blob, prop, &name, NULL);
Packit Service 87beb7
		if (name)
Packit Service 87beb7
			puts(name);
Packit Service 87beb7
		prop = fdt_next_property_offset(blob, prop);
Packit Service 87beb7
	} while (1);
Packit Service 87beb7
}
Packit Service 87beb7
Packit Service 87beb7
#define MAX_LEVEL	32		/* how deeply nested we will go */
Packit Service 87beb7
Packit Service 87beb7
/**
Packit Service 87beb7
 * List all subnodes in a node, one per line
Packit Service 87beb7
 *
Packit Service 87beb7
 * @param blob		FDT blob
Packit Service 87beb7
 * @param node		Node to display
Packit Service 87beb7
 * @return 0 if ok, or FDT_ERR... if not.
Packit Service 87beb7
 */
Packit Service 87beb7
static int list_subnodes(const void *blob, int node)
Packit Service 87beb7
{
Packit Service 87beb7
	int nextoffset;		/* next node offset from libfdt */
Packit Service 87beb7
	uint32_t tag;		/* current tag */
Packit Service 87beb7
	int level = 0;		/* keep track of nesting level */
Packit Service 87beb7
	const char *pathp;
Packit Service 87beb7
	int depth = 1;		/* the assumed depth of this node */
Packit Service 87beb7
Packit Service 87beb7
	while (level >= 0) {
Packit Service 87beb7
		tag = fdt_next_tag(blob, node, &nextoffset);
Packit Service 87beb7
		switch (tag) {
Packit Service 87beb7
		case FDT_BEGIN_NODE:
Packit Service 87beb7
			pathp = fdt_get_name(blob, node, NULL);
Packit Service 87beb7
			if (level <= depth) {
Packit Service 87beb7
				if (pathp == NULL)
Packit Service 87beb7
					pathp = "/* NULL pointer error */";
Packit Service 87beb7
				if (*pathp == '\0')
Packit Service 87beb7
					pathp = "/";	/* root is nameless */
Packit Service 87beb7
				if (level == 1)
Packit Service 87beb7
					puts(pathp);
Packit Service 87beb7
			}
Packit Service 87beb7
			level++;
Packit Service 87beb7
			if (level >= MAX_LEVEL) {
Packit Service 87beb7
				printf("Nested too deep, aborting.\n");
Packit Service 87beb7
				return 1;
Packit Service 87beb7
			}
Packit Service 87beb7
			break;
Packit Service 87beb7
		case FDT_END_NODE:
Packit Service 87beb7
			level--;
Packit Service 87beb7
			if (level == 0)
Packit Service 87beb7
				level = -1;		/* exit the loop */
Packit Service 87beb7
			break;
Packit Service 87beb7
		case FDT_END:
Packit Service 87beb7
			return 1;
Packit Service 87beb7
		case FDT_PROP:
Packit Service 87beb7
			break;
Packit Service 87beb7
		default:
Packit Service 87beb7
			if (level <= depth)
Packit Service 87beb7
				printf("Unknown tag 0x%08X\n", tag);
Packit Service 87beb7
			return 1;
Packit Service 87beb7
		}
Packit Service 87beb7
		node = nextoffset;
Packit Service 87beb7
	}
Packit Service 87beb7
	return 0;
Packit Service 87beb7
}
Packit Service 87beb7
Packit Service 87beb7
/**
Packit Service 87beb7
 * Show the data for a given node (and perhaps property) according to the
Packit Service 87beb7
 * display option provided.
Packit Service 87beb7
 *
Packit Service 87beb7
 * @param blob		FDT blob
Packit Service 87beb7
 * @param disp		Display information / options
Packit Service 87beb7
 * @param node		Node to display
Packit Service 87beb7
 * @param property	Name of property to display, or NULL if none
Packit Service 87beb7
 * @return 0 if ok, -ve on error
Packit Service 87beb7
 */
Packit Service 87beb7
static int show_data_for_item(const void *blob, struct display_info *disp,
Packit Service 87beb7
		int node, const char *property)
Packit Service 87beb7
{
Packit Service 87beb7
	const void *value = NULL;
Packit Service 87beb7
	int len, err = 0;
Packit Service 87beb7
Packit Service 87beb7
	switch (disp->mode) {
Packit Service 87beb7
	case MODE_LIST_PROPS:
Packit Service 87beb7
		err = list_properties(blob, node);
Packit Service 87beb7
		break;
Packit Service 87beb7
Packit Service 87beb7
	case MODE_LIST_SUBNODES:
Packit Service 87beb7
		err = list_subnodes(blob, node);
Packit Service 87beb7
		break;
Packit Service 87beb7
Packit Service 87beb7
	default:
Packit Service 87beb7
		assert(property);
Packit Service 87beb7
		value = fdt_getprop(blob, node, property, &len;;
Packit Service 87beb7
		if (value) {
Packit Service 87beb7
			if (show_data(disp, value, len))
Packit Service 87beb7
				err = -1;
Packit Service 87beb7
			else
Packit Service 87beb7
				printf("\n");
Packit Service 87beb7
		} else if (disp->default_val) {
Packit Service 87beb7
			puts(disp->default_val);
Packit Service 87beb7
		} else {
Packit Service 87beb7
			report_error(property, len);
Packit Service 87beb7
			err = -1;
Packit Service 87beb7
		}
Packit Service 87beb7
		break;
Packit Service 87beb7
	}
Packit Service 87beb7
Packit Service 87beb7
	return err;
Packit Service 87beb7
}
Packit Service 87beb7
Packit Service 87beb7
/**
Packit Service 87beb7
 * Run the main fdtget operation, given a filename and valid arguments
Packit Service 87beb7
 *
Packit Service 87beb7
 * @param disp		Display information / options
Packit Service 87beb7
 * @param filename	Filename of blob file
Packit Service 87beb7
 * @param arg		List of arguments to process
Packit Service 87beb7
 * @param arg_count	Number of arguments
Packit Service 87beb7
 * @return 0 if ok, -ve on error
Packit Service 87beb7
 */
Packit Service 87beb7
static int do_fdtget(struct display_info *disp, const char *filename,
Packit Service 87beb7
		     char **arg, int arg_count, int args_per_step)
Packit Service 87beb7
{
Packit Service 87beb7
	char *blob;
Packit Service 87beb7
	const char *prop;
Packit Service 87beb7
	int i, node;
Packit Service 87beb7
Packit Service 87beb7
	blob = utilfdt_read(filename, NULL);
Packit Service 87beb7
	if (!blob)
Packit Service 87beb7
		return -1;
Packit Service 87beb7
Packit Service 87beb7
	for (i = 0; i + args_per_step <= arg_count; i += args_per_step) {
Packit Service 87beb7
		node = fdt_path_offset(blob, arg[i]);
Packit Service 87beb7
		if (node < 0) {
Packit Service 87beb7
			if (disp->default_val) {
Packit Service 87beb7
				puts(disp->default_val);
Packit Service 87beb7
				continue;
Packit Service 87beb7
			} else {
Packit Service 87beb7
				report_error(arg[i], node);
Packit Service 87beb7
				free(blob);
Packit Service 87beb7
				return -1;
Packit Service 87beb7
			}
Packit Service 87beb7
		}
Packit Service 87beb7
		prop = args_per_step == 1 ? NULL : arg[i + 1];
Packit Service 87beb7
Packit Service 87beb7
		if (show_data_for_item(blob, disp, node, prop)) {
Packit Service 87beb7
			free(blob);
Packit Service 87beb7
			return -1;
Packit Service 87beb7
		}
Packit Service 87beb7
	}
Packit Service 87beb7
Packit Service 87beb7
	free(blob);
Packit Service 87beb7
Packit Service 87beb7
	return 0;
Packit Service 87beb7
}
Packit Service 87beb7
Packit Service 87beb7
/* Usage related data. */
Packit Service 87beb7
static const char usage_synopsis[] =
Packit Service 87beb7
	"read values from device tree\n"
Packit Service 87beb7
	"	fdtget <options> 
[<node> <property>]...\n"
Packit Service 87beb7
	"	fdtget -p <options> 
[<node> ]...\n"
Packit Service 87beb7
	"\n"
Packit Service 87beb7
	"Each value is printed on a new line.\n"
Packit Service 87beb7
	USAGE_TYPE_MSG;
Packit Service 87beb7
static const char usage_short_opts[] = "t:pld:" USAGE_COMMON_SHORT_OPTS;
Packit Service 87beb7
static struct option const usage_long_opts[] = {
Packit Service 87beb7
	{"type",              a_argument, NULL, 't'},
Packit Service 87beb7
	{"properties",       no_argument, NULL, 'p'},
Packit Service 87beb7
	{"list",             no_argument, NULL, 'l'},
Packit Service 87beb7
	{"default",           a_argument, NULL, 'd'},
Packit Service 87beb7
	USAGE_COMMON_LONG_OPTS,
Packit Service 87beb7
};
Packit Service 87beb7
static const char * const usage_opts_help[] = {
Packit Service 87beb7
	"Type of data",
Packit Service 87beb7
	"List properties for each node",
Packit Service 87beb7
	"List subnodes for each node",
Packit Service 87beb7
	"Default value to display when the property is missing",
Packit Service 87beb7
	USAGE_COMMON_OPTS_HELP
Packit Service 87beb7
};
Packit Service 87beb7
Packit Service 87beb7
int main(int argc, char *argv[])
Packit Service 87beb7
{
Packit Service 87beb7
	int opt;
Packit Service 87beb7
	char *filename = NULL;
Packit Service 87beb7
	struct display_info disp;
Packit Service 87beb7
	int args_per_step = 2;
Packit Service 87beb7
Packit Service 87beb7
	/* set defaults */
Packit Service 87beb7
	memset(&disp, '\0', sizeof(disp));
Packit Service 87beb7
	disp.size = -1;
Packit Service 87beb7
	disp.mode = MODE_SHOW_VALUE;
Packit Service 87beb7
	while ((opt = util_getopt_long()) != EOF) {
Packit Service 87beb7
		switch (opt) {
Packit Service 87beb7
		case_USAGE_COMMON_FLAGS
Packit Service 87beb7
Packit Service 87beb7
		case 't':
Packit Service 87beb7
			if (utilfdt_decode_type(optarg, &disp.type,
Packit Service 87beb7
					&disp.size))
Packit Service 87beb7
				usage("invalid type string");
Packit Service 87beb7
			break;
Packit Service 87beb7
Packit Service 87beb7
		case 'p':
Packit Service 87beb7
			disp.mode = MODE_LIST_PROPS;
Packit Service 87beb7
			args_per_step = 1;
Packit Service 87beb7
			break;
Packit Service 87beb7
Packit Service 87beb7
		case 'l':
Packit Service 87beb7
			disp.mode = MODE_LIST_SUBNODES;
Packit Service 87beb7
			args_per_step = 1;
Packit Service 87beb7
			break;
Packit Service 87beb7
Packit Service 87beb7
		case 'd':
Packit Service 87beb7
			disp.default_val = optarg;
Packit Service 87beb7
			break;
Packit Service 87beb7
		}
Packit Service 87beb7
	}
Packit Service 87beb7
Packit Service 87beb7
	if (optind < argc)
Packit Service 87beb7
		filename = argv[optind++];
Packit Service 87beb7
	if (!filename)
Packit Service 87beb7
		usage("missing filename");
Packit Service 87beb7
Packit Service 87beb7
	argv += optind;
Packit Service 87beb7
	argc -= optind;
Packit Service 87beb7
Packit Service 87beb7
	/* Allow no arguments, and silently succeed */
Packit Service 87beb7
	if (!argc)
Packit Service 87beb7
		return 0;
Packit Service 87beb7
Packit Service 87beb7
	/* Check for node, property arguments */
Packit Service 87beb7
	if (args_per_step == 2 && (argc % 2))
Packit Service 87beb7
		usage("must have an even number of arguments");
Packit Service 87beb7
Packit Service 87beb7
	if (do_fdtget(&disp, filename, argv, argc, args_per_step))
Packit Service 87beb7
		return 1;
Packit Service 87beb7
	return 0;
Packit Service 87beb7
}