1 /* 2 * Copyright 2011 The Chromium Authors, All Rights Reserved. 3 * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc. 4 * 5 * util_is_printable_string contributed by 6 * Pantelis Antoniou <pantelis.antoniou AT gmail.com> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of the 11 * License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 21 * USA 22 */ 23 24 #include <ctype.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <stdarg.h> 28 #include <string.h> 29 #include <assert.h> 30 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 35 #include "libfdt.h" 36 #include "util.h" 37 #include "version_gen.h" 38 39 char *xstrdup(const char *s) 40 { 41 int len = strlen(s) + 1; 42 char *d = xmalloc(len); 43 44 memcpy(d, s, len); 45 46 return d; 47 } 48 49 /* based in part from (3) vsnprintf */ 50 int xasprintf(char **strp, const char *fmt, ...) 51 { 52 int n, size = 128; /* start with 128 bytes */ 53 char *p; 54 va_list ap; 55 56 /* initial pointer is NULL making the fist realloc to be malloc */ 57 p = NULL; 58 while (1) { 59 p = xrealloc(p, size); 60 61 /* Try to print in the allocated space. */ 62 va_start(ap, fmt); 63 n = vsnprintf(p, size, fmt, ap); 64 va_end(ap); 65 66 /* If that worked, return the string. */ 67 if (n > -1 && n < size) 68 break; 69 /* Else try again with more space. */ 70 if (n > -1) /* glibc 2.1 */ 71 size = n + 1; /* precisely what is needed */ 72 else /* glibc 2.0 */ 73 size *= 2; /* twice the old size */ 74 } 75 *strp = p; 76 return strlen(p); 77 } 78 79 char *join_path(const char *path, const char *name) 80 { 81 int lenp = strlen(path); 82 int lenn = strlen(name); 83 int len; 84 int needslash = 1; 85 char *str; 86 87 len = lenp + lenn + 2; 88 if ((lenp > 0) && (path[lenp-1] == '/')) { 89 needslash = 0; 90 len--; 91 } 92 93 str = xmalloc(len); 94 memcpy(str, path, lenp); 95 if (needslash) { 96 str[lenp] = '/'; 97 lenp++; 98 } 99 memcpy(str+lenp, name, lenn+1); 100 return str; 101 } 102 103 bool util_is_printable_string(const void *data, int len) 104 { 105 const char *s = data; 106 const char *ss, *se; 107 108 /* zero length is not */ 109 if (len == 0) 110 return 0; 111 112 /* must terminate with zero */ 113 if (s[len - 1] != '\0') 114 return 0; 115 116 se = s + len; 117 118 while (s < se) { 119 ss = s; 120 while (s < se && *s && isprint((unsigned char)*s)) 121 s++; 122 123 /* not zero, or not done yet */ 124 if (*s != '\0' || s == ss) 125 return 0; 126 127 s++; 128 } 129 130 return 1; 131 } 132 133 /* 134 * Parse a octal encoded character starting at index i in string s. The 135 * resulting character will be returned and the index i will be updated to 136 * point at the character directly after the end of the encoding, this may be 137 * the '\0' terminator of the string. 138 */ 139 static char get_oct_char(const char *s, int *i) 140 { 141 char x[4]; 142 char *endx; 143 long val; 144 145 x[3] = '\0'; 146 strncpy(x, s + *i, 3); 147 148 val = strtol(x, &endx, 8); 149 150 assert(endx > x); 151 152 (*i) += endx - x; 153 return val; 154 } 155 156 /* 157 * Parse a hexadecimal encoded character starting at index i in string s. The 158 * resulting character will be returned and the index i will be updated to 159 * point at the character directly after the end of the encoding, this may be 160 * the '\0' terminator of the string. 161 */ 162 static char get_hex_char(const char *s, int *i) 163 { 164 char x[3]; 165 char *endx; 166 long val; 167 168 x[2] = '\0'; 169 strncpy(x, s + *i, 2); 170 171 val = strtol(x, &endx, 16); 172 if (!(endx > x)) 173 die("\\x used with no following hex digits\n"); 174 175 (*i) += endx - x; 176 return val; 177 } 178 179 char get_escape_char(const char *s, int *i) 180 { 181 char c = s[*i]; 182 int j = *i + 1; 183 char val; 184 185 switch (c) { 186 case 'a': 187 val = '\a'; 188 break; 189 case 'b': 190 val = '\b'; 191 break; 192 case 't': 193 val = '\t'; 194 break; 195 case 'n': 196 val = '\n'; 197 break; 198 case 'v': 199 val = '\v'; 200 break; 201 case 'f': 202 val = '\f'; 203 break; 204 case 'r': 205 val = '\r'; 206 break; 207 case '0': 208 case '1': 209 case '2': 210 case '3': 211 case '4': 212 case '5': 213 case '6': 214 case '7': 215 j--; /* need to re-read the first digit as 216 * part of the octal value */ 217 val = get_oct_char(s, &j); 218 break; 219 case 'x': 220 val = get_hex_char(s, &j); 221 break; 222 default: 223 val = c; 224 } 225 226 (*i) = j; 227 return val; 228 } 229 230 int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len) 231 { 232 int fd = 0; /* assume stdin */ 233 char *buf = NULL; 234 off_t bufsize = 1024, offset = 0; 235 int ret = 0; 236 237 *buffp = NULL; 238 if (strcmp(filename, "-") != 0) { 239 fd = open(filename, O_RDONLY); 240 if (fd < 0) 241 return errno; 242 } 243 244 /* Loop until we have read everything */ 245 buf = xmalloc(bufsize); 246 do { 247 /* Expand the buffer to hold the next chunk */ 248 if (offset == bufsize) { 249 bufsize *= 2; 250 buf = xrealloc(buf, bufsize); 251 } 252 253 ret = read(fd, &buf[offset], bufsize - offset); 254 if (ret < 0) { 255 ret = errno; 256 break; 257 } 258 offset += ret; 259 } while (ret != 0); 260 261 /* Clean up, including closing stdin; return errno on error */ 262 close(fd); 263 if (ret) 264 free(buf); 265 else 266 *buffp = buf; 267 *len = bufsize; 268 return ret; 269 } 270 271 int utilfdt_read_err(const char *filename, char **buffp) 272 { 273 off_t len; 274 return utilfdt_read_err_len(filename, buffp, &len); 275 } 276 277 char *utilfdt_read_len(const char *filename, off_t *len) 278 { 279 char *buff; 280 int ret = utilfdt_read_err_len(filename, &buff, len); 281 282 if (ret) { 283 fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename, 284 strerror(ret)); 285 return NULL; 286 } 287 /* Successful read */ 288 return buff; 289 } 290 291 char *utilfdt_read(const char *filename) 292 { 293 off_t len; 294 return utilfdt_read_len(filename, &len); 295 } 296 297 int utilfdt_write_err(const char *filename, const void *blob) 298 { 299 int fd = 1; /* assume stdout */ 300 int totalsize; 301 int offset; 302 int ret = 0; 303 const char *ptr = blob; 304 305 if (strcmp(filename, "-") != 0) { 306 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); 307 if (fd < 0) 308 return errno; 309 } 310 311 totalsize = fdt_totalsize(blob); 312 offset = 0; 313 314 while (offset < totalsize) { 315 ret = write(fd, ptr + offset, totalsize - offset); 316 if (ret < 0) { 317 ret = -errno; 318 break; 319 } 320 offset += ret; 321 } 322 /* Close the file/stdin; return errno on error */ 323 if (fd != 1) 324 close(fd); 325 return ret < 0 ? -ret : 0; 326 } 327 328 329 int utilfdt_write(const char *filename, const void *blob) 330 { 331 int ret = utilfdt_write_err(filename, blob); 332 333 if (ret) { 334 fprintf(stderr, "Couldn't write blob to '%s': %s\n", filename, 335 strerror(ret)); 336 } 337 return ret ? -1 : 0; 338 } 339 340 int utilfdt_decode_type(const char *fmt, int *type, int *size) 341 { 342 int qualifier = 0; 343 344 if (!*fmt) 345 return -1; 346 347 /* get the conversion qualifier */ 348 *size = -1; 349 if (strchr("hlLb", *fmt)) { 350 qualifier = *fmt++; 351 if (qualifier == *fmt) { 352 switch (*fmt++) { 353 /* TODO: case 'l': qualifier = 'L'; break;*/ 354 case 'h': 355 qualifier = 'b'; 356 break; 357 } 358 } 359 } 360 361 /* we should now have a type */ 362 if ((*fmt == '\0') || !strchr("iuxs", *fmt)) 363 return -1; 364 365 /* convert qualifier (bhL) to byte size */ 366 if (*fmt != 's') 367 *size = qualifier == 'b' ? 1 : 368 qualifier == 'h' ? 2 : 369 qualifier == 'l' ? 4 : -1; 370 *type = *fmt++; 371 372 /* that should be it! */ 373 if (*fmt) 374 return -1; 375 return 0; 376 } 377 378 void utilfdt_print_data(const char *data, int len) 379 { 380 int i; 381 const char *s; 382 383 /* no data, don't print */ 384 if (len == 0) 385 return; 386 387 if (util_is_printable_string(data, len)) { 388 printf(" = "); 389 390 s = data; 391 do { 392 printf("\"%s\"", s); 393 s += strlen(s) + 1; 394 if (s < data + len) 395 printf(", "); 396 } while (s < data + len); 397 398 } else if ((len % 4) == 0) { 399 const uint32_t *cell = (const uint32_t *)data; 400 401 printf(" = <"); 402 for (i = 0, len /= 4; i < len; i++) 403 printf("0x%08x%s", fdt32_to_cpu(cell[i]), 404 i < (len - 1) ? " " : ""); 405 printf(">"); 406 } else { 407 const unsigned char *p = (const unsigned char *)data; 408 printf(" = ["); 409 for (i = 0; i < len; i++) 410 printf("%02x%s", *p++, i < len - 1 ? " " : ""); 411 printf("]"); 412 } 413 } 414 415 void util_version(void) 416 { 417 printf("Version: %s\n", DTC_VERSION); 418 exit(0); 419 } 420 421 void util_usage(const char *errmsg, const char *synopsis, 422 const char *short_opts, struct option const long_opts[], 423 const char * const opts_help[]) 424 { 425 FILE *fp = errmsg ? stderr : stdout; 426 const char a_arg[] = "<arg>"; 427 size_t a_arg_len = strlen(a_arg) + 1; 428 size_t i; 429 int optlen; 430 431 fprintf(fp, 432 "Usage: %s\n" 433 "\n" 434 "Options: -[%s]\n", synopsis, short_opts); 435 436 /* prescan the --long opt length to auto-align */ 437 optlen = 0; 438 for (i = 0; long_opts[i].name; ++i) { 439 /* +1 is for space between --opt and help text */ 440 int l = strlen(long_opts[i].name) + 1; 441 if (long_opts[i].has_arg == a_argument) 442 l += a_arg_len; 443 if (optlen < l) 444 optlen = l; 445 } 446 447 for (i = 0; long_opts[i].name; ++i) { 448 /* helps when adding new applets or options */ 449 assert(opts_help[i] != NULL); 450 451 /* first output the short flag if it has one */ 452 if (long_opts[i].val > '~') 453 fprintf(fp, " "); 454 else 455 fprintf(fp, " -%c, ", long_opts[i].val); 456 457 /* then the long flag */ 458 if (long_opts[i].has_arg == no_argument) 459 fprintf(fp, "--%-*s", optlen, long_opts[i].name); 460 else 461 fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg, 462 (int)(optlen - strlen(long_opts[i].name) - a_arg_len), ""); 463 464 /* finally the help text */ 465 fprintf(fp, "%s\n", opts_help[i]); 466 } 467 468 if (errmsg) { 469 fprintf(fp, "\nError: %s\n", errmsg); 470 exit(EXIT_FAILURE); 471 } else 472 exit(EXIT_SUCCESS); 473 } 474