mtd: improve check for TRX header being already fixed
[oweals/openwrt.git] / package / system / mtd / src / linksys_bootcount.c
1 /*
2  * Linksys boot counter reset code for mtd
3  *
4  * Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License v2
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stddef.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <sys/mman.h>
27 #include <sys/stat.h>
28 #include <endian.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <stdint.h>
32
33 #include <sys/ioctl.h>
34 #include <mtd/mtd-user.h>
35
36 #include "mtd.h"
37
38 #define BOOTCOUNT_MAGIC 0x20110811
39
40 struct bootcounter {
41         uint32_t magic;
42         uint32_t count;
43         uint32_t checksum;
44 };
45
46 static char page[2048];
47
48 int mtd_resetbc(const char *mtd)
49 {
50         struct mtd_info_user mtd_info;
51         struct bootcounter *curr = (struct bootcounter *)page;
52         unsigned int i;
53         int last_count = 0;
54         int num_bc;
55         int fd;
56         int ret;
57
58         fd = mtd_check_open(mtd);
59
60         if (ioctl(fd, MEMGETINFO, &mtd_info) < 0) {
61                 fprintf(stderr, "failed to get mtd info!\n");
62                 return -1;
63         }
64
65         num_bc = mtd_info.size / mtd_info.writesize;
66
67         for (i = 0; i < num_bc; i++) {
68                 pread(fd, curr, sizeof(*curr), i * mtd_info.writesize);
69
70                 if (curr->magic != BOOTCOUNT_MAGIC && curr->magic != 0xffffffff) {
71                         fprintf(stderr, "unexpected magic %08x, bailing out\n", curr->magic);
72                         goto out;
73                 }
74
75                 if (curr->magic == 0xffffffff)
76                         break;
77
78                 last_count = curr->count;
79         }
80
81         /* no need to do writes when last boot count is already 0 */
82         if (last_count == 0)
83                 goto out;
84
85
86         if (i == num_bc) {
87                 struct erase_info_user erase_info;
88                 erase_info.start = 0;
89                 erase_info.length = mtd_info.size;
90
91                 /* erase block */
92                 ret = ioctl(fd, MEMERASE, &erase_info);
93                 if (ret < 0) {
94                         fprintf(stderr, "failed to erase block: %i\n", ret);
95                         return -1;
96                 }
97
98                 i = 0;
99         }
100
101         memset(curr, 0xff, mtd_info.writesize);
102
103         curr->magic = BOOTCOUNT_MAGIC;
104         curr->count = 0;
105         curr->checksum = BOOTCOUNT_MAGIC;
106
107         ret = pwrite(fd, curr, mtd_info.writesize, i * mtd_info.writesize);
108         if (ret < 0)
109                 fprintf(stderr, "failed to write: %i\n", ret);
110         sync();
111 out:
112         close(fd);
113
114         return 0;
115 }