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