aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKoushik K. Dutta <koushd@gmail.com>2010-02-20 15:59:06 -0800
committerKoushik K. Dutta <koushd@gmail.com>2010-02-20 15:59:06 -0800
commit8ce0be4956f8a942f06644a00347769126b4976e (patch)
treedc9c6f38c431db3b24266e1eca801449c9d332b9
parent3ab130fa9e213e40983472571da246e197930a9d (diff)
downloadbootable_recovery-8ce0be4956f8a942f06644a00347769126b4976e.zip
bootable_recovery-8ce0be4956f8a942f06644a00347769126b4976e.tar.gz
bootable_recovery-8ce0be4956f8a942f06644a00347769126b4976e.tar.bz2
nearly working nandroid, built against libc
-rw-r--r--Android.mk2
-rw-r--r--dump_image/Android.mk15
-rw-r--r--dump_image/mtdutils.c600
-rw-r--r--dump_image/mtdutils.h55
-rw-r--r--mtdutils/Android.mk19
-rw-r--r--mtdutils/dump_image.c (renamed from dump_image/dump_image.c)0
-rw-r--r--mtdutils/mtdutils.c82
-rw-r--r--mtdutils/mtdutils.h2
-rw-r--r--nandroid/Android.mk24
-rwxr-xr-xnandroid/nandroid-mobile.sh1790
-rw-r--r--nandroid/unyaffs.c118
-rw-r--r--nandroid/unyaffs.h144
-rwxr-xr-xres/nandroid-mobile.sh293
13 files changed, 2180 insertions, 964 deletions
diff --git a/Android.mk b/Android.mk
index 60c2487..2afb46f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -49,7 +49,7 @@ LOCAL_STATIC_LIBRARIES += libamend
include $(BUILD_EXECUTABLE)
include $(commands_recovery_local_path)/amend/Android.mk
-include $(commands_recovery_local_path)/dump_image/Android.mk
+include $(commands_recovery_local_path)/nandroid/Android.mk
include $(commands_recovery_local_path)/minui/Android.mk
include $(commands_recovery_local_path)/minzip/Android.mk
include $(commands_recovery_local_path)/mtdutils/Android.mk
diff --git a/dump_image/Android.mk b/dump_image/Android.mk
deleted file mode 100644
index ab8ac38..0000000
--- a/dump_image/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-ifneq ($(TARGET_SIMULATOR),true)
-ifeq ($(TARGET_ARCH),arm)
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := dump_image.c mtdutils.c ../mtdutils/mounts.c
-LOCAL_MODULE := recovery_dump_image
-LOCAL_MODULE_TAGS := eng
-LOCAL_STATIC_LIBRARIES := libcutils libc
-LOCAL_MODULE_STEM := dump_image
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-include $(BUILD_EXECUTABLE)
-
-endif # TARGET_ARCH == arm
-endif # !TARGET_SIMULATOR
diff --git a/dump_image/mtdutils.c b/dump_image/mtdutils.c
deleted file mode 100644
index 9ee7246..0000000
--- a/dump_image/mtdutils.c
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/mount.h> // for _IOW, _IOR, mount()
-#include <sys/stat.h>
-#include <mtd/mtd-user.h>
-#undef NDEBUG
-#include <assert.h>
-
-#include "mtdutils.h"
-
-struct MtdPartition {
- int device_index;
- unsigned int size;
- unsigned int erase_size;
- char *name;
-};
-
-struct MtdReadContext {
- const MtdPartition *partition;
- char *buffer;
- size_t read_size;
- size_t consumed;
- int fd;
-};
-
-struct MtdWriteContext {
- const MtdPartition *partition;
- char *buffer;
- size_t stored;
- int fd;
-};
-
-typedef struct {
- MtdPartition *partitions;
- int partitions_allocd;
- int partition_count;
-} MtdState;
-
-static MtdState g_mtd_state = {
- NULL, // partitions
- 0, // partitions_allocd
- -1 // partition_count
-};
-
-#define MTD_PROC_FILENAME "/proc/mtd"
-
-int
-mtd_scan_partitions()
-{
- char buf[2048];
- const char *bufp;
- int fd;
- int i;
- ssize_t nbytes;
-
- if (g_mtd_state.partitions == NULL) {
- const int nump = 32;
- MtdPartition *partitions = malloc(nump * sizeof(*partitions));
- if (partitions == NULL) {
- errno = ENOMEM;
- return -1;
- }
- g_mtd_state.partitions = partitions;
- g_mtd_state.partitions_allocd = nump;
- memset(partitions, 0, nump * sizeof(*partitions));
- }
- g_mtd_state.partition_count = 0;
-
- /* Initialize all of the entries to make things easier later.
- * (Lets us handle sparsely-numbered partitions, which
- * may not even be possible.)
- */
- for (i = 0; i < g_mtd_state.partitions_allocd; i++) {
- MtdPartition *p = &g_mtd_state.partitions[i];
- if (p->name != NULL) {
- free(p->name);
- p->name = NULL;
- }
- p->device_index = -1;
- }
-
- /* Open and read the file contents.
- */
- fd = open(MTD_PROC_FILENAME, O_RDONLY);
- if (fd < 0) {
- goto bail;
- }
- nbytes = read(fd, buf, sizeof(buf) - 1);
- close(fd);
- if (nbytes < 0) {
- goto bail;
- }
- buf[nbytes] = '\0';
-
- /* Parse the contents of the file, which looks like:
- *
- * # cat /proc/mtd
- * dev: size erasesize name
- * mtd0: 00080000 00020000 "bootloader"
- * mtd1: 00400000 00020000 "mfg_and_gsm"
- * mtd2: 00400000 00020000 "0000000c"
- * mtd3: 00200000 00020000 "0000000d"
- * mtd4: 04000000 00020000 "system"
- * mtd5: 03280000 00020000 "userdata"
- */
- bufp = buf;
- while (nbytes > 0) {
- int mtdnum, mtdsize, mtderasesize;
- int matches;
- char mtdname[64];
- mtdname[0] = '\0';
- mtdnum = -1;
-
- matches = sscanf(bufp, "mtd%d: %x %x \"%63[^\"]",
- &mtdnum, &mtdsize, &mtderasesize, mtdname);
- /* This will fail on the first line, which just contains
- * column headers.
- */
- if (matches == 4) {
- MtdPartition *p = &g_mtd_state.partitions[mtdnum];
- p->device_index = mtdnum;
- p->size = mtdsize;
- p->erase_size = mtderasesize;
- p->name = strdup(mtdname);
- if (p->name == NULL) {
- errno = ENOMEM;
- goto bail;
- }
- g_mtd_state.partition_count++;
- }
-
- /* Eat the line.
- */
- while (nbytes > 0 && *bufp != '\n') {
- bufp++;
- nbytes--;
- }
- if (nbytes > 0) {
- bufp++;
- nbytes--;
- }
- }
-
- return g_mtd_state.partition_count;
-
-bail:
- // keep "partitions" around so we can free the names on a rescan.
- g_mtd_state.partition_count = -1;
- return -1;
-}
-
-const MtdPartition *
-mtd_find_partition_by_name(const char *name)
-{
- if (g_mtd_state.partitions != NULL) {
- int i;
- for (i = 0; i < g_mtd_state.partitions_allocd; i++) {
- MtdPartition *p = &g_mtd_state.partitions[i];
- if (p->device_index >= 0 && p->name != NULL) {
- if (strcmp(p->name, name) == 0) {
- return p;
- }
- }
- }
- }
- return NULL;
-}
-
-int
-mtd_mount_partition(const MtdPartition *partition, const char *mount_point,
- const char *filesystem, int read_only)
-{
- const unsigned long flags = MS_NOATIME | MS_NODEV | MS_NODIRATIME;
- char devname[64];
- int rv = -1;
-
- sprintf(devname, "/dev/block/mtdblock%d", partition->device_index);
- if (!read_only) {
- rv = mount(devname, mount_point, filesystem, flags, NULL);
- }
- if (read_only || rv < 0) {
- rv = mount(devname, mount_point, filesystem, flags | MS_RDONLY, 0);
- if (rv < 0) {
- printf("Failed to mount %s on %s: %s\n",
- devname, mount_point, strerror(errno));
- } else {
- printf("Mount %s on %s read-only\n", devname, mount_point);
- }
- }
-#if 1 //TODO: figure out why this is happening; remove include of stat.h
- if (rv >= 0) {
- /* For some reason, the x bits sometimes aren't set on the root
- * of mounted volumes.
- */
- struct stat st;
- rv = stat(mount_point, &st);
- if (rv < 0) {
- return rv;
- }
- mode_t new_mode = st.st_mode | S_IXUSR | S_IXGRP | S_IXOTH;
- if (new_mode != st.st_mode) {
-printf("Fixing execute permissions for %s\n", mount_point);
- rv = chmod(mount_point, new_mode);
- if (rv < 0) {
- printf("Couldn't fix permissions for %s: %s\n",
- mount_point, strerror(errno));
- }
- }
- }
-#endif
- return rv;
-}
-
-int
-mtd_partition_info(const MtdPartition *partition,
- size_t *total_size, size_t *erase_size, size_t *write_size)
-{
- char mtddevname[32];
- sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index);
- int fd = open(mtddevname, O_RDONLY);
- if (fd < 0) return -1;
-
- struct mtd_info_user mtd_info;
- int ret = ioctl(fd, MEMGETINFO, &mtd_info);
- close(fd);
- if (ret < 0) return -1;
-
- if (total_size != NULL) *total_size = mtd_info.size;
- if (erase_size != NULL) *erase_size = mtd_info.erasesize;
- if (write_size != NULL) *write_size = mtd_info.writesize;
- return 0;
-}
-
-MtdReadContext *mtd_read_partition(const MtdPartition *partition)
-{
- MtdReadContext *ctx = (MtdReadContext*) malloc(sizeof(MtdReadContext));
- if (ctx == NULL) return NULL;
-
- ctx->buffer = malloc(partition->erase_size);
- if (ctx->buffer == NULL) {
- free(ctx);
- return NULL;
- }
-
- char mtddevname[32];
- sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index);
- ctx->fd = open(mtddevname, O_RDONLY);
- if (ctx->fd < 0) {
- free(ctx);
- free(ctx->buffer);
- return NULL;
- }
-
- ctx->partition = partition;
- ctx->read_size = partition->erase_size;
- ctx->consumed = ctx->read_size;
- return ctx;
-}
-
-static int read_block(const MtdReadContext *ctx, char *data)
-{
- struct mtd_ecc_stats before, after;
- off_t pos;
- ssize_t size;
-
- if (ioctl(ctx->fd, ECCGETSTATS, &before)) {
- fprintf(stderr, "mtd: ECCGETSTATS error (%s)\n", strerror(errno));
- return -1;
- }
-
- pos = lseek(ctx->fd, 0, SEEK_CUR);
- size = ctx->read_size;
-
- while (pos + size <= (int) ctx->partition->size) {
- if (lseek(ctx->fd, pos, SEEK_SET) != pos || read(ctx->fd, data, size) != size) {
- fprintf(stderr, "mtd: read error at 0x%08lx (%s)\n",
- pos, strerror(errno));
- } else if (ioctl(ctx->fd, ECCGETSTATS, &after)) {
- fprintf(stderr, "mtd: ECCGETSTATS error (%s)\n", strerror(errno));
- return -1;
- } else if (after.failed != before.failed) {
- fprintf(stderr, "mtd: ECC errors (%d soft, %d hard) at 0x%08lx\n",
- after.corrected - before.corrected,
- after.failed - before.failed, pos);
- /*
- * Reset error counts, so next read may succeed.
- */
- before = after;
- } else {
- return 0; // Success!
- }
-
- pos += ctx->read_size;
- }
-
- errno = ENOSPC;
- return -1;
-}
-
-ssize_t mtd_read_data(MtdReadContext *ctx, char *data, size_t len)
-{
- ssize_t read = 0;
- while (read < (int) len) {
- if (ctx->consumed < ctx->read_size) {
- size_t avail = ctx->read_size - ctx->consumed;
- size_t copy = len - read < avail ? len - read : avail;
- memcpy(data + read, ctx->buffer + ctx->consumed, copy);
- ctx->consumed += copy;
- read += copy;
- }
-
- // Read complete blocks directly into the user's buffer
- while (ctx->consumed == ctx->read_size &&
- len - read >= ctx->read_size) {
- if (read_block(ctx, data + read)) return -1;
- read += ctx->read_size;
- }
-
- // Read the next block into the buffer
- if (ctx->consumed == ctx->read_size && read < (int) len) {
- if (read_block(ctx, ctx->buffer)) return -1;
- ctx->consumed = 0;
- }
- }
-
- return read;
-}
-
-ssize_t mtd_read_raw(MtdReadContext *ctx, char *data, size_t len)
-{
- static const int SPARE_SIZE = (2048 >> 5);
- struct mtd_info_user mtd_info;
- struct mtd_oob_buf oob_buf;
- struct nand_ecclayout ecc_layout;
- struct nand_oobfree *fp;
- unsigned char ecc[SPARE_SIZE];
- char *src, *dst;
- int i, n, ret;
-
-/*
- * FIXME: These two ioctls should be cached in MtdReadContext.
- */
- ret = ioctl(ctx->fd, MEMGETINFO, &mtd_info);
- if (ret < 0)
- return -1;
-
- ret = ioctl(ctx->fd, ECCGETLAYOUT, &ecc_layout);
- if (ret < 0)
- return -1;
-
- ctx->read_size = mtd_info.writesize;
- ctx->consumed = ctx->read_size;
-
-/*
- * Read next good data block.
- */
- ret = read_block(ctx, data);
- if (ret < 0)
- return -1;
-
- dst = src = data + ctx->read_size;
-
-/*
- * Read OOB data for last block read in read_block().
- */
- oob_buf.start = lseek(ctx->fd, 0, SEEK_CUR) - ctx->read_size;
- oob_buf.length = mtd_info.oobsize;
- oob_buf.ptr = (unsigned char *) src;
-
- ret = ioctl(ctx->fd, MEMREADOOB, &oob_buf);
- if (ret < 0)
- return -1;
-
-/*
- * As yaffs and yaffs2 use mode MEM_OOB_AUTO, but mtdchar uses
- * MEM_OOB_PLACE, copy the spare data down the hard way.
- *
- * Safe away ECC data:
- */
- for (i = 0; i < ecc_layout.eccbytes; i++) {
- ecc[i] = src[ecc_layout.eccpos[i]];
- }
- for ( ; i < SPARE_SIZE; i++) {
- ecc[i] = 0;
- }
-
-/*
- * Copy yaffs2 spare data down.
- */
- n = ecc_layout.oobavail;
- fp = &ecc_layout.oobfree[0];
- while (n) {
- if (fp->offset) {
- memmove(dst, src + fp->offset, fp->length);
- }
- dst += fp->length;
- n -= fp->length;
- ++fp;
- }
-
-/*
- * Restore ECC data behind spare data.
- */
- memcpy(dst, ecc, (ctx->read_size >> 5) - ecc_layout.oobavail);
-
- return ctx->read_size + (ctx->read_size >> 5);
-}
-
-void mtd_read_close(MtdReadContext *ctx)
-{
- close(ctx->fd);
- free(ctx->buffer);
- free(ctx);
-}
-
-MtdWriteContext *mtd_write_partition(const MtdPartition *partition)
-{
- MtdWriteContext *ctx = (MtdWriteContext*) malloc(sizeof(MtdWriteContext));
- if (ctx == NULL) return NULL;
-
- ctx->buffer = malloc(partition->erase_size);
- if (ctx->buffer == NULL) {
- free(ctx);
- return NULL;
- }
-
- char mtddevname[32];
- sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index);
- ctx->fd = open(mtddevname, O_RDWR);
- if (ctx->fd < 0) {
- free(ctx->buffer);
- free(ctx);
- return NULL;
- }
-
- ctx->partition = partition;
- ctx->stored = 0;
- return ctx;
-}
-
-static int write_block(const MtdPartition *partition, int fd, const char *data)
-{
- off_t pos = lseek(fd, 0, SEEK_CUR);
- if (pos == (off_t) -1) return 1;
-
- ssize_t size = partition->erase_size;
- while (pos + size <= (int) partition->size) {
- loff_t bpos = pos;
- if (ioctl(fd, MEMGETBADBLOCK, &bpos) > 0) {
- fprintf(stderr, "mtd: not writing bad block at 0x%08lx\n", pos);
- pos += partition->erase_size;
- continue; // Don't try to erase known factory-bad blocks.
- }
-
- struct erase_info_user erase_info;
- erase_info.start = pos;
- erase_info.length = size;
- int retry;
- for (retry = 0; retry < 2; ++retry) {
- if (ioctl(fd, MEMERASE, &erase_info) < 0) {
- fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n",
- pos, strerror(errno));
- continue;
- }
- if (lseek(fd, pos, SEEK_SET) != pos ||
- write(fd, data, size) != size) {
- fprintf(stderr, "mtd: write error at 0x%08lx (%s)\n",
- pos, strerror(errno));
- }
-
- char verify[size];
- if (lseek(fd, pos, SEEK_SET) != pos ||
- read(fd, verify, size) != size) {
- fprintf(stderr, "mtd: re-read error at 0x%08lx (%s)\n",
- pos, strerror(errno));
- continue;
- }
- if (memcmp(data, verify, size) != 0) {
- fprintf(stderr, "mtd: verification error at 0x%08lx (%s)\n",
- pos, strerror(errno));
- continue;
- }
-
- if (retry > 0) {
- fprintf(stderr, "mtd: wrote block after %d retries\n", retry);
- }
- return 0; // Success!
- }
-
- // Try to erase it once more as we give up on this block
- fprintf(stderr, "mtd: skipping write block at 0x%08lx\n", pos);
- ioctl(fd, MEMERASE, &erase_info);
- pos += partition->erase_size;
- }
-
- // Ran out of space on the device
- errno = ENOSPC;
- return -1;
-}
-
-ssize_t mtd_write_data(MtdWriteContext *ctx, const char *data, size_t len)
-{
- size_t wrote = 0;
- while (wrote < len) {
- // Coalesce partial writes into complete blocks
- if (ctx->stored > 0 || len - wrote < ctx->partition->erase_size) {
- size_t avail = ctx->partition->erase_size - ctx->stored;
- size_t copy = len - wrote < avail ? len - wrote : avail;
- memcpy(ctx->buffer + ctx->stored, data + wrote, copy);
- ctx->stored += copy;
- wrote += copy;
- }
-
- // If a complete block was accumulated, write it
- if (ctx->stored == ctx->partition->erase_size) {
- if (write_block(ctx->partition, ctx->fd, ctx->buffer)) return -1;
- ctx->stored = 0;
- }
-
- // Write complete blocks directly from the user's buffer
- while (ctx->stored == 0 && len - wrote >= ctx->partition->erase_size) {
- if (write_block(ctx->partition, ctx->fd, data + wrote)) return -1;
- wrote += ctx->partition->erase_size;
- }
- }
-
- return wrote;
-}
-
-off_t mtd_erase_blocks(MtdWriteContext *ctx, int blocks)
-{
- // Zero-pad and write any pending data to get us to a block boundary
- if (ctx->stored > 0) {
- size_t zero = ctx->partition->erase_size - ctx->stored;
- memset(ctx->buffer + ctx->stored, 0, zero);
- if (write_block(ctx->partition, ctx->fd, ctx->buffer)) return -1;
- ctx->stored = 0;
- }
-
- off_t pos = lseek(ctx->fd, 0, SEEK_CUR);
- if ((off_t) pos == (off_t) -1) return pos;
-
- const int total = (ctx->partition->size - pos) / ctx->partition->erase_size;
- if (blocks < 0) blocks = total;
- if (blocks > total) {
- errno = ENOSPC;
- return -1;
- }
-
- // Erase the specified number of blocks
- while (blocks-- > 0) {
- loff_t bpos = pos;
- if (ioctl(ctx->fd, MEMGETBADBLOCK, &bpos) > 0) {
- fprintf(stderr, "mtd: not erasing bad block at 0x%08lx\n", pos);
- pos += ctx->partition->erase_size;
- continue; // Don't try to erase known factory-bad blocks.
- }
-
- struct erase_info_user erase_info;
- erase_info.start = pos;
- erase_info.length = ctx->partition->erase_size;
- if (ioctl(ctx->fd, MEMERASE, &erase_info) < 0) {
- fprintf(stderr, "mtd: erase failure at 0x%08lx\n", pos);
- }
- pos += ctx->partition->erase_size;
- }
-
- return pos;
-}
-
-int mtd_write_close(MtdWriteContext *ctx)
-{
- int r = 0;
- // Make sure any pending data gets written
- if (mtd_erase_blocks(ctx, 0) == (off_t) -1) r = -1;
- if (close(ctx->fd)) r = -1;
- free(ctx->buffer);
- free(ctx);
- return r;
-}
diff --git a/dump_image/mtdutils.h b/dump_image/mtdutils.h
deleted file mode 100644
index 4a35543..0000000
--- a/dump_image/mtdutils.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MTDUTILS_H_
-#define MTDUTILS_H_
-
-#include <sys/types.h> // for size_t, etc.
-
-typedef struct MtdPartition MtdPartition;
-
-int mtd_scan_partitions(void);
-
-const MtdPartition *mtd_find_partition_by_name(const char *name);
-
-/* mount_point is like "/system"
- * filesystem is like "yaffs2"
- */
-int mtd_mount_partition(const MtdPartition *partition, const char *mount_point,
- const char *filesystem, int read_only);
-
-/* get the partition and the minimum erase/write block size. NULL is ok.
- */
-int mtd_partition_info(const MtdPartition *partition,
- size_t *total_size, size_t *erase_size, size_t *write_size);
-
-/* read or write raw data from a partition, starting at the beginning.
- * skips bad blocks as best we can.
- */
-typedef struct MtdReadContext MtdReadContext;
-typedef struct MtdWriteContext MtdWriteContext;
-
-MtdReadContext *mtd_read_partition(const MtdPartition *);
-ssize_t mtd_read_data(MtdReadContext *, char *data, size_t data_len);
-ssize_t mtd_read_raw(MtdReadContext *, char *data, size_t data_len);
-void mtd_read_close(MtdReadContext *);
-
-MtdWriteContext *mtd_write_partition(const MtdPartition *);
-ssize_t mtd_write_data(MtdWriteContext *, const char *data, size_t data_len);
-off_t mtd_erase_blocks(MtdWriteContext *, int blocks); /* 0 ok, -1 for all */
-int mtd_write_close(MtdWriteContext *);
-
-#endif // MTDUTILS_H_
diff --git a/mtdutils/Android.mk b/mtdutils/Android.mk
index c96c702..b6a5ae4 100644
--- a/mtdutils/Android.mk
+++ b/mtdutils/Android.mk
@@ -27,6 +27,25 @@ LOCAL_MODULE_TAGS := eng
LOCAL_STATIC_LIBRARIES := libmtdutils libcutils libc
LOCAL_MODULE_STEM := flash_image
LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+ADDITIONAL_RECOVERY_EXECUTABLES += recovery_flash_image
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := dump_image.c mtdutils.c mounts.c
+LOCAL_MODULE := recovery_dump_image
+LOCAL_MODULE_TAGS := eng
+LOCAL_STATIC_LIBRARIES := libcutils libc
+LOCAL_MODULE_STEM := dump_image
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+ADDITIONAL_RECOVERY_EXECUTABLES += recovery_dump_image
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := dump_image.c mtdutils.c mounts.c
+LOCAL_MODULE := dump_image
+LOCAL_MODULE_TAGS := eng
include $(BUILD_EXECUTABLE)
endif # TARGET_ARCH == arm
diff --git a/dump_image/dump_image.c b/mtdutils/dump_image.c
index bc96abc..bc96abc 100644
--- a/dump_image/dump_image.c
+++ b/mtdutils/dump_image.c
diff --git a/mtdutils/mtdutils.c b/mtdutils/mtdutils.c
index 18e6a5d..25feabd 100644
--- a/mtdutils/mtdutils.c
+++ b/mtdutils/mtdutils.c
@@ -38,6 +38,7 @@ struct MtdPartition {
struct MtdReadContext {
const MtdPartition *partition;
char *buffer;
+ size_t read_size;
size_t consumed;
int fd;
};
@@ -564,3 +565,84 @@ off_t mtd_find_write_start(MtdWriteContext *ctx, off_t pos) {
}
return pos;
}
+
+
+ssize_t mtd_read_raw(MtdReadContext *ctx, char *data, size_t len)
+{
+ static const int SPARE_SIZE = (2048 >> 5);
+ struct mtd_info_user mtd_info;
+ struct mtd_oob_buf oob_buf;
+ struct nand_ecclayout ecc_layout;
+ struct nand_oobfree *fp;
+ unsigned char ecc[SPARE_SIZE];
+ char *src, *dst;
+ int i, n, ret;
+
+/*
+ * FIXME: These two ioctls should be cached in MtdReadContext.
+ */
+ ret = ioctl(ctx->fd, MEMGETINFO, &mtd_info);
+ if (ret < 0)
+ return -1;
+
+ ret = ioctl(ctx->fd, ECCGETLAYOUT, &ecc_layout);
+ if (ret < 0)
+ return -1;
+
+ ctx->read_size = mtd_info.writesize;
+ ctx->consumed = ctx->read_size;
+
+/*
+ * Read next good data block.
+ */
+ ret = read_block(ctx->partition, ctx->fd, data);
+ if (ret < 0)
+ return -1;
+
+ dst = src = data + ctx->read_size;
+
+/*
+ * Read OOB data for last block read in read_block().
+ */
+ oob_buf.start = lseek(ctx->fd, 0, SEEK_CUR) - ctx->read_size;
+ oob_buf.length = mtd_info.oobsize;
+ oob_buf.ptr = (unsigned char *) src;
+
+ ret = ioctl(ctx->fd, MEMREADOOB, &oob_buf);
+ if (ret < 0)
+ return -1;
+
+/*
+ * As yaffs and yaffs2 use mode MEM_OOB_AUTO, but mtdchar uses
+ * MEM_OOB_PLACE, copy the spare data down the hard way.
+ *
+ * Safe away ECC data:
+ */
+ for (i = 0; i < ecc_layout.eccbytes; i++) {
+ ecc[i] = src[ecc_layout.eccpos[i]];
+ }
+ for ( ; i < SPARE_SIZE; i++) {
+ ecc[i] = 0;
+ }
+
+/*
+ * Copy yaffs2 spare data down.
+ */
+ n = ecc_layout.oobavail;
+ fp = &ecc_layout.oobfree[0];
+ while (n) {
+ if (fp->offset) {
+ memmove(dst, src + fp->offset, fp->length);
+ }
+ dst += fp->length;
+ n -= fp->length;
+ ++fp;
+ }
+
+/*
+ * Restore ECC data behind spare data.
+ */
+ memcpy(dst, ecc, (ctx->read_size >> 5) - ecc_layout.oobavail);
+
+ return ctx->read_size + (ctx->read_size >> 5);
+}
diff --git a/mtdutils/mtdutils.h b/mtdutils/mtdutils.h
index 528a5bb..bd0ce17 100644
--- a/mtdutils/mtdutils.h
+++ b/mtdutils/mtdutils.h
@@ -52,4 +52,6 @@ off_t mtd_erase_blocks(MtdWriteContext *, int blocks); /* 0 ok, -1 for all */
off_t mtd_find_write_start(MtdWriteContext *ctx, off_t pos);
int mtd_write_close(MtdWriteContext *);
+ssize_t mtd_read_raw(MtdReadContext *ctx, char *data, size_t len);
+
#endif // MTDUTILS_H_
diff --git a/nandroid/Android.mk b/nandroid/Android.mk
new file mode 100644
index 0000000..ae2e7fd
--- /dev/null
+++ b/nandroid/Android.mk
@@ -0,0 +1,24 @@
+ifneq ($(TARGET_SIMULATOR),true)
+ifeq ($(TARGET_ARCH),arm)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := recovery_nandroid
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_SRC_FILES := nandroid-mobile.sh
+LOCAL_MODULE_STEM := nandroid-mobile.sh
+ADDITIONAL_RECOVERY_EXECUTABLES += recovery_nandroid
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := recovery_unyaffs
+LOCAL_MODULE_STEM := unyaffs
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SRC_FILES := unyaffs.c
+LOCAL_STATIC_LIBRARIES := libc libcutils
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+include $(BUILD_EXECUTABLE)
+
+endif # TARGET_ARCH == arm
+endif # !TARGET_SIMULATOR
diff --git a/nandroid/nandroid-mobile.sh b/nandroid/nandroid-mobile.sh
new file mode 100755
index 0000000..b5cae3d
--- /dev/null
+++ b/nandroid/nandroid-mobile.sh
@@ -0,0 +1,1790 @@
+#!/sbin/sh
+
+# nandroid v2.2.2 - an Android backup tool for the G1 by infernix and brainaid
+# restore capability added by cyanogen
+
+# pensive modified to allow to add prefixes to backups, and to restore specific backups
+# pensive added the ability to exclude various images from the restore/backup operations, allows to preserve the newer
+# recovery image if an older backup is being restored or to preserve user data. Also, saves space by not backing up
+# partitions which change rarely.
+# pensive added compressing backups and restoring compressed backups
+# pensive added fetching system updates directly from the web into /sdcard/update.zip
+# pensive added fetching system updates directly from the web into /cache and applying it.
+# pensive added moving *update*.zip from /sdcard/download where a browser puts it to /sdcard/update.zip
+# pensive added deletion of stale backups
+# pensive added backup for ext2 partition on the sdcard to switch roms
+# pensive added composite options --save NAME and --switchto NAME to switch ROMS
+# pensive added list backup anywhere on the sdcard
+# pensive added list updates (more precisely *.zip) anywhere on the sdcard
+# Amon_RA : ext restore -> added check if ext backup is existing
+# Amon_RA : ext restore -> added check if ext parition is existing
+
+# Requirements:
+
+# - a modded android in recovery mode (JF 1.3 will work by default)
+# - adb shell as root in recovery mode if not using a pre-made recovery image
+# - busybox in recovery mode
+# - dump_image-arm-uclibc compiled and in path on phone
+# - mkyaffs2image-arm-uclibc compiled and installed in path on phone
+# - flash_image-arm-uclibc compiled and in path on phone
+# - unyaffs-arm-uclibc compiled and in path on phone
+# - for [de]compression needs gzip or bzip2, part of the busybox
+# - wget for the wireless updates
+
+# Reference data:
+
+# dev: size erasesize name
+#mtd0: 00040000 00020000 "misc"
+#mtd1: 00500000 00020000 "recovery"
+#mtd2: 00280000 00020000 "boot"
+#mtd3: 04380000 00020000 "system"
+#mtd4: 04380000 00020000 "cache"
+#mtd5: 04ac0000 00020000 "userdata"
+#mtd6 is everything, dump splash1 with: dd if=/dev/mtd/mtd6ro of=/sdcard/splash1.img skip=19072 bs=2048 count=150
+
+# We don't dump misc or cache because they do not contain any useful data that we are aware of at this time.
+
+# Logical steps (v2.2.1):
+#
+# 0. test for a target dir and the various tools needed, if not found then exit with error.
+# 1. check "adb devices" for a device in recovery mode. set DEVICEID variable to the device ID. abort when not found.
+# 2. mount system and data partitions read-only, set up adb portforward and create destdir
+# 3. check free space on /cache, exit if less blocks than 20MB free
+# 4. push required tools to device in /cache
+# 5 for partitions boot recovery misc:
+# 5a get md5sum for content of current partition *on the device* (no data transfered)
+# 5b while MD5sum comparison is incorrect (always is the first time):
+# 5b1 dump current partition to a netcat session
+# 5b2 start local netcat to dump image to current dir
+# 5b3 compare md5sums of dumped data with dump in current dir. if correct, contine, else restart the loop (6b1)
+# 6 for partitions system data:
+# 6a get md5sum for tar of content of current partition *on the device* (no data transfered)
+# 6b while MD5sum comparison is incorrect (always is the first time):
+# 6b1 tar current partition to a netcat session
+# 6b2 start local netcat to dump tar to current dir
+# 6b3 compare md5sums of dumped data with dump in current dir. if correct, contine, else restart the loop (6b1)
+# 6c if i'm running as root:
+# 6c1 create a temp dir using either tempdir command or the deviceid in /tmp
+# 6c2 extract tar to tempdir
+# 6c3 invoke mkyaffs2image to create the img
+# 6c4 clean up
+# 7. remove tools from device /cache
+# 8. umount system and data on device
+# 9. print success.
+
+
+DEVICEID=foo
+RECOVERY=foo
+
+SUBNAME=""
+NORECOVERY=0
+NOBOOT=0
+NODATA=0
+NOSYSTEM=0
+NOMISC=0
+NOCACHE=0
+NOSPLASH1=0
+NOSPLASH2=0
+EXT2=0
+
+COMPRESS=0
+GETUPDATE=0
+RESTORE=0
+BACKUP=0
+DELETE=0
+WEBGET=0
+LISTBACKUP=0
+LISTUPDATE=0
+AUTOREBOOT=0
+AUTOAPPLY=0
+ITSANUPDATE=0
+ITSANIMAGE=0
+WEBGETSOURCE=""
+WEBGETTARGET="/sdcard"
+
+DEFAULTUPDATEPATH="/sdcard/download"
+
+DEFAULTWEBUPDATE=http://n0rp.chemlab.org/android/update-cm-3.6.8.1-signed.zip
+# There really should be a clone link always pointing to the latest
+#DEFAULTWEBUPDATE="http://n0rp.chemlab.org/android/latestupdate-signed.zip"
+DEFAULTWEBIMAGE=http://n0rp.chemlab.org/android/cm-recovery-1.4-signed.zip
+
+# Set up the default (for pensive at least) nameservers
+NAMESERVER1=64.46.128.3
+NAMESERVER2=64.46.128.4
+
+# WiFi works, rmnet0 setup ???
+# Do not know how to start the rmnet0 interface in recovery
+# If in normal mode "ifconfig rmnet0 down" kills rild too
+# /system/bin/rild& exits immediately, todo?
+
+
+DEVICEID=`cat /proc/cmdline | sed "s/.*serialno=//" | cut -d" " -f1`
+
+# This is the default repository for backups
+BACKUPPATH="/sdcard/nandroid/$DEVICEID"
+
+
+# Boot, Cache, Data, Ext2, Misc, Recovery, System, Splash1, Splash2
+# BACKUPLEGEND, If all the partitions are backed up it should be "CBDEMRS12"
+# Enables the user to figure at a glance what is in the backup
+BACKUPLEGEND=""
+
+# Normally we want tar to be verbose for confidence building.
+TARFLAGS="v"
+
+DEFAULTCOMPRESSOR=gzip
+DEFAULTEXT=.gz
+DEFAULTLEVEL="-1"
+
+ASSUMEDEFAULTUSERINPUT=0
+
+echo2log()
+{
+ if [ -e /cache/recovery/log ]; then
+ echo $1 >>/cache/recovery/log
+ else
+ echo $1 >/cache/recovery/log
+ fi
+}
+
+batteryAtLeast()
+{
+ REQUIREDLEVEL=$1
+ ENERGY=`cat /sys/class/power_supply/battery/capacity`
+ if [ "`cat /sys/class/power_supply/battery/status`" == "Charging" ]; then
+ ENERGY=100
+ fi
+ if [ ! $ENERGY -ge $REQUIREDLEVEL ]; then
+ $ECHO "Error: not enough battery power, need at least $REQUIREDLEVEL%."
+ $ECHO "Connect charger or USB power and try again"
+ exit 1
+ fi
+}
+
+if [ "`echo $0 | grep /sbin/nandroid-mobile.sh`" == "" ]; then
+ cp $0 /sbin
+ chmod 755 /sbin/`basename $0`
+ exec /sbin/`basename $0` $@
+fi
+
+
+# Hm, have to handle old options for the current UI
+case $1 in
+ restore)
+ shift
+ RESTORE=1
+ ;;
+ backup)
+ shift
+ BACKUP=1
+ ;;
+ --)
+ ;;
+esac
+
+ECHO=echo
+OUTPUT=""
+
+for option in $(getopt --name="nandroid-mobile v2.2.2" -l norecovery -l noboot -l nodata -l nosystem -l nocache -l nomisc -l nosplash1 -l nosplash2 -l subname: -l backup -l restore -l compress -l getupdate -l delete -l path -l webget: -l webgettarget: -l nameserver: -l nameserver2: -l bzip2: -l defaultinput -l autoreboot -l autoapplyupdate -l ext2 -l save: -l switchto: -l listbackup -l listupdate -l silent -l quiet -l help -- "cbruds:p:eql" "$@"); do
+ case $option in
+ --silent)
+ ECHO=echo2log
+ ASSUMEDEFAULTUSERINPUT=1
+ TARFLAGS=""
+ OUTPUT=>>/cache/recovery/log
+ shift
+ ;;
+ --quiet)
+ ECHO=echo2log
+ ASSUMEDEFAULTUSERINPUT=1
+ TARFLAGS=""
+ OUTPUT=>>/cache/recovery/log
+ shift
+ ;;
+ -q)
+ ECHO=echo2log
+ ASSUMEDEFAULTUSERINPUT=1
+ TARFLAGS=""
+ OUTPUT=>>/cache/recovery/log
+ shift
+ ;;
+ --help)
+ ECHO=echo
+ $ECHO "Usage: $0 {--backup|--restore|--getupdate|--delete|--compress|--bzip2:ARG|--webget:URL|--listbackup|--listupdate} [options]"
+ $ECHO ""
+ $ECHO "--help Display this help"
+ $ECHO ""
+ $ECHO "-s | --subname: SUBSTRING In case of --backup the SUBSTRING is"
+ $ECHO " the prefix used with backup name"
+ $ECHO " in case of --restore or -c|--compress|--bzip2 or"
+ $ECHO " --delete SUBSTRING specifies backups on which to"
+ $ECHO " operate"
+ $ECHO ""
+ $ECHO "-u | --getupdate Will search /sdcard/download for files named"
+ $ECHO " *update*.zip, will prompt the user"
+ $ECHO " to narrow the choice if more than one is found,"
+ $ECHO " and then move the latest, if not unique,"
+ $ECHO " to sdcard root /sdcard with the update.zip name"
+ $ECHO " It is assumed the browser was used to put the *.zip"
+ $ECHO " in the /sdcard/download folder. -p|--path option"
+ $ECHO " would override /sdcard/download with the path of your"
+ $ECHO " choosing."
+ $ECHO ""
+ $ECHO "-p | --path DIR Requires an ARGUMENT, which is the path to where "
+ $ECHO " the backups are stored, can be used"
+ $ECHO " when the default path /sdcard/nandroid/$DEVICEID "
+ $ECHO " needs to be changed"
+ $ECHO ""
+ $ECHO "-b | --backup Will store a full system backup on $BACKUPPATH"
+ $ECHO " One can suppress backup of any image however with options"
+ $ECHO " starting with --no[partionname]"
+ $ECHO ""
+ $ECHO "-e | --ext2 Preserve the contents of the ext2 partition along with"
+ $ECHO " the other partitions being backed up, to easily switch roms."
+ $ECHO ""
+ $ECHO "-r | --restore Will restore the last made backup which matches --subname"
+ $ECHO " ARGUMENT for boot, system, recovery and data"
+ $ECHO " unless suppressed by other options"
+ $ECHO " if no --subname is supplied and the user fails to"
+ $ECHO " provide any input then the latest backup is used"
+ $ECHO " When restoring compressed backups, the images will remain"
+ $ECHO " decompressed after the restore, you need to use -c|-compress"
+ $ECHO " or --bzip2 to compress the backup again"
+ $ECHO ""
+ $ECHO "-d | --delete Will remove backups whose names match --subname ARGUMENT"
+ $ECHO " Will allow to narrow down, will ask if the user is certain."
+ $ECHO " Removes one backup at a time, repeat to remove multiple backups"
+ $ECHO ""
+ $ECHO "-c | --compress Will operate on chosen backups to compress image files,"
+ $ECHO " resulting in saving of about 40MB out of 90+mb,"
+ $ECHO " i.e. up to 20 backups can be stored in 1 GIG, if this "
+ $ECHO " option is turned on with --backup, the resulting backup will"
+ $ECHO " be compressed, no effect if restoring since restore will"
+ $ECHO " automatically uncompress compressed images if space is available"
+ $ECHO ""
+ $ECHO "--bzip2: -# Turns on -c|--compress and uses bzip2 for compression instead"
+ $ECHO " of gzip, requires an ARG -[1-9] compression level"
+ $ECHO ""
+ $ECHO "--webget: URL|\"\" Requires an argument, a valid URL for an *update*.zip file"
+ $ECHO " If a null string is passed then the default URL is used"
+ $ECHO " Will also create an update.MD5sum file and update.name with the"
+ $ECHO " original file name."
+ $ECHO ""
+ $ECHO "--nameserver: IP addr Provide the first nameserver IP address, to override the default"
+ $ECHO ""
+ $ECHO "--nameserver2: IP addr Provide the second nameserver IP address, to override the default"
+ $ECHO ""
+ $ECHO "--webgettarget: DIR Target directory to deposit the fetched update, default is"
+ $ECHO " /sdcard"
+ $ECHO ""
+ $ECHO "--norecovery Will suppress restore/backup of the recovery partition"
+ $ECHO " If recovery.img was not part of the backup, no need to use this"
+ $ECHO " option as the nandroid will not attempt to restore it, same goes"
+ $ECHO " for all the options below"
+ $ECHO ""
+ $ECHO "--noboot Will suppress restore/backup of the boot partition"
+ $ECHO ""
+ $ECHO "--nodata Will suppress restore/backup of the data partition"
+ $ECHO ""
+ $ECHO "--nosystem Will suppress restore/backup of the system partition"
+ $ECHO ""
+ $ECHO "--nocache Will suppress restore/backup of the cache partition"
+ $ECHO ""
+ $ECHO "--nomisc Will suppress restore/backup of the misc partition"
+ $ECHO ""
+ $ECHO "--nosplash1 Will suppress restore/backup of the splash1 partition"
+ $ECHO ""
+ $ECHO "--nosplash2 Will suppress restore/backup of the splash2 partition"
+ $ECHO ""
+ $ECHO "--defaultinput Makes nandroid-mobile non-interactive, assumes default"
+ $ECHO " inputs from the user."
+ $ECHO ""
+ $ECHO "--autoreboot Automatically reboot the phone after a backup, especially"
+ $ECHO " useful when the compression options are on -c|--compress| "
+ $ECHO " --bzip2 -level since the compression op takes time and"
+ $ECHO " you may want to go to sleep or do something else, and"
+ $ECHO " when a backup is over you want the calls and mms coming"
+ $ECHO " through, right?"
+ $ECHO ""
+ $ECHO "--autoapplyupdate Once the specific update is downloaded or chosen from the"
+ $ECHO " sdcard, apply it immediately. This option is valid as a "
+ $ECHO " modifier for either --webget or --getupdate options."
+ $ECHO ""
+ $ECHO "-e|--ext2 Save the contents of ext2 partition in the backup folder too."
+ $ECHO " Enables to keep different sets of apps for different ROMS and"
+ $ECHO " switch easily between them."
+ $ECHO ""
+ $ECHO "--save: ROMTAG Preserve EVERYTHING under ROMTAG name, a composite option,"
+ $ECHO " it uses several other options."
+ $ECHO ""
+ $ECHO "--switchto: ROMTAG Restores your entire environment including app2sd apps, cache"
+ $ECHO " to the ROM environment named ROMTAG."
+ $ECHO ""
+ $ECHO "-q|--quiet|--silent Direct all the output to the recovery log, and assume default"
+ $ECHO " user inputs."
+ $ECHO ""
+ $ECHO "-l|--listbackup Will search the entire SDCARD for backup folders and will dump"
+ $ECHO " the list to stdout for use by the UI. Should be run with --silent"
+ $ECHO ""
+ $ECHO "--listupdate Will search the entire SDCARD for updates and will dump"
+ $ECHO " the list to stdout for use by the UI. Should be run with --silent"
+ exit 0
+ ;;
+ --norecovery)
+ NORECOVERY=1
+ #$ECHO "No recovery"
+ shift
+ ;;
+ --noboot)
+ NOBOOT=1
+ #$ECHO "No boot"
+ shift
+ ;;
+ --nodata)
+ NODATA=1
+ #$ECHO "No data"
+ shift
+ ;;
+ --nosystem)
+ NOSYSTEM=1
+ #$ECHO "No system"
+ shift
+ ;;
+ --nocache)
+ NOCACHE=1
+ #$ECHO "No cache"
+ shift
+ ;;
+ --nomisc)
+ NOMISC=1
+ #$ECHO "No misc"
+ shift
+ ;;
+ --nosplash1)
+ NOSPLASH1=1
+ #$ECHO "No splash1"
+ shift
+ ;;
+ --nosplash2)
+ NOSPLASH2=1
+ #$ECHO "No splash2"
+ shift
+ ;;
+ --backup)
+ BACKUP=1
+ #$ECHO "backup"
+ shift
+ ;;
+ -b)
+ BACKUP=1
+ #$ECHO "backup"
+ shift
+ ;;
+ -e)
+ EXT2=1
+ shift
+ ;;
+ --ext2)
+ EXT2=1
+ shift
+ ;;
+ --restore)
+ RESTORE=1
+ #$ECHO "restore"
+ shift
+ ;;
+ -r)
+ RESTORE=1
+ #$ECHO "restore"
+ shift
+ ;;
+ --compress)
+ COMPRESS=1
+ #$ECHO "Compress"
+ shift
+ ;;
+ -c)
+ COMPRESS=1
+ #$ECHO "Compress"
+ shift
+ ;;
+ --bzip2)
+ COMPRESS=1
+ DEFAULTCOMPRESSOR=bzip2
+ DEFAULTEXT=.bz2
+ if [ "$2" == "$option" ]; then
+ shift
+ fi
+ DEFAULTLEVEL="$2"
+ shift
+ ;;
+ --getupdate)
+ GETUPDATE=1
+ shift
+ ;;
+ -u)
+ GETUPDATE=1
+ shift
+ ;;
+ --subname)
+ if [ "$2" == "$option" ]; then
+ shift
+ fi
+ #$ECHO $2
+ SUBNAME="$2"
+ shift
+ ;;
+ -s)
+ if [ "$2" == "$option" ]; then
+ shift
+ fi
+ #$ECHO $2
+ SUBNAME="$2"
+ shift
+ ;;
+ --path)
+ if [ "$2" == "$option" ]; then
+ shift
+ fi
+ #$ECHO $2
+ BACKUPPATH="$2"
+ DEFAULTUPDATEPATH="$2"
+ shift 2
+ ;;
+ -p)
+ if [ "$2" == "$option" ]; then
+ shift
+ fi
+ #$ECHO $2
+ BACKUPPATH="$2"
+ shift 2
+ ;;
+ --delete)
+ DELETE=1
+ shift
+ ;;
+ -d)
+ DELETE=1
+ shift
+ ;;
+ --webgettarget)
+ if [ "$2" == "$option" ]; then
+ shift
+ fi
+ WEBGETTARGET="$2"
+ shift
+ ;;
+ --webget)
+ if [ "$2" == "$option" ]; then
+ shift
+ fi
+ #$ECHO "WEBGET"
+ # if the argument is "" stick with the default: /sdcard
+ if [ ! "$2" == "" ]; then
+ WEBGETSOURCE="$2"
+ fi
+ WEBGET=1
+ shift
+ ;;
+ --nameserver)
+ if [ "$2" == "$option" ]; then
+ shift
+ fi
+ NAMESERVER1="$2"
+ shift
+ ;;
+ --nameserver2)
+ if [ "$2" == "$option" ]; then
+ shift
+ fi
+ NAMESERVER2="$2"
+ shift
+ ;;
+ --defaultinput)
+ ASSUMEDEFAULTUSERINPUT=1
+ shift
+ ;;
+ --autoreboot)
+ AUTOREBOOT=1
+ shift
+ ;;
+ --autoapplyupdate)
+ AUTOAPPLY=1
+ shift
+ ;;
+ --save)
+ if [ "$2" == "$option" ]; then
+ shift
+ fi
+ SUBNAME="$2"
+ BACKUP=1
+ ASSUMEDEFAULTUSERINPUT=1
+ EXT2=1
+ COMPRESS=1
+ shift
+ ;;
+ --switchto)
+ if [ "$2" == "$option" ]; then
+ shift
+ fi
+ SUBNAME="$2"
+ RESTORE=1
+ ASSUMEDEFAULTUSERINPUT=1
+ EXT2=1
+ shift
+ ;;
+ -l)
+ shift
+ LISTBACKUP=1
+ ;;
+ --listbackup)
+ shift
+ LISTBACKUP=1
+ ;;
+ --listupdate)
+ shift
+ LISTUPDATE=1
+ ;;
+ --)
+ shift
+ break
+ ;;
+ esac
+done
+
+$ECHO ""
+$ECHO "nandroid-mobile v2.2.1"
+$ECHO ""
+
+let OPS=$BACKUP
+let OPS=$OPS+$RESTORE
+let OPS=$OPS+$DELETE
+let OPS=$OPS+$WEBGET
+let OPS=$OPS+$GETUPDATE
+let OPS=$OPS+$LISTBACKUP
+let OPS=$OPS+$LISTUPDATE
+
+if [ "$OPS" -ge 2 ]; then
+ ECHO=echo
+ $ECHO "--backup, --restore, --delete, --webget, --getupdate, --listbackup, --listupdate are mutually exclusive operations."
+ $ECHO "Please, choose one and only one option!"
+ $ECHO "Aborting."
+ exit 1
+fi
+
+let OPS=$OPS+$COMPRESS
+
+if [ "$OPS" -lt 1 ]; then
+ ECHO=echo
+ $ECHO "Usage: $0 {-b|--backup|-r|--restore|-d|--delete|-u|--getupdate|--webget|-c|--compress|--bzip2 -level|-l|--listbackup|--listupdate} [options]"
+ $ECHO "At least one operation must be defined, try $0 --help for more information."
+ exit 0
+fi
+
+
+if [ "$LISTBACKUP" == 1 ]; then
+ umount /sdcard 2>/dev/null
+ mount /sdcard 2>/dev/null
+ CHECK=`mount | grep /sdcard`
+ if [ "$CHECK" == "" ]; then
+ echo "Error: sdcard not mounted, aborting."
+ exit 1
+ else
+ find /sdcard | grep nandroid.md5 | sed s/.gz//g | sed s/.bz2//g | sed s/nandroid.md5//g
+ umount /sdcard 2>/dev/null
+ exit 0
+ fi
+fi
+
+if [ "$LISTUPDATE" == 1 ]; then
+ umount /sdcard 2>/dev/null
+ mount /sdcard 2>/dev/null
+ CHECK=`mount | grep /sdcard`
+ if [ "$CHECK" == "" ]; then
+ echo "Error: sdcard not mounted, aborting."
+ exit 1
+ else
+ find /sdcard | grep .zip
+ umount /sdcard 2>/dev/null
+ exit 0
+ fi
+fi
+
+# Make sure it exists
+touch /cache/recovery/log
+
+
+if [ "$AUTOAPPLY" == 1 -a "$WEBGET" == 0 -a "$GETUPDATE" == 0 ]; then
+ ECHO=echo
+ $ECHO "The --autoapplyupdate option is valid only in conjunction with --webget or --getupdate."
+ $ECHO "Aborting."
+ exit 1
+fi
+
+if [ "$COMPRESS" == 1 ]; then
+ $ECHO "Compressing with $DEFAULTCOMPRESSOR, level $DEFAULTLEVEL"
+fi
+
+if [ "$WEBGET" == 1 ]; then
+ $ECHO "Fetching $WEBGETSOURCE to target folder: $WEBGETTARGET"
+fi
+
+if [ ! "$SUBNAME" == "" ]; then
+ if [ "$BACKUP" == 1 ]; then
+ if [ "$COMPRESS" == 1 ]; then
+ $ECHO "Using $SUBNAME- prefix to create a compressed backup folder"
+ else
+ $ECHO "Using $SUBNAME- prefix to create a backup folder"
+ fi
+ else
+ if [ "$RESTORE" == 1 -o "$DELETE" == 1 -o "$COMPRESS" == 1 ]; then
+ $ECHO "Searching for backup directories, matching $SUBNAME, to delete or restore"
+ $ECHO "or compress"
+ $ECHO ""
+ fi
+ fi
+else
+ if [ "$BACKUP" == 1 ]; then
+ $ECHO "Using G1 keyboard, enter a prefix substring and then <CR>"
+ $ECHO -n "or just <CR> to accept default: "
+ if [ "$ASSUMEDEFAULTUSERINPUT" == 0 ]; then
+ read SUBNAME
+ else
+ $ECHO "Accepting default."
+ fi
+ $ECHO ""
+ if [ "$COMPRESS" == 1 ]; then
+ $ECHO "Using $SUBNAME- prefix to create a compressed backup folder"
+ else
+ $ECHO "Using $SUBNAME- prefix to create a backup folder"
+ fi
+ $ECHO ""
+ else
+ if [ "$RESTORE" == 1 -o "$DELETE" == 1 -o "$COMPRESS" == 1 ]; then
+ $ECHO "Using G1 keyboard, enter a directory name substring and then <CR>"
+ $ECHO -n "to find matches or just <CR> to accept default: "
+ if [ "$ASSUMEDEFAULTUSERINPUT" == 0 ]; then
+ read SUBNAME
+ else
+ $ECHO "Accepting default."
+ fi
+ $ECHO ""
+ $ECHO "Using $SUBNAME string to search for matching backup directories"
+ $ECHO ""
+ fi
+ fi
+fi
+
+if [ "$BACKUP" == 1 ]; then
+ mkyaffs2image=`which mkyaffs2image`
+ if [ "$mkyaffs2image" == "" ]; then
+ mkyaffs2image=`which mkyaffs2image-arm-uclibc`
+ if [ "$mkyaffs2image" == "" ]; then
+ $ECHO "error: mkyaffs2image or mkyaffs2image-arm-uclibc not found in path"
+ exit 1
+ fi
+ fi
+ dump_image=`which dump_image`
+ if [ "$dump_image" == "" ]; then
+ dump_image=`which dump_image-arm-uclibc`
+ if [ "$dump_image" == "" ]; then
+ $ECHO "error: dump_image or dump_image-arm-uclibc not found in path"
+ exit 1
+ fi
+ fi
+fi
+
+if [ "$RESTORE" == 1 ]; then
+ flash_image=`which flash_image`
+ if [ "$flash_image" == "" ]; then
+ flash_image=`which flash_image-arm-uclibc`
+ if [ "$flash_image" == "" ]; then
+ $ECHO "error: flash_image or flash_image-arm-uclibc not found in path"
+ exit 1
+ fi
+ fi
+ unyaffs=`which unyaffs`
+ if [ "$unyaffs" == "" ]; then
+ unyaffs=`which unyaffs-arm-uclibc`
+ if [ "$unyaffs" == "" ]; then
+ $ECHO "error: unyaffs or unyaffs-arm-uclibc not found in path"
+ exit 1
+ fi
+ fi
+fi
+if [ "$COMPRESS" == 1 ]; then
+ compressor=`busybox | grep $DEFAULTCOMPRESSOR`
+ if [ "$compressor" == "" ]; then
+ $ECHO "Warning: busybox/$DEFAULTCOMPRESSOR is not found"
+ $ECHO "No compression operations will be performed"
+ COMPRESS=0
+ else
+ $ECHO "Found $DEFAULTCOMPRESSOR, will compress the backup"
+ fi
+fi
+
+# 1
+DEVICEID=`cat /proc/cmdline | sed "s/.*serialno=//" | cut -d" " -f1`
+RECOVERY=`cat /proc/cmdline | grep "androidboot.mode=recovery"`
+if [ "$RECOVERY" == "foo" ]; then
+ $ECHO "Error: Must be in recovery mode, aborting"
+ exit 1
+fi
+if [ "$DEVICEID" == "foo" ]; then
+ $ECHO "Error: device id not found in /proc/cmdline, aborting"
+ exit 1
+fi
+if [ ! "`id -u 2>/dev/null`" == "0" ]; then
+ if [ "`whoami 2>&1 | grep 'uid 0'`" == "" ]; then
+ $ECHO "Error: must run as root, aborting"
+ exit 1
+ fi
+fi
+
+
+if [ "$RESTORE" == 1 ]; then
+ batteryAtLeast 30
+# ENERGY=`cat /sys/class/power_supply/battery/capacity`
+# if [ "`cat /sys/class/power_supply/battery/status`" == "Charging" ]; then
+# ENERGY=100
+# fi
+# if [ ! $ENERGY -ge 30 ]; then
+# $ECHO "Error: not enough battery power"
+# $ECHO "Connect charger or USB power and try again"
+# exit 1
+# fi
+
+
+ umount /sdcard 2>/dev/null
+ mount /sdcard 2>/dev/null
+ if [ "`mount | grep sdcard`" == "" ]; then
+ $ECHO "error: unable to mount /sdcard, aborting"
+ exit 1
+ fi
+
+ # find the latest backup, but show the user other options
+ $ECHO ""
+ $ECHO "Looking for the latest backup, will display other choices!"
+ $ECHO ""
+
+ RESTOREPATH=`ls -trd $BACKUPPATH/*$SUBNAME* 2>/dev/null | tail -1`
+ $ECHO " "
+
+ if [ "$RESTOREPATH" = "" ];
+ then
+ $ECHO "Error: no backups found"
+ exit 2
+ else
+ $ECHO "Default backup is the latest: $RESTOREPATH"
+ $ECHO ""
+ $ECHO "Other available backups are: "
+ $ECHO ""
+ ls -trd $BACKUPPATH/*$SUBNAME* 2>/dev/null | grep -v $RESTOREPATH $OUTPUT
+ $ECHO ""
+ $ECHO "Using G1 keyboard, enter a unique name substring to change it and <CR>"
+ $ECHO -n "or just <CR> to accept: "
+ if [ "$ASSUMEDEFAULTUSERINPUT" == 0 ]; then
+ read SUBSTRING
+ else
+ $ECHO "Accepting default."
+ SUBSTRING=""
+ fi
+ $ECHO ""
+
+ if [ ! "$SUBSTRING" == "" ]; then
+ RESTOREPATH=`ls -trd $BACKUPPATH/*$SUBNAME* 2>/dev/null | grep $SUBSTRING | tail -1`
+ else
+ RESTOREPATH=`ls -trd $BACKUPPATH/*$SUBNAME* 2>/dev/null | tail -1`
+ fi
+ if [ "$RESTOREPATH" = "" ]; then
+ $ECHO "Error: no matching backups found, aborting"
+ exit 2
+ fi
+ fi
+
+ $ECHO "Restore path: $RESTOREPATH"
+ $ECHO ""
+
+ umount /system /data 2>/dev/null
+ mount /system 2>/dev/null
+ mount /data 2>/dev/null
+ if [ "`mount | grep data`" == "" ]; then
+ $ECHO "error: unable to mount /data, aborting"
+ exit 1
+ fi
+ if [ "`mount | grep system`" == "" ]; then
+ $ECHO "error: unable to mount /system, aborting"
+ exit 1
+ fi
+
+ CWD=$PWD
+ cd $RESTOREPATH
+
+ DEFAULTEXT=""
+ if [ `ls *.bz2 2>/dev/null|wc -l` -ge 1 ]; then
+ DEFAULTCOMPRESSOR=bzip2
+ DEFAULTDECOMPRESSOR=bunzip2
+ DEFAULTEXT=.bz2
+ fi
+ if [ `ls *.gz 2>/dev/null|wc -l` -ge 1 ]; then
+ DEFAULTCOMPRESSOR=gzip
+ DEFAULTDECOMPRESSOR=gunzip
+ DEFAULTEXT=.gz
+ fi
+
+ if [ ! -f $RESTOREPATH/nandroid.md5$DEFAULTEXT ]; then
+ $ECHO "error: $RESTOREPATH/nandroid.md5 not found, cannot verify backup data"
+ exit 1
+ fi
+
+ if [ `ls *.bz2 2>/dev/null|wc -l` -ge 1 -o `ls *.gz 2>/dev/null|wc -l` -ge 1 ]; then
+ $ECHO "This backup is compressed with $DEFAULTCOMPRESSOR."
+
+ # Make sure that $DEFAULT[DE]COMPRESSOR exists
+ if [ `busybox | grep $DEFAULTCOMPRESSOR | wc -l` -le 0 -a\
+ `busybox | grep $DEFAULTDECOMPRESSOR | wc -l` -le 0 ]; then
+
+ $ECHO "You do not have either the $DEFAULTCOMPRESSOR or the $DEFAULTDECOMPRESSOR"
+ $ECHO "to unpack this backup, cleaning up and aborting!"
+ umount /system 2>/dev/null
+ umount /data 2>/dev/null
+ umount /sdcard 2>/dev/null
+ exit 1
+ fi
+ $ECHO "Checking free space /sdcard for the decompression operation."
+ FREEBLOCKS="`df -k /sdcard| grep sdcard | awk '{ print $4 }'`"
+ # we need about 100MB for gzip to uncompress the files
+ if [ $FREEBLOCKS -le 100000 ]; then
+ $ECHO "Error: not enough free space available on sdcard (need about 100mb)"
+ $ECHO "to perform restore from the compressed images, aborting."
+ umount /system 2>/dev/null
+ umount /data 2>/dev/null
+ umount /sdcard 2>/dev/null
+ exit 1
+ fi
+ $ECHO "Decompressing images, please wait...."
+ $ECHO ""
+ # Starting from the largest while we still have more space to reduce
+ # space requirements
+ $DEFAULTCOMPRESSOR -d `ls -S *$DEFAULTEXT`
+ $ECHO "Backup images decompressed"
+ $ECHO ""
+ fi
+
+ $ECHO "Verifying backup images..."
+ md5sum -c nandroid.md5
+ if [ $? -eq 1 ]; then
+ $ECHO "Error: md5sum mismatch, aborting"
+ exit 1
+ fi
+
+ if [ `ls boot* 2>/dev/null | wc -l` == 0 ]; then
+ NOBOOT=1
+ fi
+ if [ `ls recovery* 2>/dev/null | wc -l` == 0 ]; then
+ NORECOVERY=1
+ fi
+ if [ `ls data* 2>/dev/null | wc -l` == 0 ]; then
+ NODATA=1
+ fi
+ if [ `ls system* 2>/dev/null | wc -l` == 0 ]; then
+ NOSYSTEM=1
+ fi
+ # Amon_RA : If there's no ext backup set EXT2 to 0 so ext2 restore doesn't start
+ if [ `ls ext2* 2>/dev/null | wc -l` == 0 ]; then
+ EXT2=0
+ fi
+
+ for image in boot recovery; do
+ if [ "$NOBOOT" == "1" -a "$image" == "boot" ]; then
+ $ECHO ""
+ $ECHO "Not flashing boot image!"
+ $ECHO ""
+ continue
+ fi
+ if [ "$NORECOVERY" == "1" -a "$image" == "recovery" ]; then
+ $ECHO ""
+ $ECHO "Not flashing recovery image!"
+ $ECHO ""
+ continue
+ fi
+ $ECHO "Flashing $image..."
+ $flash_image $image $image.img $OUTPUT
+ done
+
+ for image in data system; do
+ if [ "$NODATA" == "1" -a "$image" == "data" ]; then
+ $ECHO ""
+ $ECHO "Not restoring data image!"
+ $ECHO ""
+ continue
+ fi
+ if [ "$NOSYSTEM" == "1" -a "$image" == "system" ]; then
+ $ECHO ""
+ $ECHO "Not restoring system image!"
+ $ECHO ""
+ continue
+ fi
+ $ECHO "Erasing /$image..."
+ cd /$image
+ rm -rf * 2>/dev/null
+ $ECHO "Unpacking $image image..."
+ $unyaffs $RESTOREPATH/$image.img $OUTPUT
+ cd /
+ sync
+ umount /$image
+ done
+
+ if [ "$EXT2" == 1 ]; then
+ # Amon_RA : Check if there's an ext partition before starting to restore
+ if [ -e /dev/block/mmcblk0p2 ]; then
+ $ECHO "Restoring the ext2 contents."
+ CWD=`pwd`
+ cd /
+
+ if [ `mount | grep /system | wc -l` == 0 ]; then
+ mount /system
+ else
+ mount -o rw,remount /system
+ fi
+
+ if [ `mount | grep /system/sd | wc -l` == 0 ]; then
+ mount /system/sd
+ fi
+
+ cd $CWD
+ CHECK=`mount | grep /system/sd`
+
+ if [ "$CHECK" == "" ]; then
+ $ECHO "Warning: --ext2 specified but unable to mount the ext2 partition."
+ $ECHO "Warning: your phone may be in an inconsistent state on reboot."
+ exit 1
+ else
+ CWD=`pwd`
+ cd /system/sd
+ # Depending on whether the ext2 backup is compressed we do either or.
+ if [ -e $RESTOREPATH/ext2.tar ]; then
+ rm -rf * 2>/dev/null
+ tar -x$TARFLAGS -f $RESTOREPATH/ext2.tar
+ else
+ if [ -e $RESTOREPATH/ext2.tgz ]; then
+ rm -rf * 2>/dev/null
+ tar -x$TARFLAGS -zf $RESTOREPATH/ext2.tgz
+ else
+ if [ -e $RESTOREPATH/ext2.tar.bz2 ]; then
+ rm -rf * 2>/dev/null
+ tar -x$TARFLAGS -jf $RESTOREPATH/ext2.tar.bz2
+ else
+ $ECHO "Warning: --ext2 specified but cannot find the ext2 backup."
+ $ECHO "Warning: your phone may be in an inconsistent state on reboot."
+ fi
+ fi
+ fi
+ cd $CWD
+ sync
+ umount /system/sd
+ umount /system
+
+ fi
+ else
+ # Amon_RA : Just display a warning
+ $ECHO "Warning: --ext2 specified but ext2 partition present on sdcard"
+ $ECHO "Warning: your phone may be in an inconsistent state on reboot."
+ fi
+ fi
+ $ECHO "Restore done"
+ exit 0
+fi
+
+# 2.
+if [ "$BACKUP" == 1 ]; then
+
+ if [ "$COMPRESS" == 1 ]; then
+ ENERGY=`cat /sys/class/power_supply/battery/capacity`
+ if [ "`cat /sys/class/power_supply/battery/status`" == "Charging" ]; then
+ ENERGY=100
+ fi
+ if [ ! $ENERGY -ge 30 ]; then
+ $ECHO "Warning: Not enough battery power to perform compression."
+ COMPRESS=0
+ $ECHO "Turning off compression option, you can compress the backup later"
+ $ECHO "with the compression options."
+ fi
+ fi
+
+$ECHO "mounting system and data read-only, sdcard read-write"
+umount /system 2>/dev/null
+umount /data 2>/dev/null
+umount /sdcard 2>/dev/null
+mount -o ro /system || FAIL=1
+mount -o ro /data || FAIL=2
+mount /sdcard || mount /dev/block/mmcblk0 /sdcard || FAIL=3
+case $FAIL in
+ 1) $ECHO "Error mounting system read-only"; umount /system /data /sdcard; exit 1;;
+ 2) $ECHO "Error mounting data read-only"; umount /system /data /sdcard; exit 1;;
+ 3) $ECHO "Error mounting sdcard read-write"; umount /system /data /sdcard; exit 1;;
+esac
+
+if [ ! "$SUBNAME" == "" ]; then
+ SUBNAME=$SUBNAME-
+fi
+
+# Identify the backup with what partitions have been backed up
+if [ "$NOBOOT" == 0 ]; then
+ BACKUPLEGEND=$BACKUPLEGEND"B"
+fi
+if [ "$NOCACHE" == 0 ]; then
+ BACKUPLEGEND=$BACKUPLEGEND"C"
+fi
+if [ "$NODATA" == 0 ]; then
+ BACKUPLEGEND=$BACKUPLEGEND"D"
+fi
+if [ "$EXT2" == 1 ]; then
+ BACKUPLEGEND=$BACKUPLEGEND"E"
+fi
+if [ "$NOMISC" == 0 ]; then
+ BACKUPLEGEND=$BACKUPLEGEND"M"
+fi
+if [ "$NORECOVERY" == 0 ]; then
+ BACKUPLEGEND=$BACKUPLEGEND"R"
+fi
+if [ "$NOSYSTEM" == 0 ]; then
+ BACKUPLEGEND=$BACKUPLEGEND"S"
+fi
+
+if [ ! -e /dev/mtd/mtd6ro ]; then
+ NOSPLASH1=1
+ NOSPLASH2=1
+fi
+
+if [ "$NOSPLASH1" == 0 ]; then
+ BACKUPLEGEND=$BACKUPLEGEND"1"
+fi
+if [ "$NOSPLASH2" == 0 ]; then
+ BACKUPLEGEND=$BACKUPLEGEND"2"
+fi
+
+if [ ! "$BACKUPLEGEND" == "" ]; then
+ BACKUPLEGEND=$BACKUPLEGEND-
+fi
+
+
+TIMESTAMP="`date +%Y%m%d-%H%M`"
+DESTDIR="$BACKUPPATH/$SUBNAME$BACKUPLEGEND$TIMESTAMP"
+if [ ! -d $DESTDIR ]; then
+ mkdir -p $DESTDIR
+ if [ ! -d $DESTDIR ]; then
+ $ECHO "error: cannot create $DESTDIR"
+ umount /system 2>/dev/null
+ umount /data 2>/dev/null
+ umount /sdcard 2>/dev/null
+ exit 1
+ fi
+else
+ touch $DESTDIR/.nandroidwritable
+ if [ ! -e $DESTDIR/.nandroidwritable ]; then
+ $ECHO "error: cannot write to $DESTDIR"
+ umount /system 2>/dev/null
+ umount /data 2>/dev/null
+ umount /sdcard 2>/dev/null
+ exit 1
+ fi
+ rm $DESTDIR/.nandroidwritable
+fi
+
+# 3.
+$ECHO "checking free space on sdcard"
+FREEBLOCKS="`df -k /sdcard| grep sdcard | awk '{ print $4 }'`"
+# we need about 130MB for the dump
+if [ $FREEBLOCKS -le 130000 ]; then
+ $ECHO "Error: not enough free space available on sdcard (need 130mb), aborting."
+ umount /system 2>/dev/null
+ umount /data 2>/dev/null
+ umount /sdcard 2>/dev/null
+ exit 1
+fi
+
+
+
+if [ -e /dev/mtd/mtd6ro ]; then
+ if [ "$NOSPLASH1" == 0 ]; then
+ $ECHO -n "Dumping splash1 from device over tcp to $DESTDIR/splash1.img..."
+ dd if=/dev/mtd/mtd6ro of=$DESTDIR/splash1.img skip=19072 bs=2048 count=150 2>/dev/null
+ $ECHO "done"
+ sleep 1s
+ else
+ $ECHO "Dump of the splash1 image suppressed."
+ fi
+ if [ "$NOSPLASH2" == 0 ]; then
+ $ECHO -n "Dumping splash2 from device over tcp to $DESTDIR/splash2.img..."
+ dd if=/dev/mtd/mtd6ro of=$DESTDIR/splash2.img skip=19456 bs=2048 count=150 2>/dev/null
+ $ECHO "done"
+ else
+ $ECHO "Dump of the splash2 image suppressed."
+ fi
+fi
+
+
+# 5.
+for image in boot recovery misc; do
+
+ case $image in
+ boot)
+ if [ "$NOBOOT" == 1 ]; then
+ $ECHO "Dump of the boot partition suppressed."
+ continue
+ fi
+ ;;
+ recovery)
+ if [ "$NORECOVERY" == 1 ]; then
+ $ECHO "Dump of the recovery partition suppressed."
+ continue
+ fi
+ ;;
+ misc)
+ if [ "$NOMISC" == 1 ]; then
+ $ECHO "Dump of the misc partition suppressed."
+ continue
+ fi
+ ;;
+ esac
+
+ # 5a
+ DEVICEMD5=`$dump_image $image - | md5sum | awk '{ print $1 }'`
+ sleep 1s
+ MD5RESULT=1
+ # 5b
+ $ECHO -n "Dumping $image to $DESTDIR/$image.img..."
+ ATTEMPT=0
+ while [ $MD5RESULT -eq 1 ]; do
+ let ATTEMPT=$ATTEMPT+1
+ # 5b1
+ $dump_image $image $DESTDIR/$image.img $OUTPUT
+ sync
+ # 5b3
+ echo "${DEVICEMD5} $DESTDIR/$image.img" | md5sum -c -s - $OUTPUT
+ if [ $? -eq 1 ]; then
+ true
+ else
+ MD5RESULT=0
+ fi
+ if [ "$ATTEMPT" == "5" ]; then
+ $ECHO "Fatal error while trying to dump $image, aborting."
+ umount /system
+ umount /data
+ umount /sdcard
+ exit 1
+ fi
+ done
+ $ECHO "done"
+done
+
+# 6
+for image in system data cache; do
+ case $image in
+ system)
+ if [ "$NOSYSTEM" == 1 ]; then
+ $ECHO "Dump of the system partition suppressed."
+ continue
+ fi
+ ;;
+ data)
+ if [ "$NODATA" == 1 ]; then
+ $ECHO "Dump of the data partition suppressed."
+ continue
+ fi
+ ;;
+ cache)
+ if [ "$NOCACHE" == 1 ]; then
+ $ECHO "Dump of the cache partition suppressed."
+ continue
+ fi
+ ;;
+ esac
+
+ # 6a
+ $ECHO -n "Dumping $image to $DESTDIR/$image.img..."
+ $mkyaffs2image /$image $DESTDIR/$image.img $OUTPUT
+ sync
+ $ECHO "done"
+done
+
+# Backing up the ext2 partition, not really for the backup but to switch ROMS and apps at the same time.
+
+if [ "$EXT2" == 1 ]; then
+ $ECHO "Storing the ext2(Apps, Dalvik-cache) contents in the backup folder."
+
+ CHECK1=`mount | grep /system`
+ if [ "$CHECK1" == "" ]; then
+ mount /system 2>/dev/null
+ fi
+ CHECK2=`mount | grep /system/sd`
+ if [ "$CHECK2" == "" ]; then
+ mount /system/sd 2>/dev/null
+ fi
+
+ CHECK1=`mount | grep /system`
+ CHECK2=`mount | grep /system/sd`
+ if [ "$CHECK1" == "" -o "$CHECK2" == "" ]; then
+ $ECHO "Warning: --ext2 specified but unable to mount the ext2 partition."
+ exit 1
+ else
+
+ CWD=`pwd`
+ cd /system/sd
+ # Depending on the whether we want it compressed we do either or.
+ if [ "$COMPRESS" == 0 ]; then
+ tar -cvf $DESTDIR/ext2.tar ./
+ else
+ if [ "$DEFAULTCOMPRESSOR" == "bzip2" ]; then
+ tar -cvjf $DESTDIR/ext2.tar.bz2 ./
+ else
+ tar -cvzf $DESTDIR/ext2.tgz ./
+ fi
+ fi
+ cd $CWD
+ umount /system/sd
+ fi
+fi
+
+
+# 7.
+$ECHO -n "generating md5sum file..."
+CWD=$PWD
+cd $DESTDIR
+md5sum *img > nandroid.md5
+
+# 7b.
+if [ "$COMPRESS" == 1 ]; then
+ $ECHO "Compressing the backup, may take a bit of time, please wait..."
+ $ECHO "checking free space on sdcard for the compression operation."
+ FREEBLOCKS="`df -k /sdcard| grep sdcard | awk '{ print $4 }'`"
+ # we need about 70MB for the intermediate storage needs
+ if [ $FREEBLOCKS -le 70000 ]; then
+ $ECHO "error: not enough free space available on sdcard for compression operation (need 70mb)"
+ $ECHO "leaving this backup uncompressed."
+ else
+ # we are already in $DESTDIR, start compression from the smallest files
+ # to maximize space for the largest's compression, less likely to fail.
+ # To decompress reverse the order.
+ $DEFAULTCOMPRESSOR $DEFAULTLEVEL `ls -S -r * | grep -v ext2`
+ fi
+fi
+
+cd $CWD
+$ECHO "done"
+
+# 8.
+$ECHO "unmounting system, data and sdcard"
+umount /system
+umount /data
+umount /sdcard
+
+# 9.
+$ECHO "Backup successful."
+if [ "$AUTOREBOOT" == 1 ]; then
+ reboot
+fi
+exit 0
+fi
+
+
+# ----------------------------------GETTING UPDATES DIRECT FROM THE WEB USING WIFI-------------
+
+if [ "$WEBGET" == 1 ]; then
+ $ECHO "mounting system and data read-only, sdcard read-write"
+ umount /system 2>/dev/null
+ umount /data 2>/dev/null
+ umount /sdcard 2>/dev/null
+
+ # Since we are in recovery, these file-systems have to be mounted
+ $ECHO "Mounting /system and /data for starting WiFi"
+ mount -o ro /system || FAIL=1
+ # Need to write to this system to setup nameservers for the wifi
+ mount -o rw /data || FAIL=2
+ mount /sdcard || mount /dev/block/mmcblk0 /sdcard || FAIL=3
+
+ case $FAIL in
+ 1) $ECHO "Error mounting system read-only"; umount /system /data /sdcard; exit 1;;
+ 2) $ECHO "Error mounting data read-write"; umount /system /data /sdcard; exit 1;;
+ 3) $ECHO "Error mounting sdcard read-write"; umount /system /data /sdcard; exit 1;;
+ esac
+
+ if [ "$WEBGETSOURCE" == "" ]; then
+ # Set the URL to the current latest update
+ if [ "$ITSANUPDATE" == 1 ]; then
+ WEBGETSOURCE=$DEFAULTWEBUPDATE
+ else
+ WEBGETSOURCE=$DEFAULTWEBIMAGE
+ fi
+ fi
+
+ if [ "$AUTOAPPLY" == 0 ]; then
+ # Need to check space on sdcard only if we dump the update there.
+ $ECHO "Checking free space on sdcard for the update download."
+ FREEBLOCKS="`df -k /sdcard| grep sdcard | awk '{ print $4 }'`"
+ # we need about 50MB for the storage needs
+ if [ $FREEBLOCKS -le 50000 ]; then
+ $ECHO "Error: not enough free space available on sdcard for the update operation (need 50mb)"
+ $ECHO "Please free up space before invoking this option again."
+ $ECHO "Cleaning up, unmounting file systems, aborting."
+ umount /system /data /sdcard
+ exit 1
+ fi
+ fi
+
+ if [ ! `basename $WEBGETSOURCE` == `basename $WEBGETSOURCE .zip` ]; then
+ # It is a zip, not img.
+ ITSANUPDATE=1
+ else
+ if [ ! `basename $WEBGETSOURCE` == `basename $WEBGETSOURCE .img` ]; then
+ # It is an img file.
+ ITSANIMAGE=1
+ else
+ # Unknown file type
+ $ECHO "Unknown file type, cleaning up, aborting."
+ umount /system /data /sdcard
+ exit 1
+ fi
+ fi
+
+
+ if [ "$ITSANUPDATE" == 1 -a "$AUTOAPPLY" == 0 ]; then
+ # Move the previous update aside, if things go badly with the new update, it is good
+ # to have the last one still around :-)
+
+ # If we cannot figure out what the file name used to be, create this new one with a time stamp
+ OLDNAME="OLD-update-`date +%Y%m%d-%H%M`"
+
+ if [ -e $WEBGETTARGET/update.zip ]; then
+ $ECHO "There is already an update.zip in $WEBGETTARGET, backing it up to"
+ if [ -e $WEBGETTARGET/update.name ]; then
+ OLDNAME=`cat $WEBGETTARGET/update.name`
+ # Backup the name file (presumably contains the old name of the update.zip
+ mv -f $WEBGETTARGET/update.name $WEBGETTARGET/`basename $OLDNAME .zip`.name
+ fi
+ $ECHO "`basename $OLDNAME .zip`.zip"
+ mv -f $WEBGETTARGET/update.zip $WEBGETTARGET/`basename $OLDNAME .zip`.zip
+
+ # Backup the MD5sum file
+ if [ -e $WEBGETTARGET/update.MD5sum ]; then
+ mv -f $WEBGETTARGET/update.MD5sum $WEBGETTARGET/`basename $OLDNAME .zip`.MD5sum
+ fi
+ fi
+ fi
+
+ $ECHO "Starting WiFI, please wait..."
+ insmod /system/lib/modules/wlan.ko
+
+ wlan_loader -f /system/etc/wifi/Fw1251r1c.bin -e /proc/calibration -i /system/etc/wifi/tiwlan.ini
+
+ CWD=`pwd`
+ cd /data/local/tmp
+
+ wpa_supplicant -f -Dtiwlan0 -itiwlan0 -c/data/misc/wifi/wpa_supplicant.conf&
+
+ sleep 5
+ $ECHO "wpa_supplicant started"
+ $ECHO ""
+
+ echo "nameserver $NAMESERVER1" >/etc/resolv.conf
+ echo "nameserver $NAMESERVER2" >>/etc/resolv.conf
+
+ #We want the wifi to assign a dynamic address
+ $ECHO "Starting DHCPCD server (dynamic address assignment)"
+ # -BKL flags????
+ dhcpcd -d tiwlan0 2>/dev/null &
+
+ # Have to wait for it to init stuff
+ sleep 10
+
+
+ CHECK1=`ps | grep -v grep | grep dhcpcd`
+ CHECK2=`ps | grep -v grep | grep wpa_supplicant`
+ if [ "$CHECK1" == "" -o "$CHECK2" == "" ]; then
+ $ECHO "Error: wpa_supplicant or DHCPCD server is not running, cleaning up, aborting"
+ rm -- -Dtiwlan0
+ cd $CWD
+
+ $ECHO "unmounting /system, /data and /sdcard"
+ umount /system
+ umount /data
+ umount /sdcard
+ exit 2
+ fi
+
+ $ECHO "DHCPCD server started"
+ $ECHO ""
+
+ $ECHO "WiFi is running!"
+ $ECHO ""
+
+ if [ "$AUTOAPPLY" == 1 ]; then
+ $ECHO "Autoapply is on, retrieving the update into /cache/`basename $WEBGETSOURCE`"
+
+ wget -O /cache/`basename $WEBGETSOURCE` $WEBGETSOURCE $OUTPUT
+
+ if [ ! -e /cache/recovery ]; then
+ mkdir /cache/recovery
+ chmod 777 /cache/recovery
+ fi
+ if [ -e /cache/recovery/command ]; then
+ echo "--update_package=CACHE:`basename $WEBGETSOURCE`" >>/cache/recovery/command
+ else
+ echo "--update_package=CACHE:`basename $WEBGETSOURCE`" >/cache/recovery/command
+ fi
+ chmod 555 /cache/recovery/command
+ # Once rebooted the update will be applied.
+
+ else
+
+ if [ "$ITSANUPDATE" == 1 ]; then
+ $ECHO "Retrieving system update into $WEBGETTARGET/update.zip, please wait..."
+ wget -O $WEBGETTARGET/update.zip $WEBGETSOURCE $OUTPUT
+
+ echo "`basename $WEBGETSOURCE`" > $WEBGETTARGET/update.name
+ $ECHO ""
+ $ECHO "Update retrieved, if concerned, please compare the md5sum with the number"
+ $ECHO "you see on the web page, if it is NOT the same, the retrieval"
+ $ECHO "has failed and has to be repeated."
+ $ECHO ""
+ $ECHO `md5sum $WEBGETTARGET/update.zip | tee $WEBGETTARGET/update.MD5sum`
+ $ECHO ""
+ $ECHO "MD5sum has been stored in $WEBGETTARGET/update.MD5sum"
+ else
+ $ECHO "Retrieving the image into $WEBGETTARGET/`basename $WEBGETSOURCE`, please wait..."
+ wget -O $WEBGETTARGET/`basename $WEBGETSOURCE` $WEBGETSOURCE $OUTPUT
+ $ECHO ""
+ $ECHO "$WEBGETSOURCE retrieved, if concerned, please compare the md5sum with the number"
+ $ECHO "you see on the web page, if it is NOT the same, the retrieval"
+ $ECHO "has failed and has to be repeated."
+ $ECHO ""
+ md5sum $WEBGETTARGET/`basename $WEBGETSOURCE` | tee $WEBGETTARGET/`basename $WEBGETSOURCE .img`.MD5sum $OUTPUT
+ $ECHO ""
+ $ECHO "MD5sum has been stored in $WEBGETTARGET/`basename $WEBGETSOURCE .img`.MD5sum"
+ $ECHO ""
+ $ECHO -n "Would you like to flash this image into boot or recovery? (or no for no flash) "
+ read ANSWER
+ if [ "$ANSWER" == "boot" ]; then
+ $ECHO "Flashing $WEBGETTARGET/`basename $WEBGETSOURCE` into the boot partition."
+ $flash_image boot $WEBGETTARGET/`basename $WEBGETSOURCE`
+ else
+ if [ "$ANSWER" == "recovery" ]; then
+ $ECHO "Moving $WEBGETTARGET/`basename $WEBGETSOURCE` into the /data/recovery.img"
+ $ECHO "and /system/recovery.img"
+ cp -f $WEBGETTARGET/`basename $WEBGETSOURCE` /data/recovery.img
+ mount -o rw,remount /system
+ cp -f $WEBGETTARGET/`basename $WEBGETSOURCE` /system/recovery.img
+ $ECHO "Depending on the settings of your specific ROM, the recovery.img will be"
+ $ECHO "flashed at the normal bootup time either from /system or /data."
+ else
+ $ECHO "Not flashing the image."
+ fi
+ fi
+ fi
+ $ECHO ""
+
+ fi
+
+ $ECHO "Shutting down DHCPCD service and wpa_supplicant"
+ killall -TERM dhcpcd
+ TEMPVAR=`ps | grep -v grep | grep wpa_supplicant`
+ TEMPVAR=`echo $TEMPVAR | cut -f 1 -d ' '`
+ kill -TERM $TEMPVAR
+
+ while true; do
+ CHECK=`ps | grep -v grep | grep dhcpcd`
+ if [ ! "$CHECK" == "" ]; then
+ sleep 1
+ else
+ break
+ fi
+ done
+
+ while true; do
+ CHECK=`ps | grep -v grep | grep wpa_supplicant`
+ if [ ! "$CHECK" == "" ]; then
+ sleep 1
+ else
+ break
+ fi
+ done
+ #sleep 5
+
+ $ECHO "Cleaning up..."
+ # Looks like cannot clean up wlan module since chdir is missing
+ #rmmod wlan
+ rm -- -Dtiwlan0
+ cd $CWD
+
+ $ECHO "unmounting /system, /data and /sdcard"
+ umount /system
+ umount /data
+ umount /sdcard
+
+ if [ "$AUTOAPPLY" == 1 ]; then
+ $ECHO "Auto apply update is on, rebooting into recovery to apply the update."
+ $ECHO "When the update is complete reboot into the normal mode."
+ $ECHO "The device will reboot and the update will be applied in 10 seconds!"
+ sleep 10
+ reboot recovery
+ else
+ if [ "$ITSANUPDATE" == 1 ]; then
+ $ECHO "If you put the update into a folder other than /sdcard you need to use --getupdate to"
+ $ECHO "prepare the update for application."
+ $ECHO "You may want to execute 'reboot recovery' and choose update option to flash the update."
+ $ECHO "Or in the alternative, shutdown your phone with reboot -p, and then press <CAMERA>+<POWER>"
+ $ECHO "to initiate a normal system update procedure, if you have stock SPL."
+ fi
+ exit 0
+ fi
+fi
+
+# -------------------------------------DELETION, COMPRESSION OF BACKUPS---------------------------------
+if [ "$COMPRESS" == 1 -o "$DELETE" == 1 ]; then
+ $ECHO "Unmounting /system and /data to be on the safe side, mounting /sdcard read-write."
+ umount /system 2>/dev/null
+ umount /data 2>/dev/null
+ umount /sdcard 2>/dev/null
+
+ FAIL=0
+ # Since we are in recovery, these file-system have to be mounted
+ $ECHO "Mounting /sdcard to look for backups."
+ mount /sdcard || mount /dev/block/mmcblk0 /sdcard || FAIL=1
+
+ if [ "$FAIL" == 1 ]; then
+ $ECHO "Error mounting /sdcard read-write, cleaning up..."; umount /system /data /sdcard; exit 1
+ fi
+
+ $ECHO "The current size of /sdcard FAT32 filesystem is `du /sdcard | tail -1 | cut -f 1 -d '/'`Kb"
+ $ECHO ""
+
+ # find the oldest backup, but show the user other options
+ $ECHO "Looking for the oldest backup to delete, newest to compress,"
+ $ECHO "will display all choices!"
+ $ECHO ""
+ $ECHO "Here are the backups you have picked within this repository $BACKUPPATH:"
+
+ if [ "$DELETE" == 1 ]; then
+ RESTOREPATH=`ls -td $BACKUPPATH/*$SUBNAME* 2>/dev/null | tail -1`
+ ls -td $BACKUPPATH/*$SUBNAME* 2>/dev/null $OUTPUT
+ else
+ RESTOREPATH=`ls -trd $BACKUPPATH/*$SUBNAME* 2>/dev/null | tail -1`
+ ls -trd $BACKUPPATH/*$SUBNAME* 2>/dev/null $OUTPUT
+ fi
+ $ECHO " "
+
+ if [ "$RESTOREPATH" = "" ]; then
+ $ECHO "Error: no backups found"
+ exit 2
+ else
+ if [ "$DELETE" == 1 ]; then
+ $ECHO "Default backup to delete is the oldest: $RESTOREPATH"
+ $ECHO ""
+ $ECHO "Other candidates for deletion are: "
+ ls -td $BACKUPPATH/*$SUBNAME* 2>/dev/null | grep -v $RESTOREPATH $OUTPUT
+ fi
+ if [ "$COMPRESS" == 1 ]; then
+ $ECHO "Default backup to compress is the latest: $RESTOREPATH"
+ $ECHO ""
+ $ECHO "Other candidates for compression are: "
+ ls -trd $BACKUPPATH/*$SUBNAME* 2>/dev/null | grep -v $RESTOREPATH $OUTPUT
+ fi
+
+ $ECHO ""
+ $ECHO "Using G1 keyboard, enter a unique name substring to change it and <CR>"
+ $ECHO -n "or just <CR> to accept: "
+ if [ "$ASSUMEDEFAULTUSERINPUT" == 0 ]; then
+ read SUBSTRING
+ else
+ $ECHO "Accepting default."
+ SUBSTRING=""
+ fi
+
+ if [ ! "$SUBSTRING" == "" ]; then
+ RESTOREPATH=`ls -td $BACKUPPATH/*$SUBNAME* 2>/dev/null | grep $SUBSTRING | tail -1`
+ else
+ RESTOREPATH=`ls -td $BACKUPPATH/*$SUBNAME* 2>/dev/null | tail -1`
+ fi
+ if [ "$RESTOREPATH" = "" ]; then
+ $ECHO "Error: no matching backup found, aborting"
+ exit 2
+ fi
+ fi
+
+ if [ "$DELETE" == 1 ]; then
+ $ECHO "Deletion path: $RESTOREPATH"
+ $ECHO ""
+ $ECHO "WARNING: Deletion of a backup is an IRREVERSIBLE action!!!"
+ $ECHO -n "Are you absolutely sure? {yes | YES | Yes | no | NO | No}: "
+ if [ "$ASSUMEDEFAULTUSERINPUT" == 0 ]; then
+ read ANSWER
+ else
+ ANSWER=yes
+ $ECHO "Accepting default."
+ fi
+ $ECHO ""
+ if [ "$ANSWER" == "yes" -o "$ANSWER" == "YES" -o "$ANSWER" == "Yes" ]; then
+ rm -rf $RESTOREPATH
+ $ECHO ""
+ $ECHO "$RESTOREPATH has been permanently removed from your SDCARD."
+ $ECHO "Post deletion size of the /sdcard FAT32 filesystem is `du /sdcard | tail -1 | cut -f 1 -d '/'`Kb"
+ else
+ if [ "$ANSWER" == "no" -o "$ANSWER" == "NO" -o "$ANSWER" == "No" ]; then
+ $ECHO "The chosen backup will NOT be removed."
+ else
+ $ECHO "Invalid answer: assuming NO."
+ fi
+ fi
+ fi
+
+ if [ "$COMPRESS" == 1 ]; then
+
+ CWD=`pwd`
+ cd $RESTOREPATH
+
+ if [ `ls *.bz2 2>/dev/null|wc -l` -ge 1 -o `ls *.gz 2>/dev/null|wc -l` -ge 1 ]; then
+ $ECHO "This backup is already compressed, cleaning up, aborting..."
+ cd $CWD
+ umount /sdcard 2>/dev/null
+ exit 0
+ fi
+
+ $ECHO "checking free space on sdcard for the compression operation."
+ FREEBLOCKS="`df -k /sdcard| grep sdcard | awk '{ print $4 }'`"
+ # we need about 70MB for the intermediate storage needs
+ if [ $FREEBLOCKS -le 70000 ]; then
+ $ECHO "Error: not enough free space available on sdcard for compression operation (need 70mb)"
+ $ECHO "leaving this backup uncompressed."
+ else
+ # we are already in $DESTDIR, start compression from the smallest files
+ # to maximize space for the largest's compression, less likely to fail.
+ # To decompress reverse the order.
+ $ECHO "Pre compression size of the /sdcard FAT32 filesystem is `du /sdcard | tail -1 | cut -f 1 -d '/'`Kb"
+ $ECHO ""
+ $ECHO "Compressing the backup may take a bit of time, please wait..."
+ $DEFAULTCOMPRESSOR $DEFAULTLEVEL `ls -S -r *`
+ $ECHO ""
+ $ECHO "Post compression size of the /sdcard FAT32 filesystem is `du /sdcard | tail -1 | cut -f 1 -d '/'`Kb"
+ fi
+ fi
+
+ $ECHO "Cleaning up."
+ cd $CWD
+ umount /sdcard 2>/dev/null
+ exit 0
+
+fi
+
+if [ "$GETUPDATE" == 1 ]; then
+ $ECHO "Unmounting /system and /data to be on the safe side, mounting /sdcard read-write."
+ umount /system 2>/dev/null
+ umount /data 2>/dev/null
+ umount /sdcard 2>/dev/null
+
+ FAIL=0
+ # Since we are in recovery, these file-system have to be mounted
+ $ECHO "Mounting /sdcard to look for updates to flash."
+ mount /sdcard || mount /dev/block/mmcblk0 /sdcard || FAIL=1
+
+ if [ "$FAIL" == 1 ]; then
+ $ECHO "Error mounting /sdcard read-write, cleaning up..."; umount /system /data /sdcard; exit 1
+ fi
+
+ $ECHO "The current size of /sdcard FAT32 filesystem is `du /sdcard | tail -1 | cut -f 1 -d '/'`Kb"
+ $ECHO ""
+
+ # find all the files with update in them, but show the user other options
+ $ECHO "Looking for all *update*.zip candidate files to flash."
+ $ECHO ""
+ $ECHO "Here are the updates limited by the subname $SUBNAME found"
+ $ECHO "within the repository $DEFAULTUPDATEPATH:"
+ $ECHO ""
+ RESTOREPATH=`ls -trd $DEFAULTUPDATEPATH/*$SUBNAME*.zip 2>/dev/null | grep update | tail -1`
+ if [ "$RESTOREPATH" == "" ]; then
+ $ECHO "Error: found no matching updates, cleaning up, aborting..."
+ umount /sdcard 2>/dev/null
+ exit 2
+ fi
+ ls -trd $DEFAULTUPDATEPATH/*$SUBNAME*.zip 2>/dev/null | grep update $OUTPUT
+ $ECHO ""
+ $ECHO "The default update is the latest $RESTOREPATH"
+ $ECHO ""
+ $ECHO "Using G1 keyboard, enter a unique name substring to change it and <CR>"
+ $ECHO -n "or just <CR> to accept: "
+ if [ "$ASSUMEDEFAULTUSERINPUT" == 0 ]; then
+ read SUBSTRING
+ else
+ $ECHO "Accepting default."
+ SUBSTRING=""
+ fi
+ $ECHO ""
+
+ if [ ! "$SUBSTRING" == "" ]; then
+ RESTOREPATH=`ls -trd $DEFAULTUPDATEPATH/*$SUBNAME*.zip 2>/dev/null | grep update | grep $SUBSTRING | tail -1`
+ else
+ RESTOREPATH=`ls -trd $DEFAULTUPDATEPATH/*$SUBNAME*.zip 2>/dev/null | grep update | tail -1`
+ fi
+ if [ "$RESTOREPATH" = "" ]; then
+ $ECHO "Error: no matching backups found, aborting"
+ exit 2
+ fi
+
+ if [ "$RESTOREPATH" == "/sdcard/update.zip" ]; then
+ $ECHO "You chose update.zip, it is ready for flashing, there nothing to do."
+ else
+
+ # Things seem ok so far.
+
+ # Move the previous update aside, if things go badly with the new update, it is good
+ # have the last one still around :-)
+
+ # If we cannot figure out what the file name used to be, create this new one with a time stamp
+ OLDNAME="OLD-update-`date +%Y%m%d-%H%M`"
+
+ if [ -e /sdcard/update.zip ]; then
+ $ECHO "There is already an update.zip in /sdcard, backing it up to"
+ if [ -e /sdcard/update.name ]; then
+ OLDNAME=`cat /sdcard/update.name`
+ # Backup the name file (presumably contains the old name of the update.zip
+ mv -f /sdcard/update.name /sdcard/`basename $OLDNAME .zip`.name
+ fi
+ $ECHO "`basename $OLDNAME .zip`.zip"
+ mv -f /sdcard/update.zip /sdcard/`basename $OLDNAME .zip`.zip
+
+ # Backup the MD5sum file
+ if [ -e /sdcard/update.MD5sum ]; then
+ mv -f /sdcard/update.MD5sum /sdcard/`basename $OLDNAME .zip`.MD5sum
+ fi
+ fi
+
+ if [ -e $DEFAULTUPDATEPATH/`basename $RESTOREPATH .zip`.MD5sum ]; then
+ mv -f $DEFAULTUPDATEPATH/`basename $RESTOREPATH .zip`.MD5sum /sdcard/update.MD5sum
+ else
+ $ECHO `md5sum $RESTOREPATH | tee /sdcard/update.MD5sum`
+ $ECHO ""
+ $ECHO "MD5sum has been stored in /sdcard/update.MD5sum"
+ $ECHO ""
+ fi
+ if [ -e $DEFAULTUPDATEPATH/`basename $RESTOREPATH .zip`.name ]; then
+ mv -f $DEFAULTUPDATEPATH/`basename $RESTOREPATH .zip`.name /sdcard/update.name
+ else
+ echo "`basename $RESTOREPATH`" > /sdcard/update.name
+ fi
+
+ mv -i $RESTOREPATH /sdcard/update.zip
+
+
+ $ECHO "Your file $RESTOREPATH has been moved to the root of sdcard, and is ready for flashing!!!"
+
+ fi
+
+ $ECHO "You may want to execute 'reboot recovery' and then choose the update option to flash the update."
+ $ECHO "Or in the alternative, shutdown your phone with reboot -p, and then press <CAMERA>+<POWER> to"
+ $ECHO "initiate a standard update procedure if you have stock SPL."
+ $ECHO ""
+ $ECHO "Cleaning up and exiting."
+ umount /sdcard 2>/dev/null
+ exit 0
+fi
diff --git a/nandroid/unyaffs.c b/nandroid/unyaffs.c
new file mode 100644
index 0000000..aa8a735
--- /dev/null
+++ b/nandroid/unyaffs.c
@@ -0,0 +1,118 @@
+/*
+ * unyaffs: extract files from yaffs2 file system image to current directory
+ *
+ * Created by Kai Wei <kai.wei.cn@gmail.com>
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "unyaffs.h"
+
+#define CHUNK_SIZE 2048
+#define SPARE_SIZE 64
+#define MAX_OBJECTS 10000
+#define YAFFS_OBJECTID_ROOT 1
+
+
+unsigned char data[CHUNK_SIZE + SPARE_SIZE];
+unsigned char *chunk_data = data;
+unsigned char *spare_data = data + CHUNK_SIZE;
+int img_file;
+
+char *obj_list[MAX_OBJECTS];
+void process_chunk()
+{
+ int out_file, remain, s;
+ char *full_path_name;
+
+ yaffs_PackedTags2 *pt = (yaffs_PackedTags2 *)spare_data;
+ if (pt->t.byteCount == 0xffff) { //a new object
+
+ yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)malloc(sizeof(yaffs_ObjectHeader));
+ memcpy(oh, chunk_data, sizeof(yaffs_ObjectHeader));
+
+ full_path_name = (char *)malloc(strlen(oh->name) + strlen(obj_list[oh->parentObjectId]) + 2);
+ if (full_path_name == NULL) {
+ perror("malloc full path name\n");
+ }
+ strcpy(full_path_name, obj_list[oh->parentObjectId]);
+ strcat(full_path_name, "/");
+ strcat(full_path_name, oh->name);
+ obj_list[pt->t.objectId] = full_path_name;
+
+ switch(oh->type) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ remain = oh->fileSize;
+ out_file = creat(full_path_name, oh->yst_mode);
+ while(remain > 0) {
+ if (read_chunk())
+ return -1;
+ s = (remain < pt->t.byteCount) ? remain : pt->t.byteCount;
+ if (write(out_file, chunk_data, s) == -1)
+ return -1;
+ remain -= s;
+ }
+ close(out_file);
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ symlink(oh->alias, full_path_name);
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ mkdir(full_path_name, 0777);
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ link(obj_list[oh->equivalentObjectId], full_path_name);
+ break;
+ }
+ }
+}
+
+
+int read_chunk()
+{
+ ssize_t s;
+ int ret = -1;
+ memset(chunk_data, 0xff, sizeof(chunk_data));
+ s = read(img_file, data, CHUNK_SIZE + SPARE_SIZE);
+ if (s == -1) {
+ perror("read image file\n");
+ } else if (s == 0) {
+ printf("end of image\n");
+ } else if ((s == (CHUNK_SIZE + SPARE_SIZE))) {
+ ret = 0;
+ } else {
+ fprintf(stderr, "broken image file\n");
+ }
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 2) {
+ printf("Usage: unyaffs image_file_name\n");
+ exit(1);
+ }
+ img_file = open(argv[1], O_RDONLY);
+ if (img_file == -1) {
+ printf("open image file failed\n");
+ exit(1);
+ }
+
+ obj_list[YAFFS_OBJECTID_ROOT] = ".";
+ while(1) {
+ if (read_chunk() == -1)
+ break;
+ process_chunk();
+ }
+ close(img_file);
+ return 0;
+}
diff --git a/nandroid/unyaffs.h b/nandroid/unyaffs.h
new file mode 100644
index 0000000..fcd8046
--- /dev/null
+++ b/nandroid/unyaffs.h
@@ -0,0 +1,144 @@
+/*
+ * definition copied from yaffs project
+ */
+
+#ifndef __UNYAFFS_H__
+#define __UNYAFFS_H__
+
+
+#define YAFFS_MAX_NAME_LENGTH 255
+#define YAFFS_MAX_ALIAS_LENGTH 159
+
+#include <sys/types.h>
+
+/* Definition of types */
+#ifndef __ASM_ARM_TYPES_H
+typedef unsigned char __u8;
+typedef unsigned short __u16;
+typedef unsigned __u32;
+#endif
+typedef struct {
+ unsigned sequenceNumber;
+ unsigned objectId;
+ unsigned chunkId;
+ unsigned byteCount;
+} yaffs_PackedTags2TagsPart;
+
+typedef struct {
+ unsigned char colParity;
+ unsigned lineParity;
+ unsigned lineParityPrime;
+} yaffs_ECCOther;
+
+typedef struct {
+ yaffs_PackedTags2TagsPart t;
+ yaffs_ECCOther ecc;
+} yaffs_PackedTags2;
+
+typedef enum {
+ YAFFS_ECC_RESULT_UNKNOWN,
+ YAFFS_ECC_RESULT_NO_ERROR,
+ YAFFS_ECC_RESULT_FIXED,
+ YAFFS_ECC_RESULT_UNFIXED
+} yaffs_ECCResult;
+
+typedef enum {
+ YAFFS_OBJECT_TYPE_UNKNOWN,
+ YAFFS_OBJECT_TYPE_FILE,
+ YAFFS_OBJECT_TYPE_SYMLINK,
+ YAFFS_OBJECT_TYPE_DIRECTORY,
+ YAFFS_OBJECT_TYPE_HARDLINK,
+ YAFFS_OBJECT_TYPE_SPECIAL
+} yaffs_ObjectType;
+
+
+typedef struct {
+
+ unsigned validMarker0;
+ unsigned chunkUsed; /* Status of the chunk: used or unused */
+ unsigned objectId; /* If 0 then this is not part of an object (unused) */
+ unsigned chunkId; /* If 0 then this is a header, else a data chunk */
+ unsigned byteCount; /* Only valid for data chunks */
+
+ /* The following stuff only has meaning when we read */
+ yaffs_ECCResult eccResult;
+ unsigned blockBad;
+
+ /* YAFFS 1 stuff */
+ unsigned chunkDeleted; /* The chunk is marked deleted */
+ unsigned serialNumber; /* Yaffs1 2-bit serial number */
+
+ /* YAFFS2 stuff */
+ unsigned sequenceNumber; /* The sequence number of this block */
+
+ /* Extra info if this is an object header (YAFFS2 only) */
+
+ unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */
+ unsigned extraParentObjectId; /* The parent object */
+ unsigned extraIsShrinkHeader; /* Is it a shrink header? */
+ unsigned extraShadows; /* Does this shadow another object? */
+
+ yaffs_ObjectType extraObjectType; /* What object type? */
+
+ unsigned extraFileLength; /* Length if it is a file */
+ unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */
+
+ unsigned validMarker1;
+
+} yaffs_ExtendedTags;
+
+/* -------------------------- Object structure -------------------------------*/
+/* This is the object structure as stored on NAND */
+
+typedef struct {
+ yaffs_ObjectType type;
+
+ /* Apply to everything */
+ int parentObjectId;
+ __u16 sum__NoLongerUsed; /* checksum of name. No longer used */
+ char name[YAFFS_MAX_NAME_LENGTH + 1];
+
+ /* The following apply to directories, files, symlinks - not hard links */
+ __u32 yst_mode; /* protection */
+
+#ifdef CONFIG_YAFFS_WINCE
+ __u32 notForWinCE[5];
+#else
+ __u32 yst_uid;
+ __u32 yst_gid;
+ __u32 yst_atime;
+ __u32 yst_mtime;
+ __u32 yst_ctime;
+#endif
+
+ /* File size applies to files only */
+ int fileSize;
+
+ /* Equivalent object id applies to hard links only. */
+ int equivalentObjectId;
+
+ /* Alias is for symlinks only. */
+ char alias[YAFFS_MAX_ALIAS_LENGTH + 1];
+
+ __u32 yst_rdev; /* device stuff for block and char devices (major/min) */
+
+#ifdef CONFIG_YAFFS_WINCE
+ __u32 win_ctime[2];
+ __u32 win_atime[2];
+ __u32 win_mtime[2];
+#else
+ __u32 roomToGrow[6];
+
+#endif
+ __u32 inbandShadowsObject;
+ __u32 inbandIsShrink;
+
+ __u32 reservedSpace[2];
+ int shadowsObject; /* This object header shadows the specified object if > 0 */
+
+ /* isShrink applies to object headers written when we shrink the file (ie resize) */
+ __u32 isShrink;
+
+} yaffs_ObjectHeader;
+
+#endif
diff --git a/res/nandroid-mobile.sh b/res/nandroid-mobile.sh
deleted file mode 100755
index 9a9a824..0000000
--- a/res/nandroid-mobile.sh
+++ /dev/null
@@ -1,293 +0,0 @@
-#!/sbin/sh
-
-# nandroid v2.1 - an Android backup tool for the G1 by infernix and brainaid
-
-# Requirements:
-
-# - a modded android in recovery mode (JF 1.3 will work by default)
-# - adb shell as root in recovery mode if not using a pre-made recovery image
-# - busybox in recovery mode
-# - dump_image-arm-uclibc compiled and in path on phone
-# - mkyaffs2image-arm-uclibc compiled and installed in path on phone
-
-# Reference data:
-
-# dev: size erasesize name
-#mtd0: 00040000 00020000 "misc"
-#mtd1: 00500000 00020000 "recovery"
-#mtd2: 00280000 00020000 "boot"
-#mtd3: 04380000 00020000 "system"
-#mtd4: 04380000 00020000 "cache"
-#mtd5: 04ac0000 00020000 "userdata"
-#mtd6 is everything, dump splash1 with: dd if=/dev/mtd/mtd6ro of=/sdcard/splash1.img skip=19072 bs=2048 count=150
-
-# We don't dump misc or cache because they do not contain any useful data that we are aware of at this time.
-
-# Logical steps (v2.1):
-#
-# 0. test for a target dir and the various tools needed, if not found then exit with error.
-# 1. check "adb devices" for a device in recovery mode. set DEVICEID variable to the device ID. abort when not found.
-# 2. mount system and data partitions read-only, set up adb portforward and create destdir
-# 3. check free space on /cache, exit if less blocks than 20MB free
-# 4. push required tools to device in /cache
-# 5 for partitions boot recovery misc:
-# 5a get md5sum for content of current partition *on the device* (no data transfered)
-# 5b while MD5sum comparison is incorrect (always is the first time):
-# 5b1 dump current partition to a netcat session
-# 5b2 start local netcat to dump image to current dir
-# 5b3 compare md5sums of dumped data with dump in current dir. if correct, contine, else restart the loop (6b1)
-# 6 for partitions system data:
-# 6a get md5sum for tar of content of current partition *on the device* (no data transfered)
-# 6b while MD5sum comparison is incorrect (always is the first time):
-# 6b1 tar current partition to a netcat session
-# 6b2 start local netcat to dump tar to current dir
-# 6b3 compare md5sums of dumped data with dump in current dir. if correct, contine, else restart the loop (6b1)
-# 6c if i'm running as root:
-# 6c1 create a temp dir using either tempdir command or the deviceid in /tmp
-# 6c2 extract tar to tempdir
-# 6c3 invoke mkyaffs2image to create the img
-# 6c4 clean up
-# 7. remove tools from device /cache
-# 8. umount system and data on device
-# 9. print success.
-
-
-DEVICEID=foo
-RECOVERY=foo
-
-echo "nandroid-mobile v2.1"
-
-
-if [ "$1" == "" ]; then
- echo "Usage: $0 {backup|restore} [/path/to/nandroid/backup/]"
- echo "- backup will store a full system backup on /sdcard/nandroid/$DEVICEID"
- echo "- restore path will restore the last made backup for boot, system, recovery and data"
- exit 0
-fi
-
-case $1 in
- backup)
- mkyaffs2image=`which mkyaffs2image`
- if [ "$mkyaffs2image" == "" ]; then
- mkyaffs2image=`which mkyaffs2image-arm-uclibc`
- if [ "$mkyaffs2image" == "" ]; then
- echo "error: mkyaffs2image or mkyaffs2image-arm-uclibc not found in path"
- exit 1
- fi
- fi
- dump_image=`which dump_image`
- if [ "$dump_image" == "" ]; then
- dump_image=`which dump_image-arm-uclibc`
- if [ "$dump_image" == "" ]; then
- echo "error: dump_image or dump_image-arm-uclibc not found in path"
- exit 1
- fi
- fi
- break
- ;;
- restore)
- flash_image=`which flash_image`
- if [ "$flash_image" == "" ]; then
- flash_image=`which flash_image-arm-uclibc`
- if [ "$flash_image" == "" ]; then
- echo "error: flash_image or flash_image-arm-uclibc not found in path"
- exit 1
- fi
- fi
- break
- ;;
-esac
-
-# 1
-DEVICEID=`cat /proc/cmdline | sed "s/.*serialno=//" | cut -d" " -f1`
-RECOVERY=`cat /proc/cmdline | grep "androidboot.mode=recovery"`
-if [ "$RECOVERY" == "foo" ]; then
- echo "error: not running in recovery mode, aborting"
- exit 1
-fi
-if [ "$DEVICEID" == "foo" ]; then
- echo "error: device id not found in /proc/cmdline, aborting"
- exit 1
-fi
-if [ ! "`id -u 2>/dev/null`" == "0" ]; then
- if [ "`whoami 2>&1 | grep 'uid 0'`" == "" ]; then
- echo "error: must run as root, aborting"
- exit 1
- fi
-fi
-
-
-case $1 in
- restore)
- ENERGY=`cat /sys/class/power_supply/battery/capacity`
- if [ "`cat /sys/class/power_supply/battery/status`" == "Charging" ]; then
- ENERGY=100
- fi
- if [ ! $ENERGY -ge 30 ]; then
- echo "Error: not enough battery power"
- echo "Connect charger or USB power and try again"
- exit 1
- fi
- RESTOREPATH=$2
- if [ ! -f $RESTOREPATH/nandroid.md5 ]; then
- echo "error: $RESTOREPATH/nandroid.md5 not found, cannot verify backup data"
- exit 1
- fi
- umount /system 2>/dev/null
- umount /data 2>/dev/null
- if [ ! "`mount | grep data`" == "" ]; then
- echo "error: unable to umount /data, aborting"
- exit 1
- fi
- if [ ! "`mount | grep system`" == "" ]; then
- echo "error: unable to umount /system, aborting"
- exit 1
- fi
-
- echo "Verifying backup images..."
- CWD=$PWD
- cd $RESTOREPATH
- md5sum -c nandroid.md5
- if [ $? -eq 1 ]; then
- echo "error: md5sum mismatch, aborting"
- exit 1
- fi
- for image in boot recovery; do
- echo "Flashing $image..."
- $flash_image $image $image.img
- done
- echo "Flashing system and data not currently supported"
- echo "Restore done"
- exit 0
- ;;
- backup)
- break
- ;;
- *)
- echo "Usage: $0 {backup|restore} [/path/to/nandroid/backup/]"
- echo "- backup will store a full system backup on /sdcard/nandroid/$DEVICEID"
- echo "- restore path will restore the last made backup for boot, system, recovery and data"
- exit 1
- ;;
-esac
-
-# 2.
-echo "mounting system and data read-only, sdcard read-write"
-umount /system 2>/dev/null
-umount /data 2>/dev/null
-umount /sdcard 2>/dev/null
-mount -o ro /system || FAIL=1
-mount -o ro /data || FAIL=2
-mount /sdcard || mount /dev/block/mmcblk0 /sdcard || FAIL=3
-case $FAIL in
- 1) echo "Error mounting system read-only"; umount /system /data /sdcard; exit 1;;
- 2) echo "Error mounting data read-only"; umount /system /data /sdcard; exit 1;;
- 3) echo "Error mounting sdcard read-write"; umount /system /data /sdcard; exit 1;;
-esac
-
-TIMESTAMP="`date +%Y%m%d-%H%M`"
-DESTDIR="/sdcard/nandroid/$DEVICEID/$TIMESTAMP"
-if [ ! -d $DESTDIR ]; then
- mkdir -p $DESTDIR
- if [ ! -d $DESTDIR ]; then
- echo "error: cannot create $DESTDIR"
- umount /system 2>/dev/null
- umount /data 2>/dev/null
- umount /sdcard 2>/dev/null
- exit 1
- fi
-else
- touch $DESTDIR/.nandroidwritable
- if [ ! -e $DESTDIR/.nandroidwritable ]; then
- echo "error: cannot write to $DESTDIR"
- umount /system 2>/dev/null
- umount /data 2>/dev/null
- umount /sdcard 2>/dev/null
- exit 1
- fi
- rm $DESTDIR/.nandroidwritable
-fi
-
-# 3.
-echo "checking free space on sdcard"
-FREEBLOCKS="`df -k /sdcard| grep sdcard | awk '{ print $4 }'`"
-# we need about 130MB for the dump
-if [ $FREEBLOCKS -le 130000 ]; then
- echo "error: not enough free space available on sdcard (need 130mb), aborting."
- umount /system 2>/dev/null
- umount /data 2>/dev/null
- umount /sdcard 2>/dev/null
- exit 1
-fi
-
-
-
-if [ -e /dev/mtd/mtd6ro ]; then
- echo -n "Dumping splash1 from device over tcp to $DESTDIR/splash1.img..."
- dd if=/dev/mtd/mtd6ro of=$DESTDIR/splash1.img skip=19072 bs=2048 count=150 2>/dev/null
- echo "done"
- sleep 1s
- echo -n "Dumping splash2 from device over tcp to $DESTDIR/splash2.img..."
- dd if=/dev/mtd/mtd6ro of=$DESTDIR/splash2.img skip=19456 bs=2048 count=150 2>/dev/null
- echo "done"
-fi
-
-
-# 5.
-for image in boot recovery misc; do
- # 5a
- DEVICEMD5=`$dump_image $image - | md5sum | awk '{ print $1 }'`
- sleep 1s
- MD5RESULT=1
- # 5b
- echo -n "Dumping $image to $DESTDIR/$image.img..."
- ATTEMPT=0
- while [ $MD5RESULT -eq 1 ]; do
- let ATTEMPT=$ATTEMPT+1
- # 5b1
- $dump_image $image $DESTDIR/$image.img
- sync
- # 5b3
- echo "${DEVICEMD5} $DESTDIR/$image.img" | md5sum -c -s -
- if [ $? -eq 1 ]; then
- true
- else
- MD5RESULT=0
- fi
- if [ "$ATTEMPT" == "5" ]; then
- echo "fatal error while trying to dump $image, aborting"
- umount /system
- umount /data
- umount /sdcard
- exit 1
- fi
- done
- echo "done"
-done
-
-# 6
-for image in system data cache; do
- # 6a
- echo -n "Dumping $image to $DESTDIR/$image.img..."
- $mkyaffs2image /$image $DESTDIR/$image.img
- sync
- echo "done"
-done
-
-
-# 7.
-echo -n "generating md5sum file..."
-CWD=$PWD
-cd $DESTDIR
-md5sum *img > nandroid.md5
-cd $CWD
-echo "done"
-
-# 8.
-echo "unmounting system, data and sdcard"
-umount /system
-umount /data
-umount /sdcard
-
-# 9.
-echo "Backup successful."