util.c revision 238742
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
38char *xstrdup(const char *s)
39{
40	int len = strlen(s) + 1;
41	char *dup = xmalloc(len);
42
43	memcpy(dup, s, len);
44
45	return dup;
46}
47
48char *join_path(const char *path, const char *name)
49{
50	int lenp = strlen(path);
51	int lenn = strlen(name);
52	int len;
53	int needslash = 1;
54	char *str;
55
56	len = lenp + lenn + 2;
57	if ((lenp > 0) && (path[lenp-1] == '/')) {
58		needslash = 0;
59		len--;
60	}
61
62	str = xmalloc(len);
63	memcpy(str, path, lenp);
64	if (needslash) {
65		str[lenp] = '/';
66		lenp++;
67	}
68	memcpy(str+lenp, name, lenn+1);
69	return str;
70}
71
72int util_is_printable_string(const void *data, int len)
73{
74	const char *s = data;
75	const char *ss;
76
77	/* zero length is not */
78	if (len == 0)
79		return 0;
80
81	/* must terminate with zero */
82	if (s[len - 1] != '\0')
83		return 0;
84
85	ss = s;
86	while (*s && isprint(*s))
87		s++;
88
89	/* not zero, or not done yet */
90	if (*s != '\0' || (s + 1 - ss) < len)
91		return 0;
92
93	return 1;
94}
95
96/*
97 * Parse a octal encoded character starting at index i in string s.  The
98 * resulting character will be returned and the index i will be updated to
99 * point at the character directly after the end of the encoding, this may be
100 * the '\0' terminator of the string.
101 */
102static char get_oct_char(const char *s, int *i)
103{
104	char x[4];
105	char *endx;
106	long val;
107
108	x[3] = '\0';
109	strncpy(x, s + *i, 3);
110
111	val = strtol(x, &endx, 8);
112
113	assert(endx > x);
114
115	(*i) += endx - x;
116	return val;
117}
118
119/*
120 * Parse a hexadecimal encoded character starting at index i in string s.  The
121 * resulting character will be returned and the index i will be updated to
122 * point at the character directly after the end of the encoding, this may be
123 * the '\0' terminator of the string.
124 */
125static char get_hex_char(const char *s, int *i)
126{
127	char x[3];
128	char *endx;
129	long val;
130
131	x[2] = '\0';
132	strncpy(x, s + *i, 2);
133
134	val = strtol(x, &endx, 16);
135	if (!(endx  > x))
136		die("\\x used with no following hex digits\n");
137
138	(*i) += endx - x;
139	return val;
140}
141
142char get_escape_char(const char *s, int *i)
143{
144	char	c = s[*i];
145	int	j = *i + 1;
146	char	val;
147
148	assert(c);
149	switch (c) {
150	case 'a':
151		val = '\a';
152		break;
153	case 'b':
154		val = '\b';
155		break;
156	case 't':
157		val = '\t';
158		break;
159	case 'n':
160		val = '\n';
161		break;
162	case 'v':
163		val = '\v';
164		break;
165	case 'f':
166		val = '\f';
167		break;
168	case 'r':
169		val = '\r';
170		break;
171	case '0':
172	case '1':
173	case '2':
174	case '3':
175	case '4':
176	case '5':
177	case '6':
178	case '7':
179		j--; /* need to re-read the first digit as
180		      * part of the octal value */
181		val = get_oct_char(s, &j);
182		break;
183	case 'x':
184		val = get_hex_char(s, &j);
185		break;
186	default:
187		val = c;
188	}
189
190	(*i) = j;
191	return val;
192}
193
194int utilfdt_read_err(const char *filename, char **buffp)
195{
196	int fd = 0;	/* assume stdin */
197	char *buf = NULL;
198	off_t bufsize = 1024, offset = 0;
199	int ret = 0;
200
201	*buffp = NULL;
202	if (strcmp(filename, "-") != 0) {
203		fd = open(filename, O_RDONLY);
204		if (fd < 0)
205			return errno;
206	}
207
208	/* Loop until we have read everything */
209	buf = malloc(bufsize);
210	do {
211		/* Expand the buffer to hold the next chunk */
212		if (offset == bufsize) {
213			bufsize *= 2;
214			buf = realloc(buf, bufsize);
215			if (!buf) {
216				ret = ENOMEM;
217				break;
218			}
219		}
220
221		ret = read(fd, &buf[offset], bufsize - offset);
222		if (ret < 0) {
223			ret = errno;
224			break;
225		}
226		offset += ret;
227	} while (ret != 0);
228
229	/* Clean up, including closing stdin; return errno on error */
230	close(fd);
231	if (ret)
232		free(buf);
233	else
234		*buffp = buf;
235	return ret;
236}
237
238char *utilfdt_read(const char *filename)
239{
240	char *buff;
241	int ret = utilfdt_read_err(filename, &buff);
242
243	if (ret) {
244		fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
245			strerror(ret));
246		return NULL;
247	}
248	/* Successful read */
249	return buff;
250}
251
252int utilfdt_write_err(const char *filename, const void *blob)
253{
254	int fd = 1;	/* assume stdout */
255	int totalsize;
256	int offset;
257	int ret = 0;
258	const char *ptr = blob;
259
260	if (strcmp(filename, "-") != 0) {
261		fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
262		if (fd < 0)
263			return errno;
264	}
265
266	totalsize = fdt_totalsize(blob);
267	offset = 0;
268
269	while (offset < totalsize) {
270		ret = write(fd, ptr + offset, totalsize - offset);
271		if (ret < 0) {
272			ret = -errno;
273			break;
274		}
275		offset += ret;
276	}
277	/* Close the file/stdin; return errno on error */
278	if (fd != 1)
279		close(fd);
280	return ret < 0 ? -ret : 0;
281}
282
283
284int utilfdt_write(const char *filename, const void *blob)
285{
286	int ret = utilfdt_write_err(filename, blob);
287
288	if (ret) {
289		fprintf(stderr, "Couldn't write blob to '%s': %s\n", filename,
290			strerror(ret));
291	}
292	return ret ? -1 : 0;
293}
294
295int utilfdt_decode_type(const char *fmt, int *type, int *size)
296{
297	int qualifier = 0;
298
299	if (!*fmt)
300		return -1;
301
302	/* get the conversion qualifier */
303	*size = -1;
304	if (strchr("hlLb", *fmt)) {
305		qualifier = *fmt++;
306		if (qualifier == *fmt) {
307			switch (*fmt++) {
308/* TODO:		case 'l': qualifier = 'L'; break;*/
309			case 'h':
310				qualifier = 'b';
311				break;
312			}
313		}
314	}
315
316	/* we should now have a type */
317	if ((*fmt == '\0') || !strchr("iuxs", *fmt))
318		return -1;
319
320	/* convert qualifier (bhL) to byte size */
321	if (*fmt != 's')
322		*size = qualifier == 'b' ? 1 :
323				qualifier == 'h' ? 2 :
324				qualifier == 'l' ? 4 : -1;
325	*type = *fmt++;
326
327	/* that should be it! */
328	if (*fmt)
329		return -1;
330	return 0;
331}
332