1/* 2 * WAPI mtd read/write utility functions 3 * 4 * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: wapi_utils.c 241182 2011-02-17 21:50:03Z $ 19 */ 20 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#include <unistd.h> 25#include <limits.h> 26#include <sys/stat.h> 27#include <fcntl.h> 28#include <errno.h> 29#include <error.h> 30#include <sys/ioctl.h> 31 32#ifdef LINUX26 33#include <mtd/mtd-user.h> 34#else /* LINUX26 */ 35#include <linux/mtd/mtd.h> 36#endif /* LINUX26 */ 37 38#include <bcmconfig.h> 39#include <wapi_utils.h> 40 41static unsigned short 42wapi_checksum(const char *data, int datalen) 43{ 44 unsigned short checksum = 0; 45 unsigned short *ptr = (unsigned short *)data; 46 int len = datalen; 47 48 while (len > 0) { 49 if (len == 1) 50 checksum += (*ptr & 0xff00); 51 else 52 checksum += *ptr; 53 ptr++; 54 len -= 2; 55 } 56 return checksum; 57} 58 59/* 60 * Open an MTD device 61 * @param mtd path to or partition name of MTD device 62 * @param flags open() flags 63 * @return return value of open() 64 */ 65int 66wapi_mtd_open(const char *mtd, int flags) 67{ 68 FILE *fp; 69 char dev[PATH_MAX]; 70 int i; 71 72 if ((fp = fopen("/proc/mtd", "r"))) { 73 while (fgets(dev, sizeof(dev), fp)) { 74 if (sscanf(dev, "mtd%d:", &i) && strstr(dev, mtd)) { 75#ifdef LINUX26 76 snprintf(dev, sizeof(dev), "/dev/mtd%d", i); 77#else 78 snprintf(dev, sizeof(dev), "/dev/mtd/%d", i); 79#endif 80 fclose(fp); 81 return open(dev, flags); 82 } 83 } 84 fclose(fp); 85 } 86 87 return open(mtd, flags); 88} 89 90/* 91 * Write a file to an MTD device 92 * @param path file to write or a URL 93 * @param mtd path to or partition name of MTD device 94 * @return 0 on success and errno on failure 95 */ 96int 97wapi_mtd_backup() 98{ 99 char *cmd = "tar cf - "CONFIG_DIR" -C "RAMFS_WAPI_DIR" | gzip -c > "WAPI_TGZ_TMP_FILE; 100 mtd_info_t mtd_info; 101 erase_info_t erase_info; 102 int mtd_fd = -1; 103 FILE *fp = NULL; 104 char *buf = NULL; 105 struct stat tmp_stat; 106 int ret = -1; 107 wapi_mtd_hdr_t mtd_hdr; 108 109 /* backup wapi directiries to raw partition */ 110 unlink(WAPI_TGZ_TMP_FILE); 111 112 /* Open MTD device and get sector size */ 113 if ((mtd_fd = wapi_mtd_open("wapi", O_RDWR)) < 0 || 114 ioctl(mtd_fd, MEMGETINFO, &mtd_info) != 0) { 115 perror("wapi"); 116 goto fail; 117 } 118 119 /* create as tar file */ 120 errno = 0; 121 system(cmd); 122 if (stat(WAPI_TGZ_TMP_FILE, &tmp_stat) || 123 errno == ENOENT) { 124 perror("tgz"); 125 goto fail; 126 } 127 128 if ((tmp_stat.st_size + sizeof(wapi_mtd_hdr_t)) > mtd_info.size || tmp_stat.st_size == 0) { 129 perror("size"); 130 goto fail; 131 } 132 133 /* Allocate temporary buffer */ 134 if ((buf = malloc(tmp_stat.st_size)) == NULL) { 135 perror("malloc"); 136 goto fail; 137 } 138 139 fp = fopen(WAPI_TGZ_TMP_FILE, "r"); 140 if (fp == NULL) { 141 fprintf(stderr, "%s: can't open file\n", WAPI_TGZ_TMP_FILE); 142 goto fail; 143 } 144 145 if (fread(buf, 1, tmp_stat.st_size, fp) != tmp_stat.st_size) { 146 perror("read"); 147 goto fail; 148 } 149 150 erase_info.start = 0; 151 erase_info.length = mtd_info.size; 152 153 /* create mtd header content */ 154 memcpy(&mtd_hdr.magic, WAPI_MTD_MAGIC, 4); 155 mtd_hdr.len = tmp_stat.st_size; 156 mtd_hdr.checksum = wapi_checksum(buf, tmp_stat.st_size); 157 158 /* Do it */ 159 (void) ioctl(mtd_fd, MEMUNLOCK, &erase_info); 160 if (ioctl(mtd_fd, MEMERASE, &erase_info) != 0 || 161 write(mtd_fd, &mtd_hdr, sizeof(wapi_mtd_hdr_t)) != sizeof(wapi_mtd_hdr_t) || 162 write(mtd_fd, buf, tmp_stat.st_size) != tmp_stat.st_size) { 163 perror("write"); 164 goto fail; 165 } 166 167 printf("update wapi partition OK\n"); 168 ret = 0; 169 170fail: 171 unlink(WAPI_TGZ_TMP_FILE); 172 173 if (buf) 174 free(buf); 175 176 if (mtd_fd >= 0) 177 close(mtd_fd); 178 179 if (fp) 180 fclose(fp); 181 182 return ret; 183} 184 185/* 186 * Write a file to an MTD device 187 * @param path file to write or a URL 188 * @param mtd path to or partition name of MTD device 189 * @return 0 on success and errno on failure 190 */ 191int 192wapi_mtd_restore() 193{ 194 char *cmd = "gunzip -c "WAPI_TGZ_TMP_FILE" | tar xf - -C "RAMFS_WAPI_DIR; 195 mtd_info_t mtd_info; 196 int mtd_fd = -1; 197 FILE *fp = NULL; 198 char *buf = NULL; 199 int ret = -1; 200 wapi_mtd_hdr_t mtd_hdr = {0}; 201 202 /* create wapi directory */ 203 mkdir(RAMFS_WAPI_DIR, 0777); 204 205 /* Open MTD device and get sector size */ 206 if ((mtd_fd = wapi_mtd_open("wapi", O_RDWR)) < 0 || 207 ioctl(mtd_fd, MEMGETINFO, &mtd_info) != 0) { 208 printf("mtd"); 209 goto fail; 210 } 211 212 read(mtd_fd, &mtd_hdr, sizeof(wapi_mtd_hdr_t)); 213 214 if (memcmp(&mtd_hdr.magic, WAPI_MTD_MAGIC, 4)) { 215 printf("magic incorrect"); 216 goto fail; 217 } 218 219 if (mtd_hdr.len > mtd_info.size) { 220 printf("size too long"); 221 goto fail; 222 } 223 224 /* Allocate temporary buffer */ 225 if ((buf = malloc(mtd_hdr.len)) == NULL) { 226 printf("buffer"); 227 goto fail; 228 } 229 read(mtd_fd, buf, mtd_hdr.len); 230 231 if (wapi_checksum(buf, mtd_hdr.len) != mtd_hdr.checksum) { 232 printf("checksum"); 233 goto fail; 234 } 235 236 /* write mtd data to tar file */ 237 if ((fp = fopen(WAPI_TGZ_TMP_FILE, "w")) == NULL) { 238 printf("%s: can't open file\n", WAPI_TGZ_TMP_FILE); 239 goto fail; 240 } 241 fwrite(buf, 1, mtd_hdr.len, fp); 242 fclose(fp); 243 244 /* untar wapi directory */ 245 system(cmd); 246 247 unlink(WAPI_TGZ_TMP_FILE); 248 249 ret = 0; 250fail: 251 if (buf) 252 free(buf); 253 254 if (mtd_fd >= 0) 255 close(mtd_fd); 256 257 if (ret) { 258 /* create directory */ 259 mkdir(WAPI_WAI_DIR, 0777); 260 mkdir(WAPI_AS_DIR, 0777); 261 } 262 263 return ret; 264} 265