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