Blame view

tools/mkenvimage.c 7.32 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
a6337e6ff   David Wagner   new tool mkenvima...
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
a6337e6ff   David Wagner   new tool mkenvima...
9
10
11
12
13
   */
  
  #include <errno.h>
  #include <fcntl.h>
  #include <stdio.h>
d1acdae98   David Wagner   mkenvimage: Corre...
14
  #include <stdlib.h>
a6337e6ff   David Wagner   new tool mkenvima...
15
16
  #include <stdint.h>
  #include <string.h>
3db711085   Simon Glass   crc32: Use the cr...
17
  #include <u-boot/crc.h>
a6337e6ff   David Wagner   new tool mkenvima...
18
  #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);
  }
849f9bef4   Andre Przywara   tools: mkenvimage...
85
  #define CHUNK_SIZE 4096
a6337e6ff   David Wagner   new tool mkenvima...
86
87
88
  int main(int argc, char **argv)
  {
  	uint32_t crc, targetendian_crc;
849f9bef4   Andre Przywara   tools: mkenvimage...
89
  	const char *bin_filename = NULL;
a6337e6ff   David Wagner   new tool mkenvima...
90
91
92
93
94
95
96
  	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;
849f9bef4   Andre Przywara   tools: mkenvimage...
97
  	int readbytes = 0;
a6337e6ff   David Wagner   new tool mkenvima...
98
99
100
  
  	int option;
  	int ret = EXIT_SUCCESS;
a6337e6ff   David Wagner   new tool mkenvima...
101
  	int fp, ep;
af44f4b2a   Horst Kronstorfer   Print program bas...
102
103
104
  	const char *prg;
  
  	prg = basename(argv[0]);
a6337e6ff   David Wagner   new tool mkenvima...
105

5e0c63e2e   Horst Kronstorfer   mkenvimage: Fix g...
106
107
  	/* Turn off getopt()'s internal error message */
  	opterr = 0;
a6337e6ff   David Wagner   new tool mkenvima...
108
  	/* Parse the cmdline */
1895420b2   Horst Kronstorfer   mkenvimage: Add v...
109
  	while ((option = getopt(argc, argv, ":s:o:rbp:hV")) != -1) {
a6337e6ff   David Wagner   new tool mkenvima...
110
111
  		switch (option) {
  		case 's':
3d0f9bd03   David Wagner   mkenvimage: More ...
112
  			datasize = xstrtol(optarg);
a6337e6ff   David Wagner   new tool mkenvima...
113
114
115
116
  			break;
  		case 'o':
  			bin_filename = strdup(optarg);
  			if (!bin_filename) {
8a1b8fc78   David Wagner   mkenvimage: corre...
117
118
  				fprintf(stderr, "Can't strdup() the output filename
  ");
a6337e6ff   David Wagner   new tool mkenvima...
119
120
121
122
123
124
125
126
127
128
  				return EXIT_FAILURE;
  			}
  			break;
  		case 'r':
  			redundant = 1;
  			break;
  		case 'b':
  			bigendian = 1;
  			break;
  		case 'p':
3d0f9bd03   David Wagner   mkenvimage: More ...
129
  			padbyte = xstrtol(optarg);
a6337e6ff   David Wagner   new tool mkenvima...
130
131
  			break;
  		case 'h':
af44f4b2a   Horst Kronstorfer   Print program bas...
132
  			usage(prg);
a6337e6ff   David Wagner   new tool mkenvima...
133
  			return EXIT_SUCCESS;
1895420b2   Horst Kronstorfer   mkenvimage: Add v...
134
135
136
137
  		case 'V':
  			printf("%s version %s
  ", prg, PLAIN_VERSION);
  			return EXIT_SUCCESS;
5e0c63e2e   Horst Kronstorfer   mkenvimage: Fix g...
138
139
140
  		case ':':
  			fprintf(stderr, "Missing argument for option -%c
  ",
72ebafbe2   Horst Kronstorfer   tools/mkenvimage....
141
  				optopt);
e758a5c4a   Wolfgang Denk   mkenvimage: fix u...
142
  			usage(prg);
5e0c63e2e   Horst Kronstorfer   mkenvimage: Fix g...
143
  			return EXIT_FAILURE;
a6337e6ff   David Wagner   new tool mkenvima...
144
  		default:
72ebafbe2   Horst Kronstorfer   tools/mkenvimage....
145
146
  			fprintf(stderr, "Wrong option -%c
  ", optopt);
af44f4b2a   Horst Kronstorfer   Print program bas...
147
  			usage(prg);
a6337e6ff   David Wagner   new tool mkenvima...
148
149
150
151
152
153
  			return EXIT_FAILURE;
  		}
  	}
  
  	/* Check datasize and allocate the data */
  	if (datasize == 0) {
8a1b8fc78   David Wagner   mkenvimage: corre...
154
155
  		fprintf(stderr, "Please specify the size of the environment partition.
  ");
af44f4b2a   Horst Kronstorfer   Print program bas...
156
  		usage(prg);
a6337e6ff   David Wagner   new tool mkenvima...
157
158
159
160
161
  		return EXIT_FAILURE;
  	}
  
  	dataptr = malloc(datasize * sizeof(*dataptr));
  	if (!dataptr) {
8a1b8fc78   David Wagner   mkenvimage: corre...
162
163
164
  		fprintf(stderr, "Can't alloc %d bytes for dataptr.
  ",
  				datasize);
a6337e6ff   David Wagner   new tool mkenvima...
165
166
167
168
169
  		return EXIT_FAILURE;
  	}
  
  	/*
  	 * envptr points to the beginning of the actual environment (after the
8a1b8fc78   David Wagner   mkenvimage: corre...
170
  	 * crc and possible `redundant' byte
a6337e6ff   David Wagner   new tool mkenvima...
171
172
173
174
175
176
177
178
  	 */
  	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/...
179
  	if (optind >= argc || strcmp(argv[optind], "-") == 0) {
a6337e6ff   David Wagner   new tool mkenvima...
180
  		txt_fd = STDIN_FILENO;
a6337e6ff   David Wagner   new tool mkenvima...
181
  	} else {
849f9bef4   Andre Przywara   tools: mkenvimage...
182
  		txt_fd = open(argv[optind], O_RDONLY);
a6337e6ff   David Wagner   new tool mkenvima...
183
184
185
  		if (txt_fd == -1) {
  			fprintf(stderr, "Can't open \"%s\": %s
  ",
849f9bef4   Andre Przywara   tools: mkenvimage...
186
  					argv[optind], strerror(errno));
a6337e6ff   David Wagner   new tool mkenvima...
187
188
  			return EXIT_FAILURE;
  		}
849f9bef4   Andre Przywara   tools: mkenvimage...
189
190
191
192
193
194
195
  	}
  
  	do {
  		filebuf = realloc(filebuf, filesize + CHUNK_SIZE);
  		if (!filebuf) {
  			fprintf(stderr, "Can't realloc memory for the input file buffer
  ");
a6337e6ff   David Wagner   new tool mkenvima...
196
197
  			return EXIT_FAILURE;
  		}
849f9bef4   Andre Przywara   tools: mkenvimage...
198
199
200
201
202
203
  		readbytes = read(txt_fd, filebuf + filesize, CHUNK_SIZE);
  		if (readbytes < 0) {
  			fprintf(stderr, "Error while reading: %s
  ",
  				strerror(errno));
  			return EXIT_FAILURE;
a6337e6ff   David Wagner   new tool mkenvima...
204
  		}
849f9bef4   Andre Przywara   tools: mkenvimage...
205
206
207
208
  		filesize += readbytes;
  	} while (readbytes > 0);
  
  	if (txt_fd != STDIN_FILENO)
a6337e6ff   David Wagner   new tool mkenvima...
209
  		ret = close(txt_fd);
a6337e6ff   David Wagner   new tool mkenvima...
210

80ee0196a   Brian McFarland   Patch to mkenvima...
211
212
213
  	/* 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...
214
215
  		if (filebuf[fp] == '
  ') {
e72be8947   Dominik Muth   Added support for...
216
217
  			if (fp == 0 || filebuf[fp-1] == '
  ') {
a6337e6ff   David Wagner   new tool mkenvima...
218
  				/*
e72be8947   Dominik Muth   Added support for...
219
  				 * Skip empty lines.
a6337e6ff   David Wagner   new tool mkenvima...
220
221
222
223
224
225
  				 */
  				continue;
  			} else if (filebuf[fp-1] == '\\') {
  				/*
  				 * Embedded newline in a variable.
  				 *
dbee61db4   David Wagner   Correctly handle ...
226
227
  				 * The backslash was added to the envptr; rewind
  				 * and replace it with a newline
a6337e6ff   David Wagner   new tool mkenvima...
228
229
230
231
232
233
234
235
  				 */
  				ep--;
  				envptr[ep++] = '
  ';
  			} else {
  				/* End of a variable */
  				envptr[ep++] = '\0';
  			}
e72be8947   Dominik Muth   Added support for...
236
237
238
239
240
241
  		} 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...
242
243
244
245
  		} else {
  			envptr[ep++] = filebuf[fp];
  		}
  	}
80ee0196a   Brian McFarland   Patch to mkenvima...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
  	/* 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...
270
271
272
273
274
275
276
277
278
279
280
  	/*
  	 * 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...
281
282
  			fprintf(stderr, "The environment file is too large for the target environment storage
  ");
a6337e6ff   David Wagner   new tool mkenvima...
283
284
285
286
287
288
289
290
291
292
  			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...
293
294
295
  	memcpy(dataptr, &targetendian_crc, sizeof(targetendian_crc));
  	if (redundant)
  		dataptr[sizeof(targetendian_crc)] = 1;
a6337e6ff   David Wagner   new tool mkenvima...
296

48995b5a9   David Wagner   mkenvimage: Read/...
297
298
299
  	if (!bin_filename || strcmp(bin_filename, "-") == 0) {
  		bin_fd = STDOUT_FILENO;
  	} else {
4f7136e7c   Mike Frysinger   tools: clean up m...
300
301
  		bin_fd = creat(bin_filename, S_IRUSR | S_IWUSR | S_IRGRP |
  					     S_IWGRP);
48995b5a9   David Wagner   mkenvimage: Read/...
302
303
304
305
306
307
  		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...
308
309
310
311
312
313
314
315
316
317
318
319
320
  	}
  
  	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;
  }