First git repo commit for the libreCMC project
[librecmc/librecmc.git] / tools / firmware-utils / src / mkbuffaloimg.c
1 /*
2  *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
3  *  Copyright (C) 2016 FUKAUMI Naoki <naobsd@gmail.com>
4  *
5  *  Based on mkdniimg.c
6  *
7  *  This program is free software; you can redistribute it and/or modify it
8  *  under the terms of the GNU General Public License version 2 as published
9  *  by the Free Software Foundation.
10  *
11  */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdint.h>
16 #include <string.h>
17 #include <unistd.h>     /* for unlink() */
18 #include <libgen.h>
19 #include <getopt.h>     /* for getopt() */
20 #include <stdarg.h>
21 #include <errno.h>
22 #include <sys/stat.h>
23
24 #define DNI_HDR_LEN     128
25
26 /*
27  * Globals
28  */
29 static char *ifname;
30 static char *progname;
31 static char *ofname;
32 static char *version = "0.00_0.00";
33 static char *region = "JP";
34 static char *rootfs_size;
35 static char *kernel_size;
36
37 static char *board_id;
38 /*
39  * Message macros
40  */
41 #define ERR(fmt, ...) do { \
42         fflush(0); \
43         fprintf(stderr, "[%s] *** error: " fmt "\n", \
44                         progname, ## __VA_ARGS__ ); \
45 } while (0)
46
47 #define ERRS(fmt, ...) do { \
48         int save = errno; \
49         fflush(0); \
50         fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
51                         progname, ## __VA_ARGS__, strerror(save)); \
52 } while (0)
53
54 void usage(int status)
55 {
56         FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
57
58         fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
59         fprintf(stream,
60 "\n"
61 "Options:\n"
62 "  -B <board>       create image for the board specified with <board>\n"
63 "  -i <file>        read input from the file <file>\n"
64 "  -o <file>        write output to the file <file>\n"
65 "  -v <version>     set image version to <version>\n"
66 "  -r <region>      set image region to <region>\n"
67 "  -R <rootfs_size> set RootfsSize to <rootfs_size>\n"
68 "  -K <kernel_size> set KernelSize to <kernel_size>\n"
69 "  -h               show this screen\n"
70         );
71
72         exit(status);
73 }
74
75 int main(int argc, char *argv[])
76 {
77         int res = EXIT_FAILURE;
78         int buflen;
79         int err;
80         struct stat st;
81         char *buf;
82         int i;
83         uint8_t csum;
84
85         FILE *outfile, *infile;
86
87         progname = basename(argv[0]);
88
89         while ( 1 ) {
90                 int c;
91
92                 c = getopt(argc, argv, "B:i:o:v:r:R:K:h");
93                 if (c == -1)
94                         break;
95
96                 switch (c) {
97                 case 'B':
98                         board_id = optarg;
99                         break;
100                 case 'i':
101                         ifname = optarg;
102                         break;
103                 case 'o':
104                         ofname = optarg;
105                         break;
106                 case 'v':
107                         version = optarg;
108                         break;
109                 case 'r':
110                         region = optarg;
111                         break;
112                 case 'R':
113                         rootfs_size = optarg;
114                         break;
115                 case 'K':
116                         kernel_size = optarg;
117                         break;
118                 case 'h':
119                         usage(EXIT_SUCCESS);
120                         break;
121                 default:
122                         usage(EXIT_FAILURE);
123                         break;
124                 }
125         }
126
127         if (board_id == NULL) {
128                 ERR("no board specified");
129                 goto err;
130         }
131
132         if (rootfs_size == NULL) {
133                 ERR("no rootfs_size specified");
134                 goto err;
135         }
136
137         if (kernel_size == NULL) {
138                 ERR("no kernel_size specified");
139                 goto err;
140         }
141
142         if (ifname == NULL) {
143                 ERR("no input file specified");
144                 goto err;
145         }
146
147         if (ofname == NULL) {
148                 ERR("no output file specified");
149                 goto err;
150         }
151
152         err = stat(ifname, &st);
153         if (err){
154                 ERRS("stat failed on %s", ifname);
155                 goto err;
156         }
157
158         buflen = st.st_size + DNI_HDR_LEN + 1;
159         buf = malloc(buflen);
160         if (!buf) {
161                 ERR("no memory for buffer\n");
162                 goto err;
163         }
164
165         memset(buf, 0, DNI_HDR_LEN);
166         snprintf(buf, DNI_HDR_LEN, "device:%s\nversion:%s\nregion:%s\n"
167                  "RootfsSize:%s\nKernelSize:%s\nInfoHeadSize:128\n",
168                  board_id, version, region, rootfs_size, kernel_size);
169         buf[DNI_HDR_LEN - 2] = 0x12;
170         buf[DNI_HDR_LEN - 1] = 0x32;
171
172         infile = fopen(ifname, "r");
173         if (infile == NULL) {
174                 ERRS("could not open \"%s\" for reading", ifname);
175                 goto err_free;
176         }
177
178         errno = 0;
179         fread(buf +  DNI_HDR_LEN, st.st_size, 1, infile);
180         if (errno != 0) {
181                 ERRS("unable to read from file %s", ifname);
182                 goto err_close_in;
183         }
184
185         csum = 0;
186         for (i = 0; i < (st.st_size + DNI_HDR_LEN); i++)
187                 csum += buf[i];
188
189         csum = 0xff - csum;
190         buf[st.st_size + DNI_HDR_LEN] = csum;
191
192         outfile = fopen(ofname, "w");
193         if (outfile == NULL) {
194                 ERRS("could not open \"%s\" for writing", ofname);
195                 goto err_close_in;
196         }
197
198         errno = 0;
199         fwrite(buf, buflen, 1, outfile);
200         if (errno) {
201                 ERRS("unable to write to file %s", ofname);
202                 goto err_close_out;
203         }
204
205         res = EXIT_SUCCESS;
206
207         fflush(outfile);
208
209  err_close_out:
210         fclose(outfile);
211         if (res != EXIT_SUCCESS) {
212                 unlink(ofname);
213         }
214
215  err_close_in:
216         fclose(infile);
217
218  err_free:
219         free(buf);
220
221  err:
222         return res;
223 }