blob: 3bb471d310ee6f1fa5f5d9e388290d11f395bb16 [file] [log] [blame]
David Wagnera6337e62011-09-26 03:26:34 +00001/*
2 * (C) Copyright 2011 Free Electrons
3 * David Wagner <david.wagner@free-electrons.com>
4 *
5 * Inspired from envcrc.c:
6 * (C) Copyright 2001
7 * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
8 *
9 * See file CREDITS for list of people who contributed to this
10 * project.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
26 */
27
Horst Kronstorferaf44f4b2011-12-21 10:39:39 +000028/* We want the GNU version of basename() */
29#define _GNU_SOURCE
30
David Wagnera6337e62011-09-26 03:26:34 +000031#include <errno.h>
32#include <fcntl.h>
33#include <stdio.h>
34#include <stdint.h>
35#include <string.h>
36#include <unistd.h>
37#include <compiler.h>
38#include <sys/types.h>
39#include <sys/stat.h>
40
41#include <u-boot/crc.h>
42
43#define CRC_SIZE sizeof(uint32_t)
44
45static void usage(const char *exec_name)
46{
47 fprintf(stderr, "%s [-h] [-r] [-b] [-p <byte>] "
48 "-s <environment partition size> -o <output> <input file>\n"
49 "\n"
50 "This tool takes a key=value input file (same as would a "
51 "`printenv' show) and generates the corresponding environment "
52 "image, ready to be flashed.\n"
53 "\n"
54 "\tThe input file is in format:\n"
55 "\t\tkey1=value1\n"
56 "\t\tkey2=value2\n"
57 "\t\t...\n"
58 "\t-r : the environment has multiple copies in flash\n"
59 "\t-b : the target is big endian (default is little endian)\n"
60 "\t-p <byte> : fill the image with <byte> bytes instead of "
61 "0xff bytes\n"
62 "\n"
63 "If the input file is \"-\", data is read from standard input\n",
64 exec_name);
65}
66
67int main(int argc, char **argv)
68{
69 uint32_t crc, targetendian_crc;
70 const char *txt_filename = NULL, *bin_filename = NULL;
71 int txt_fd, bin_fd;
72 unsigned char *dataptr, *envptr;
73 unsigned char *filebuf = NULL;
74 unsigned int filesize = 0, envsize = 0, datasize = 0;
75 int bigendian = 0;
76 int redundant = 0;
77 unsigned char padbyte = 0xff;
78
79 int option;
80 int ret = EXIT_SUCCESS;
81
82 struct stat txt_file_stat;
83
84 int fp, ep;
Horst Kronstorferaf44f4b2011-12-21 10:39:39 +000085 const char *prg;
86
87 prg = basename(argv[0]);
David Wagnera6337e62011-09-26 03:26:34 +000088
89 /* Parse the cmdline */
90 while ((option = getopt(argc, argv, "s:o:rbp:h")) != -1) {
91 switch (option) {
92 case 's':
93 datasize = strtol(optarg, NULL, 0);
94 break;
95 case 'o':
96 bin_filename = strdup(optarg);
97 if (!bin_filename) {
98 fprintf(stderr, "Can't strdup() the output "
99 "filename\n");
100 return EXIT_FAILURE;
101 }
102 break;
103 case 'r':
104 redundant = 1;
105 break;
106 case 'b':
107 bigendian = 1;
108 break;
109 case 'p':
110 padbyte = strtol(optarg, NULL, 0);
111 break;
112 case 'h':
Horst Kronstorferaf44f4b2011-12-21 10:39:39 +0000113 usage(prg);
David Wagnera6337e62011-09-26 03:26:34 +0000114 return EXIT_SUCCESS;
115 default:
116 fprintf(stderr, "Wrong option -%c\n", option);
Horst Kronstorferaf44f4b2011-12-21 10:39:39 +0000117 usage(prg);
David Wagnera6337e62011-09-26 03:26:34 +0000118 return EXIT_FAILURE;
119 }
120 }
121
122 /* Check datasize and allocate the data */
123 if (datasize == 0) {
124 fprintf(stderr,
125 "Please specify the size of the envrionnment "
126 "partition.\n");
Horst Kronstorferaf44f4b2011-12-21 10:39:39 +0000127 usage(prg);
David Wagnera6337e62011-09-26 03:26:34 +0000128 return EXIT_FAILURE;
129 }
130
131 dataptr = malloc(datasize * sizeof(*dataptr));
132 if (!dataptr) {
133 fprintf(stderr, "Can't alloc dataptr.\n");
134 return EXIT_FAILURE;
135 }
136
137 /*
138 * envptr points to the beginning of the actual environment (after the
139 * crc and possible `redundant' bit
140 */
141 envsize = datasize - (CRC_SIZE + redundant);
142 envptr = dataptr + CRC_SIZE + redundant;
143
144 /* Pad the environment with the padding byte */
145 memset(envptr, padbyte, envsize);
146
147 /* Open the input file ... */
148 if (optind >= argc) {
149 fprintf(stderr, "Please specify an input filename\n");
150 return EXIT_FAILURE;
151 }
152
153 txt_filename = argv[optind];
154 if (strcmp(txt_filename, "-") == 0) {
155 int readbytes = 0;
156 int readlen = sizeof(*envptr) * 2048;
157 txt_fd = STDIN_FILENO;
158
159 do {
160 filebuf = realloc(filebuf, readlen);
161 readbytes = read(txt_fd, filebuf + filesize, readlen);
162 filesize += readbytes;
163 } while (readbytes == readlen);
164
165 } else {
166 txt_fd = open(txt_filename, O_RDONLY);
167 if (txt_fd == -1) {
168 fprintf(stderr, "Can't open \"%s\": %s\n",
169 txt_filename, strerror(errno));
170 return EXIT_FAILURE;
171 }
172 /* ... and check it */
173 ret = fstat(txt_fd, &txt_file_stat);
174 if (ret == -1) {
175 fprintf(stderr, "Can't stat() on \"%s\": "
176 "%s\n", txt_filename, strerror(errno));
177 return EXIT_FAILURE;
178 }
179
180 filesize = txt_file_stat.st_size;
181 /* Read the raw input file and transform it */
182 filebuf = malloc(sizeof(*envptr) * filesize);
183 ret = read(txt_fd, filebuf, sizeof(*envptr) * filesize);
184 if (ret != sizeof(*envptr) * filesize) {
185 fprintf(stderr, "Can't read the whole input file\n");
186 return EXIT_FAILURE;
187 }
188 ret = close(txt_fd);
189 }
190 /*
191 * The right test to do is "=>" (not ">") because of the additionnal
192 * ending \0. See below.
193 */
194 if (filesize >= envsize) {
195 fprintf(stderr, "The input file is larger than the "
196 "envrionnment partition size\n");
197 return EXIT_FAILURE;
198 }
199
200 /* Replace newlines separating variables with \0 */
201 for (fp = 0, ep = 0 ; fp < filesize ; fp++) {
202 if (filebuf[fp] == '\n') {
203 if (fp == 0) {
204 /*
205 * Newline at the beggining of the file ?
206 * Ignore it.
207 */
208 continue;
209 } else if (filebuf[fp-1] == '\\') {
210 /*
211 * Embedded newline in a variable.
212 *
213 * The backslash was added to the envptr ;
214 * rewind and replace it with a newline
215 */
216 ep--;
217 envptr[ep++] = '\n';
218 } else {
219 /* End of a variable */
220 envptr[ep++] = '\0';
221 }
222 } else if (filebuf[fp] == '#') {
223 if (fp != 0 && filebuf[fp-1] == '\n') {
224 /* This line is a comment, let's skip it */
225 while (fp < txt_file_stat.st_size && fp++ &&
226 filebuf[fp] != '\n');
227 } else {
228 envptr[ep++] = filebuf[fp];
229 }
230 } else {
231 envptr[ep++] = filebuf[fp];
232 }
233 }
234 /*
235 * Make sure there is a final '\0'
236 * And do it again on the next byte to mark the end of the environment.
237 */
238 if (envptr[ep-1] != '\0') {
239 envptr[ep++] = '\0';
240 /*
241 * The text file doesn't have an ending newline. We need to
242 * check the env size again to make sure we have room for two \0
243 */
244 if (ep >= envsize) {
245 fprintf(stderr, "The environment file is too large for "
246 "the target environment storage\n");
247 return EXIT_FAILURE;
248 }
249 envptr[ep] = '\0';
250 } else {
251 envptr[ep] = '\0';
252 }
253
254 /* Computes the CRC and put it at the beginning of the data */
255 crc = crc32(0, envptr, envsize);
256 targetendian_crc = bigendian ? cpu_to_be32(crc) : cpu_to_le32(crc);
257
258 memcpy(dataptr, &targetendian_crc, sizeof(uint32_t));
259
260 bin_fd = creat(bin_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
261 if (bin_fd == -1) {
262 fprintf(stderr, "Can't open output file \"%s\": %s\n",
263 bin_filename, strerror(errno));
264 return EXIT_FAILURE;
265 }
266
267 if (write(bin_fd, dataptr, sizeof(*dataptr) * datasize) !=
268 sizeof(*dataptr) * datasize) {
269 fprintf(stderr, "write() failed: %s\n", strerror(errno));
270 return EXIT_FAILURE;
271 }
272
273 ret = close(bin_fd);
274
275 return ret;
276}