blob: d7e459a56b30169e1d8df49a1189761c15de1360 [file] [log] [blame]
Shashank Mittal815ca5d2010-07-27 11:09:19 -07001/*
2 * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of Code Aurora Forum, Inc. nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <stdlib.h>
31#include <stdio.h>
32#include <unistd.h>
33#include <dirent.h>
34#include <string.h>
35#include <errno.h>
36#include <sys/types.h>
37#include <sys/reboot.h>
38#include <sys/stat.h>
39#include <sys/wait.h>
40#include <sys/mount.h> // for _IOW, _IOR, mount()
41
42#include "mmcutils.h"
43
44unsigned ext3_count = 0;
45char *ext3_partitions[] = {"system", "userdata", "cache", "NONE"};
46
47unsigned vfat_count = 0;
48char *vfat_partitions[] = {"modem", "NONE"};
49
50struct MmcPartition {
51 char *device_index;
52 char *filesystem;
53 char *name;
54 unsigned dstatus;
55 unsigned dtype ;
56 unsigned dfirstsec;
57 unsigned dsize;
58};
59
60typedef struct {
61 MmcPartition *partitions;
62 int partitions_allocd;
63 int partition_count;
64} MmcState;
65
66static MmcState g_mmc_state = {
67 NULL, // partitions
68 0, // partitions_allocd
69 -1 // partition_count
70};
71
72#define MMC_DEVICENAME "/dev/block/mmcblk0"
73
74static void
75mmc_partition_name (MmcPartition *mbr, unsigned int type) {
76 switch(type)
77 {
78 char name[64];
79 case MMC_BOOT_TYPE:
80 sprintf(name,"boot");
81 mbr->name = strdup(name);
82 break;
83 case MMC_EXT3_TYPE:
84 if (strcmp("NONE", ext3_partitions[ext3_count])) {
85 strcpy((char *)name,(const char *)ext3_partitions[ext3_count]);
86 mbr->name = strdup(name);
87 ext3_count++;
88 }
89 mbr->filesystem = strdup("ext3");
90 break;
91 case MMC_VFAT_TYPE:
92 if (strcmp("NONE", vfat_partitions[vfat_count])) {
93 strcpy((char *)name,(const char *)vfat_partitions[vfat_count]);
94 mbr->name = strdup(name);
95 vfat_count++;
96 }
97 mbr->filesystem = strdup("vfat");
98 break;
99 };
100}
101
102static int
103mmc_read_mbr (const char *device, MmcPartition *mbr) {
104 FILE *fd;
105 unsigned char buffer[512];
106 int idx, i;
107 unsigned mmc_partition_count = 0;
108 unsigned int dtype;
109 unsigned int dfirstsec;
110 unsigned int EBR_first_sec;
111 unsigned int EBR_current_sec;
112 int ret = -1;
113
114 fd = fopen(device, "r");
115 if(fd == NULL)
116 {
117 printf("Can't open device: \"%s\"\n", device);
118 goto ERROR2;
119 }
120 if ((fread(buffer, 512, 1, fd)) != 1)
121 {
122 printf("Can't read device: \"%s\"\n", device);
123 goto ERROR1;
124 }
125 /* Check to see if signature exists */
126 if ((buffer[TABLE_SIGNATURE] != 0x55) || \
127 (buffer[TABLE_SIGNATURE + 1] != 0xAA))
128 {
129 printf("Incorrect mbr signatures!\n");
130 goto ERROR1;
131 }
132 idx = TABLE_ENTRY_0;
133 for (i = 0; i < 4; i++)
134 {
135 char device_index[128];
136
137 mbr[mmc_partition_count].dstatus = \
138 buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
139 mbr[mmc_partition_count].dtype = \
140 buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
141 mbr[mmc_partition_count].dfirstsec = \
142 GET_LWORD_FROM_BYTE(&buffer[idx + \
143 i * TABLE_ENTRY_SIZE + \
144 OFFSET_FIRST_SEC]);
145 mbr[mmc_partition_count].dsize = \
146 GET_LWORD_FROM_BYTE(&buffer[idx + \
147 i * TABLE_ENTRY_SIZE + \
148 OFFSET_SIZE]);
149 dtype = mbr[mmc_partition_count].dtype;
150 dfirstsec = mbr[mmc_partition_count].dfirstsec;
151 mmc_partition_name(&mbr[mmc_partition_count], \
152 mbr[mmc_partition_count].dtype);
153
154 sprintf(device_index, "%sp%d", device, (mmc_partition_count+1));
155 mbr[mmc_partition_count].device_index = strdup(device_index);
156
157 mmc_partition_count++;
158 if (mmc_partition_count == MAX_PARTITIONS)
159 goto SUCCESS;
160 }
161
162 /* See if the last partition is EBR, if not, parsing is done */
163 if (dtype != 0x05)
164 {
165 goto SUCCESS;
166 }
167
168 EBR_first_sec = dfirstsec;
169 EBR_current_sec = dfirstsec;
170
171 fseek (fd, (EBR_first_sec * 512), SEEK_SET);
172 if ((fread(buffer, 512, 1, fd)) != 1)
173 goto ERROR1;
174
175 /* Loop to parse the EBR */
176 for (i = 0;; i++)
177 {
178 char device_index[128];
179
180 if ((buffer[TABLE_SIGNATURE] != 0x55) || (buffer[TABLE_SIGNATURE + 1] != 0xAA))
181 {
182 break;
183 }
184 mbr[mmc_partition_count].dstatus = \
185 buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
186 mbr[mmc_partition_count].dtype = \
187 buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
188 mbr[mmc_partition_count].dfirstsec = \
189 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
190 OFFSET_FIRST_SEC]) + \
191 EBR_current_sec;
192 mbr[mmc_partition_count].dsize = \
193 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
194 OFFSET_SIZE]);
195 mmc_partition_name(&mbr[mmc_partition_count], \
196 mbr[mmc_partition_count].dtype);
197
198 sprintf(device_index, "%sp%d", device, (mmc_partition_count+1));
199 mbr[mmc_partition_count].device_index = strdup(device_index);
200
201 mmc_partition_count++;
202 if (mmc_partition_count == MAX_PARTITIONS)
203 goto SUCCESS;
204
205 dfirstsec = GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
206 if(dfirstsec == 0)
207 {
208 /* Getting to the end of the EBR tables */
209 break;
210 }
211 /* More EBR to follow - read in the next EBR sector */
212 fseek (fd, ((EBR_first_sec + dfirstsec) * 512), SEEK_SET);
213 if ((fread(buffer, 512, 1, fd)) != 1)
214 goto ERROR1;
215
216 EBR_current_sec = EBR_first_sec + dfirstsec;
217 }
218
219SUCCESS:
220 ret = mmc_partition_count;
221ERROR1:
222 fclose(fd);
223ERROR2:
224 return ret;
225}
226
227int
228mmc_scan_partitions() {
229 int i;
230 ssize_t nbytes;
231
232 if (g_mmc_state.partitions == NULL) {
233 const int nump = MAX_PARTITIONS;
234 MmcPartition *partitions = malloc(nump * sizeof(*partitions));
235 if (partitions == NULL) {
236 errno = ENOMEM;
237 return -1;
238 }
239 g_mmc_state.partitions = partitions;
240 g_mmc_state.partitions_allocd = nump;
241 memset(partitions, 0, nump * sizeof(*partitions));
242 }
243 g_mmc_state.partition_count = 0;
244 ext3_count = 0;
245 vfat_count = 0;
246
247 /* Initialize all of the entries to make things easier later.
248 * (Lets us handle sparsely-numbered partitions, which
249 * may not even be possible.)
250 */
251 for (i = 0; i < g_mmc_state.partitions_allocd; i++) {
252 MmcPartition *p = &g_mmc_state.partitions[i];
253 if (p->device_index != NULL) {
254 free(p->device_index);
255 p->device_index = NULL;
256 }
257 if (p->name != NULL) {
258 free(p->name);
259 p->name = NULL;
260 }
261 if (p->filesystem != NULL) {
262 free(p->filesystem);
263 p->filesystem = NULL;
264 }
265 }
266
267 g_mmc_state.partition_count = mmc_read_mbr(MMC_DEVICENAME, g_mmc_state.partitions);
268 if(g_mmc_state.partition_count == -1)
269 {
270 printf("Error in reading mbr!\n");
271 // keep "partitions" around so we can free the names on a rescan.
272 g_mmc_state.partition_count = -1;
273 }
274 return g_mmc_state.partition_count;
275}
276
277const MmcPartition *
278mmc_find_partition_by_name(const char *name)
279{
280 if (g_mmc_state.partitions != NULL) {
281 int i;
282 for (i = 0; i < g_mmc_state.partitions_allocd; i++) {
283 MmcPartition *p = &g_mmc_state.partitions[i];
284 if (p->device_index !=NULL && p->name != NULL) {
285 if (strcmp(p->name, name) == 0) {
286 return p;
287 }
288 }
289 }
290 }
291 return NULL;
292}
293
294#define MKE2FS_BIN "/sbin/mke2fs_static"
295#define TUNE2FS_BIN "/sbin/tune2fs_static"
296#define E2FSCK_BIN "/sbin/e2fsck_static"
297
298static int
299run_exec_process ( char **argv) {
300 pid_t pid;
301 int status;
302 pid = fork();
303 if (pid == 0) {
304 execv(argv[0], argv);
305 fprintf(stderr, "E:Can't run (%s)\n",strerror(errno));
306 _exit(-1);
307 }
308
309 waitpid(pid, &status, 0);
310 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
311 return 1;
312 }
313 return 0;
314}
315
316int
317mmc_format_ext3 (MmcPartition *partition) {
318 char device[128];
319 strcpy(device, partition->device_index);
320 // Run mke2fs
321 char *const mke2fs[] = {MKE2FS_BIN, "-j", device, NULL};
322 if(run_exec_process(mke2fs))
323 return -1;
324
325 // Run tune2fs
326 char *const tune2fs[] = {TUNE2FS_BIN, "-C", "1", device, NULL};
327 if(run_exec_process(tune2fs))
328 return -1;
329
330 // Run e2fsck
331 char *const e2fsck[] = {E2FSCK_BIN, "-fy", device, NULL};
332 if(run_exec_process(e2fsck))
333 return -1;
334
335 return 0;
336}
337
338int
339mmc_mount_partition(const MmcPartition *partition, const char *mount_point,
340 int read_only)
341{
342 const unsigned long flags = MS_NOATIME | MS_NODEV | MS_NODIRATIME;
343 char devname[128];
344 int rv = -1;
345 strcpy(devname, partition->device_index);
346 if (partition->filesystem == NULL) {
347 printf("Null filesystem!\n");
348 return rv;
349 }
350 if (!read_only) {
351 rv = mount(devname, mount_point, partition->filesystem, flags, NULL);
352 }
353 if (read_only || rv < 0) {
354 rv = mount(devname, mount_point, partition->filesystem, flags | MS_RDONLY, 0);
355 if (rv < 0) {
356 printf("Failed to mount %s on %s: %s\n",
357 devname, mount_point, strerror(errno));
358 } else {
359 printf("Mount %s on %s read-only\n", devname, mount_point);
360 }
361 }
362 return rv;
363}
364
365int
366mmc_raw_copy (const MmcPartition *partition, char *in_file) {
367 int ch;
368 FILE *in;
369 FILE *out;
370 int val = 0;
371 char buf[512];
372 unsigned sz = 0;
373 unsigned i;
374 int ret = -1;
375 char *out_file = partition->device_index;
376
377 in = fopen ( in_file, "r" );
378 if (in == NULL)
379 goto ERROR3;
380
381 out = fopen ( out_file, "w" );
382 if (out == NULL)
383 goto ERROR2;
384
385 fseek(in, 0L, SEEK_END);
386 sz = ftell(in);
387 fseek(in, 0L, SEEK_SET);
388
389 if (sz % 512)
390 {
391 while ( ( ch = fgetc ( in ) ) != EOF )
392 fputc ( ch, out );
393 }
394 else
395 {
396 for (i=0; i< (sz/512); i++)
397 {
398 if ((fread(buf, 512, 1, in)) != 1)
399 goto ERROR1;
400 if ((fwrite(buf, 512, 1, out)) != 1)
401 goto ERROR1;
402 }
403 }
404
405 fsync(out);
406 ret = 0;
407ERROR1:
408 fclose ( out );
409ERROR2:
410 fclose ( in );
411ERROR3:
412 return ret;
413
414}
415