Blame view

tools/mkenvimage.c 8.19 KB
a6337e6ff   David Wagner   new tool mkenvima...
1
2
3
4
5
6
7
8
  /*
   * (C) Copyright 2011 Free Electrons
   * David Wagner <david.wagner@free-electrons.com>
   *
   * Inspired from envcrc.c:
   * (C) Copyright 2001
   * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
9
   * SPDX-License-Identifier:	GPL-2.0+
a6337e6ff   David Wagner   new tool mkenvima...
10
11
12
13
14
   */
  
  #include <errno.h>
  #include <fcntl.h>
  #include <stdio.h>
d1acdae98   David Wagner   mkenvimage: Corre...
15
  #include <stdlib.h>
a6337e6ff   David Wagner   new tool mkenvima...
16
17
18
  #include <stdint.h>
  #include <string.h>
  #include <unistd.h>
558cd995d   Andreas Bießmann   tools/mkenvimage....
19
  #include <libgen.h>
a6337e6ff   David Wagner   new tool mkenvima...
20
21
  #include <sys/types.h>
  #include <sys/stat.h>
6ee39f805   David Wagner   mkenvimage: Use m...
22
  #include <sys/mman.h>
a6337e6ff   David Wagner   new tool mkenvima...
23

d1acdae98   David Wagner   mkenvimage: Corre...
24
  #include "compiler.h"
a6337e6ff   David Wagner   new tool mkenvima...
25
  #include <u-boot/crc.h>
1895420b2   Horst Kronstorfer   mkenvimage: Add v...
26
  #include <version.h>
a6337e6ff   David Wagner   new tool mkenvima...
27
28
29
30
31
  
  #define CRC_SIZE sizeof(uint32_t)
  
  static void usage(const char *exec_name)
  {
8a1b8fc78   David Wagner   mkenvimage: corre...
32
33
  	fprintf(stderr, "%s [-h] [-r] [-b] [-p <byte>] -s <environment partition size> -o <output> <input file>
  "
a6337e6ff   David Wagner   new tool mkenvima...
34
35
  	       "
  "
8a1b8fc78   David Wagner   mkenvimage: corre...
36
37
  	       "This tool takes a key=value input file (same as would a `printenv' show) and generates the corresponding environment image, ready to be flashed.
  "
a6337e6ff   David Wagner   new tool mkenvima...
38
39
40
41
42
43
44
45
46
47
  	       "
  "
  	       "\tThe input file is in format:
  "
  	       "\t\tkey1=value1
  "
  	       "\t\tkey2=value2
  "
  	       "\t\t...
  "
e72be8947   Dominik Muth   Added support for...
48
49
50
51
  	       "\tEmpty lines are skipped, and lines with a # in the first
  "
  	       "\tcolumn are treated as comments (also skipped).
  "
a6337e6ff   David Wagner   new tool mkenvima...
52
53
54
55
  	       "\t-r : the environment has multiple copies in flash
  "
  	       "\t-b : the target is big endian (default is little endian)
  "
8a1b8fc78   David Wagner   mkenvimage: corre...
56
57
  	       "\t-p <byte> : fill the image with <byte> bytes instead of 0xff bytes
  "
1895420b2   Horst Kronstorfer   mkenvimage: Add v...
58
59
  	       "\t-V : print version information and exit
  "
a6337e6ff   David Wagner   new tool mkenvima...
60
61
62
63
64
65
  	       "
  "
  	       "If the input file is \"-\", data is read from standard input
  ",
  	       exec_name);
  }
3d0f9bd03   David Wagner   mkenvimage: More ...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  long int xstrtol(const char *s)
  {
  	long int tmp;
  
  	errno = 0;
  	tmp = strtol(s, NULL, 0);
  	if (!errno)
  		return tmp;
  
  	if (errno == ERANGE)
  		fprintf(stderr, "Bad integer format: %s
  ",  s);
  	else
  		fprintf(stderr, "Error while parsing %s: %s
  ", s,
  				strerror(errno));
  
  	exit(EXIT_FAILURE);
  }
a6337e6ff   David Wagner   new tool mkenvima...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  int main(int argc, char **argv)
  {
  	uint32_t crc, targetendian_crc;
  	const char *txt_filename = NULL, *bin_filename = NULL;
  	int txt_fd, bin_fd;
  	unsigned char *dataptr, *envptr;
  	unsigned char *filebuf = NULL;
  	unsigned int filesize = 0, envsize = 0, datasize = 0;
  	int bigendian = 0;
  	int redundant = 0;
  	unsigned char padbyte = 0xff;
  
  	int option;
  	int ret = EXIT_SUCCESS;
  
  	struct stat txt_file_stat;
  
  	int fp, ep;
af44f4b2a   Horst Kronstorfer   Print program bas...
103
104
105
  	const char *prg;
  
  	prg = basename(argv[0]);
a6337e6ff   David Wagner   new tool mkenvima...
106

5e0c63e2e   Horst Kronstorfer   mkenvimage: Fix g...
107
108
  	/* Turn off getopt()'s internal error message */
  	opterr = 0;
a6337e6ff   David Wagner   new tool mkenvima...
109
  	/* Parse the cmdline */
1895420b2   Horst Kronstorfer   mkenvimage: Add v...
110
  	while ((option = getopt(argc, argv, ":s:o:rbp:hV")) != -1) {
a6337e6ff   David Wagner   new tool mkenvima...
111
112
  		switch (option) {
  		case 's':
3d0f9bd03   David Wagner   mkenvimage: More ...
113
  			datasize = xstrtol(optarg);
a6337e6ff   David Wagner   new tool mkenvima...
114
115
116
117
  			break;
  		case 'o':
  			bin_filename = strdup(optarg);
  			if (!bin_filename) {
8a1b8fc78   David Wagner   mkenvimage: corre...
118
119
  				fprintf(stderr, "Can't strdup() the output filename
  ");
a6337e6ff   David Wagner   new tool mkenvima...
120
121
122
123
124
125
126
127
128
129
  				return EXIT_FAILURE;
  			}
  			break;
  		case 'r':
  			redundant = 1;
  			break;
  		case 'b':
  			bigendian = 1;
  			break;
  		case 'p':
3d0f9bd03   David Wagner   mkenvimage: More ...
130
  			padbyte = xstrtol(optarg);
a6337e6ff   David Wagner   new tool mkenvima...
131
132
  			break;
  		case 'h':
af44f4b2a   Horst Kronstorfer   Print program bas...
133
  			usage(prg);
a6337e6ff   David Wagner   new tool mkenvima...
134
  			return EXIT_SUCCESS;
1895420b2   Horst Kronstorfer   mkenvimage: Add v...
135
136
137
138
  		case 'V':
  			printf("%s version %s
  ", prg, PLAIN_VERSION);
  			return EXIT_SUCCESS;
5e0c63e2e   Horst Kronstorfer   mkenvimage: Fix g...
139
140
141
  		case ':':
  			fprintf(stderr, "Missing argument for option -%c
  ",
72ebafbe2   Horst Kronstorfer   tools/mkenvimage....
142
  				optopt);
e758a5c4a   Wolfgang Denk   mkenvimage: fix u...
143
  			usage(prg);
5e0c63e2e   Horst Kronstorfer   mkenvimage: Fix g...
144
  			return EXIT_FAILURE;
a6337e6ff   David Wagner   new tool mkenvima...
145
  		default:
72ebafbe2   Horst Kronstorfer   tools/mkenvimage....
146
147
  			fprintf(stderr, "Wrong option -%c
  ", optopt);
af44f4b2a   Horst Kronstorfer   Print program bas...
148
  			usage(prg);
a6337e6ff   David Wagner   new tool mkenvima...
149
150
151
152
153
154
  			return EXIT_FAILURE;
  		}
  	}
  
  	/* Check datasize and allocate the data */
  	if (datasize == 0) {
8a1b8fc78   David Wagner   mkenvimage: corre...
155
156
  		fprintf(stderr, "Please specify the size of the environment partition.
  ");
af44f4b2a   Horst Kronstorfer   Print program bas...
157
  		usage(prg);
a6337e6ff   David Wagner   new tool mkenvima...
158
159
160
161
162
  		return EXIT_FAILURE;
  	}
  
  	dataptr = malloc(datasize * sizeof(*dataptr));
  	if (!dataptr) {
8a1b8fc78   David Wagner   mkenvimage: corre...
163
164
165
  		fprintf(stderr, "Can't alloc %d bytes for dataptr.
  ",
  				datasize);
a6337e6ff   David Wagner   new tool mkenvima...
166
167
168
169
170
  		return EXIT_FAILURE;
  	}
  
  	/*
  	 * envptr points to the beginning of the actual environment (after the
8a1b8fc78   David Wagner   mkenvimage: corre...
171
  	 * crc and possible `redundant' byte
a6337e6ff   David Wagner   new tool mkenvima...
172
173
174
175
176
177
178
179
  	 */
  	envsize = datasize - (CRC_SIZE + redundant);
  	envptr = dataptr + CRC_SIZE + redundant;
  
  	/* Pad the environment with the padding byte */
  	memset(envptr, padbyte, envsize);
  
  	/* Open the input file ... */
48995b5a9   David Wagner   mkenvimage: Read/...
180
  	if (optind >= argc || strcmp(argv[optind], "-") == 0) {
a6337e6ff   David Wagner   new tool mkenvima...
181
  		int readbytes = 0;
48995b5a9   David Wagner   mkenvimage: Read/...
182
  		int readlen = sizeof(*envptr) * 4096;
a6337e6ff   David Wagner   new tool mkenvima...
183
184
185
186
  		txt_fd = STDIN_FILENO;
  
  		do {
  			filebuf = realloc(filebuf, readlen);
3d0f9bd03   David Wagner   mkenvimage: More ...
187
188
189
190
191
  			if (!filebuf) {
  				fprintf(stderr, "Can't realloc memory for the input file buffer
  ");
  				return EXIT_FAILURE;
  			}
a6337e6ff   David Wagner   new tool mkenvima...
192
  			readbytes = read(txt_fd, filebuf + filesize, readlen);
3d0f9bd03   David Wagner   mkenvimage: More ...
193
194
195
196
197
198
  			if (errno) {
  				fprintf(stderr, "Error while reading stdin: %s
  ",
  						strerror(errno));
  				return EXIT_FAILURE;
  			}
a6337e6ff   David Wagner   new tool mkenvima...
199
200
201
202
  			filesize += readbytes;
  		} while (readbytes == readlen);
  
  	} else {
48995b5a9   David Wagner   mkenvimage: Read/...
203
  		txt_filename = argv[optind];
a6337e6ff   David Wagner   new tool mkenvima...
204
205
206
207
208
209
210
211
212
213
  		txt_fd = open(txt_filename, O_RDONLY);
  		if (txt_fd == -1) {
  			fprintf(stderr, "Can't open \"%s\": %s
  ",
  					txt_filename, strerror(errno));
  			return EXIT_FAILURE;
  		}
  		/* ... and check it */
  		ret = fstat(txt_fd, &txt_file_stat);
  		if (ret == -1) {
8a1b8fc78   David Wagner   mkenvimage: corre...
214
215
216
  			fprintf(stderr, "Can't stat() on \"%s\": %s
  ",
  					txt_filename, strerror(errno));
a6337e6ff   David Wagner   new tool mkenvima...
217
218
219
220
  			return EXIT_FAILURE;
  		}
  
  		filesize = txt_file_stat.st_size;
6ee39f805   David Wagner   mkenvimage: Use m...
221
222
223
224
  
  		filebuf = mmap(NULL, sizeof(*envptr) * filesize, PROT_READ,
  			       MAP_PRIVATE, txt_fd, 0);
  		if (filebuf == MAP_FAILED) {
1ebff63fb   Dirk Behme   mkenvimage: Fix c...
225
226
  			fprintf(stderr, "mmap (%zu bytes) failed: %s
  ",
6ee39f805   David Wagner   mkenvimage: Use m...
227
228
229
230
231
232
233
234
  					sizeof(*envptr) * filesize,
  					strerror(errno));
  			fprintf(stderr, "Falling back to read()
  ");
  
  			filebuf = malloc(sizeof(*envptr) * filesize);
  			ret = read(txt_fd, filebuf, sizeof(*envptr) * filesize);
  			if (ret != sizeof(*envptr) * filesize) {
1ebff63fb   Dirk Behme   mkenvimage: Fix c...
235
236
  				fprintf(stderr, "Can't read the whole input file (%zu bytes): %s
  ",
6ee39f805   David Wagner   mkenvimage: Use m...
237
238
239
240
241
  					sizeof(*envptr) * filesize,
  					strerror(errno));
  
  				return EXIT_FAILURE;
  			}
a6337e6ff   David Wagner   new tool mkenvima...
242
243
244
  		}
  		ret = close(txt_fd);
  	}
a6337e6ff   David Wagner   new tool mkenvima...
245

80ee0196a   Brian McFarland   Patch to mkenvima...
246
247
248
  	/* Parse a byte at time until reaching the file OR until the environment fills
  	 * up. Check ep against envsize - 1 to allow for extra trailing '\0'. */
  	for (fp = 0, ep = 0 ; fp < filesize && ep < envsize - 1; fp++) {
a6337e6ff   David Wagner   new tool mkenvima...
249
250
  		if (filebuf[fp] == '
  ') {
e72be8947   Dominik Muth   Added support for...
251
252
  			if (fp == 0 || filebuf[fp-1] == '
  ') {
a6337e6ff   David Wagner   new tool mkenvima...
253
  				/*
e72be8947   Dominik Muth   Added support for...
254
  				 * Skip empty lines.
a6337e6ff   David Wagner   new tool mkenvima...
255
256
257
258
259
260
  				 */
  				continue;
  			} else if (filebuf[fp-1] == '\\') {
  				/*
  				 * Embedded newline in a variable.
  				 *
dbee61db4   David Wagner   Correctly handle ...
261
262
  				 * The backslash was added to the envptr; rewind
  				 * and replace it with a newline
a6337e6ff   David Wagner   new tool mkenvima...
263
264
265
266
267
268
269
270
  				 */
  				ep--;
  				envptr[ep++] = '
  ';
  			} else {
  				/* End of a variable */
  				envptr[ep++] = '\0';
  			}
e72be8947   Dominik Muth   Added support for...
271
272
273
274
275
276
  		} else if ((fp == 0 || filebuf[fp-1] == '
  ') && filebuf[fp] == '#') {
  			/* Comment, skip the line. */
  			while (++fp < filesize && filebuf[fp] != '
  ')
  			continue;
a6337e6ff   David Wagner   new tool mkenvima...
277
278
279
280
  		} else {
  			envptr[ep++] = filebuf[fp];
  		}
  	}
80ee0196a   Brian McFarland   Patch to mkenvima...
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  	/* If there are more bytes in the file still, it means the env filled up
  	 * before parsing the whole file.  Eat comments & whitespace here to see if
  	 * there was anything meaning full left in the file, and if so, throw a error
  	 * and exit. */
  	for( ; fp < filesize; fp++ )
  	{
  		if (filebuf[fp] == '
  ') {
  			if (fp == 0 || filebuf[fp-1] == '
  ') {
  				/* Ignore blank lines */
  				continue;
  			}
  		} else if ((fp == 0 || filebuf[fp-1] == '
  ') && filebuf[fp] == '#') {
  			while (++fp < filesize && filebuf[fp] != '
  ')
  			continue;
  		} else {
  			fprintf(stderr, "The environment file is too large for the target environment storage
  ");
  			return EXIT_FAILURE;
  		}
  	}
a6337e6ff   David Wagner   new tool mkenvima...
305
306
307
308
309
310
311
312
313
314
315
  	/*
  	 * Make sure there is a final '\0'
  	 * And do it again on the next byte to mark the end of the environment.
  	 */
  	if (envptr[ep-1] != '\0') {
  		envptr[ep++] = '\0';
  		/*
  		 * The text file doesn't have an ending newline.  We need to
  		 * check the env size again to make sure we have room for two \0
  		 */
  		if (ep >= envsize) {
8a1b8fc78   David Wagner   mkenvimage: corre...
316
317
  			fprintf(stderr, "The environment file is too large for the target environment storage
  ");
a6337e6ff   David Wagner   new tool mkenvima...
318
319
320
321
322
323
324
325
326
327
  			return EXIT_FAILURE;
  		}
  		envptr[ep] = '\0';
  	} else {
  		envptr[ep] = '\0';
  	}
  
  	/* Computes the CRC and put it at the beginning of the data */
  	crc = crc32(0, envptr, envsize);
  	targetendian_crc = bigendian ? cpu_to_be32(crc) : cpu_to_le32(crc);
d8d265999   David Wagner   mkenvimage: Reall...
328
329
330
  	memcpy(dataptr, &targetendian_crc, sizeof(targetendian_crc));
  	if (redundant)
  		dataptr[sizeof(targetendian_crc)] = 1;
a6337e6ff   David Wagner   new tool mkenvima...
331

48995b5a9   David Wagner   mkenvimage: Read/...
332
333
334
  	if (!bin_filename || strcmp(bin_filename, "-") == 0) {
  		bin_fd = STDOUT_FILENO;
  	} else {
4f7136e7c   Mike Frysinger   tools: clean up m...
335
336
  		bin_fd = creat(bin_filename, S_IRUSR | S_IWUSR | S_IRGRP |
  					     S_IWGRP);
48995b5a9   David Wagner   mkenvimage: Read/...
337
338
339
340
341
342
  		if (bin_fd == -1) {
  			fprintf(stderr, "Can't open output file \"%s\": %s
  ",
  					bin_filename, strerror(errno));
  			return EXIT_FAILURE;
  		}
a6337e6ff   David Wagner   new tool mkenvima...
343
344
345
346
347
348
349
350
351
352
353
354
355
  	}
  
  	if (write(bin_fd, dataptr, sizeof(*dataptr) * datasize) !=
  			sizeof(*dataptr) * datasize) {
  		fprintf(stderr, "write() failed: %s
  ", strerror(errno));
  		return EXIT_FAILURE;
  	}
  
  	ret = close(bin_fd);
  
  	return ret;
  }