vold2: Get mounting/unmounting/formatting/sharing working

Signed-off-by: San Mehat <san@google.com>
diff --git a/DirectVolume.cpp b/DirectVolume.cpp
index cd12cf4..1fda955 100644
--- a/DirectVolume.cpp
+++ b/DirectVolume.cpp
@@ -19,20 +19,33 @@
 #include <string.h>
 #include <errno.h>
 
-#define LOG_TAG "Vold"
+#include <linux/kdev_t.h>
+
+#define LOG_TAG "DirectVolume"
 
 #include <cutils/log.h>
 #include <sysutils/NetlinkEvent.h>
 
 #include "DirectVolume.h"
+#include "VolumeManager.h"
+#include "ResponseCode.h"
 
-DirectVolume::DirectVolume(const char *label, const char *mount_point, int partIdx) :
-              Volume(label, mount_point) {
+// #define PARTITION_DEBUG
+
+DirectVolume::DirectVolume(VolumeManager *vm, const char *label,
+                           const char *mount_point, int partIdx) :
+              Volume(vm, label, mount_point) {
     mPartIdx = partIdx;
-  
+
     mPaths = new PathCollection();
     for (int i = 0; i < MAX_PARTITIONS; i++)
         mPartMinors[i] = -1;
+    mPendingPartMap = 0;
+    mDiskMajor = -1;
+    mDiskMinor = -1;
+    mDiskNumParts = 0;
+
+    setState(Volume::State_NoMedia);
 }
 
 DirectVolume::~DirectVolume() {
@@ -48,6 +61,18 @@
     return 0;
 }
 
+dev_t DirectVolume::getDiskDevice() {
+    return MKDEV(mDiskMajor, mDiskMinor);
+}
+
+void DirectVolume::handleVolumeShared() {
+    setState(Volume::State_Shared);
+}
+
+void DirectVolume::handleVolumeUnshared() {
+    setState(Volume::State_Idle);
+}
+
 int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
     const char *dp = evt->findParam("DEVPATH");
 
@@ -58,20 +83,37 @@
             int action = evt->getAction();
             const char *devtype = evt->findParam("DEVTYPE");
 
-            if (!strcmp(devtype, "disk")) {
-                if (action == NetlinkEvent::NlActionAdd)
+            if (action == NetlinkEvent::NlActionAdd) {
+                int major = atoi(evt->findParam("MAJOR"));
+                int minor = atoi(evt->findParam("MINOR"));
+                char nodepath[255];
+
+                snprintf(nodepath,
+                         sizeof(nodepath), "/dev/block/vold/%d:%d",
+                         major, minor);
+                if (createDeviceNode(nodepath, major, minor)) {
+                    LOGE("Error making device node '%s' (%s)", nodepath,
+                                                               strerror(errno));
+                }
+                if (!strcmp(devtype, "disk")) {
                     handleDiskAdded(dp, evt);
-                else if (action == NetlinkEvent::NlActionRemove)
-                    handleDiskRemoved(dp, evt);
-                else
-                    LOGD("Ignoring non add/remove event");
-            } else {
-                if (action == NetlinkEvent::NlActionAdd)
+                } else {
                     handlePartitionAdded(dp, evt);
-                else if (action == NetlinkEvent::NlActionRemove)
+                }
+            } else if (action == NetlinkEvent::NlActionRemove) {
+                if (!strcmp(devtype, "disk")) {
+                    handleDiskRemoved(dp, evt);
+                } else {
                     handlePartitionRemoved(dp, evt);
-                else
-                    LOGD("Ignoring non add/remove event");
+                }
+            } else if (action == NetlinkEvent::NlActionChange) {
+                if (!strcmp(devtype, "disk")) {
+                    handleDiskChanged(dp, evt);
+                } else {
+                    handlePartitionChanged(dp, evt);
+                }
+            } else {
+                    LOGW("Ignoring non add/remove/change event");
             }
 
             return 0;
@@ -83,8 +125,9 @@
 
 void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {
     mDiskMajor = atoi(evt->findParam("MAJOR"));
-    mDiskMinor = atoi(evt->findParam("MAJOR"));
+    mDiskMinor = atoi(evt->findParam("MINOR"));
     mDiskNumParts = atoi(evt->findParam("NPARTS"));
+    char msg[255];
 
     int partmask = 0;
     int i;
@@ -94,13 +137,22 @@
     mPendingPartMap = partmask;
 
     if (mDiskNumParts == 0) {
+#ifdef PARTITION_DEBUG
         LOGD("Dv::diskIns - No partitions - good to go son!");
+#endif
         setState(Volume::State_Idle);
     } else {
+#ifdef PARTITION_DEBUG
         LOGD("Dv::diskIns - waiting for %d partitions (mask 0x%x)",
              mDiskNumParts, mPendingPartMap);
+#endif
         setState(Volume::State_Pending);
     }
+
+    snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",
+             getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
+    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
+                                             msg, false);
 }
 
 void DirectVolume::handlePartitionAdded(const char *devpath, NetlinkEvent *evt) {
@@ -112,54 +164,122 @@
         LOGE("Partition '%s' has a different major than its disk!", devpath);
         return;
     }
+#ifdef PARTITION_DEBUG
+    LOGD("Dv:partAdd: part_num = %d, minor = %d\n", part_num, minor);
+#endif
     mPartMinors[part_num -1] = minor;
 
     mPendingPartMap &= ~(1 << part_num);
     if (!mPendingPartMap) {
+#ifdef PARTITION_DEBUG
         LOGD("Dv:partAdd: Got all partitions - ready to rock!");
+#endif
         setState(Volume::State_Idle);
     } else {
+#ifdef PARTITION_DEBUG
         LOGD("Dv:partAdd: pending mask now = 0x%x", mPendingPartMap);
+#endif
     }
 }
 
+void DirectVolume::handleDiskChanged(const char *devpath, NetlinkEvent *evt) {
+    int major = atoi(evt->findParam("MAJOR"));
+    int minor = atoi(evt->findParam("MINOR"));
+
+    if ((major != mDiskMajor) || (minor != mDiskMinor)) {
+        return;
+    }
+
+    LOGI("Volume %s disk has changed", getLabel());
+    mDiskNumParts = atoi(evt->findParam("NPARTS"));
+    int partmask = 0;
+    int i;
+    for (i = 1; i <= mDiskNumParts; i++) {
+        partmask |= (1 << i);
+    }
+    mPendingPartMap = partmask;
+
+    if (mDiskNumParts == 0) {
+        setState(Volume::State_Idle);
+    } else {
+        setState(Volume::State_Pending);
+    }
+
+}
+
+void DirectVolume::handlePartitionChanged(const char *devpath, NetlinkEvent *evt) {
+}
+
 void DirectVolume::handleDiskRemoved(const char *devpath, NetlinkEvent *evt) {
+    int major = atoi(evt->findParam("MAJOR"));
+    int minor = atoi(evt->findParam("MINOR"));
+    char msg[255];
+
+    LOGD("Volume %s %s disk %d:%d removed\n", getLabel(), getMountpoint(), major, minor);
+    snprintf(msg, sizeof(msg), "Volume %s %s disk removed (%d:%d)",
+             getLabel(), getMountpoint(), major, minor);
+    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskRemoved,
+                                             msg, false);
+    setState(Volume::State_NoMedia);
 }
 
 void DirectVolume::handlePartitionRemoved(const char *devpath, NetlinkEvent *evt) {
+    int major = atoi(evt->findParam("MAJOR"));
+    int minor = atoi(evt->findParam("MINOR"));
+    int part_num = atoi(evt->findParam("PARTN"));
+    char msg[255];
+
+    LOGD("Volume %s %s partition %d:%d removed\n", getLabel(), getMountpoint(), major, minor);
+
+    /*
+     * The framework doesn't need to get notified of
+     * partition removal unless it's mounted. Otherwise
+     * the removal notification will be sent on the Disk
+     * itself
+     */
+    if (getState() != Volume::State_Mounted) {
+        return;
+    }
+        
+    if ((dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev) {
+        /*
+         * Yikes, our mounted partition is going away!
+         */
+
+        snprintf(msg, sizeof(msg), "Volume %s %s bad removal (%d:%d)",
+                 getLabel(), getMountpoint(), major, minor);
+        mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval,
+                                             msg, false);
+        if (Volume::unmountVol()) {
+            LOGE("Failed to unmount volume on bad removal (%s)", 
+                 strerror(errno));
+            // XXX: At this point we're screwed for now
+        } else {
+            LOGD("Crisis averted");
+        }
+    }
 }
 
 /*
- * Called from Volume to determine the major/minor numbers
- * to be used for mounting
+ * Called from base to get a list of devicenodes for mounting
  */
-int DirectVolume::prepareToMount(int *major, int *minor) {
-    *major = mDiskMajor;
+int DirectVolume::getDeviceNodes(dev_t *devs, int max) {
 
     if (mPartIdx == -1) {
-        /* No specific partition specified */
-
+        // If the disk has no partitions, try the disk itself
         if (!mDiskNumParts) {
-            *minor = mDiskMinor;
-            return 0;
+            devs[0] = MKDEV(mDiskMajor, mDiskMinor);
+            return 1;
         }
 
-        /* 
-         * XXX: Use first partition for now.
-         * The right thing to do would be to choose
-         * this based on the partition type.
-         *
-         */
-  
-        *minor = mPartMinors[0];
-        return 0;
+        int i;
+        for (i = 0; i < mDiskNumParts; i++) {
+            if (i == max)
+                break;
+            devs[i] = MKDEV(mDiskMajor, mPartMinors[i]);
+        }
+        return mDiskNumParts;
     }
-
-    if (mPartIdx - 1 > mDiskNumParts) {
-        errno = EINVAL;
-        return -1;
-    }
-
-    *minor = mPartMinors[mPartIdx-1];
-    return 0;
+    devs[0] = MKDEV(mDiskMajor, mPartMinors[mPartIdx -1]);
+    return 1;
 }