|  | /* | 
|  | * 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" | 
|  |  | 
|  | 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; | 
|  |  | 
|  | /* zero length is not */ | 
|  | if (len == 0) | 
|  | return 0; | 
|  |  | 
|  | /* must terminate with zero */ | 
|  | if (s[len - 1] != '\0') | 
|  | return 0; | 
|  |  | 
|  | ss = s; | 
|  | while (*s && isprint(*s)) | 
|  | s++; | 
|  |  | 
|  | /* not zero, or not done yet */ | 
|  | if (*s != '\0' || (s + 1 - ss) < len) | 
|  | return 0; | 
|  |  | 
|  | 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(const char *filename, char **buffp) | 
|  | { | 
|  | 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 = malloc(bufsize); | 
|  | do { | 
|  | /* Expand the buffer to hold the next chunk */ | 
|  | if (offset == bufsize) { | 
|  | bufsize *= 2; | 
|  | buf = realloc(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; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | char *utilfdt_read(const char *filename) | 
|  | { | 
|  | char *buff; | 
|  | int ret = utilfdt_read_err(filename, &buff); | 
|  |  | 
|  | if (ret) { | 
|  | fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename, | 
|  | strerror(ret)); | 
|  | return NULL; | 
|  | } | 
|  | /* Successful read */ | 
|  | return buff; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } |