am 5ebced39: init.rc: update the permission of /data/local.

* commit '5ebced39093d1223566166b8cc6abfe6729c487d':
  init.rc: update the permission of /data/local.
diff --git a/adb/adb.c b/adb/adb.c
index e35c334..e7a28d2 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -940,24 +940,29 @@
         }
     }
 
-        /* for the device, start the usb transport if the
-        ** android usb device exists and the "service.adb.tcp.port" and
-        ** "persist.adb.tcp.port" properties are not set.
-        ** Otherwise start the network transport.
-        */
-    property_get("service.adb.tcp.port", value, "");
-    if (!value[0])
-        property_get("persist.adb.tcp.port", value, "");
-    if (sscanf(value, "%d", &port) == 1 && port > 0) {
-        // listen on TCP port specified by service.adb.tcp.port property
-        local_init(port);
-    } else if (access("/dev/android_adb", F_OK) == 0) {
+    int usb = 0;
+    if (access("/dev/android_adb", F_OK) == 0) {
         // listen on USB
         usb_init();
-    } else {
+        usb = 1;
+    }
+
+    // If one of these properties is set, also listen on that port
+    // If one of the properties isn't set and we couldn't listen on usb,
+    // listen on the default port.
+    property_get("service.adb.tcp.port", value, "");
+    if (!value[0]) {
+        property_get("persist.adb.tcp.port", value, "");
+    }
+    if (sscanf(value, "%d", &port) == 1 && port > 0) {
+        printf("using port=%d\n", port);
+        // listen on TCP port specified by service.adb.tcp.port property
+        local_init(port);
+    } else if (!usb) {
         // listen on default port
         local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
     }
+
     D("adb_main(): pre init_jdwp()\n");
     init_jdwp();
     D("adb_main(): post init_jdwp()\n");
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 3c5538f..8c130ff 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -16,8 +16,9 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg
-LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c 
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
+  $(LOCAL_PATH)/../../extras/ext4_utils
+LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c
 LOCAL_MODULE := fastboot
 
 ifeq ($(HOST_OS),linux)
@@ -47,7 +48,7 @@
   LOCAL_C_INCLUDES += development/host/windows/usb/api
 endif
 
-LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz
+LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz libext4_utils libz
 
 include $(BUILD_HOST_EXECUTABLE)
 $(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE))
diff --git a/fastboot/engine.c b/fastboot/engine.c
index 6d94035..345577d 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -26,13 +26,24 @@
  * SUCH DAMAGE.
  */
 
+#include "fastboot.h"
+#include "make_ext4fs.h"
+#include "ext4_utils.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <stdbool.h>
 #include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
 
-#include "fastboot.h"
+extern struct fs_info info;
+
+#define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
 
 double now()
 {
@@ -60,15 +71,18 @@
 #define OP_COMMAND    2
 #define OP_QUERY      3
 #define OP_NOTICE     4
+#define OP_FORMAT     5
 
 typedef struct Action Action;
 
+#define CMD_SIZE 64
+
 struct Action 
 {
     unsigned op;
     Action *next;
 
-    char cmd[64];    
+    char cmd[CMD_SIZE];
     const char *prod;
     void *data;
     unsigned size;
@@ -82,6 +96,35 @@
 static Action *action_list = 0;
 static Action *action_last = 0;
 
+
+struct image_data {
+    long long partition_size;
+    long long image_size; // real size of image file
+    void *buffer;
+};
+
+void generate_ext4_image(struct image_data *image);
+void munmap_image(struct image_data *image);
+
+struct generator {
+    char *fs_type;
+
+    /* generate image and return it as image->buffer.
+     * size of the buffer returned as image->image_size.
+     *
+     * image->partition_size specifies what is the size of the
+     * file partition we generate image for.
+     */
+    void (*generate)(struct image_data *image);
+
+    /* it cleans the buffer allocated during image creation.
+     * this function probably does free() or munmap().
+     */
+    void (*cleanup)(struct image_data *image);
+} generators[] = {
+    { "ext4", generate_ext4_image, munmap_image }
+};
+
 static int cb_default(Action *a, int status, char *resp)
 {
     if (status) {
@@ -133,6 +176,127 @@
     a->msg = mkmsg("erasing '%s'", ptn);
 }
 
+void munmap_image(struct image_data *image)
+{
+    munmap(image->buffer, image->image_size);
+}
+
+void generate_ext4_image(struct image_data *image)
+{
+    int fd;
+    struct stat st;
+
+    fd = fileno(tmpfile());
+    /* reset ext4fs info so we can be called multiple times */
+    reset_ext4fs_info();
+    info.len = image->partition_size;
+    make_ext4fs_internal(fd, NULL, NULL, 0, 0, 1, 0, 0, 0);
+
+    fstat(fd, &st);
+    image->image_size = st.st_size;
+
+    image->buffer = mmap(NULL, image->image_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (image->buffer == MAP_FAILED) {
+        perror("mmap");
+        image->buffer = NULL;
+    }
+
+    close(fd);
+}
+
+int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported)
+{
+    const char *partition = a->cmd;
+    char query[256];
+    char response[FB_RESPONSE_SZ+1];
+    int status = 0;
+    struct image_data image;
+    struct generator *generator = NULL;
+    int fd;
+    unsigned i;
+    char cmd[CMD_SIZE];
+
+    response[FB_RESPONSE_SZ] = '\0';
+    snprintf(query, sizeof(query), "getvar:partition-type:%s", partition);
+    status = fb_command_response(usb, query, response);
+    if (status) {
+        if (skip_if_not_supported) {
+            fprintf(stderr,
+                    "Erase successful, but not automatically formatting.\n");
+            fprintf(stderr,
+                    "Can't determine partition type.\n");
+            return 0;
+        }
+        fprintf(stderr,"FAILED (%s)\n", fb_get_error());
+        return status;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(generators); i++) {
+        if (!strncmp(generators[i].fs_type, response, FB_RESPONSE_SZ)) {
+            generator = &generators[i];
+            break;
+        }
+    }
+    if (!generator) {
+        if (skip_if_not_supported) {
+            fprintf(stderr,
+                    "Erase successful, but not automatically formatting.\n");
+            fprintf(stderr,
+                    "File system type %s not supported.\n", response);
+            return 0;
+        }
+        fprintf(stderr,"Formatting is not supported for filesystem with type '%s'.\n",
+                response);
+        return -1;
+    }
+
+    response[FB_RESPONSE_SZ] = '\0';
+    snprintf(query, sizeof(query), "getvar:partition-size:%s", partition);
+    status = fb_command_response(usb, query, response);
+    if (status) {
+        if (skip_if_not_supported) {
+            fprintf(stderr,
+                    "Erase successful, but not automatically formatting.\n");
+            fprintf(stderr, "Unable to get partition size\n.");
+            return 0;
+        }
+        fprintf(stderr,"FAILED (%s)\n", fb_get_error());
+        return status;
+    }
+    image.partition_size = strtoll(response, (char **)NULL, 16);
+
+    generator->generate(&image);
+    if (!image.buffer) {
+        fprintf(stderr,"Cannot generate image.\n");
+        return -1;
+    }
+
+    // Following piece of code is similar to fb_queue_flash() but executes
+    // actions directly without queuing
+    fprintf(stderr, "sending '%s' (%lli KB)...\n", partition, image.image_size/1024);
+    status = fb_download_data(usb, image.buffer, image.image_size);
+    if (status) goto cleanup;
+
+    fprintf(stderr, "writing '%s'...\n", partition);
+    snprintf(cmd, CMD_SIZE, "flash:%s", partition);
+    status = fb_command(usb, cmd);
+    if (status) goto cleanup;
+
+cleanup:
+    generator->cleanup(&image);
+
+    return status;
+}
+
+void fb_queue_format(const char *partition, int skip_if_not_supported)
+{
+    Action *a;
+
+    a = queue_action(OP_FORMAT, partition);
+    a->data = (void*)skip_if_not_supported;
+    a->msg = mkmsg("formatting '%s' partition", partition);
+}
+
 void fb_queue_flash(const char *ptn, void *data, unsigned sz)
 {
     Action *a;
@@ -340,6 +504,10 @@
             if (status) break;
         } else if (a->op == OP_NOTICE) {
             fprintf(stderr,"%s\n",(char*)a->data);
+        } else if (a->op == OP_FORMAT) {
+            status = fb_format(a, usb, (int)a->data);
+            status = a->func(a, status, status ? fb_get_error() : "");
+            if (status) break;
         } else {
             die("bogus action");
         }
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index a069d33..805014f 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -222,6 +222,7 @@
             "  flashall                                 flash boot + recovery + system\n"
             "  flash <partition> [ <filename> ]         write a file to a flash partition\n"
             "  erase <partition>                        erase a flash partition\n"
+            "  format <partition>                       format a flash partition \n"
             "  getvar <variable>                        display a bootloader variable\n"
             "  boot <kernel> [ <ramdisk> ]              download and boot kernel\n"
             "  flash:raw boot <kernel> [ <ramdisk> ]    create bootimage and flash it\n"
@@ -633,6 +634,10 @@
             require(2);
             fb_queue_erase(argv[1]);
             skip(2);
+        } else if(!strcmp(*argv, "format")) {
+            require(2);
+            fb_queue_format(argv[1], 0);
+            skip(2);
         } else if(!strcmp(*argv, "signature")) {
             require(2);
             data = load_file(argv[1], &sz);
@@ -718,7 +723,9 @@
 
     if (wants_wipe) {
         fb_queue_erase("userdata");
+        fb_queue_format("userdata", 1);
         fb_queue_erase("cache");
+        fb_queue_format("cache", 1);
     }
     if (wants_reboot) {
         fb_queue_reboot();
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 9e043fe..b77cb19 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -43,6 +43,7 @@
 /* engine.c - high level command queue engine */
 void fb_queue_flash(const char *ptn, void *data, unsigned sz);;
 void fb_queue_erase(const char *ptn);
+void fb_queue_format(const char *ptn, int skip_if_not_supported);
 void fb_queue_require(const char *prod, const char *var, int invert,
         unsigned nvalues, const char **value);
 void fb_queue_display(const char *var, const char *prettyname);
diff --git a/init/init.c b/init/init.c
index 165fea0..68e9f49 100755
--- a/init/init.c
+++ b/init/init.c
@@ -59,13 +59,12 @@
 #endif
 
 static char console[32];
-static char serialno[32];
-static char bootmode[32];
-static char baseband[32];
-static char carrier[32];
-static char bootloader[32];
-static char hardware[32];
-static char modelno[32];
+static char serialno[PROP_VALUE_MAX];
+static char bootmode[PROP_VALUE_MAX];
+static char baseband[PROP_VALUE_MAX];
+static char carrier[PROP_VALUE_MAX];
+static char bootloader[PROP_VALUE_MAX];
+static char hardware[PROP_VALUE_MAX];
 static unsigned revision = 0;
 static char qemu[32];
 
@@ -448,8 +447,6 @@
             strlcpy(bootloader, value, sizeof(bootloader));
         } else if (!strcmp(name,"androidboot.hardware")) {
             strlcpy(hardware, value, sizeof(hardware));
-        } else if (!strcmp(name,"androidboot.modelno")) {
-            strlcpy(modelno, value, sizeof(modelno));
         }
     } else {
         /* in the emulator, export any kernel option with the
@@ -599,9 +596,6 @@
     property_set("ro.carrier", carrier[0] ? carrier : "unknown");
     property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown");
 
-    if (modelno[0])
-        property_set("ro.boot.modelno", modelno);
-
     property_set("ro.hardware", hardware);
     snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
     property_set("ro.revision", tmp);
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 0510696..a9541e7 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -163,6 +163,8 @@
     mkdir /data/app-private 0771 system system
     mkdir /data/app 0771 system system
     mkdir /data/property 0700 root root
+    mkdir /data/ssh 0750 root shell
+    mkdir /data/ssh/empty 0700 root root
 
     # create dalvik-cache, so as to enforce our permissions
     mkdir /data/dalvik-cache 0771 system system
@@ -486,3 +488,6 @@
     socket dumpstate stream 0660 shell log
     disabled
     oneshot
+
+service sshd /system/bin/start-ssh
+    class main
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index d7a675a..7e20448 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -55,7 +55,8 @@
 	nandread \
 	ionice \
 	touch \
-	lsof
+	lsof \
+	md5
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
 TOOLS += r
@@ -68,6 +69,8 @@
 
 LOCAL_SHARED_LIBRARIES := libcutils libc libusbhost
 
+LOCAL_C_INCLUDES := bionic/libc/bionic
+
 LOCAL_MODULE:= toolbox
 
 # Including this will define $(intermediates).
diff --git a/toolbox/hd.c b/toolbox/hd.c
index da31245..0d2f96a 100644
--- a/toolbox/hd.c
+++ b/toolbox/hd.c
@@ -68,6 +68,8 @@
 			if(count > 0 && base + count - filepos < read_len)
 				read_len = base + count - filepos;
 	        res = read(fd, &buf, read_len);
+			if(res == 0)
+				break;
 			for(i = 0; i < res; i++) {
 				if((i & 15) == 0) {
 					printf("%08x: ", filepos + i);
@@ -80,7 +82,7 @@
 					lsum = 0;
 				}
 			}
-			if(res <= 0) {
+			if(res < 0) {
 				printf("Read error on %s, offset %d len %d, %s\n", argv[optind], filepos, read_len, strerror(errno));
 				return 1;
 			}
diff --git a/toolbox/md5.c b/toolbox/md5.c
new file mode 100644
index 0000000..2fb8b05
--- /dev/null
+++ b/toolbox/md5.c
@@ -0,0 +1,77 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <md5.h>
+
+/* When this was written, bionic's md5.h did not define this. */
+#ifndef MD5_DIGEST_LENGTH
+#define MD5_DIGEST_LENGTH 16
+#endif
+
+static int usage()
+{
+    fprintf(stderr,"md5 file ...\n");
+    return -1;
+}
+
+static int do_md5(const char *path)
+{
+    unsigned int i;
+    int fd;
+    MD5_CTX md5_ctx;
+    unsigned char md5[MD5_DIGEST_LENGTH];
+
+    fd = open(path, O_RDONLY);
+    if (fd < 0) {
+        fprintf(stderr,"could not open %s, %s\n", path, strerror(errno));
+        return -1;
+    }
+
+    /* Note that bionic's MD5_* functions return void. */
+    MD5_Init(&md5_ctx);
+
+    while (1) {
+        char buf[4096];
+        ssize_t rlen;
+        rlen = read(fd, buf, sizeof(buf));
+        if (rlen == 0)
+            break;
+        else if (rlen < 0) {
+            (void)close(fd);
+            fprintf(stderr,"could not read %s, %s\n", path, strerror(errno));
+            return -1;
+        }
+        MD5_Update(&md5_ctx, buf, rlen);
+    }
+    if (close(fd)) {
+        fprintf(stderr,"could not close %s, %s\n", path, strerror(errno));
+        return -1;
+    }
+
+    MD5_Final(md5, &md5_ctx);
+
+    for (i = 0; i < (int)sizeof(md5); i++)
+        printf("%02x", md5[i]);
+    printf("  %s\n", path);
+
+    return 0;
+}
+
+int md5_main(int argc, char *argv[])
+{
+    int i, ret = 0;
+
+    if (argc < 2)
+        return usage();
+
+    /* loop over the file args */
+    for (i = 1; i < argc; i++) {
+        if (do_md5(argv[i]))
+            ret = 1;
+    }
+
+    return ret;
+}