]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - scripts/dtc/util.c
Merge tag 'riscv-for-linus-4.20-mw3' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-jammy-kernel.git] / scripts / dtc / util.c
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 }