mirror of
https://github.com/dgibson/dtc.git
synced 2025-10-13 16:27:39 -04:00
For a follow up commit, we want to be able to scan the buffer that was returned to us. In order to do that safely, we need to know how big the buffer actually is, so create a new set of funcs to pass that back. Acked-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
394 lines
7.4 KiB
C
394 lines
7.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 *dup = xmalloc(len);
|
|
|
|
memcpy(dup, s, len);
|
|
|
|
return dup;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
int 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(*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;
|
|
|
|
assert(c);
|
|
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);
|
|
if (!buf) {
|
|
ret = ENOMEM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
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 *p = data;
|
|
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; i < len; i += 4)
|
|
printf("0x%08x%s", fdt32_to_cpu(cell[i]),
|
|
i < (len - 4) ? " " : "");
|
|
printf(">");
|
|
} else {
|
|
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);
|
|
}
|