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