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