linux/scripts/dtc/util.c
Rob Herring 6f05afcbb0 scripts/dtc: Update to upstream version 0931cea3ba20
Sync to upstream dtc commit 0931cea3ba20 ("dtc: fdtdump: check fdt if
not in scanning mode"). In particular, this pulls in dtc overlay
support.

This adds the following commits from upstream:

f88865469b65 dtc: Fix memory leak in character literal parsing
00fbb8696b66 Rename boot_info
1ef86ad2c24f dtc: Clean up /dts-v1/ and /plugin/ handling in grammar
e3c769aa9c16 dtc: Don't always generate __symbols__ for plugins
c96cb3c0169e tests: Don't use -@ on plugin de/recompile tests
66381538ce24 tests: Remove "suppression of fixups" tests
ba765b273f0f tests: Clarify dtc overlay tests
6ea8cd944fcd tests: More thorough tests of libfdt overlay application without dtc
7d8ef6e1db97 tests: Correct fdt handling of overlays without fixups and base trees without symbols
b4dc0ed8b127 tests: Fix double expansion bugs in test code
3ea879dc0c8f tests: Split overlay tests into those with do/don't exercise dtc plugin generation
47b4d66a2f11 tests: Test auto-alias generation on base tree, not overlay
72e1ad811523 tests: Make overlay/plugin tests unconditional
e7b3c3b5951b tests: Add overlay tests
9637e3f772a9 tests: Add check_path test
20f29d8d41f6 dtc: Plugin and fixup support
a2c92cac53f8 dtc: Document the dynamic plugin internals
8f70ac39801d checks: Pass boot_info instead of root node
ea10f953878f libfdt: add missing errors to fdt_strerror()
daa75e8fa594 libfdt: fix fdt_stringlist_search()
e28eff5b787a libfdt: fix fdt_stringlist_count()
ae97c7722840 tests: overlay: Rename the device tree blobs to be more explicit
96162d2bd9cb tests: overlay: Add test suffix to the compiled blobs
5ce8634733b7 libfdt: Add fdt_overlay_apply to the exported symbols
804a9db90ad2 fdt: strerr: Remove spurious BADOVERLAY
e8c3a1a493fa tests: overlay: Move back the bad fixup tests
7a72d89d3f81 libfdt: overlay: Fix symbols and fixups nodes condition
cabbaa972cdd libfdt: overlay: Report a bad overlay for mismatching local fixups
deb0a5c1aeaa libfdt: Add BADPHANDLE error string
7b7a6be9ba15 libfdt: Don't use 'index' as a local variable name
aea8860d831e tests: Add tests cases for the overlay code
0cdd06c5135b libfdt: Add overlay application function
39240cc865cf libfdt: Extend the reach of FDT_ERR_BADPHANDLE
4aa3a6f5e6d9 libfdt: Add new errors for the overlay code
6d1832c9e64b dtc: Remove "home page" link
45fd440a9561 Fix some typing errors in libfdt.h and livetree.c
a59be4939c13 Merge tag 'v1.4.2'
a34bb721caca dtc: Fix assorted problems in the testcases for the -a option
874f40588d3e Implement the -a option to pad dtb aligned
ec02b34c05be dtc: Makefile improvements for release uploading
1ed45d40a137 dtc: Bump version to 1.4.2
36fd7331fb11 libfdt: simplify fdt_del_mem_rsv()
d877364e4a0f libfdt: Add fdt_setprop_inplace_namelen_partial
3e9037aaad44 libfdt: Add fdt_getprop_namelen_w
84e0e1346c68 libfdt: Add max phandle retrieval function
d29126c90acb libfdt: Add iterator over properties
902d0f0953d0 libfdt: Add a subnodes iterator macro
c539075ba8ba fdtput.c: Fix memory leak.
f79ddb83e185 fdtget.c: Fix memory leak
1074ee54b63f convert-dtsv0-lexer.l: fix memory leak
e24d39a024e6 fdtdump.c: make sure size_t argument to memchr is always unsigned.
44a59713cf05 Remove unused srcpos_dump() function
cb9241ae3453 DTC: Fix memory leak on flatname.
1ee0ae24ea09 Simplify check field and macro names
9d97527a8621 Remove property check functions
2e709d158e11 Remove tree check functions
c4cb12e193e3 Alter grammar to allow multiple /dts-v1/ tags
d71d25d76012 Use xasprintf() in srcpos
9dc404958e9c util: Add xasprintf portable asprintf variant
beef80b8b55f Correct a missing space in a fdt_header cast
68d43cec1253 Correct line lengths in libfdt.h
b0dbceafd49a Correct space-after-tab in libfdt.h

Signed-off-by: Rob Herring <robh@kernel.org>
2017-01-04 10:47:53 -06:00

474 lines
9.4 KiB
C

/*
* Copyright 2011 The Chromium Authors, All Rights Reserved.
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
*
* util_is_printable_string contributed by
* Pantelis Antoniou <pantelis.antoniou AT gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "libfdt.h"
#include "util.h"
#include "version_gen.h"
char *xstrdup(const char *s)
{
int len = strlen(s) + 1;
char *d = xmalloc(len);
memcpy(d, s, len);
return d;
}
/* based in part from (3) vsnprintf */
int xasprintf(char **strp, const char *fmt, ...)
{
int n, size = 128; /* start with 128 bytes */
char *p;
va_list ap;
/* initial pointer is NULL making the fist realloc to be malloc */
p = NULL;
while (1) {
p = xrealloc(p, size);
/* Try to print in the allocated space. */
va_start(ap, fmt);
n = vsnprintf(p, size, fmt, ap);
va_end(ap);
/* If that worked, return the string. */
if (n > -1 && n < size)
break;
/* Else try again with more space. */
if (n > -1) /* glibc 2.1 */
size = n + 1; /* precisely what is needed */
else /* glibc 2.0 */
size *= 2; /* twice the old size */
}
*strp = p;
return strlen(p);
}
char *join_path(const char *path, const char *name)
{
int lenp = strlen(path);
int lenn = strlen(name);
int len;
int needslash = 1;
char *str;
len = lenp + lenn + 2;
if ((lenp > 0) && (path[lenp-1] == '/')) {
needslash = 0;
len--;
}
str = xmalloc(len);
memcpy(str, path, lenp);
if (needslash) {
str[lenp] = '/';
lenp++;
}
memcpy(str+lenp, name, lenn+1);
return str;
}
bool util_is_printable_string(const void *data, int len)
{
const char *s = data;
const char *ss, *se;
/* zero length is not */
if (len == 0)
return 0;
/* must terminate with zero */
if (s[len - 1] != '\0')
return 0;
se = s + len;
while (s < se) {
ss = s;
while (s < se && *s && isprint((unsigned char)*s))
s++;
/* not zero, or not done yet */
if (*s != '\0' || s == ss)
return 0;
s++;
}
return 1;
}
/*
* Parse a octal encoded character starting at index i in string s. The
* resulting character will be returned and the index i will be updated to
* point at the character directly after the end of the encoding, this may be
* the '\0' terminator of the string.
*/
static char get_oct_char(const char *s, int *i)
{
char x[4];
char *endx;
long val;
x[3] = '\0';
strncpy(x, s + *i, 3);
val = strtol(x, &endx, 8);
assert(endx > x);
(*i) += endx - x;
return val;
}
/*
* Parse a hexadecimal encoded character starting at index i in string s. The
* resulting character will be returned and the index i will be updated to
* point at the character directly after the end of the encoding, this may be
* the '\0' terminator of the string.
*/
static char get_hex_char(const char *s, int *i)
{
char x[3];
char *endx;
long val;
x[2] = '\0';
strncpy(x, s + *i, 2);
val = strtol(x, &endx, 16);
if (!(endx > x))
die("\\x used with no following hex digits\n");
(*i) += endx - x;
return val;
}
char get_escape_char(const char *s, int *i)
{
char c = s[*i];
int j = *i + 1;
char val;
switch (c) {
case 'a':
val = '\a';
break;
case 'b':
val = '\b';
break;
case 't':
val = '\t';
break;
case 'n':
val = '\n';
break;
case 'v':
val = '\v';
break;
case 'f':
val = '\f';
break;
case 'r':
val = '\r';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
j--; /* need to re-read the first digit as
* part of the octal value */
val = get_oct_char(s, &j);
break;
case 'x':
val = get_hex_char(s, &j);
break;
default:
val = c;
}
(*i) = j;
return val;
}
int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
{
int fd = 0; /* assume stdin */
char *buf = NULL;
off_t bufsize = 1024, offset = 0;
int ret = 0;
*buffp = NULL;
if (strcmp(filename, "-") != 0) {
fd = open(filename, O_RDONLY);
if (fd < 0)
return errno;
}
/* Loop until we have read everything */
buf = xmalloc(bufsize);
do {
/* Expand the buffer to hold the next chunk */
if (offset == bufsize) {
bufsize *= 2;
buf = xrealloc(buf, bufsize);
}
ret = read(fd, &buf[offset], bufsize - offset);
if (ret < 0) {
ret = errno;
break;
}
offset += ret;
} while (ret != 0);
/* Clean up, including closing stdin; return errno on error */
close(fd);
if (ret)
free(buf);
else
*buffp = buf;
*len = bufsize;
return ret;
}
int utilfdt_read_err(const char *filename, char **buffp)
{
off_t len;
return utilfdt_read_err_len(filename, buffp, &len);
}
char *utilfdt_read_len(const char *filename, off_t *len)
{
char *buff;
int ret = utilfdt_read_err_len(filename, &buff, len);
if (ret) {
fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
strerror(ret));
return NULL;
}
/* Successful read */
return buff;
}
char *utilfdt_read(const char *filename)
{
off_t len;
return utilfdt_read_len(filename, &len);
}
int utilfdt_write_err(const char *filename, const void *blob)
{
int fd = 1; /* assume stdout */
int totalsize;
int offset;
int ret = 0;
const char *ptr = blob;
if (strcmp(filename, "-") != 0) {
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
return errno;
}
totalsize = fdt_totalsize(blob);
offset = 0;
while (offset < totalsize) {
ret = write(fd, ptr + offset, totalsize - offset);
if (ret < 0) {
ret = -errno;
break;
}
offset += ret;
}
/* Close the file/stdin; return errno on error */
if (fd != 1)
close(fd);
return ret < 0 ? -ret : 0;
}
int utilfdt_write(const char *filename, const void *blob)
{
int ret = utilfdt_write_err(filename, blob);
if (ret) {
fprintf(stderr, "Couldn't write blob to '%s': %s\n", filename,
strerror(ret));
}
return ret ? -1 : 0;
}
int utilfdt_decode_type(const char *fmt, int *type, int *size)
{
int qualifier = 0;
if (!*fmt)
return -1;
/* get the conversion qualifier */
*size = -1;
if (strchr("hlLb", *fmt)) {
qualifier = *fmt++;
if (qualifier == *fmt) {
switch (*fmt++) {
/* TODO: case 'l': qualifier = 'L'; break;*/
case 'h':
qualifier = 'b';
break;
}
}
}
/* we should now have a type */
if ((*fmt == '\0') || !strchr("iuxs", *fmt))
return -1;
/* convert qualifier (bhL) to byte size */
if (*fmt != 's')
*size = qualifier == 'b' ? 1 :
qualifier == 'h' ? 2 :
qualifier == 'l' ? 4 : -1;
*type = *fmt++;
/* that should be it! */
if (*fmt)
return -1;
return 0;
}
void utilfdt_print_data(const char *data, int len)
{
int i;
const char *s;
/* no data, don't print */
if (len == 0)
return;
if (util_is_printable_string(data, len)) {
printf(" = ");
s = data;
do {
printf("\"%s\"", s);
s += strlen(s) + 1;
if (s < data + len)
printf(", ");
} while (s < data + len);
} else if ((len % 4) == 0) {
const uint32_t *cell = (const uint32_t *)data;
printf(" = <");
for (i = 0, len /= 4; i < len; i++)
printf("0x%08x%s", fdt32_to_cpu(cell[i]),
i < (len - 1) ? " " : "");
printf(">");
} else {
const unsigned char *p = (const unsigned char *)data;
printf(" = [");
for (i = 0; i < len; i++)
printf("%02x%s", *p++, i < len - 1 ? " " : "");
printf("]");
}
}
void util_version(void)
{
printf("Version: %s\n", DTC_VERSION);
exit(0);
}
void util_usage(const char *errmsg, const char *synopsis,
const char *short_opts, struct option const long_opts[],
const char * const opts_help[])
{
FILE *fp = errmsg ? stderr : stdout;
const char a_arg[] = "<arg>";
size_t a_arg_len = strlen(a_arg) + 1;
size_t i;
int optlen;
fprintf(fp,
"Usage: %s\n"
"\n"
"Options: -[%s]\n", synopsis, short_opts);
/* prescan the --long opt length to auto-align */
optlen = 0;
for (i = 0; long_opts[i].name; ++i) {
/* +1 is for space between --opt and help text */
int l = strlen(long_opts[i].name) + 1;
if (long_opts[i].has_arg == a_argument)
l += a_arg_len;
if (optlen < l)
optlen = l;
}
for (i = 0; long_opts[i].name; ++i) {
/* helps when adding new applets or options */
assert(opts_help[i] != NULL);
/* first output the short flag if it has one */
if (long_opts[i].val > '~')
fprintf(fp, " ");
else
fprintf(fp, " -%c, ", long_opts[i].val);
/* then the long flag */
if (long_opts[i].has_arg == no_argument)
fprintf(fp, "--%-*s", optlen, long_opts[i].name);
else
fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
(int)(optlen - strlen(long_opts[i].name) - a_arg_len), "");
/* finally the help text */
fprintf(fp, "%s\n", opts_help[i]);
}
if (errmsg) {
fprintf(fp, "\nError: %s\n", errmsg);
exit(EXIT_FAILURE);
} else
exit(EXIT_SUCCESS);
}