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