1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <errno.h> 21 22 #include <linux/kdev_t.h> 23 24 #define LOG_TAG "DirectVolume" 25 26 #include <cutils/log.h> 27 #include <sysutils/NetlinkEvent.h> 28 29 #include "DirectVolume.h" 30 #include "VolumeManager.h" 31 #include "ResponseCode.h" 32 #include "cryptfs.h" 33 34 // #define PARTITION_DEBUG 35 36 DirectVolume::DirectVolume(VolumeManager *vm, const char *label, 37 const char *mount_point, int partIdx) : 38 Volume(vm, label, mount_point) { 39 mPartIdx = partIdx; 40 41 mPaths = new PathCollection(); 42 for (int i = 0; i < MAX_PARTITIONS; i++) 43 mPartMinors[i] = -1; 44 mPendingPartMap = 0; 45 mDiskMajor = -1; 46 mDiskMinor = -1; 47 mDiskNumParts = 0; 48 49 setState(Volume::State_NoMedia); 50 } 51 52 DirectVolume::~DirectVolume() { 53 PathCollection::iterator it; 54 55 for (it = mPaths->begin(); it != mPaths->end(); ++it) 56 free(*it); 57 delete mPaths; 58 } 59 60 int DirectVolume::addPath(const char *path) { 61 mPaths->push_back(strdup(path)); 62 return 0; 63 } 64 65 void DirectVolume::setFlags(int flags) { 66 mFlags = flags; 67 } 68 69 dev_t DirectVolume::getDiskDevice() { 70 return MKDEV(mDiskMajor, mDiskMinor); 71 } 72 73 dev_t DirectVolume::getShareDevice() { 74 if (mPartIdx != -1) { 75 return MKDEV(mDiskMajor, mPartIdx); 76 } else { 77 return MKDEV(mDiskMajor, mDiskMinor); 78 } 79 } 80 81 void DirectVolume::handleVolumeShared() { 82 setState(Volume::State_Shared); 83 } 84 85 void DirectVolume::handleVolumeUnshared() { 86 setState(Volume::State_Idle); 87 } 88 89 int DirectVolume::handleBlockEvent(NetlinkEvent *evt) { 90 const char *dp = evt->findParam("DEVPATH"); 91 92 PathCollection::iterator it; 93 for (it = mPaths->begin(); it != mPaths->end(); ++it) { 94 if (!strncmp(dp, *it, strlen(*it))) { 95 /* We can handle this disk */ 96 int action = evt->getAction(); 97 const char *devtype = evt->findParam("DEVTYPE"); 98 99 if (action == NetlinkEvent::NlActionAdd) { 100 int major = atoi(evt->findParam("MAJOR")); 101 int minor = atoi(evt->findParam("MINOR")); 102 char nodepath[255]; 103 104 snprintf(nodepath, 105 sizeof(nodepath), "/dev/block/vold/%d:%d", 106 major, minor); 107 if (createDeviceNode(nodepath, major, minor)) { 108 SLOGE("Error making device node '%s' (%s)", nodepath, 109 strerror(errno)); 110 } 111 if (!strcmp(devtype, "disk")) { 112 handleDiskAdded(dp, evt); 113 } else { 114 handlePartitionAdded(dp, evt); 115 } 116 } else if (action == NetlinkEvent::NlActionRemove) { 117 if (!strcmp(devtype, "disk")) { 118 handleDiskRemoved(dp, evt); 119 } else { 120 handlePartitionRemoved(dp, evt); 121 } 122 } else if (action == NetlinkEvent::NlActionChange) { 123 if (!strcmp(devtype, "disk")) { 124 handleDiskChanged(dp, evt); 125 } else { 126 handlePartitionChanged(dp, evt); 127 } 128 } else { 129 SLOGW("Ignoring non add/remove/change event"); 130 } 131 132 return 0; 133 } 134 } 135 errno = ENODEV; 136 return -1; 137 } 138 139 void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) { 140 mDiskMajor = atoi(evt->findParam("MAJOR")); 141 mDiskMinor = atoi(evt->findParam("MINOR")); 142 143 const char *tmp = evt->findParam("NPARTS"); 144 if (tmp) { 145 mDiskNumParts = atoi(tmp); 146 } else { 147 SLOGW("Kernel block uevent missing 'NPARTS'"); 148 mDiskNumParts = 1; 149 } 150 151 char msg[255]; 152 153 int partmask = 0; 154 int i; 155 for (i = 1; i <= mDiskNumParts; i++) { 156 partmask |= (1 << i); 157 } 158 mPendingPartMap = partmask; 159 160 if (mDiskNumParts == 0) { 161 #ifdef PARTITION_DEBUG 162 SLOGD("Dv::diskIns - No partitions - good to go son!"); 163 #endif 164 setState(Volume::State_Idle); 165 } else { 166 #ifdef PARTITION_DEBUG 167 SLOGD("Dv::diskIns - waiting for %d partitions (mask 0x%x)", 168 mDiskNumParts, mPendingPartMap); 169 #endif 170 setState(Volume::State_Pending); 171 } 172 173 snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", 174 getLabel(), getMountpoint(), mDiskMajor, mDiskMinor); 175 mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, 176 msg, false); 177 } 178 179 void DirectVolume::handlePartitionAdded(const char *devpath, NetlinkEvent *evt) { 180 int major = atoi(evt->findParam("MAJOR")); 181 int minor = atoi(evt->findParam("MINOR")); 182 183 int part_num; 184 185 const char *tmp = evt->findParam("PARTN"); 186 187 if (tmp) { 188 part_num = atoi(tmp); 189 } else { 190 SLOGW("Kernel block uevent missing 'PARTN'"); 191 part_num = 1; 192 } 193 194 if (part_num > MAX_PARTITIONS || part_num < 1) { 195 SLOGE("Invalid 'PARTN' value"); 196 return; 197 } 198 199 if (part_num > mDiskNumParts) { 200 mDiskNumParts = part_num; 201 } 202 203 if (major != mDiskMajor) { 204 SLOGE("Partition '%s' has a different major than its disk!", devpath); 205 return; 206 } 207 #ifdef PARTITION_DEBUG 208 SLOGD("Dv:partAdd: part_num = %d, minor = %d\n", part_num, minor); 209 #endif 210 if (part_num >= MAX_PARTITIONS) { 211 SLOGE("Dv:partAdd: ignoring part_num = %d (max: %d)\n", part_num, MAX_PARTITIONS-1); 212 } else { 213 mPartMinors[part_num -1] = minor; 214 } 215 mPendingPartMap &= ~(1 << part_num); 216 217 if (!mPendingPartMap) { 218 #ifdef PARTITION_DEBUG 219 SLOGD("Dv:partAdd: Got all partitions - ready to rock!"); 220 #endif 221 if (getState() != Volume::State_Formatting) { 222 setState(Volume::State_Idle); 223 if (mRetryMount == true) { 224 mRetryMount = false; 225 mountVol(); 226 } 227 } 228 } else { 229 #ifdef PARTITION_DEBUG 230 SLOGD("Dv:partAdd: pending mask now = 0x%x", mPendingPartMap); 231 #endif 232 } 233 } 234 235 void DirectVolume::handleDiskChanged(const char *devpath, NetlinkEvent *evt) { 236 int major = atoi(evt->findParam("MAJOR")); 237 int minor = atoi(evt->findParam("MINOR")); 238 239 if ((major != mDiskMajor) || (minor != mDiskMinor)) { 240 return; 241 } 242 243 SLOGI("Volume %s disk has changed", getLabel()); 244 const char *tmp = evt->findParam("NPARTS"); 245 if (tmp) { 246 mDiskNumParts = atoi(tmp); 247 } else { 248 SLOGW("Kernel block uevent missing 'NPARTS'"); 249 mDiskNumParts = 1; 250 } 251 252 int partmask = 0; 253 int i; 254 for (i = 1; i <= mDiskNumParts; i++) { 255 partmask |= (1 << i); 256 } 257 mPendingPartMap = partmask; 258 259 if (getState() != Volume::State_Formatting) { 260 if (mDiskNumParts == 0) { 261 setState(Volume::State_Idle); 262 } else { 263 setState(Volume::State_Pending); 264 } 265 } 266 } 267 268 void DirectVolume::handlePartitionChanged(const char *devpath, NetlinkEvent *evt) { 269 int major = atoi(evt->findParam("MAJOR")); 270 int minor = atoi(evt->findParam("MINOR")); 271 SLOGD("Volume %s %s partition %d:%d changed\n", getLabel(), getMountpoint(), major, minor); 272 } 273 274 void DirectVolume::handleDiskRemoved(const char *devpath, NetlinkEvent *evt) { 275 int major = atoi(evt->findParam("MAJOR")); 276 int minor = atoi(evt->findParam("MINOR")); 277 char msg[255]; 278 279 SLOGD("Volume %s %s disk %d:%d removed\n", getLabel(), getMountpoint(), major, minor); 280 snprintf(msg, sizeof(msg), "Volume %s %s disk removed (%d:%d)", 281 getLabel(), getMountpoint(), major, minor); 282 mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskRemoved, 283 msg, false); 284 setState(Volume::State_NoMedia); 285 } 286 287 void DirectVolume::handlePartitionRemoved(const char *devpath, NetlinkEvent *evt) { 288 int major = atoi(evt->findParam("MAJOR")); 289 int minor = atoi(evt->findParam("MINOR")); 290 char msg[255]; 291 int state; 292 293 SLOGD("Volume %s %s partition %d:%d removed\n", getLabel(), getMountpoint(), major, minor); 294 295 /* 296 * The framework doesn't need to get notified of 297 * partition removal unless it's mounted. Otherwise 298 * the removal notification will be sent on the Disk 299 * itself 300 */ 301 state = getState(); 302 if (state != Volume::State_Mounted && state != Volume::State_Shared) { 303 return; 304 } 305 306 if ((dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev) { 307 /* 308 * Yikes, our mounted partition is going away! 309 */ 310 311 snprintf(msg, sizeof(msg), "Volume %s %s bad removal (%d:%d)", 312 getLabel(), getMountpoint(), major, minor); 313 mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval, 314 msg, false); 315 316 if (mVm->cleanupAsec(this, true)) { 317 SLOGE("Failed to cleanup ASEC - unmount will probably fail!"); 318 } 319 320 if (Volume::unmountVol(true, false)) { 321 SLOGE("Failed to unmount volume on bad removal (%s)", 322 strerror(errno)); 323 // XXX: At this point we're screwed for now 324 } else { 325 SLOGD("Crisis averted"); 326 } 327 } else if (state == Volume::State_Shared) { 328 /* removed during mass storage */ 329 snprintf(msg, sizeof(msg), "Volume %s bad removal (%d:%d)", 330 getLabel(), major, minor); 331 mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval, 332 msg, false); 333 334 if (mVm->unshareVolume(getLabel(), "ums")) { 335 SLOGE("Failed to unshare volume on bad removal (%s)", 336 strerror(errno)); 337 } else { 338 SLOGD("Crisis averted"); 339 } 340 } 341 } 342 343 /* 344 * Called from base to get a list of devicenodes for mounting 345 */ 346 int DirectVolume::getDeviceNodes(dev_t *devs, int max) { 347 348 if (mPartIdx == -1) { 349 // If the disk has no partitions, try the disk itself 350 if (!mDiskNumParts) { 351 devs[0] = MKDEV(mDiskMajor, mDiskMinor); 352 return 1; 353 } 354 355 int i; 356 for (i = 0; i < mDiskNumParts; i++) { 357 if (i == max) 358 break; 359 devs[i] = MKDEV(mDiskMajor, mPartMinors[i]); 360 } 361 return mDiskNumParts; 362 } 363 devs[0] = MKDEV(mDiskMajor, mPartMinors[mPartIdx -1]); 364 return 1; 365 } 366 367 /* 368 * Called from base to update device info, 369 * e.g. When setting up an dm-crypt mapping for the sd card. 370 */ 371 int DirectVolume::updateDeviceInfo(char *new_path, int new_major, int new_minor) 372 { 373 PathCollection::iterator it; 374 375 if (mPartIdx == -1) { 376 SLOGE("Can only change device info on a partition\n"); 377 return -1; 378 } 379 380 /* 381 * This is to change the sysfs path associated with a partition, in particular, 382 * for an internal SD card partition that is encrypted. Thus, the list is 383 * expected to be only 1 entry long. Check that and bail if not. 384 */ 385 if (mPaths->size() != 1) { 386 SLOGE("Cannot change path if there are more than one for a volume\n"); 387 return -1; 388 } 389 390 it = mPaths->begin(); 391 free(*it); /* Free the string storage */ 392 mPaths->erase(it); /* Remove it from the list */ 393 addPath(new_path); /* Put the new path on the list */ 394 395 /* Save away original info so we can restore it when doing factory reset. 396 * Then, when doing the format, it will format the original device in the 397 * clear, otherwise it just formats the encrypted device which is not 398 * readable when the device boots unencrypted after the reset. 399 */ 400 mOrigDiskMajor = mDiskMajor; 401 mOrigDiskMinor = mDiskMinor; 402 mOrigPartIdx = mPartIdx; 403 memcpy(mOrigPartMinors, mPartMinors, sizeof(mPartMinors)); 404 405 mDiskMajor = new_major; 406 mDiskMinor = new_minor; 407 /* Ugh, virual block devices don't use minor 0 for whole disk and minor > 0 for 408 * partition number. They don't have partitions, they are just virtual block 409 * devices, and minor number 0 is the first dm-crypt device. Luckily the first 410 * dm-crypt device is for the userdata partition, which gets minor number 0, and 411 * it is not managed by vold. So the next device is minor number one, which we 412 * will call partition one. 413 */ 414 mPartIdx = new_minor; 415 mPartMinors[new_minor-1] = new_minor; 416 417 mIsDecrypted = 1; 418 419 return 0; 420 } 421 422 /* 423 * Called from base to revert device info to the way it was before a 424 * crypto mapping was created for it. 425 */ 426 void DirectVolume::revertDeviceInfo(void) 427 { 428 if (mIsDecrypted) { 429 mDiskMajor = mOrigDiskMajor; 430 mDiskMinor = mOrigDiskMinor; 431 mPartIdx = mOrigPartIdx; 432 memcpy(mPartMinors, mOrigPartMinors, sizeof(mPartMinors)); 433 434 mIsDecrypted = 0; 435 } 436 437 return; 438 } 439 440 /* 441 * Called from base to give cryptfs all the info it needs to encrypt eligible volumes 442 */ 443 int DirectVolume::getVolInfo(struct volume_info *v) 444 { 445 strcpy(v->label, mLabel); 446 strcpy(v->mnt_point, mMountpoint); 447 v->flags=mFlags; 448 /* Other fields of struct volume_info are filled in by the caller or cryptfs.c */ 449 450 return 0; 451 } 452