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