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