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" 37266130Sian#include "version_gen.h" 38238742Simp 39204433Srajchar *xstrdup(const char *s) 40204433Sraj{ 41204433Sraj int len = strlen(s) + 1; 42204433Sraj char *dup = xmalloc(len); 43204433Sraj 44204433Sraj memcpy(dup, s, len); 45204433Sraj 46204433Sraj return dup; 47204433Sraj} 48238742Simp 49238742Simpchar *join_path(const char *path, const char *name) 50238742Simp{ 51238742Simp int lenp = strlen(path); 52238742Simp int lenn = strlen(name); 53238742Simp int len; 54238742Simp int needslash = 1; 55238742Simp char *str; 56238742Simp 57238742Simp len = lenp + lenn + 2; 58238742Simp if ((lenp > 0) && (path[lenp-1] == '/')) { 59238742Simp needslash = 0; 60238742Simp len--; 61238742Simp } 62238742Simp 63238742Simp str = xmalloc(len); 64238742Simp memcpy(str, path, lenp); 65238742Simp if (needslash) { 66238742Simp str[lenp] = '/'; 67238742Simp lenp++; 68238742Simp } 69238742Simp memcpy(str+lenp, name, lenn+1); 70238742Simp return str; 71238742Simp} 72238742Simp 73266130Sianbool util_is_printable_string(const void *data, int len) 74238742Simp{ 75238742Simp const char *s = data; 76266130Sian const char *ss, *se; 77238742Simp 78238742Simp /* zero length is not */ 79238742Simp if (len == 0) 80238742Simp return 0; 81238742Simp 82238742Simp /* must terminate with zero */ 83238742Simp if (s[len - 1] != '\0') 84238742Simp return 0; 85238742Simp 86266130Sian se = s + len; 87266130Sian 88266130Sian while (s < se) { 89266130Sian ss = s; 90266130Sian while (s < se && *s && isprint((unsigned char)*s)) 91266130Sian s++; 92266130Sian 93266130Sian /* not zero, or not done yet */ 94266130Sian if (*s != '\0' || s == ss) 95266130Sian return 0; 96266130Sian 97238742Simp s++; 98266130Sian } 99238742Simp 100238742Simp return 1; 101238742Simp} 102238742Simp 103238742Simp/* 104238742Simp * Parse a octal encoded character starting at index i in string s. The 105238742Simp * resulting character will be returned and the index i will be updated to 106238742Simp * point at the character directly after the end of the encoding, this may be 107238742Simp * the '\0' terminator of the string. 108238742Simp */ 109238742Simpstatic char get_oct_char(const char *s, int *i) 110238742Simp{ 111238742Simp char x[4]; 112238742Simp char *endx; 113238742Simp long val; 114238742Simp 115238742Simp x[3] = '\0'; 116238742Simp strncpy(x, s + *i, 3); 117238742Simp 118238742Simp val = strtol(x, &endx, 8); 119238742Simp 120238742Simp assert(endx > x); 121238742Simp 122238742Simp (*i) += endx - x; 123238742Simp return val; 124238742Simp} 125238742Simp 126238742Simp/* 127238742Simp * Parse a hexadecimal encoded character starting at index i in string s. The 128238742Simp * resulting character will be returned and the index i will be updated to 129238742Simp * point at the character directly after the end of the encoding, this may be 130238742Simp * the '\0' terminator of the string. 131238742Simp */ 132238742Simpstatic char get_hex_char(const char *s, int *i) 133238742Simp{ 134238742Simp char x[3]; 135238742Simp char *endx; 136238742Simp long val; 137238742Simp 138238742Simp x[2] = '\0'; 139238742Simp strncpy(x, s + *i, 2); 140238742Simp 141238742Simp val = strtol(x, &endx, 16); 142238742Simp if (!(endx > x)) 143238742Simp die("\\x used with no following hex digits\n"); 144238742Simp 145238742Simp (*i) += endx - x; 146238742Simp return val; 147238742Simp} 148238742Simp 149238742Simpchar get_escape_char(const char *s, int *i) 150238742Simp{ 151238742Simp char c = s[*i]; 152238742Simp int j = *i + 1; 153238742Simp char val; 154238742Simp 155238742Simp assert(c); 156238742Simp switch (c) { 157238742Simp case 'a': 158238742Simp val = '\a'; 159238742Simp break; 160238742Simp case 'b': 161238742Simp val = '\b'; 162238742Simp break; 163238742Simp case 't': 164238742Simp val = '\t'; 165238742Simp break; 166238742Simp case 'n': 167238742Simp val = '\n'; 168238742Simp break; 169238742Simp case 'v': 170238742Simp val = '\v'; 171238742Simp break; 172238742Simp case 'f': 173238742Simp val = '\f'; 174238742Simp break; 175238742Simp case 'r': 176238742Simp val = '\r'; 177238742Simp break; 178238742Simp case '0': 179238742Simp case '1': 180238742Simp case '2': 181238742Simp case '3': 182238742Simp case '4': 183238742Simp case '5': 184238742Simp case '6': 185238742Simp case '7': 186238742Simp j--; /* need to re-read the first digit as 187238742Simp * part of the octal value */ 188238742Simp val = get_oct_char(s, &j); 189238742Simp break; 190238742Simp case 'x': 191238742Simp val = get_hex_char(s, &j); 192238742Simp break; 193238742Simp default: 194238742Simp val = c; 195238742Simp } 196238742Simp 197238742Simp (*i) = j; 198238742Simp return val; 199238742Simp} 200238742Simp 201266130Sianint utilfdt_read_err_len(const char *filename, char **buffp, off_t *len) 202238742Simp{ 203238742Simp int fd = 0; /* assume stdin */ 204238742Simp char *buf = NULL; 205238742Simp off_t bufsize = 1024, offset = 0; 206238742Simp int ret = 0; 207238742Simp 208238742Simp *buffp = NULL; 209238742Simp if (strcmp(filename, "-") != 0) { 210238742Simp fd = open(filename, O_RDONLY); 211238742Simp if (fd < 0) 212238742Simp return errno; 213238742Simp } 214238742Simp 215238742Simp /* Loop until we have read everything */ 216266130Sian buf = xmalloc(bufsize); 217238742Simp do { 218238742Simp /* Expand the buffer to hold the next chunk */ 219238742Simp if (offset == bufsize) { 220238742Simp bufsize *= 2; 221266130Sian buf = xrealloc(buf, bufsize); 222238742Simp if (!buf) { 223238742Simp ret = ENOMEM; 224238742Simp break; 225238742Simp } 226238742Simp } 227238742Simp 228238742Simp ret = read(fd, &buf[offset], bufsize - offset); 229238742Simp if (ret < 0) { 230238742Simp ret = errno; 231238742Simp break; 232238742Simp } 233238742Simp offset += ret; 234238742Simp } while (ret != 0); 235238742Simp 236238742Simp /* Clean up, including closing stdin; return errno on error */ 237238742Simp close(fd); 238238742Simp if (ret) 239238742Simp free(buf); 240238742Simp else 241238742Simp *buffp = buf; 242266130Sian *len = bufsize; 243238742Simp return ret; 244238742Simp} 245238742Simp 246266130Sianint utilfdt_read_err(const char *filename, char **buffp) 247238742Simp{ 248266130Sian off_t len; 249266130Sian return utilfdt_read_err_len(filename, buffp, &len); 250266130Sian} 251266130Sian 252266130Sianchar *utilfdt_read_len(const char *filename, off_t *len) 253266130Sian{ 254238742Simp char *buff; 255266130Sian int ret = utilfdt_read_err_len(filename, &buff, len); 256238742Simp 257238742Simp if (ret) { 258238742Simp fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename, 259238742Simp strerror(ret)); 260238742Simp return NULL; 261238742Simp } 262238742Simp /* Successful read */ 263238742Simp return buff; 264238742Simp} 265238742Simp 266266130Sianchar *utilfdt_read(const char *filename) 267266130Sian{ 268266130Sian off_t len; 269266130Sian return utilfdt_read_len(filename, &len); 270266130Sian} 271266130Sian 272238742Simpint utilfdt_write_err(const char *filename, const void *blob) 273238742Simp{ 274238742Simp int fd = 1; /* assume stdout */ 275238742Simp int totalsize; 276238742Simp int offset; 277238742Simp int ret = 0; 278238742Simp const char *ptr = blob; 279238742Simp 280238742Simp if (strcmp(filename, "-") != 0) { 281238742Simp fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); 282238742Simp if (fd < 0) 283238742Simp return errno; 284238742Simp } 285238742Simp 286238742Simp totalsize = fdt_totalsize(blob); 287238742Simp offset = 0; 288238742Simp 289238742Simp while (offset < totalsize) { 290238742Simp ret = write(fd, ptr + offset, totalsize - offset); 291238742Simp if (ret < 0) { 292238742Simp ret = -errno; 293238742Simp break; 294238742Simp } 295238742Simp offset += ret; 296238742Simp } 297238742Simp /* Close the file/stdin; return errno on error */ 298238742Simp if (fd != 1) 299238742Simp close(fd); 300238742Simp return ret < 0 ? -ret : 0; 301238742Simp} 302238742Simp 303238742Simp 304238742Simpint utilfdt_write(const char *filename, const void *blob) 305238742Simp{ 306238742Simp int ret = utilfdt_write_err(filename, blob); 307238742Simp 308238742Simp if (ret) { 309238742Simp fprintf(stderr, "Couldn't write blob to '%s': %s\n", filename, 310238742Simp strerror(ret)); 311238742Simp } 312238742Simp return ret ? -1 : 0; 313238742Simp} 314238742Simp 315238742Simpint utilfdt_decode_type(const char *fmt, int *type, int *size) 316238742Simp{ 317238742Simp int qualifier = 0; 318238742Simp 319238742Simp if (!*fmt) 320238742Simp return -1; 321238742Simp 322238742Simp /* get the conversion qualifier */ 323238742Simp *size = -1; 324238742Simp if (strchr("hlLb", *fmt)) { 325238742Simp qualifier = *fmt++; 326238742Simp if (qualifier == *fmt) { 327238742Simp switch (*fmt++) { 328238742Simp/* TODO: case 'l': qualifier = 'L'; break;*/ 329238742Simp case 'h': 330238742Simp qualifier = 'b'; 331238742Simp break; 332238742Simp } 333238742Simp } 334238742Simp } 335238742Simp 336238742Simp /* we should now have a type */ 337238742Simp if ((*fmt == '\0') || !strchr("iuxs", *fmt)) 338238742Simp return -1; 339238742Simp 340238742Simp /* convert qualifier (bhL) to byte size */ 341238742Simp if (*fmt != 's') 342238742Simp *size = qualifier == 'b' ? 1 : 343238742Simp qualifier == 'h' ? 2 : 344238742Simp qualifier == 'l' ? 4 : -1; 345238742Simp *type = *fmt++; 346238742Simp 347238742Simp /* that should be it! */ 348238742Simp if (*fmt) 349238742Simp return -1; 350238742Simp return 0; 351238742Simp} 352266130Sian 353266130Sianvoid utilfdt_print_data(const char *data, int len) 354266130Sian{ 355266130Sian int i; 356266130Sian const char *p = data; 357266130Sian const char *s; 358266130Sian 359266130Sian /* no data, don't print */ 360266130Sian if (len == 0) 361266130Sian return; 362266130Sian 363266130Sian if (util_is_printable_string(data, len)) { 364266130Sian printf(" = "); 365266130Sian 366266130Sian s = data; 367266130Sian do { 368266130Sian printf("\"%s\"", s); 369266130Sian s += strlen(s) + 1; 370266130Sian if (s < data + len) 371266130Sian printf(", "); 372266130Sian } while (s < data + len); 373266130Sian 374266130Sian } else if ((len % 4) == 0) { 375266130Sian const uint32_t *cell = (const uint32_t *)data; 376266130Sian 377266130Sian printf(" = <"); 378266130Sian for (i = 0; i < len; i += 4) 379266130Sian printf("0x%08x%s", fdt32_to_cpu(cell[i / 4]), 380266130Sian i < (len - 4) ? " " : ""); 381266130Sian printf(">"); 382266130Sian } else { 383266130Sian printf(" = ["); 384266130Sian for (i = 0; i < len; i++) 385266130Sian printf("%02x%s", *p++, i < len - 1 ? " " : ""); 386266130Sian printf("]"); 387266130Sian } 388266130Sian} 389266130Sian 390266130Sianvoid util_version(void) 391266130Sian{ 392266130Sian printf("Version: %s\n", DTC_VERSION); 393266130Sian exit(0); 394266130Sian} 395266130Sian 396266130Sianvoid util_usage(const char *errmsg, const char *synopsis, 397266130Sian const char *short_opts, struct option const long_opts[], 398266130Sian const char * const opts_help[]) 399266130Sian{ 400266130Sian FILE *fp = errmsg ? stderr : stdout; 401266130Sian const char a_arg[] = "<arg>"; 402266130Sian size_t a_arg_len = strlen(a_arg) + 1; 403266130Sian size_t i; 404266130Sian int optlen; 405266130Sian 406266130Sian fprintf(fp, 407266130Sian "Usage: %s\n" 408266130Sian "\n" 409266130Sian "Options: -[%s]\n", synopsis, short_opts); 410266130Sian 411266130Sian /* prescan the --long opt length to auto-align */ 412266130Sian optlen = 0; 413266130Sian for (i = 0; long_opts[i].name; ++i) { 414266130Sian /* +1 is for space between --opt and help text */ 415266130Sian int l = strlen(long_opts[i].name) + 1; 416266130Sian if (long_opts[i].has_arg == a_argument) 417266130Sian l += a_arg_len; 418266130Sian if (optlen < l) 419266130Sian optlen = l; 420266130Sian } 421266130Sian 422266130Sian for (i = 0; long_opts[i].name; ++i) { 423266130Sian /* helps when adding new applets or options */ 424266130Sian assert(opts_help[i] != NULL); 425266130Sian 426266130Sian /* first output the short flag if it has one */ 427266130Sian if (long_opts[i].val > '~') 428266130Sian fprintf(fp, " "); 429266130Sian else 430266130Sian fprintf(fp, " -%c, ", long_opts[i].val); 431266130Sian 432266130Sian /* then the long flag */ 433266130Sian if (long_opts[i].has_arg == no_argument) 434266130Sian fprintf(fp, "--%-*s", optlen, long_opts[i].name); 435266130Sian else 436266130Sian fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg, 437266130Sian (int)(optlen - strlen(long_opts[i].name) - a_arg_len), ""); 438266130Sian 439266130Sian /* finally the help text */ 440266130Sian fprintf(fp, "%s\n", opts_help[i]); 441266130Sian } 442266130Sian 443266130Sian if (errmsg) { 444266130Sian fprintf(fp, "\nError: %s\n", errmsg); 445266130Sian exit(EXIT_FAILURE); 446266130Sian } else 447266130Sian exit(EXIT_SUCCESS); 448266130Sian} 449