1204433Sraj/*
2238742Simp * Copyright 2011 The Chromium Authors, All Rights Reserved.
3204433Sraj * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
4204433Sraj *
5238742Simp * util_is_printable_string contributed by
6238742Simp *	Pantelis Antoniou <pantelis.antoniou AT gmail.com>
7238742Simp *
8204433Sraj * This program is free software; you can redistribute it and/or
9204433Sraj * modify it under the terms of the GNU General Public License as
10204433Sraj * published by the Free Software Foundation; either version 2 of the
11204433Sraj * License, or (at your option) any later version.
12204433Sraj *
13204433Sraj *  This program is distributed in the hope that it will be useful,
14204433Sraj *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15204433Sraj *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16204433Sraj *  General Public License for more details.
17204433Sraj *
18204433Sraj *  You should have received a copy of the GNU General Public License
19204433Sraj *  along with this program; if not, write to the Free Software
20204433Sraj *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
21204433Sraj *                                                                   USA
22204433Sraj */
23204433Sraj
24238742Simp#include <ctype.h>
25238742Simp#include <stdio.h>
26238742Simp#include <stdlib.h>
27238742Simp#include <stdarg.h>
28238742Simp#include <string.h>
29238742Simp#include <assert.h>
30204433Sraj
31238742Simp#include <errno.h>
32238742Simp#include <fcntl.h>
33238742Simp#include <unistd.h>
34238742Simp
35238742Simp#include "libfdt.h"
36238742Simp#include "util.h"
37266130Sian#include "version_gen.h"
38238742Simp
39204433Srajchar *xstrdup(const char *s)
40204433Sraj{
41204433Sraj	int len = strlen(s) + 1;
42204433Sraj	char *dup = xmalloc(len);
43204433Sraj
44204433Sraj	memcpy(dup, s, len);
45204433Sraj
46204433Sraj	return dup;
47204433Sraj}
48238742Simp
49238742Simpchar *join_path(const char *path, const char *name)
50238742Simp{
51238742Simp	int lenp = strlen(path);
52238742Simp	int lenn = strlen(name);
53238742Simp	int len;
54238742Simp	int needslash = 1;
55238742Simp	char *str;
56238742Simp
57238742Simp	len = lenp + lenn + 2;
58238742Simp	if ((lenp > 0) && (path[lenp-1] == '/')) {
59238742Simp		needslash = 0;
60238742Simp		len--;
61238742Simp	}
62238742Simp
63238742Simp	str = xmalloc(len);
64238742Simp	memcpy(str, path, lenp);
65238742Simp	if (needslash) {
66238742Simp		str[lenp] = '/';
67238742Simp		lenp++;
68238742Simp	}
69238742Simp	memcpy(str+lenp, name, lenn+1);
70238742Simp	return str;
71238742Simp}
72238742Simp
73266130Sianbool util_is_printable_string(const void *data, int len)
74238742Simp{
75238742Simp	const char *s = data;
76266130Sian	const char *ss, *se;
77238742Simp
78238742Simp	/* zero length is not */
79238742Simp	if (len == 0)
80238742Simp		return 0;
81238742Simp
82238742Simp	/* must terminate with zero */
83238742Simp	if (s[len - 1] != '\0')
84238742Simp		return 0;
85238742Simp
86266130Sian	se = s + len;
87266130Sian
88266130Sian	while (s < se) {
89266130Sian		ss = s;
90266130Sian		while (s < se && *s && isprint((unsigned char)*s))
91266130Sian			s++;
92266130Sian
93266130Sian		/* not zero, or not done yet */
94266130Sian		if (*s != '\0' || s == ss)
95266130Sian			return 0;
96266130Sian
97238742Simp		s++;
98266130Sian	}
99238742Simp
100238742Simp	return 1;
101238742Simp}
102238742Simp
103238742Simp/*
104238742Simp * Parse a octal encoded character starting at index i in string s.  The
105238742Simp * resulting character will be returned and the index i will be updated to
106238742Simp * point at the character directly after the end of the encoding, this may be
107238742Simp * the '\0' terminator of the string.
108238742Simp */
109238742Simpstatic char get_oct_char(const char *s, int *i)
110238742Simp{
111238742Simp	char x[4];
112238742Simp	char *endx;
113238742Simp	long val;
114238742Simp
115238742Simp	x[3] = '\0';
116238742Simp	strncpy(x, s + *i, 3);
117238742Simp
118238742Simp	val = strtol(x, &endx, 8);
119238742Simp
120238742Simp	assert(endx > x);
121238742Simp
122238742Simp	(*i) += endx - x;
123238742Simp	return val;
124238742Simp}
125238742Simp
126238742Simp/*
127238742Simp * Parse a hexadecimal encoded character starting at index i in string s.  The
128238742Simp * resulting character will be returned and the index i will be updated to
129238742Simp * point at the character directly after the end of the encoding, this may be
130238742Simp * the '\0' terminator of the string.
131238742Simp */
132238742Simpstatic char get_hex_char(const char *s, int *i)
133238742Simp{
134238742Simp	char x[3];
135238742Simp	char *endx;
136238742Simp	long val;
137238742Simp
138238742Simp	x[2] = '\0';
139238742Simp	strncpy(x, s + *i, 2);
140238742Simp
141238742Simp	val = strtol(x, &endx, 16);
142238742Simp	if (!(endx  > x))
143238742Simp		die("\\x used with no following hex digits\n");
144238742Simp
145238742Simp	(*i) += endx - x;
146238742Simp	return val;
147238742Simp}
148238742Simp
149238742Simpchar get_escape_char(const char *s, int *i)
150238742Simp{
151238742Simp	char	c = s[*i];
152238742Simp	int	j = *i + 1;
153238742Simp	char	val;
154238742Simp
155238742Simp	assert(c);
156238742Simp	switch (c) {
157238742Simp	case 'a':
158238742Simp		val = '\a';
159238742Simp		break;
160238742Simp	case 'b':
161238742Simp		val = '\b';
162238742Simp		break;
163238742Simp	case 't':
164238742Simp		val = '\t';
165238742Simp		break;
166238742Simp	case 'n':
167238742Simp		val = '\n';
168238742Simp		break;
169238742Simp	case 'v':
170238742Simp		val = '\v';
171238742Simp		break;
172238742Simp	case 'f':
173238742Simp		val = '\f';
174238742Simp		break;
175238742Simp	case 'r':
176238742Simp		val = '\r';
177238742Simp		break;
178238742Simp	case '0':
179238742Simp	case '1':
180238742Simp	case '2':
181238742Simp	case '3':
182238742Simp	case '4':
183238742Simp	case '5':
184238742Simp	case '6':
185238742Simp	case '7':
186238742Simp		j--; /* need to re-read the first digit as
187238742Simp		      * part of the octal value */
188238742Simp		val = get_oct_char(s, &j);
189238742Simp		break;
190238742Simp	case 'x':
191238742Simp		val = get_hex_char(s, &j);
192238742Simp		break;
193238742Simp	default:
194238742Simp		val = c;
195238742Simp	}
196238742Simp
197238742Simp	(*i) = j;
198238742Simp	return val;
199238742Simp}
200238742Simp
201266130Sianint utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
202238742Simp{
203238742Simp	int fd = 0;	/* assume stdin */
204238742Simp	char *buf = NULL;
205238742Simp	off_t bufsize = 1024, offset = 0;
206238742Simp	int ret = 0;
207238742Simp
208238742Simp	*buffp = NULL;
209238742Simp	if (strcmp(filename, "-") != 0) {
210238742Simp		fd = open(filename, O_RDONLY);
211238742Simp		if (fd < 0)
212238742Simp			return errno;
213238742Simp	}
214238742Simp
215238742Simp	/* Loop until we have read everything */
216266130Sian	buf = xmalloc(bufsize);
217238742Simp	do {
218238742Simp		/* Expand the buffer to hold the next chunk */
219238742Simp		if (offset == bufsize) {
220238742Simp			bufsize *= 2;
221266130Sian			buf = xrealloc(buf, bufsize);
222238742Simp			if (!buf) {
223238742Simp				ret = ENOMEM;
224238742Simp				break;
225238742Simp			}
226238742Simp		}
227238742Simp
228238742Simp		ret = read(fd, &buf[offset], bufsize - offset);
229238742Simp		if (ret < 0) {
230238742Simp			ret = errno;
231238742Simp			break;
232238742Simp		}
233238742Simp		offset += ret;
234238742Simp	} while (ret != 0);
235238742Simp
236238742Simp	/* Clean up, including closing stdin; return errno on error */
237238742Simp	close(fd);
238238742Simp	if (ret)
239238742Simp		free(buf);
240238742Simp	else
241238742Simp		*buffp = buf;
242266130Sian	*len = bufsize;
243238742Simp	return ret;
244238742Simp}
245238742Simp
246266130Sianint utilfdt_read_err(const char *filename, char **buffp)
247238742Simp{
248266130Sian	off_t len;
249266130Sian	return utilfdt_read_err_len(filename, buffp, &len);
250266130Sian}
251266130Sian
252266130Sianchar *utilfdt_read_len(const char *filename, off_t *len)
253266130Sian{
254238742Simp	char *buff;
255266130Sian	int ret = utilfdt_read_err_len(filename, &buff, len);
256238742Simp
257238742Simp	if (ret) {
258238742Simp		fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
259238742Simp			strerror(ret));
260238742Simp		return NULL;
261238742Simp	}
262238742Simp	/* Successful read */
263238742Simp	return buff;
264238742Simp}
265238742Simp
266266130Sianchar *utilfdt_read(const char *filename)
267266130Sian{
268266130Sian	off_t len;
269266130Sian	return utilfdt_read_len(filename, &len);
270266130Sian}
271266130Sian
272238742Simpint utilfdt_write_err(const char *filename, const void *blob)
273238742Simp{
274238742Simp	int fd = 1;	/* assume stdout */
275238742Simp	int totalsize;
276238742Simp	int offset;
277238742Simp	int ret = 0;
278238742Simp	const char *ptr = blob;
279238742Simp
280238742Simp	if (strcmp(filename, "-") != 0) {
281238742Simp		fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
282238742Simp		if (fd < 0)
283238742Simp			return errno;
284238742Simp	}
285238742Simp
286238742Simp	totalsize = fdt_totalsize(blob);
287238742Simp	offset = 0;
288238742Simp
289238742Simp	while (offset < totalsize) {
290238742Simp		ret = write(fd, ptr + offset, totalsize - offset);
291238742Simp		if (ret < 0) {
292238742Simp			ret = -errno;
293238742Simp			break;
294238742Simp		}
295238742Simp		offset += ret;
296238742Simp	}
297238742Simp	/* Close the file/stdin; return errno on error */
298238742Simp	if (fd != 1)
299238742Simp		close(fd);
300238742Simp	return ret < 0 ? -ret : 0;
301238742Simp}
302238742Simp
303238742Simp
304238742Simpint utilfdt_write(const char *filename, const void *blob)
305238742Simp{
306238742Simp	int ret = utilfdt_write_err(filename, blob);
307238742Simp
308238742Simp	if (ret) {
309238742Simp		fprintf(stderr, "Couldn't write blob to '%s': %s\n", filename,
310238742Simp			strerror(ret));
311238742Simp	}
312238742Simp	return ret ? -1 : 0;
313238742Simp}
314238742Simp
315238742Simpint utilfdt_decode_type(const char *fmt, int *type, int *size)
316238742Simp{
317238742Simp	int qualifier = 0;
318238742Simp
319238742Simp	if (!*fmt)
320238742Simp		return -1;
321238742Simp
322238742Simp	/* get the conversion qualifier */
323238742Simp	*size = -1;
324238742Simp	if (strchr("hlLb", *fmt)) {
325238742Simp		qualifier = *fmt++;
326238742Simp		if (qualifier == *fmt) {
327238742Simp			switch (*fmt++) {
328238742Simp/* TODO:		case 'l': qualifier = 'L'; break;*/
329238742Simp			case 'h':
330238742Simp				qualifier = 'b';
331238742Simp				break;
332238742Simp			}
333238742Simp		}
334238742Simp	}
335238742Simp
336238742Simp	/* we should now have a type */
337238742Simp	if ((*fmt == '\0') || !strchr("iuxs", *fmt))
338238742Simp		return -1;
339238742Simp
340238742Simp	/* convert qualifier (bhL) to byte size */
341238742Simp	if (*fmt != 's')
342238742Simp		*size = qualifier == 'b' ? 1 :
343238742Simp				qualifier == 'h' ? 2 :
344238742Simp				qualifier == 'l' ? 4 : -1;
345238742Simp	*type = *fmt++;
346238742Simp
347238742Simp	/* that should be it! */
348238742Simp	if (*fmt)
349238742Simp		return -1;
350238742Simp	return 0;
351238742Simp}
352266130Sian
353266130Sianvoid utilfdt_print_data(const char *data, int len)
354266130Sian{
355266130Sian	int i;
356266130Sian	const char *p = data;
357266130Sian	const char *s;
358266130Sian
359266130Sian	/* no data, don't print */
360266130Sian	if (len == 0)
361266130Sian		return;
362266130Sian
363266130Sian	if (util_is_printable_string(data, len)) {
364266130Sian		printf(" = ");
365266130Sian
366266130Sian		s = data;
367266130Sian		do {
368266130Sian			printf("\"%s\"", s);
369266130Sian			s += strlen(s) + 1;
370266130Sian			if (s < data + len)
371266130Sian				printf(", ");
372266130Sian		} while (s < data + len);
373266130Sian
374266130Sian	} else if ((len % 4) == 0) {
375266130Sian		const uint32_t *cell = (const uint32_t *)data;
376266130Sian
377266130Sian		printf(" = <");
378266130Sian		for (i = 0; i < len; i += 4)
379266130Sian			printf("0x%08x%s", fdt32_to_cpu(cell[i / 4]),
380266130Sian			       i < (len - 4) ? " " : "");
381266130Sian		printf(">");
382266130Sian	} else {
383266130Sian		printf(" = [");
384266130Sian		for (i = 0; i < len; i++)
385266130Sian			printf("%02x%s", *p++, i < len - 1 ? " " : "");
386266130Sian		printf("]");
387266130Sian	}
388266130Sian}
389266130Sian
390266130Sianvoid util_version(void)
391266130Sian{
392266130Sian	printf("Version: %s\n", DTC_VERSION);
393266130Sian	exit(0);
394266130Sian}
395266130Sian
396266130Sianvoid util_usage(const char *errmsg, const char *synopsis,
397266130Sian		const char *short_opts, struct option const long_opts[],
398266130Sian		const char * const opts_help[])
399266130Sian{
400266130Sian	FILE *fp = errmsg ? stderr : stdout;
401266130Sian	const char a_arg[] = "<arg>";
402266130Sian	size_t a_arg_len = strlen(a_arg) + 1;
403266130Sian	size_t i;
404266130Sian	int optlen;
405266130Sian
406266130Sian	fprintf(fp,
407266130Sian		"Usage: %s\n"
408266130Sian		"\n"
409266130Sian		"Options: -[%s]\n", synopsis, short_opts);
410266130Sian
411266130Sian	/* prescan the --long opt length to auto-align */
412266130Sian	optlen = 0;
413266130Sian	for (i = 0; long_opts[i].name; ++i) {
414266130Sian		/* +1 is for space between --opt and help text */
415266130Sian		int l = strlen(long_opts[i].name) + 1;
416266130Sian		if (long_opts[i].has_arg == a_argument)
417266130Sian			l += a_arg_len;
418266130Sian		if (optlen < l)
419266130Sian			optlen = l;
420266130Sian	}
421266130Sian
422266130Sian	for (i = 0; long_opts[i].name; ++i) {
423266130Sian		/* helps when adding new applets or options */
424266130Sian		assert(opts_help[i] != NULL);
425266130Sian
426266130Sian		/* first output the short flag if it has one */
427266130Sian		if (long_opts[i].val > '~')
428266130Sian			fprintf(fp, "      ");
429266130Sian		else
430266130Sian			fprintf(fp, "  -%c, ", long_opts[i].val);
431266130Sian
432266130Sian		/* then the long flag */
433266130Sian		if (long_opts[i].has_arg == no_argument)
434266130Sian			fprintf(fp, "--%-*s", optlen, long_opts[i].name);
435266130Sian		else
436266130Sian			fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
437266130Sian				(int)(optlen - strlen(long_opts[i].name) - a_arg_len), "");
438266130Sian
439266130Sian		/* finally the help text */
440266130Sian		fprintf(fp, "%s\n", opts_help[i]);
441266130Sian	}
442266130Sian
443266130Sian	if (errmsg) {
444266130Sian		fprintf(fp, "\nError: %s\n", errmsg);
445266130Sian		exit(EXIT_FAILURE);
446266130Sian	} else
447266130Sian		exit(EXIT_SUCCESS);
448266130Sian}
449