1204433Sraj/* 2238742Simp * Copyright 2011 The Chromium Authors, All Rights Reserved. 3204433Sraj * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc. 4204433Sraj * 5238742Simp * util_is_printable_string contributed by 6238742Simp * Pantelis Antoniou <pantelis.antoniou AT gmail.com> 7238742Simp * 8204433Sraj * This program is free software; you can redistribute it and/or 9204433Sraj * modify it under the terms of the GNU General Public License as 10204433Sraj * published by the Free Software Foundation; either version 2 of the 11204433Sraj * License, or (at your option) any later version. 12204433Sraj * 13204433Sraj * This program is distributed in the hope that it will be useful, 14204433Sraj * but WITHOUT ANY WARRANTY; without even the implied warranty of 15204433Sraj * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16204433Sraj * General Public License for more details. 17204433Sraj * 18204433Sraj * You should have received a copy of the GNU General Public License 19204433Sraj * along with this program; if not, write to the Free Software 20204433Sraj * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 21204433Sraj * USA 22204433Sraj */ 23204433Sraj 24238742Simp#include <ctype.h> 25238742Simp#include <stdio.h> 26238742Simp#include <stdlib.h> 27238742Simp#include <stdarg.h> 28238742Simp#include <string.h> 29238742Simp#include <assert.h> 30204433Sraj 31238742Simp#include <errno.h> 32238742Simp#include <fcntl.h> 33238742Simp#include <unistd.h> 34238742Simp 35238742Simp#include "libfdt.h" 36238742Simp#include "util.h" 37261215Simp#include "version_gen.h" 38238742Simp 39204433Srajchar *xstrdup(const char *s) 40204433Sraj{ 41204433Sraj int len = strlen(s) + 1; 42318102Sgonzo char *d = xmalloc(len); 43204433Sraj 44318102Sgonzo memcpy(d, s, len); 45204433Sraj 46318102Sgonzo return d; 47204433Sraj} 48238742Simp 49318102Sgonzo/* based in part from (3) vsnprintf */ 50318102Sgonzoint xasprintf(char **strp, const char *fmt, ...) 51318102Sgonzo{ 52318102Sgonzo int n, size = 128; /* start with 128 bytes */ 53318102Sgonzo char *p; 54318102Sgonzo va_list ap; 55318102Sgonzo 56318102Sgonzo /* initial pointer is NULL making the fist realloc to be malloc */ 57318102Sgonzo p = NULL; 58318102Sgonzo while (1) { 59318102Sgonzo p = xrealloc(p, size); 60318102Sgonzo 61318102Sgonzo /* Try to print in the allocated space. */ 62318102Sgonzo va_start(ap, fmt); 63318102Sgonzo n = vsnprintf(p, size, fmt, ap); 64318102Sgonzo va_end(ap); 65318102Sgonzo 66318102Sgonzo /* If that worked, return the string. */ 67318102Sgonzo if (n > -1 && n < size) 68318102Sgonzo break; 69318102Sgonzo /* Else try again with more space. */ 70318102Sgonzo if (n > -1) /* glibc 2.1 */ 71318102Sgonzo size = n + 1; /* precisely what is needed */ 72318102Sgonzo else /* glibc 2.0 */ 73318102Sgonzo size *= 2; /* twice the old size */ 74318102Sgonzo } 75318102Sgonzo *strp = p; 76318102Sgonzo return strlen(p); 77318102Sgonzo} 78318102Sgonzo 79238742Simpchar *join_path(const char *path, const char *name) 80238742Simp{ 81238742Simp int lenp = strlen(path); 82238742Simp int lenn = strlen(name); 83238742Simp int len; 84238742Simp int needslash = 1; 85238742Simp char *str; 86238742Simp 87238742Simp len = lenp + lenn + 2; 88238742Simp if ((lenp > 0) && (path[lenp-1] == '/')) { 89238742Simp needslash = 0; 90238742Simp len--; 91238742Simp } 92238742Simp 93238742Simp str = xmalloc(len); 94238742Simp memcpy(str, path, lenp); 95238742Simp if (needslash) { 96238742Simp str[lenp] = '/'; 97238742Simp lenp++; 98238742Simp } 99238742Simp memcpy(str+lenp, name, lenn+1); 100238742Simp return str; 101238742Simp} 102238742Simp 103261215Simpbool util_is_printable_string(const void *data, int len) 104238742Simp{ 105238742Simp const char *s = data; 106261215Simp const char *ss, *se; 107238742Simp 108238742Simp /* zero length is not */ 109238742Simp if (len == 0) 110238742Simp return 0; 111238742Simp 112238742Simp /* must terminate with zero */ 113238742Simp if (s[len - 1] != '\0') 114238742Simp return 0; 115238742Simp 116261215Simp se = s + len; 117261215Simp 118261215Simp while (s < se) { 119261215Simp ss = s; 120261215Simp while (s < se && *s && isprint((unsigned char)*s)) 121261215Simp s++; 122261215Simp 123261215Simp /* not zero, or not done yet */ 124261215Simp if (*s != '\0' || s == ss) 125261215Simp return 0; 126261215Simp 127238742Simp s++; 128261215Simp } 129238742Simp 130238742Simp return 1; 131238742Simp} 132238742Simp 133238742Simp/* 134238742Simp * Parse a octal encoded character starting at index i in string s. The 135238742Simp * resulting character will be returned and the index i will be updated to 136238742Simp * point at the character directly after the end of the encoding, this may be 137238742Simp * the '\0' terminator of the string. 138238742Simp */ 139238742Simpstatic char get_oct_char(const char *s, int *i) 140238742Simp{ 141238742Simp char x[4]; 142238742Simp char *endx; 143238742Simp long val; 144238742Simp 145238742Simp x[3] = '\0'; 146238742Simp strncpy(x, s + *i, 3); 147238742Simp 148238742Simp val = strtol(x, &endx, 8); 149238742Simp 150238742Simp assert(endx > x); 151238742Simp 152238742Simp (*i) += endx - x; 153238742Simp return val; 154238742Simp} 155238742Simp 156238742Simp/* 157238742Simp * Parse a hexadecimal encoded character starting at index i in string s. The 158238742Simp * resulting character will be returned and the index i will be updated to 159238742Simp * point at the character directly after the end of the encoding, this may be 160238742Simp * the '\0' terminator of the string. 161238742Simp */ 162238742Simpstatic char get_hex_char(const char *s, int *i) 163238742Simp{ 164238742Simp char x[3]; 165238742Simp char *endx; 166238742Simp long val; 167238742Simp 168238742Simp x[2] = '\0'; 169238742Simp strncpy(x, s + *i, 2); 170238742Simp 171238742Simp val = strtol(x, &endx, 16); 172238742Simp if (!(endx > x)) 173238742Simp die("\\x used with no following hex digits\n"); 174238742Simp 175238742Simp (*i) += endx - x; 176238742Simp return val; 177238742Simp} 178238742Simp 179238742Simpchar get_escape_char(const char *s, int *i) 180238742Simp{ 181238742Simp char c = s[*i]; 182238742Simp int j = *i + 1; 183238742Simp char val; 184238742Simp 185238742Simp switch (c) { 186238742Simp case 'a': 187238742Simp val = '\a'; 188238742Simp break; 189238742Simp case 'b': 190238742Simp val = '\b'; 191238742Simp break; 192238742Simp case 't': 193238742Simp val = '\t'; 194238742Simp break; 195238742Simp case 'n': 196238742Simp val = '\n'; 197238742Simp break; 198238742Simp case 'v': 199238742Simp val = '\v'; 200238742Simp break; 201238742Simp case 'f': 202238742Simp val = '\f'; 203238742Simp break; 204238742Simp case 'r': 205238742Simp val = '\r'; 206238742Simp break; 207238742Simp case '0': 208238742Simp case '1': 209238742Simp case '2': 210238742Simp case '3': 211238742Simp case '4': 212238742Simp case '5': 213238742Simp case '6': 214238742Simp case '7': 215238742Simp j--; /* need to re-read the first digit as 216238742Simp * part of the octal value */ 217238742Simp val = get_oct_char(s, &j); 218238742Simp break; 219238742Simp case 'x': 220238742Simp val = get_hex_char(s, &j); 221238742Simp break; 222238742Simp default: 223238742Simp val = c; 224238742Simp } 225238742Simp 226238742Simp (*i) = j; 227238742Simp return val; 228238742Simp} 229238742Simp 230261215Simpint utilfdt_read_err_len(const char *filename, char **buffp, off_t *len) 231238742Simp{ 232238742Simp int fd = 0; /* assume stdin */ 233238742Simp char *buf = NULL; 234238742Simp off_t bufsize = 1024, offset = 0; 235238742Simp int ret = 0; 236238742Simp 237238742Simp *buffp = NULL; 238238742Simp if (strcmp(filename, "-") != 0) { 239238742Simp fd = open(filename, O_RDONLY); 240238742Simp if (fd < 0) 241238742Simp return errno; 242238742Simp } 243238742Simp 244238742Simp /* Loop until we have read everything */ 245261215Simp buf = xmalloc(bufsize); 246238742Simp do { 247238742Simp /* Expand the buffer to hold the next chunk */ 248238742Simp if (offset == bufsize) { 249238742Simp bufsize *= 2; 250261215Simp buf = xrealloc(buf, bufsize); 251238742Simp } 252238742Simp 253238742Simp ret = read(fd, &buf[offset], bufsize - offset); 254238742Simp if (ret < 0) { 255238742Simp ret = errno; 256238742Simp break; 257238742Simp } 258238742Simp offset += ret; 259238742Simp } while (ret != 0); 260238742Simp 261238742Simp /* Clean up, including closing stdin; return errno on error */ 262238742Simp close(fd); 263238742Simp if (ret) 264238742Simp free(buf); 265238742Simp else 266238742Simp *buffp = buf; 267261215Simp *len = bufsize; 268238742Simp return ret; 269238742Simp} 270238742Simp 271261215Simpint utilfdt_read_err(const char *filename, char **buffp) 272238742Simp{ 273261215Simp off_t len; 274261215Simp return utilfdt_read_err_len(filename, buffp, &len); 275261215Simp} 276261215Simp 277261215Simpchar *utilfdt_read_len(const char *filename, off_t *len) 278261215Simp{ 279238742Simp char *buff; 280261215Simp int ret = utilfdt_read_err_len(filename, &buff, len); 281238742Simp 282238742Simp if (ret) { 283238742Simp fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename, 284238742Simp strerror(ret)); 285238742Simp return NULL; 286238742Simp } 287238742Simp /* Successful read */ 288238742Simp return buff; 289238742Simp} 290238742Simp 291261215Simpchar *utilfdt_read(const char *filename) 292261215Simp{ 293261215Simp off_t len; 294261215Simp return utilfdt_read_len(filename, &len); 295261215Simp} 296261215Simp 297238742Simpint utilfdt_write_err(const char *filename, const void *blob) 298238742Simp{ 299238742Simp int fd = 1; /* assume stdout */ 300238742Simp int totalsize; 301238742Simp int offset; 302238742Simp int ret = 0; 303238742Simp const char *ptr = blob; 304238742Simp 305238742Simp if (strcmp(filename, "-") != 0) { 306238742Simp fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); 307238742Simp if (fd < 0) 308238742Simp return errno; 309238742Simp } 310238742Simp 311238742Simp totalsize = fdt_totalsize(blob); 312238742Simp offset = 0; 313238742Simp 314238742Simp while (offset < totalsize) { 315238742Simp ret = write(fd, ptr + offset, totalsize - offset); 316238742Simp if (ret < 0) { 317238742Simp ret = -errno; 318238742Simp break; 319238742Simp } 320238742Simp offset += ret; 321238742Simp } 322238742Simp /* Close the file/stdin; return errno on error */ 323238742Simp if (fd != 1) 324238742Simp close(fd); 325238742Simp return ret < 0 ? -ret : 0; 326238742Simp} 327238742Simp 328238742Simp 329238742Simpint utilfdt_write(const char *filename, const void *blob) 330238742Simp{ 331238742Simp int ret = utilfdt_write_err(filename, blob); 332238742Simp 333238742Simp if (ret) { 334238742Simp fprintf(stderr, "Couldn't write blob to '%s': %s\n", filename, 335238742Simp strerror(ret)); 336238742Simp } 337238742Simp return ret ? -1 : 0; 338238742Simp} 339238742Simp 340238742Simpint utilfdt_decode_type(const char *fmt, int *type, int *size) 341238742Simp{ 342238742Simp int qualifier = 0; 343238742Simp 344238742Simp if (!*fmt) 345238742Simp return -1; 346238742Simp 347238742Simp /* get the conversion qualifier */ 348238742Simp *size = -1; 349238742Simp if (strchr("hlLb", *fmt)) { 350238742Simp qualifier = *fmt++; 351238742Simp if (qualifier == *fmt) { 352238742Simp switch (*fmt++) { 353238742Simp/* TODO: case 'l': qualifier = 'L'; break;*/ 354238742Simp case 'h': 355238742Simp qualifier = 'b'; 356238742Simp break; 357238742Simp } 358238742Simp } 359238742Simp } 360238742Simp 361238742Simp /* we should now have a type */ 362238742Simp if ((*fmt == '\0') || !strchr("iuxs", *fmt)) 363238742Simp return -1; 364238742Simp 365238742Simp /* convert qualifier (bhL) to byte size */ 366238742Simp if (*fmt != 's') 367238742Simp *size = qualifier == 'b' ? 1 : 368238742Simp qualifier == 'h' ? 2 : 369238742Simp qualifier == 'l' ? 4 : -1; 370238742Simp *type = *fmt++; 371238742Simp 372238742Simp /* that should be it! */ 373238742Simp if (*fmt) 374238742Simp return -1; 375238742Simp return 0; 376238742Simp} 377261215Simp 378261215Simpvoid utilfdt_print_data(const char *data, int len) 379261215Simp{ 380261215Simp int i; 381261215Simp const char *s; 382261215Simp 383261215Simp /* no data, don't print */ 384261215Simp if (len == 0) 385261215Simp return; 386261215Simp 387261215Simp if (util_is_printable_string(data, len)) { 388261215Simp printf(" = "); 389261215Simp 390261215Simp s = data; 391261215Simp do { 392261215Simp printf("\"%s\"", s); 393261215Simp s += strlen(s) + 1; 394261215Simp if (s < data + len) 395261215Simp printf(", "); 396261215Simp } while (s < data + len); 397261215Simp 398261215Simp } else if ((len % 4) == 0) { 399261215Simp const uint32_t *cell = (const uint32_t *)data; 400261215Simp 401261215Simp printf(" = <"); 402318102Sgonzo for (i = 0, len /= 4; i < len; i++) 403318102Sgonzo printf("0x%08x%s", fdt32_to_cpu(cell[i]), 404318102Sgonzo i < (len - 1) ? " " : ""); 405261215Simp printf(">"); 406261215Simp } else { 407318102Sgonzo const unsigned char *p = (const unsigned char *)data; 408261215Simp printf(" = ["); 409261215Simp for (i = 0; i < len; i++) 410261215Simp printf("%02x%s", *p++, i < len - 1 ? " " : ""); 411261215Simp printf("]"); 412261215Simp } 413261215Simp} 414261215Simp 415261215Simpvoid util_version(void) 416261215Simp{ 417261215Simp printf("Version: %s\n", DTC_VERSION); 418261215Simp exit(0); 419261215Simp} 420261215Simp 421261215Simpvoid util_usage(const char *errmsg, const char *synopsis, 422261215Simp const char *short_opts, struct option const long_opts[], 423261215Simp const char * const opts_help[]) 424261215Simp{ 425261215Simp FILE *fp = errmsg ? stderr : stdout; 426261215Simp const char a_arg[] = "<arg>"; 427261215Simp size_t a_arg_len = strlen(a_arg) + 1; 428261215Simp size_t i; 429261215Simp int optlen; 430261215Simp 431261215Simp fprintf(fp, 432261215Simp "Usage: %s\n" 433261215Simp "\n" 434261215Simp "Options: -[%s]\n", synopsis, short_opts); 435261215Simp 436261215Simp /* prescan the --long opt length to auto-align */ 437261215Simp optlen = 0; 438261215Simp for (i = 0; long_opts[i].name; ++i) { 439261215Simp /* +1 is for space between --opt and help text */ 440261215Simp int l = strlen(long_opts[i].name) + 1; 441261215Simp if (long_opts[i].has_arg == a_argument) 442261215Simp l += a_arg_len; 443261215Simp if (optlen < l) 444261215Simp optlen = l; 445261215Simp } 446261215Simp 447261215Simp for (i = 0; long_opts[i].name; ++i) { 448261215Simp /* helps when adding new applets or options */ 449261215Simp assert(opts_help[i] != NULL); 450261215Simp 451261215Simp /* first output the short flag if it has one */ 452261215Simp if (long_opts[i].val > '~') 453261215Simp fprintf(fp, " "); 454261215Simp else 455261215Simp fprintf(fp, " -%c, ", long_opts[i].val); 456261215Simp 457261215Simp /* then the long flag */ 458261215Simp if (long_opts[i].has_arg == no_argument) 459261215Simp fprintf(fp, "--%-*s", optlen, long_opts[i].name); 460261215Simp else 461261215Simp fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg, 462261215Simp (int)(optlen - strlen(long_opts[i].name) - a_arg_len), ""); 463261215Simp 464261215Simp /* finally the help text */ 465261215Simp fprintf(fp, "%s\n", opts_help[i]); 466261215Simp } 467261215Simp 468261215Simp if (errmsg) { 469261215Simp fprintf(fp, "\nError: %s\n", errmsg); 470261215Simp exit(EXIT_FAILURE); 471261215Simp } else 472261215Simp exit(EXIT_SUCCESS); 473261215Simp} 474