Blame fdtget.c

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