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