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