OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * wrg.c |
||
3 | * |
||
4 | * Copyright (C) 2005 Mike Baker |
||
5 | * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name> |
||
6 | * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org> |
||
7 | * Copyright (C) 2016 Stijn Tintel <stijn@linux-ipv6.be> |
||
8 | * Copyright (C) 2017 George Hopkins <george-hopkins@null.net> |
||
9 | * |
||
10 | * This program is free software; you can redistribute it and/or |
||
11 | * modify it under the terms of the GNU General Public License |
||
12 | * as published by the Free Software Foundation; either version 2 |
||
13 | * of the License, or (at your option) any later version. |
||
14 | * |
||
15 | * This program is distributed in the hope that it will be useful, |
||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
18 | * GNU General Public License for more details. |
||
19 | * |
||
20 | * You should have received a copy of the GNU General Public License |
||
21 | * along with this program; if not, write to the Free Software |
||
22 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||
23 | */ |
||
24 | |||
25 | #include <byteswap.h> |
||
26 | #include <endian.h> |
||
27 | #include <stdio.h> |
||
28 | #include <stdlib.h> |
||
29 | #include <stddef.h> |
||
30 | #include <unistd.h> |
||
31 | #include <fcntl.h> |
||
32 | #include <sys/mman.h> |
||
33 | #include <sys/stat.h> |
||
34 | #include <string.h> |
||
35 | #include <errno.h> |
||
36 | #include <arpa/inet.h> |
||
37 | |||
38 | #include <sys/ioctl.h> |
||
39 | #include <mtd/mtd-user.h> |
||
40 | #include "mtd.h" |
||
41 | #include "md5.h" |
||
42 | |||
43 | #if !defined(__BYTE_ORDER) |
||
44 | #error "Unknown byte order" |
||
45 | #endif |
||
46 | |||
47 | #if __BYTE_ORDER == __BIG_ENDIAN |
||
48 | #define cpu_to_le32(x) bswap_32(x) |
||
49 | #define le32_to_cpu(x) bswap_32(x) |
||
50 | #elif __BYTE_ORDER == __LITTLE_ENDIAN |
||
51 | #define cpu_to_le32(x) (x) |
||
52 | #define le32_to_cpu(x) (x) |
||
53 | #else |
||
54 | #error "Unsupported endianness" |
||
55 | #endif |
||
56 | |||
57 | #define WRG_MAGIC 0x20040220 |
||
58 | |||
59 | struct wrg_header { |
||
60 | char signature[32]; |
||
61 | uint32_t magic1; |
||
62 | uint32_t magic2; |
||
63 | uint32_t size; |
||
64 | uint32_t offset; |
||
65 | char devname[32]; |
||
66 | char digest[16]; |
||
67 | } __attribute__ ((packed)); |
||
68 | |||
69 | ssize_t pread(int fd, void *buf, size_t count, off_t offset); |
||
70 | ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); |
||
71 | |||
72 | int |
||
73 | wrg_fix_md5(struct wrg_header *shdr, int fd, size_t data_offset, size_t data_size) |
||
74 | { |
||
75 | char *buf; |
||
76 | ssize_t res; |
||
77 | MD5_CTX ctx; |
||
78 | unsigned char digest[16]; |
||
79 | int i; |
||
80 | int err = 0; |
||
81 | |||
82 | buf = malloc(data_size); |
||
83 | if (!buf) { |
||
84 | err = -ENOMEM; |
||
85 | goto err_out; |
||
86 | } |
||
87 | |||
88 | res = pread(fd, buf, data_size, data_offset); |
||
89 | if (res != data_size) { |
||
90 | perror("pread"); |
||
91 | err = -EIO; |
||
92 | goto err_free; |
||
93 | } |
||
94 | |||
95 | MD5_Init(&ctx); |
||
96 | MD5_Update(&ctx, (char *)&shdr->offset, sizeof(shdr->offset)); |
||
97 | MD5_Update(&ctx, (char *)&shdr->devname, sizeof(shdr->devname)); |
||
98 | MD5_Update(&ctx, buf, data_size); |
||
99 | MD5_Final(digest, &ctx); |
||
100 | |||
101 | if (!memcmp(digest, shdr->digest, sizeof(digest))) { |
||
102 | if (quiet < 2) |
||
103 | fprintf(stderr, "the header is fixed already\n"); |
||
104 | return -1; |
||
105 | } |
||
106 | |||
107 | if (quiet < 2) { |
||
108 | fprintf(stderr, "new size: %u, new MD5: ", data_size); |
||
109 | for (i = 0; i < sizeof(digest); i++) |
||
110 | fprintf(stderr, "%02x", digest[i]); |
||
111 | |||
112 | fprintf(stderr, "\n"); |
||
113 | } |
||
114 | |||
115 | /* update the size in the image */ |
||
116 | shdr->size = cpu_to_le32(data_size); |
||
117 | |||
118 | /* update the checksum in the image */ |
||
119 | memcpy(shdr->digest, digest, sizeof(digest)); |
||
120 | |||
121 | err_free: |
||
122 | free(buf); |
||
123 | err_out: |
||
124 | return err; |
||
125 | } |
||
126 | |||
127 | int |
||
128 | mtd_fixwrg(const char *mtd, size_t offset, size_t data_size) |
||
129 | { |
||
130 | int fd; |
||
131 | char *first_block; |
||
132 | ssize_t res; |
||
133 | size_t block_offset; |
||
134 | size_t data_offset; |
||
135 | struct wrg_header *shdr; |
||
136 | |||
137 | if (quiet < 2) |
||
138 | fprintf(stderr, "Trying to fix WRG header in %s at 0x%x...\n", |
||
139 | mtd, offset); |
||
140 | |||
141 | block_offset = offset & ~(erasesize - 1); |
||
142 | offset -= block_offset; |
||
143 | |||
144 | fd = mtd_check_open(mtd); |
||
145 | if(fd < 0) { |
||
146 | fprintf(stderr, "Could not open mtd device: %s\n", mtd); |
||
147 | exit(1); |
||
148 | } |
||
149 | |||
150 | if (block_offset + erasesize > mtdsize) { |
||
151 | fprintf(stderr, "Offset too large, device size 0x%x\n", |
||
152 | mtdsize); |
||
153 | exit(1); |
||
154 | } |
||
155 | |||
156 | first_block = malloc(erasesize); |
||
157 | if (!first_block) { |
||
158 | perror("malloc"); |
||
159 | exit(1); |
||
160 | } |
||
161 | |||
162 | res = pread(fd, first_block, erasesize, block_offset); |
||
163 | if (res != erasesize) { |
||
164 | perror("pread"); |
||
165 | exit(1); |
||
166 | } |
||
167 | |||
168 | shdr = (struct wrg_header *)(first_block + offset); |
||
169 | if (le32_to_cpu(shdr->magic1) != WRG_MAGIC) { |
||
170 | fprintf(stderr, "No WRG header found (%08x != %08x)\n", |
||
171 | le32_to_cpu(shdr->magic1), WRG_MAGIC); |
||
172 | exit(1); |
||
173 | } else if (!le32_to_cpu(shdr->size)) { |
||
174 | fprintf(stderr, "WRG entity with empty image\n"); |
||
175 | exit(1); |
||
176 | } |
||
177 | |||
178 | data_offset = offset + sizeof(struct wrg_header); |
||
179 | if (!data_size) |
||
180 | data_size = mtdsize - data_offset; |
||
181 | if (data_size > le32_to_cpu(shdr->size)) |
||
182 | data_size = le32_to_cpu(shdr->size); |
||
183 | if (wrg_fix_md5(shdr, fd, data_offset, data_size)) |
||
184 | goto out; |
||
185 | |||
186 | if (mtd_erase_block(fd, block_offset)) { |
||
187 | fprintf(stderr, "Can't erease block at 0x%x (%s)\n", |
||
188 | block_offset, strerror(errno)); |
||
189 | exit(1); |
||
190 | } |
||
191 | |||
192 | if (quiet < 2) |
||
193 | fprintf(stderr, "Rewriting block at 0x%x\n", block_offset); |
||
194 | |||
195 | if (pwrite(fd, first_block, erasesize, block_offset) != erasesize) { |
||
196 | fprintf(stderr, "Error writing block (%s)\n", strerror(errno)); |
||
197 | exit(1); |
||
198 | } |
||
199 | |||
200 | if (quiet < 2) |
||
201 | fprintf(stderr, "Done.\n"); |
||
202 | |||
203 | out: |
||
204 | close (fd); |
||
205 | sync(); |
||
206 | |||
207 | return 0; |
||
208 | } |