1f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat/*
2f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * Copyright (C) 2008 The Android Open Source Project
3f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *
4f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * Licensed under the Apache License, Version 2.0 (the "License");
5f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * you may not use this file except in compliance with the License.
6f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * You may obtain a copy of the License at
7f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *
8f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *      http://www.apache.org/licenses/LICENSE-2.0
9f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *
10f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * Unless required by applicable law or agreed to in writing, software
11f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * distributed under the License is distributed on an "AS IS" BASIS,
12f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * See the License for the specific language governing permissions and
14f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * limitations under the License.
15f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat */
16f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
17f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <stdio.h>
18fd7f5875129adfe2845f4f3fffb17db3a89eea25San Mehat#include <stdlib.h>
19fd7f5875129adfe2845f4f3fffb17db3a89eea25San Mehat#include <string.h>
20f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <errno.h>
21a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#include <fcntl.h>
22344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root#include <fts.h>
23344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root#include <unistd.h>
24a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat#include <sys/stat.h>
25a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat#include <sys/types.h>
26a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat#include <sys/mount.h>
27fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg#include <sys/ioctl.h>
28425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall#include <dirent.h>
29a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
30a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#include <linux/kdev_t.h>
31f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
32f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#define LOG_TAG "Vold"
33f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
347b18a7b36f61574c0f0bdde0a7409dc36676fa12Kenny Root#include <openssl/md5.h>
357b18a7b36f61574c0f0bdde0a7409dc36676fa12Kenny Root
3671ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey#include <cutils/fs.h>
37f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <cutils/log.h>
38f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
39b9e3ba56cb4075f894a73b02ee70571456494ac1Robert Craig#include <selinux/android.h>
40b9e3ba56cb4075f894a73b02ee70571456494ac1Robert Craig
41fd7f5875129adfe2845f4f3fffb17db3a89eea25San Mehat#include <sysutils/NetlinkEvent.h>
42fd7f5875129adfe2845f4f3fffb17db3a89eea25San Mehat
43344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root#include <private/android_filesystem_config.h>
44344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
45f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include "VolumeManager.h"
46ae10b91044bf76b40b77d81c169e48e0bbdf6d75San Mehat#include "DirectVolume.h"
47a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#include "ResponseCode.h"
48a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat#include "Loop.h"
49344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root#include "Ext4.h"
50a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat#include "Fat.h"
51b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat#include "Devmapper.h"
52586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat#include "Process.h"
53fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat#include "Asec.h"
5429d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall#include "cryptfs.h"
5523969931fad6e993832208f099f6eea0f6f76eb5San Mehat
5697f2fc110b2ace7914671c2f5852379bd78922e4Mike Lockwood#define MASS_STORAGE_FILE_PATH  "/sys/class/android_usb/android0/f_mass_storage/lun/file"
5797f2fc110b2ace7914671c2f5852379bd78922e4Mike Lockwood
586a74dcaa6e646fea8e00b7c04332fc60fe7e017cDaniel Rosenberg#define ROUND_UP_POWER_OF_2(number, po2) (((!!(number & ((1U << po2) - 1))) << po2)\
596a74dcaa6e646fea8e00b7c04332fc60fe7e017cDaniel Rosenberg                                         + (number & (~((1U << po2) - 1))))
606a74dcaa6e646fea8e00b7c04332fc60fe7e017cDaniel Rosenberg
61fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg/* writes superblock at end of file or device given by name */
62fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenbergstatic int writeSuperBlock(const char* name, struct asec_superblock *sb, unsigned int numImgSectors) {
63fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    int sbfd = open(name, O_RDWR);
64fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (sbfd < 0) {
65fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("Failed to open %s for superblock write (%s)", name, strerror(errno));
66fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
67fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
68fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
69fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
70fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
71fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        close(sbfd);
72fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
73fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
74fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
75fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (write(sbfd, sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
76fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("Failed to write superblock (%s)", strerror(errno));
77fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        close(sbfd);
78fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
79fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
80fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    close(sbfd);
81fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    return 0;
82fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg}
83fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
84fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenbergstatic int adjustSectorNumExt4(unsigned numSectors) {
85e9196fecbb08ead0b5dcdf1b38b81a0419c24bf4Daniel Rosenberg    // Ext4 started to reserve 2% or 4096 clusters, whichever is smaller for
86e9196fecbb08ead0b5dcdf1b38b81a0419c24bf4Daniel Rosenberg    // preventing costly operations or unexpected ENOSPC error.
87e9196fecbb08ead0b5dcdf1b38b81a0419c24bf4Daniel Rosenberg    // Ext4::format() uses default block size without clustering.
88e9196fecbb08ead0b5dcdf1b38b81a0419c24bf4Daniel Rosenberg    unsigned clusterSectors = 4096 / 512;
89e9196fecbb08ead0b5dcdf1b38b81a0419c24bf4Daniel Rosenberg    unsigned reservedSectors = (numSectors * 2)/100 + (numSectors % 50 > 0);
90e9196fecbb08ead0b5dcdf1b38b81a0419c24bf4Daniel Rosenberg    numSectors += reservedSectors > (4096 * clusterSectors) ? (4096 * clusterSectors) : reservedSectors;
91fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    return ROUND_UP_POWER_OF_2(numSectors, 3);
92fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg}
93fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
94fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenbergstatic int adjustSectorNumFAT(unsigned numSectors) {
95fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    /*
96fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    * Add some headroom
97fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    */
98fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
99fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    numSectors += fatSize + 2;
100fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    /*
101fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    * FAT is aligned to 32 kb with 512b sectors.
102fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    */
103fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    return ROUND_UP_POWER_OF_2(numSectors, 6);
104fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg}
105fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
106fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenbergstatic int setupLoopDevice(char* buffer, size_t len, const char* asecFileName, const char* idHash, bool debug) {
107fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (Loop::lookupActive(idHash, buffer, len)) {
108fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        if (Loop::create(idHash, asecFileName, buffer, len)) {
109fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            SLOGE("ASEC loop device creation failed for %s (%s)", asecFileName, strerror(errno));
110fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            return -1;
111fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        }
112fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        if (debug) {
113fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            SLOGD("New loop device created at %s", buffer);
114fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        }
115fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    } else {
116fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        if (debug) {
117fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            SLOGD("Found active loopback for %s at %s", asecFileName, buffer);
118fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        }
119fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
120fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    return 0;
121fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg}
122fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
123fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenbergstatic int setupDevMapperDevice(char* buffer, size_t len, const char* loopDevice, const char* asecFileName, const char* key, const char* idHash , int numImgSectors, bool* createdDMDevice, bool debug) {
124fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (strcmp(key, "none")) {
125fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        if (Devmapper::lookupActive(idHash, buffer, len)) {
126fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            if (Devmapper::create(idHash, loopDevice, key, numImgSectors,
127fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg                                  buffer, len)) {
128fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg                SLOGE("ASEC device mapping failed for %s (%s)", asecFileName, strerror(errno));
129fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg                return -1;
130fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            }
131fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            if (debug) {
132fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg                SLOGD("New devmapper instance created at %s", buffer);
133fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            }
134fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        } else {
135fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            if (debug) {
136fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg                SLOGD("Found active devmapper for %s at %s", asecFileName, buffer);
137fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            }
138fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        }
139fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        *createdDMDevice = true;
140fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    } else {
141fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        strcpy(buffer, loopDevice);
142fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        *createdDMDevice = false;
143fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
144fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    return 0;
145fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg}
146fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
147fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenbergstatic void waitForDevMapper(const char *dmDevice) {
148fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    /*
149fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg     * Wait for the device mapper node to be created. Sometimes it takes a
150fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg     * while. Wait for up to 1 second. We could also inspect incoming uevents,
151fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg     * but that would take more effort.
152fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg     */
153fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    int tries = 25;
154fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    while (tries--) {
155fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        if (!access(dmDevice, F_OK) || errno != ENOENT) {
156fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            break;
157fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        }
158fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        usleep(40 * 1000);
159fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
160fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg}
161fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
162f1b736bc5605e92e917ab27f5abf3ba839be2270San MehatVolumeManager *VolumeManager::sInstance = NULL;
163f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
164f1b736bc5605e92e917ab27f5abf3ba839be2270San MehatVolumeManager *VolumeManager::Instance() {
165f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    if (!sInstance)
166f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat        sInstance = new VolumeManager();
167f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    return sInstance;
168f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
169f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
170f1b736bc5605e92e917ab27f5abf3ba839be2270San MehatVolumeManager::VolumeManager() {
171d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    mDebug = false;
172f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    mVolumes = new VolumeCollection();
17388705166ab82057090a070c6d4200c3d9db76f11San Mehat    mActiveContainers = new AsecIdCollection();
174f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    mBroadcaster = NULL;
175a28056b38275003895ff5d9576681aca01544822Mike Lockwood    mUmsSharingCount = 0;
176a28056b38275003895ff5d9576681aca01544822Mike Lockwood    mSavedDirtyRatio = -1;
177a28056b38275003895ff5d9576681aca01544822Mike Lockwood    // set dirty ratio to 0 when UMS is active
178a28056b38275003895ff5d9576681aca01544822Mike Lockwood    mUmsDirtyRatio = 0;
1793b17005083be230509480ea65ae67c237142fadaKen Sumrall    mVolManagerDisabled = 0;
180f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
181f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
182f1b736bc5605e92e917ab27f5abf3ba839be2270San MehatVolumeManager::~VolumeManager() {
18388705166ab82057090a070c6d4200c3d9db76f11San Mehat    delete mVolumes;
18488705166ab82057090a070c6d4200c3d9db76f11San Mehat    delete mActiveContainers;
185f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
186f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
187d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehatchar *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
188acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root    static const char* digits = "0123456789abcdef";
189acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root
1907b18a7b36f61574c0f0bdde0a7409dc36676fa12Kenny Root    unsigned char sig[MD5_DIGEST_LENGTH];
191d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
192acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root    if (buffer == NULL) {
193acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root        SLOGE("Destination buffer is NULL");
194acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root        errno = ESPIPE;
195acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root        return NULL;
196acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root    } else if (id == NULL) {
197acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root        SLOGE("Source buffer is NULL");
198acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root        errno = ESPIPE;
199acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root        return NULL;
200acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root    } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
20159846b654e8b4a22a1be11cd21d6c5b81375abd2Colin Cross        SLOGE("Target hash buffer size < %d bytes (%zu)",
202acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root                MD5_ASCII_LENGTH_PLUS_NULL, len);
203d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        errno = ESPIPE;
204d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        return NULL;
205d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
2067b18a7b36f61574c0f0bdde0a7409dc36676fa12Kenny Root
2077b18a7b36f61574c0f0bdde0a7409dc36676fa12Kenny Root    MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
208d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
209acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root    char *p = buffer;
2107b18a7b36f61574c0f0bdde0a7409dc36676fa12Kenny Root    for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
211acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root        *p++ = digits[sig[i] >> 4];
212acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root        *p++ = digits[sig[i] & 0x0F];
213d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
214acc9e7dcca8978fc809fa5b4d9b819c515a980ffKenny Root    *p = '\0';
215d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
216d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    return buffer;
217d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat}
218d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
219d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehatvoid VolumeManager::setDebug(bool enable) {
220d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    mDebug = enable;
221d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    VolumeCollection::iterator it;
222d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
223d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        (*it)->setDebug(enable);
224d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
225d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat}
226d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
227f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehatint VolumeManager::start() {
228f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    return 0;
229f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
230f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
231f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehatint VolumeManager::stop() {
232f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    return 0;
233f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
234f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
235f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehatint VolumeManager::addVolume(Volume *v) {
236f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    mVolumes->push_back(v);
237f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    return 0;
238f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
239f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
240fd7f5875129adfe2845f4f3fffb17db3a89eea25San Mehatvoid VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
241fd7f5875129adfe2845f4f3fffb17db3a89eea25San Mehat    const char *devpath = evt->findParam("DEVPATH");
242f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
243fd7f5875129adfe2845f4f3fffb17db3a89eea25San Mehat    /* Lookup a volume to handle this device */
244f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    VolumeCollection::iterator it;
245f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    bool hit = false;
246f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
247fd7f5875129adfe2845f4f3fffb17db3a89eea25San Mehat        if (!(*it)->handleBlockEvent(evt)) {
248a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#ifdef NETLINK_DEBUG
24997ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat            SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
250a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#endif
251f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat            hit = true;
252f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat            break;
253f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat        }
254f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    }
255f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
256f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    if (!hit) {
257a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#ifdef NETLINK_DEBUG
25897ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGW("No volumes handled block event for '%s'", devpath);
259a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#endif
260f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    }
261f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
262f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
26340b64a684124809132e04e3c499aa1e101fe808fJP Abgrallint VolumeManager::listVolumes(SocketClient *cli, bool broadcast) {
264f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    VolumeCollection::iterator i;
26540b64a684124809132e04e3c499aa1e101fe808fJP Abgrall    char msg[256];
266f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
267f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
268f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat        char *buffer;
269f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat        asprintf(&buffer, "%s %s %d",
270ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey                 (*i)->getLabel(), (*i)->getFuseMountpoint(),
271f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat                 (*i)->getState());
272a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
273f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat        free(buffer);
27440b64a684124809132e04e3c499aa1e101fe808fJP Abgrall        if (broadcast) {
27540b64a684124809132e04e3c499aa1e101fe808fJP Abgrall            if((*i)->getUuid()) {
27640b64a684124809132e04e3c499aa1e101fe808fJP Abgrall                snprintf(msg, sizeof(msg), "%s %s \"%s\"", (*i)->getLabel(),
27740b64a684124809132e04e3c499aa1e101fe808fJP Abgrall                    (*i)->getFuseMountpoint(), (*i)->getUuid());
27840b64a684124809132e04e3c499aa1e101fe808fJP Abgrall                mBroadcaster->sendBroadcast(ResponseCode::VolumeUuidChange,
27940b64a684124809132e04e3c499aa1e101fe808fJP Abgrall                    msg, false);
28040b64a684124809132e04e3c499aa1e101fe808fJP Abgrall            }
28140b64a684124809132e04e3c499aa1e101fe808fJP Abgrall            if((*i)->getUserLabel()) {
28240b64a684124809132e04e3c499aa1e101fe808fJP Abgrall                snprintf(msg, sizeof(msg), "%s %s \"%s\"", (*i)->getLabel(),
28340b64a684124809132e04e3c499aa1e101fe808fJP Abgrall                    (*i)->getFuseMountpoint(), (*i)->getUserLabel());
28440b64a684124809132e04e3c499aa1e101fe808fJP Abgrall                mBroadcaster->sendBroadcast(ResponseCode::VolumeUserLabelChange,
28540b64a684124809132e04e3c499aa1e101fe808fJP Abgrall                    msg, false);
28640b64a684124809132e04e3c499aa1e101fe808fJP Abgrall            }
28740b64a684124809132e04e3c499aa1e101fe808fJP Abgrall        }
288f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    }
289a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
290f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    return 0;
291f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
29249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
2939caab76c6b5aefdeeb1715a3695491ca793b8c18Ken Sumrallint VolumeManager::formatVolume(const char *label, bool wipe) {
294a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    Volume *v = lookupVolume(label);
295a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
296a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (!v) {
297a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = ENOENT;
298a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
299a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
300a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
3013b17005083be230509480ea65ae67c237142fadaKen Sumrall    if (mVolManagerDisabled) {
3023b17005083be230509480ea65ae67c237142fadaKen Sumrall        errno = EBUSY;
3033b17005083be230509480ea65ae67c237142fadaKen Sumrall        return -1;
3043b17005083be230509480ea65ae67c237142fadaKen Sumrall    }
3053b17005083be230509480ea65ae67c237142fadaKen Sumrall
3069caab76c6b5aefdeeb1715a3695491ca793b8c18Ken Sumrall    return v->formatVol(wipe);
307a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat}
308a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
309508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Rootint VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
310508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    char idHash[33];
311508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
312508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
313508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        return -1;
314508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    }
315508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
316508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    memset(mountPath, 0, mountPathLen);
317d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    int written = snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
318d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (written >= mountPathLen)) {
319d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        errno = EINVAL;
320d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        return -1;
321d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
322508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
323508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    if (access(mountPath, F_OK)) {
324508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        errno = ENOENT;
325508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        return -1;
326508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    }
327508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
328508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    return 0;
329508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root}
330508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
331a19b250bd273455933ca3502cf2c2e0a803aff77San Mehatint VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
33288ac2c06539485942bf414efda2d39647fa1a415San Mehat    char asecFileName[255];
333344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
3340de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    if (!isLegalAsecId(id)) {
3350de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        SLOGE("getAsecMountPath: Invalid asec id \"%s\"", id);
3360de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        errno = EINVAL;
3370de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return -1;
3380de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
3390de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
340344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
341344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Couldn't find ASEC %s", id);
342344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
343344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
34488ac2c06539485942bf414efda2d39647fa1a415San Mehat
34588ac2c06539485942bf414efda2d39647fa1a415San Mehat    memset(buffer, 0, maxlen);
34688ac2c06539485942bf414efda2d39647fa1a415San Mehat    if (access(asecFileName, F_OK)) {
34788ac2c06539485942bf414efda2d39647fa1a415San Mehat        errno = ENOENT;
34888ac2c06539485942bf414efda2d39647fa1a415San Mehat        return -1;
34988ac2c06539485942bf414efda2d39647fa1a415San Mehat    }
350a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
351d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    int written = snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
352d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (written >= maxlen)) {
353d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id);
354d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        errno = EINVAL;
355d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        return -1;
356d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
357d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig
358a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    return 0;
359a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat}
360a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
361736910ca99a40b9add4353bf619e778c40938948Dianne Hackbornint VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
362736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn    char asecFileName[255];
363344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
3640de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    if (!isLegalAsecId(id)) {
3650de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        SLOGE("getAsecFilesystemPath: Invalid asec id \"%s\"", id);
3660de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        errno = EINVAL;
3670de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return -1;
3680de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
3690de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
370344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
371344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Couldn't find ASEC %s", id);
372344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
373344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
374736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn
375736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn    memset(buffer, 0, maxlen);
376736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn    if (access(asecFileName, F_OK)) {
377736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        errno = ENOENT;
378736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        return -1;
379736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn    }
380736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn
381d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    int written = snprintf(buffer, maxlen, "%s", asecFileName);
382d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (written >= maxlen)) {
383d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        errno = EINVAL;
384d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        return -1;
385d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
386d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig
387736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn    return 0;
388736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn}
389736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn
390344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Rootint VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype,
391344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        const char *key, const int ownerUid, bool isExternal) {
392fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    struct asec_superblock sb;
393fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    memset(&sb, 0, sizeof(sb));
394fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat
3950de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    if (!isLegalAsecId(id)) {
3960de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        SLOGE("createAsec: Invalid asec id \"%s\"", id);
3970de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        errno = EINVAL;
3980de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return -1;
3990de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
4000de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
401344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    const bool wantFilesystem = strcmp(fstype, "none");
402344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    bool usingExt4 = false;
403344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (wantFilesystem) {
404344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        usingExt4 = !strcmp(fstype, "ext4");
405344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (usingExt4) {
406344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
407344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        } else if (strcmp(fstype, "fat")) {
408344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            SLOGE("Invalid filesystem type %s", fstype);
409344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            errno = EINVAL;
410344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            return -1;
411344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        }
412344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
413344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
414fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    sb.magic = ASEC_SB_MAGIC;
415fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    sb.ver = ASEC_SB_VER;
416a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
417d31e380bd9689dd9629b510ffe324707e261b439San Mehat    if (numSectors < ((1024*1024)/512)) {
41897ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Invalid container size specified (%d sectors)", numSectors);
419d31e380bd9689dd9629b510ffe324707e261b439San Mehat        errno = EINVAL;
420d31e380bd9689dd9629b510ffe324707e261b439San Mehat        return -1;
421d31e380bd9689dd9629b510ffe324707e261b439San Mehat    }
422d31e380bd9689dd9629b510ffe324707e261b439San Mehat
423a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    if (lookupVolume(id)) {
42497ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("ASEC id '%s' currently exists", id);
425a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        errno = EADDRINUSE;
426a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        return -1;
427a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
428a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
429a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char asecFileName[255];
430344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
431344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
432344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
433344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                asecFileName, strerror(errno));
434344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        errno = EADDRINUSE;
435344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
436344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
437344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
438344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    const char *asecDir = isExternal ? Volume::SEC_ASECDIR_EXT : Volume::SEC_ASECDIR_INT;
439344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
440d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
441d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) {
442d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        errno = EINVAL;
443d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        return -1;
444d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
445a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
446a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    if (!access(asecFileName, F_OK)) {
44797ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
448344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                asecFileName, strerror(errno));
449a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        errno = EADDRINUSE;
450a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        return -1;
451a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
452a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
453fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    unsigned numImgSectors;
4546a74dcaa6e646fea8e00b7c04332fc60fe7e017cDaniel Rosenberg    if (usingExt4)
455fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        numImgSectors = adjustSectorNumExt4(numSectors);
4566a74dcaa6e646fea8e00b7c04332fc60fe7e017cDaniel Rosenberg    else
457fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        numImgSectors = adjustSectorNumFAT(numSectors);
458fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat
459fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    // Add +1 for our superblock which is at the end
460fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
46197ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("ASEC image file creation failed (%s)", strerror(errno));
462a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        return -1;
463a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
464a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
465d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    char idHash[33];
466d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (!asecHash(id, idHash, sizeof(idHash))) {
46797ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
468d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        unlink(asecFileName);
469d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        return -1;
470d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
471d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
472a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char loopDevice[255];
473d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
47497ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
475a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        unlink(asecFileName);
476a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        return -1;
477a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
478a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
479b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    char dmDevice[255];
480b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    bool cleanupDm = false;
481a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
482b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    if (strcmp(key, "none")) {
483fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        // XXX: This is all we support for now
484fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
485d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
486b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat                             sizeof(dmDevice))) {
48797ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat            SLOGE("ASEC device mapping failed (%s)", strerror(errno));
488b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            Loop::destroyByDevice(loopDevice);
489b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            unlink(asecFileName);
490b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            return -1;
491b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        }
492b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        cleanupDm = true;
493b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    } else {
494fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
495b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        strcpy(dmDevice, loopDevice);
496b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    }
497b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
498fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    /*
499fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat     * Drop down the superblock at the end of the file
500fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat     */
501fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (writeSuperBlock(loopDevice, &sb, numImgSectors)) {
502fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        if (cleanupDm) {
503d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            Devmapper::destroy(idHash);
504fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        }
505fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        Loop::destroyByDevice(loopDevice);
506fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        unlink(asecFileName);
507fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        return -1;
508fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    }
509fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat
510344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (wantFilesystem) {
511344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        int formatStatus;
512a54e13a3dca8ad15141a9f1084b6e121caeddce5rpcraig        char mountPoint[255];
513a54e13a3dca8ad15141a9f1084b6e121caeddce5rpcraig
514d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
515d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
516d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig            SLOGE("ASEC fs format failed: couldn't construct mountPoint");
517d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig            if (cleanupDm) {
518d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig                Devmapper::destroy(idHash);
519d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig            }
520d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig            Loop::destroyByDevice(loopDevice);
521d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig            unlink(asecFileName);
522d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig            return -1;
523d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        }
524a54e13a3dca8ad15141a9f1084b6e121caeddce5rpcraig
525344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (usingExt4) {
5266a74dcaa6e646fea8e00b7c04332fc60fe7e017cDaniel Rosenberg            formatStatus = Ext4::format(dmDevice, numImgSectors, mountPoint);
527344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        } else {
5289caab76c6b5aefdeeb1715a3695491ca793b8c18Ken Sumrall            formatStatus = Fat::format(dmDevice, numImgSectors, 0);
529b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        }
530a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
531344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (formatStatus < 0) {
532344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            SLOGE("ASEC fs format failed (%s)", strerror(errno));
533b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            if (cleanupDm) {
534d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                Devmapper::destroy(idHash);
535b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            }
536eb13a90bb96b329d8e24a6c3d4720ae88451d301San Mehat            Loop::destroyByDevice(loopDevice);
537eb13a90bb96b329d8e24a6c3d4720ae88451d301San Mehat            unlink(asecFileName);
538eb13a90bb96b329d8e24a6c3d4720ae88451d301San Mehat            return -1;
539eb13a90bb96b329d8e24a6c3d4720ae88451d301San Mehat        }
540344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
541344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (mkdir(mountPoint, 0000)) {
542a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat            if (errno != EEXIST) {
54397ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat                SLOGE("Mountpoint creation failed (%s)", strerror(errno));
544a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat                if (cleanupDm) {
545d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                    Devmapper::destroy(idHash);
546a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat                }
547a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat                Loop::destroyByDevice(loopDevice);
548a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat                unlink(asecFileName);
549a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat                return -1;
550a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat            }
551a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat        }
552a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
553344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        int mountStatus;
554344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (usingExt4) {
555344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false);
556344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        } else {
557344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000,
558344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                    false);
559344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        }
560344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
561344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (mountStatus) {
56297ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat            SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
563a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat            if (cleanupDm) {
564d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                Devmapper::destroy(idHash);
565a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat            }
566a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat            Loop::destroyByDevice(loopDevice);
567a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat            unlink(asecFileName);
568a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat            return -1;
569b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        }
570344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
571344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (usingExt4) {
572344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            int dirfd = open(mountPoint, O_DIRECTORY);
573344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            if (dirfd >= 0) {
574344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                if (fchown(dirfd, ownerUid, AID_SYSTEM)
575344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                        || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
576344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                    SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
577344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                }
578344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                close(dirfd);
579344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            }
580344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        }
581a1091cb0c448a933068f9120fe6946c09812bfb6San Mehat    } else {
58297ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGI("Created raw secure container %s (no filesystem)", id);
583a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
58488705166ab82057090a070c6d4200c3d9db76f11San Mehat
585cbacf78eff70bd43bb899e164ec2ab409bc0904cKenny Root    mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
586a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    return 0;
587a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat}
588a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
589fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenbergint VolumeManager::resizeAsec(const char *id, unsigned numSectors, const char *key) {
590fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    char asecFileName[255];
591fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    char mountPoint[255];
592fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    bool cleanupDm = false;
593fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
594fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (!isLegalAsecId(id)) {
595fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("resizeAsec: Invalid asec id \"%s\"", id);
596fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        errno = EINVAL;
597fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
598fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
599fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
600fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
601fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("Couldn't find ASEC %s", id);
602fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
603fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
604fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
605fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
606fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
607fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg       SLOGE("ASEC resize failed for %s: couldn't construct mountpoint", id);
608fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg       return -1;
609fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
610fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
611fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (isMountpointMounted(mountPoint)) {
612fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg       SLOGE("ASEC %s mounted. Unmount before resizing", id);
613fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg       errno = EBUSY;
614fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg       return -1;
615fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
616fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
617fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    struct asec_superblock sb;
618fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    int fd;
619fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    unsigned int oldNumSec = 0;
620fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
621fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if ((fd = open(asecFileName, O_RDONLY)) < 0) {
622fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("Failed to open ASEC file (%s)", strerror(errno));
623fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
624fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
625fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
626fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    struct stat info;
627fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (fstat(fd, &info) < 0) {
628fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("Failed to get file size (%s)", strerror(errno));
629fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        close(fd);
630fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
631fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
632fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
633fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    oldNumSec = info.st_size / 512;
634fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
635fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    unsigned numImgSectors;
636fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (sb.c_opts & ASEC_SB_C_OPTS_EXT4)
637fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        numImgSectors = adjustSectorNumExt4(numSectors);
638fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    else
639fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        numImgSectors = adjustSectorNumFAT(numSectors);
640fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    /*
641fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg     *  add one block for the superblock
642fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg     */
643fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    SLOGD("Resizing from %d sectors to %d sectors", oldNumSec, numImgSectors + 1);
64443ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey    if (oldNumSec == numImgSectors + 1) {
64543ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        SLOGW("Size unchanged; ignoring resize request");
64643ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        return 0;
64743ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey    } else if (oldNumSec > numImgSectors + 1) {
648fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("Only growing is currently supported.");
649fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        close(fd);
650fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
651fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
652fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
653fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    /*
654fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg     * Try to read superblock.
655fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg     */
656fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    memset(&sb, 0, sizeof(struct asec_superblock));
657fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (lseek(fd, ((oldNumSec - 1) * 512), SEEK_SET) < 0) {
658fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("lseek failed (%s)", strerror(errno));
659fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        close(fd);
660fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
661fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
662fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (read(fd, &sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
663fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("superblock read failed (%s)", strerror(errno));
664fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        close(fd);
665fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
666fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
667fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    close(fd);
668fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
669fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (mDebug) {
670fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
671fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
672fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
673fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
674fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        errno = EMEDIUMTYPE;
675fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
676fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
677fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
678fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (!(sb.c_opts & ASEC_SB_C_OPTS_EXT4)) {
679fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("Only ext4 partitions are supported for resize");
680fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        errno = EINVAL;
681fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
682fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
683fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
684fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (Loop::resizeImageFile(asecFileName, numImgSectors + 1)) {
685fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("Resize of ASEC image file failed. Could not resize %s", id);
686fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
687fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
688fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
689fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    /*
690fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg     * Drop down a copy of the superblock at the end of the file
691fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg     */
692fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (writeSuperBlock(asecFileName, &sb, numImgSectors))
693fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        goto fail;
694fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
695fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    char idHash[33];
696fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (!asecHash(id, idHash, sizeof(idHash))) {
697fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
698fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        goto fail;
699fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
700fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
701fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    char loopDevice[255];
702fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug))
703fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        goto fail;
704fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
705fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    char dmDevice[255];
706fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
707fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash, numImgSectors, &cleanupDm, mDebug)) {
708fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        Loop::destroyByDevice(loopDevice);
709fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        goto fail;
710fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
711fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
712fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    /*
713fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg     * Wait for the device mapper node to be created.
714fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg     */
715fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    waitForDevMapper(dmDevice);
716fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
717fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (Ext4::resize(dmDevice, numImgSectors)) {
718fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        SLOGE("Unable to resize %s (%s)", id, strerror(errno));
719fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        if (cleanupDm) {
720fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            Devmapper::destroy(idHash);
721fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        }
722fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        Loop::destroyByDevice(loopDevice);
723fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        goto fail;
724fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    }
725fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
726fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    return 0;
727fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenbergfail:
728fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    Loop::resizeImageFile(asecFileName, oldNumSec);
729fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    return -1;
730fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg}
731fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg
732a19b250bd273455933ca3502cf2c2e0a803aff77San Mehatint VolumeManager::finalizeAsec(const char *id) {
733a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char asecFileName[255];
734a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char loopDevice[255];
735a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char mountPoint[255];
736a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
7370de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    if (!isLegalAsecId(id)) {
7380de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        SLOGE("finalizeAsec: Invalid asec id \"%s\"", id);
7390de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        errno = EINVAL;
7400de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return -1;
7410de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
7420de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
743344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
744344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Couldn't find ASEC %s", id);
745344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
746344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
747a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
748d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    char idHash[33];
749d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (!asecHash(id, idHash, sizeof(idHash))) {
75097ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
751d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        return -1;
752d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
753d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
754d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
75597ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
756a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        return -1;
757a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
758a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
759344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    unsigned int nr_sec = 0;
760344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    struct asec_superblock sb;
761344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
762344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
763344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
764344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
765344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
766d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
767d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
768d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        SLOGE("ASEC finalize failed: couldn't construct mountPoint");
769d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        return -1;
770d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
771344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
772344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    int result = 0;
773344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
774344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        result = Ext4::doMount(loopDevice, mountPoint, true, true, true);
775344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    } else {
776344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false);
777344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
778344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
779344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (result) {
78097ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
781a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        return -1;
782a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
783a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
784d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (mDebug) {
78597ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGD("ASEC %s finalized", id);
786d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
787a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    return 0;
788a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat}
789a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
790344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Rootint VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
791344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    char asecFileName[255];
792344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    char loopDevice[255];
793344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    char mountPoint[255];
794344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
795344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (gid < AID_APP) {
796344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Group ID is not in application range");
797344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
798344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
799344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
8000de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    if (!isLegalAsecId(id)) {
8010de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id);
8020de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        errno = EINVAL;
8030de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return -1;
8040de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
8050de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
806344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
807344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Couldn't find ASEC %s", id);
808344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
809344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
810344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
811344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    char idHash[33];
812344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (!asecHash(id, idHash, sizeof(idHash))) {
813344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
814344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
815344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
816344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
817344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
818344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
819344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
820344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
821344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
822344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    unsigned int nr_sec = 0;
823344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    struct asec_superblock sb;
824344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
825344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
826344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
827344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
828344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
829d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
830d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
831d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id);
832d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        return -1;
833d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
834344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
835344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    int result = 0;
836344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
837344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return 0;
838344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
839344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
840344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    int ret = Ext4::doMount(loopDevice, mountPoint,
841344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            false /* read-only */,
842344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            true  /* remount */,
843344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            false /* executable */);
844344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (ret) {
845344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
846344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
847344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
848344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
849344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    char *paths[] = { mountPoint, NULL };
850344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
851344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
852344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (fts) {
853344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        // Traverse the entire hierarchy and chown to system UID.
854344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
855344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            // We don't care about the lost+found directory.
856344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            if (!strcmp(ftsent->fts_name, "lost+found")) {
857344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                continue;
858344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            }
859344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
860344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            /*
861344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root             * There can only be one file marked as private right now.
862344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root             * This should be more robust, but it satisfies the requirements
863344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root             * we have for right now.
864344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root             */
865344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            const bool privateFile = !strcmp(ftsent->fts_name, filename);
866344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
867344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            int fd = open(ftsent->fts_accpath, O_NOFOLLOW);
868344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            if (fd < 0) {
869344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
870344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                result = -1;
871344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                continue;
872344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            }
873344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
874344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
875344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
876344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            if (ftsent->fts_info & FTS_D) {
8771a673c868c2d2d81fcaeab34b4a7c75d4a978584Kenny Root                result |= fchmod(fd, 0755);
878348c8aba0d2df2996e0fe57900ef518c6aeb4b29Kenny Root            } else if (ftsent->fts_info & FTS_F) {
879344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                result |= fchmod(fd, privateFile ? 0640 : 0644);
880344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            }
881b9e3ba56cb4075f894a73b02ee70571456494ac1Robert Craig
8825093e6187da9c237c88383540f544c8dbaf37754Stephen Smalley            if (selinux_android_restorecon(ftsent->fts_path, 0) < 0) {
883b9e3ba56cb4075f894a73b02ee70571456494ac1Robert Craig                SLOGE("restorecon failed for %s: %s\n", ftsent->fts_path, strerror(errno));
884b9e3ba56cb4075f894a73b02ee70571456494ac1Robert Craig                result |= -1;
885b9e3ba56cb4075f894a73b02ee70571456494ac1Robert Craig            }
886b9e3ba56cb4075f894a73b02ee70571456494ac1Robert Craig
887344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            close(fd);
888344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        }
889344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        fts_close(fts);
890344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
891344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        // Finally make the directory readable by everyone.
892344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        int dirfd = open(mountPoint, O_DIRECTORY);
893344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (dirfd < 0 || fchmod(dirfd, 0755)) {
894344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
895344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            result |= -1;
896344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        }
897344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        close(dirfd);
898344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    } else {
899344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        result |= -1;
900344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
901344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
902344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    result |= Ext4::doMount(loopDevice, mountPoint,
903344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            true /* read-only */,
904344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            true /* remount */,
905344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            true /* execute */);
906344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
907344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (result) {
908344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
909344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
910344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
911344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
912344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (mDebug) {
913344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGD("ASEC %s permissions fixed", id);
914344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
915344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    return 0;
916344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root}
917344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
918048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehatint VolumeManager::renameAsec(const char *id1, const char *id2) {
919344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    char asecFilename1[255];
920048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    char *asecFilename2;
921048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    char mountPoint[255];
922048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat
923344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    const char *dir;
924344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
9250de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    if (!isLegalAsecId(id1)) {
9260de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        SLOGE("renameAsec: Invalid asec id1 \"%s\"", id1);
9270de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        errno = EINVAL;
9280de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return -1;
9290de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
9300de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
9310de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    if (!isLegalAsecId(id2)) {
9320de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        SLOGE("renameAsec: Invalid asec id2 \"%s\"", id2);
9330de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        errno = EINVAL;
9340de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return -1;
9350de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
9360de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
937344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
938344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Couldn't find ASEC %s", id1);
939344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
940344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
941344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
942344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
943048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat
944d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
945d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
946d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        SLOGE("Rename failed: couldn't construct mountpoint");
947d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        goto out_err;
948d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
949d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig
950048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    if (isMountpointMounted(mountPoint)) {
95197ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGW("Rename attempt when src mounted");
952048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat        errno = EBUSY;
953048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat        goto out_err;
954048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    }
955048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat
956d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
957d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
958d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        SLOGE("Rename failed: couldn't construct mountpoint2");
959d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        goto out_err;
960d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
961d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig
96296956ed0e220cb62a4a96136976ded0d8c2d9075San Mehat    if (isMountpointMounted(mountPoint)) {
96397ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGW("Rename attempt when dst mounted");
96496956ed0e220cb62a4a96136976ded0d8c2d9075San Mehat        errno = EBUSY;
96596956ed0e220cb62a4a96136976ded0d8c2d9075San Mehat        goto out_err;
96696956ed0e220cb62a4a96136976ded0d8c2d9075San Mehat    }
96796956ed0e220cb62a4a96136976ded0d8c2d9075San Mehat
968048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    if (!access(asecFilename2, F_OK)) {
96997ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Rename attempt when dst exists");
970048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat        errno = EADDRINUSE;
971048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat        goto out_err;
972048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    }
973048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat
974048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    if (rename(asecFilename1, asecFilename2)) {
97597ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
976048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat        goto out_err;
977048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    }
978048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat
979048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    free(asecFilename2);
980048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    return 0;
981048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat
982048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehatout_err:
983048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    free(asecFilename2);
984048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    return -1;
985048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat}
986048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat
987fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root#define UNMOUNT_RETRIES 5
988fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
9894ba8948dc16463053e21cda5744f519a555080d0San Mehatint VolumeManager::unmountAsec(const char *id, bool force) {
990a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char asecFileName[255];
991a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char mountPoint[255];
992a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
9930de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    if (!isLegalAsecId(id)) {
9940de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        SLOGE("unmountAsec: Invalid asec id \"%s\"", id);
9950de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        errno = EINVAL;
9960de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return -1;
9970de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
9980de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
999344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1000344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Couldn't find ASEC %s", id);
1001344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
1002344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
1003344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1004d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
1005d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1006d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id);
1007d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        return -1;
1008d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
1009a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
1010d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    char idHash[33];
1011d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (!asecHash(id, idHash, sizeof(idHash))) {
101297ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
1013d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        return -1;
1014d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
1015d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
1016fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
1017fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root}
1018fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1019508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Rootint VolumeManager::unmountObb(const char *fileName, bool force) {
1020fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    char mountPoint[255];
1021fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1022fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    char idHash[33];
1023fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    if (!asecHash(fileName, idHash, sizeof(idHash))) {
1024fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
1025fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        return -1;
1026fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
1027fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1028d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
1029d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1030d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName);
1031d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        return -1;
1032d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
1033fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1034fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
1035fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root}
1036fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1037fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Rootint VolumeManager::unmountLoopImage(const char *id, const char *idHash,
1038fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        const char *fileName, const char *mountPoint, bool force) {
10390586d54053ee00e6d6523d4f125282ccb9a24aabSan Mehat    if (!isMountpointMounted(mountPoint)) {
1040fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        SLOGE("Unmount request for %s when not mounted", id);
1041918e5f9f10b9c1ff929683743ffbf229027ce240Kenny Root        errno = ENOENT;
1042b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        return -1;
1043b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    }
104423969931fad6e993832208f099f6eea0f6f76eb5San Mehat
1045b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    int i, rc;
1046fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    for (i = 1; i <= UNMOUNT_RETRIES; i++) {
1047b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        rc = umount(mountPoint);
1048b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        if (!rc) {
1049b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            break;
1050a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        }
1051b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        if (rc && (errno == EINVAL || errno == ENOENT)) {
1052fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            SLOGI("Container %s unmounted OK", id);
1053b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            rc = 0;
1054b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            break;
1055a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        }
1056fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        SLOGW("%s unmount attempt %d failed (%s)",
10578c940ef7dbd423cadc92982b44a65ed1014389e2San Mehat              id, i, strerror(errno));
10588c940ef7dbd423cadc92982b44a65ed1014389e2San Mehat
10594ba8948dc16463053e21cda5744f519a555080d0San Mehat        int action = 0; // default is to just complain
10604ba8948dc16463053e21cda5744f519a555080d0San Mehat
10614ba8948dc16463053e21cda5744f519a555080d0San Mehat        if (force) {
1062fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            if (i > (UNMOUNT_RETRIES - 2))
10634ba8948dc16463053e21cda5744f519a555080d0San Mehat                action = 2; // SIGKILL
1064fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            else if (i > (UNMOUNT_RETRIES - 3))
10654ba8948dc16463053e21cda5744f519a555080d0San Mehat                action = 1; // SIGHUP
10664ba8948dc16463053e21cda5744f519a555080d0San Mehat        }
10678c940ef7dbd423cadc92982b44a65ed1014389e2San Mehat
1068586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        Process::killProcessesWithOpenFiles(mountPoint, action);
1069fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
1070b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    }
1071b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
1072b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    if (rc) {
10734ba8948dc16463053e21cda5744f519a555080d0San Mehat        errno = EBUSY;
107497ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
1075b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        return -1;
1076b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    }
1077b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
107812f4b89046b54de1bdc188b7057ba77d7566e573San Mehat    int retries = 10;
107912f4b89046b54de1bdc188b7057ba77d7566e573San Mehat
108012f4b89046b54de1bdc188b7057ba77d7566e573San Mehat    while(retries--) {
108112f4b89046b54de1bdc188b7057ba77d7566e573San Mehat        if (!rmdir(mountPoint)) {
108212f4b89046b54de1bdc188b7057ba77d7566e573San Mehat            break;
108312f4b89046b54de1bdc188b7057ba77d7566e573San Mehat        }
108412f4b89046b54de1bdc188b7057ba77d7566e573San Mehat
108597ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
1086fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
108712f4b89046b54de1bdc188b7057ba77d7566e573San Mehat    }
108812f4b89046b54de1bdc188b7057ba77d7566e573San Mehat
108912f4b89046b54de1bdc188b7057ba77d7566e573San Mehat    if (!retries) {
109097ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
1091f5c61980969a0b49bda37b5dc94ffe675ebd5a5aSan Mehat    }
109288705166ab82057090a070c6d4200c3d9db76f11San Mehat
109360dec16c5026d29a52791ad790860d247f47f8f2Paul Lawrence    for (i=1; i <= UNMOUNT_RETRIES; i++) {
109460dec16c5026d29a52791ad790860d247f47f8f2Paul Lawrence        if (Devmapper::destroy(idHash) && errno != ENXIO) {
109560dec16c5026d29a52791ad790860d247f47f8f2Paul Lawrence            SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
109660dec16c5026d29a52791ad790860d247f47f8f2Paul Lawrence            usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
109760dec16c5026d29a52791ad790860d247f47f8f2Paul Lawrence            continue;
109860dec16c5026d29a52791ad790860d247f47f8f2Paul Lawrence        } else {
109960dec16c5026d29a52791ad790860d247f47f8f2Paul Lawrence          break;
110060dec16c5026d29a52791ad790860d247f47f8f2Paul Lawrence        }
1101a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
1102a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
1103a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char loopDevice[255];
1104d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
1105a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        Loop::destroyByDevice(loopDevice);
1106d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    } else {
1107fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
1108a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
110988705166ab82057090a070c6d4200c3d9db76f11San Mehat
111088705166ab82057090a070c6d4200c3d9db76f11San Mehat    AsecIdCollection::iterator it;
111188705166ab82057090a070c6d4200c3d9db76f11San Mehat    for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
1112cbacf78eff70bd43bb899e164ec2ab409bc0904cKenny Root        ContainerData* cd = *it;
1113cbacf78eff70bd43bb899e164ec2ab409bc0904cKenny Root        if (!strcmp(cd->id, id)) {
111488705166ab82057090a070c6d4200c3d9db76f11San Mehat            free(*it);
111588705166ab82057090a070c6d4200c3d9db76f11San Mehat            mActiveContainers->erase(it);
111688705166ab82057090a070c6d4200c3d9db76f11San Mehat            break;
111788705166ab82057090a070c6d4200c3d9db76f11San Mehat        }
111888705166ab82057090a070c6d4200c3d9db76f11San Mehat    }
111988705166ab82057090a070c6d4200c3d9db76f11San Mehat    if (it == mActiveContainers->end()) {
112097ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGW("mActiveContainers is inconsistent!");
112188705166ab82057090a070c6d4200c3d9db76f11San Mehat    }
1122b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    return 0;
1123b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat}
1124b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
11254ba8948dc16463053e21cda5744f519a555080d0San Mehatint VolumeManager::destroyAsec(const char *id, bool force) {
1126b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    char asecFileName[255];
1127b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    char mountPoint[255];
1128b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
11290de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    if (!isLegalAsecId(id)) {
11300de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        SLOGE("destroyAsec: Invalid asec id \"%s\"", id);
11310de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        errno = EINVAL;
11320de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return -1;
11330de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
11340de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
1135344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1136344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Couldn't find ASEC %s", id);
1137344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
1138344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
1139344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1140d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
1141d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1142d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id);
1143d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        return -1;
1144d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
1145b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
11460586d54053ee00e6d6523d4f125282ccb9a24aabSan Mehat    if (isMountpointMounted(mountPoint)) {
1147d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        if (mDebug) {
114897ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat            SLOGD("Unmounting container before destroy");
1149d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        }
11504ba8948dc16463053e21cda5744f519a555080d0San Mehat        if (unmountAsec(id, force)) {
115197ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat            SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
11520586d54053ee00e6d6523d4f125282ccb9a24aabSan Mehat            return -1;
11530586d54053ee00e6d6523d4f125282ccb9a24aabSan Mehat        }
11540586d54053ee00e6d6523d4f125282ccb9a24aabSan Mehat    }
1155a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
11560586d54053ee00e6d6523d4f125282ccb9a24aabSan Mehat    if (unlink(asecFileName)) {
115797ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
11580586d54053ee00e6d6523d4f125282ccb9a24aabSan Mehat        return -1;
11590586d54053ee00e6d6523d4f125282ccb9a24aabSan Mehat    }
1160a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
1161d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (mDebug) {
116297ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGD("ASEC %s destroyed", id);
1163d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
1164a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    return 0;
1165a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat}
1166a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
11670de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich/*
11680de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich * Legal ASEC ids consist of alphanumeric characters, '-',
11690de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich * '_', or '.'. ".." is not allowed. The first or last character
11700de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich * of the ASEC id cannot be '.' (dot).
11710de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich */
11720de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevichbool VolumeManager::isLegalAsecId(const char *id) const {
11730de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    size_t i;
11740de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    size_t len = strlen(id);
11750de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
11760de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    if (len == 0) {
11770de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return false;
11780de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
11790de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    if ((id[0] == '.') || (id[len - 1] == '.')) {
11800de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return false;
11810de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
11820de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
11830de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    for (i = 0; i < len; i++) {
11840de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        if (id[i] == '.') {
11850de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich            // i=0 is guaranteed never to have a dot. See above.
11860de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich            if (id[i-1] == '.') return false;
11870de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich            continue;
11880de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        }
11890de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        if (id[i] == '_' || id[i] == '-') continue;
11900de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        if (id[i] >= 'a' && id[i] <= 'z') continue;
11910de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        if (id[i] >= 'A' && id[i] <= 'Z') continue;
11920de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        if (id[i] >= '0' && id[i] <= '9') continue;
11930de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return false;
11940de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
11950de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
11960de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    return true;
11970de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich}
11980de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
1199344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Rootbool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
1200344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    int dirfd = open(dir, O_DIRECTORY);
1201344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (dirfd < 0) {
1202344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
1203344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
1204344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
1205344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1206344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    bool ret = false;
1207344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1208344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (!faccessat(dirfd, asecName, F_OK, AT_SYMLINK_NOFOLLOW)) {
1209344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        ret = true;
1210344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
1211344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1212344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    close(dirfd);
1213344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1214344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    return ret;
1215344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root}
1216344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1217344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Rootint VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
1218344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        const char **directory) const {
1219344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    int dirfd, fd;
1220344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    const int idLen = strlen(id);
1221344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    char *asecName;
1222344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
12230de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    if (!isLegalAsecId(id)) {
12240de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        SLOGE("findAsec: Invalid asec id \"%s\"", id);
12250de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        errno = EINVAL;
12260de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return -1;
12270de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
12280de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
1229344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (asprintf(&asecName, "%s.asec", id) < 0) {
1230344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Couldn't allocate string to write ASEC name");
1231344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
1232344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
1233344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1234344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    const char *dir;
1235344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (isAsecInDirectory(Volume::SEC_ASECDIR_INT, asecName)) {
1236344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        dir = Volume::SEC_ASECDIR_INT;
1237344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    } else if (isAsecInDirectory(Volume::SEC_ASECDIR_EXT, asecName)) {
1238344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        dir = Volume::SEC_ASECDIR_EXT;
1239344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    } else {
1240344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        free(asecName);
1241344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
1242344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
1243344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1244344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (directory != NULL) {
1245344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        *directory = dir;
1246344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
1247344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1248344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (asecPath != NULL) {
1249344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
1250d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        if ((written < 0) || (size_t(written) >= asecPathLen)) {
1251d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig            SLOGE("findAsec failed for %s: couldn't construct ASEC path", id);
1252344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            free(asecName);
1253344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            return -1;
1254344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        }
1255344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
1256344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1257344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    free(asecName);
1258344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    return 0;
1259344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root}
1260344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
126143ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkeyint VolumeManager::mountAsec(const char *id, const char *key, int ownerUid, bool readOnly) {
1262a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char asecFileName[255];
1263a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char mountPoint[255];
1264a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
12650de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    if (!isLegalAsecId(id)) {
12660de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        SLOGE("mountAsec: Invalid asec id \"%s\"", id);
12670de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        errno = EINVAL;
12680de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich        return -1;
12690de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich    }
12700de7c61102611ccd5df1ca48cb733bf037512c6bNick Kralevich
1271344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1272344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        SLOGE("Couldn't find ASEC %s", id);
1273344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return -1;
1274344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
1275344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1276d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
1277d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
127859846b654e8b4a22a1be11cd21d6c5b81375abd2Colin Cross        SLOGE("ASEC mount failed for %s: couldn't construct mountpoint", id);
1279d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        return -1;
1280d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
1281a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
1282a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    if (isMountpointMounted(mountPoint)) {
128397ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("ASEC %s already mounted", id);
1284a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        errno = EBUSY;
1285a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        return -1;
1286a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
1287a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
1288d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    char idHash[33];
1289d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (!asecHash(id, idHash, sizeof(idHash))) {
129097ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
1291d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        return -1;
1292d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
12937b18a7b36f61574c0f0bdde0a7409dc36676fa12Kenny Root
1294a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char loopDevice[255];
1295fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug))
1296fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
1297b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
1298b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    char dmDevice[255];
1299b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    bool cleanupDm = false;
1300fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    int fd;
1301fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    unsigned int nr_sec = 0;
1302fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    struct asec_superblock sb;
1303344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1304344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
1305fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        return -1;
1306fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    }
1307fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat
1308d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (mDebug) {
130997ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
1310d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
1311fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
131297ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
1313fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        Loop::destroyByDevice(loopDevice);
1314fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        errno = EMEDIUMTYPE;
1315fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        return -1;
1316fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    }
1317fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    nr_sec--; // We don't want the devmapping to extend onto our superblock
1318fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat
1319fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash , nr_sec, &cleanupDm, mDebug)) {
1320fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        Loop::destroyByDevice(loopDevice);
1321fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
1322a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
1323a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
1324344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (mkdir(mountPoint, 0000)) {
1325b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        if (errno != EEXIST) {
132697ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat            SLOGE("Mountpoint creation failed (%s)", strerror(errno));
1327b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            if (cleanupDm) {
1328d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                Devmapper::destroy(idHash);
1329b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            }
1330b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            Loop::destroyByDevice(loopDevice);
1331b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            return -1;
1332b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        }
1333a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
1334a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
1335cdc2a1c83575a349ee44035de8c3b38b8b401003Kenny Root    /*
1336fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg     * Wait for the device mapper node to be created.
1337cdc2a1c83575a349ee44035de8c3b38b8b401003Kenny Root     */
1338fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    waitForDevMapper(dmDevice);
1339cdc2a1c83575a349ee44035de8c3b38b8b401003Kenny Root
1340344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    int result;
1341344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
134243ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        result = Ext4::doMount(dmDevice, mountPoint, readOnly, false, readOnly);
1343344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    } else {
134443ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        result = Fat::doMount(dmDevice, mountPoint, readOnly, false, readOnly, ownerUid, 0, 0222, false);
1345344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
1346344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
1347344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (result) {
134897ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("ASEC mount failed (%s)", strerror(errno));
1349b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        if (cleanupDm) {
1350d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            Devmapper::destroy(idHash);
1351b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        }
1352b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        Loop::destroyByDevice(loopDevice);
1353a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        return -1;
1354a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
1355a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
1356cbacf78eff70bd43bb899e164ec2ab409bc0904cKenny Root    mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
1357d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (mDebug) {
135897ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGD("ASEC %s mounted", id);
1359d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
1360a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    return 0;
1361a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat}
1362a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
136393ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny RootVolume* VolumeManager::getVolumeForFile(const char *fileName) {
136493ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root    VolumeCollection::iterator i;
136593ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root
136693ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root    for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1367ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        const char* mountPoint = (*i)->getFuseMountpoint();
136893ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root        if (!strncmp(fileName, mountPoint, strlen(mountPoint))) {
136993ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root            return *i;
137093ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root        }
137193ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root    }
137293ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root
137393ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root    return NULL;
137493ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root}
137593ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root
1376fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root/**
1377fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root * Mounts an image file <code>img</code>.
1378fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root */
13796947904a76b69a1db20a3ddd30c0bcd281922fdeJeff Sharkeyint VolumeManager::mountObb(const char *img, const char *key, int ownerGid) {
1380fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    char mountPoint[255];
1381fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1382fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    char idHash[33];
1383fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    if (!asecHash(img, idHash, sizeof(idHash))) {
1384fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
1385fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        return -1;
1386fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
1387fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1388d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
1389d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
139059846b654e8b4a22a1be11cd21d6c5b81375abd2Colin Cross        SLOGE("OBB mount failed for %s: couldn't construct mountpoint", img);
1391d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        return -1;
1392d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
1393fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1394fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    if (isMountpointMounted(mountPoint)) {
1395fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        SLOGE("Image %s already mounted", img);
1396fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        errno = EBUSY;
1397fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        return -1;
1398fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
1399fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1400fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    char loopDevice[255];
1401fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (setupLoopDevice(loopDevice, sizeof(loopDevice), img, idHash, mDebug))
1402fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
1403fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1404fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    char dmDevice[255];
1405fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    bool cleanupDm = false;
1406fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    int fd;
1407fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    unsigned int nr_sec = 0;
1408fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1409fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    if ((fd = open(loopDevice, O_RDWR)) < 0) {
1410fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        SLOGE("Failed to open loopdevice (%s)", strerror(errno));
1411fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        Loop::destroyByDevice(loopDevice);
1412fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        return -1;
1413fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
1414fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1415fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
1416fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        SLOGE("Failed to get loop size (%s)", strerror(errno));
1417fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        Loop::destroyByDevice(loopDevice);
1418fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        close(fd);
1419fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        return -1;
1420fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
1421fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1422fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    close(fd);
1423fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1424fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    if (setupDevMapperDevice(dmDevice, sizeof(loopDevice), loopDevice, img,key, idHash , nr_sec, &cleanupDm, mDebug)) {
1425fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        Loop::destroyByDevice(loopDevice);
1426fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        return -1;
1427fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
1428fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1429fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    if (mkdir(mountPoint, 0755)) {
1430fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        if (errno != EEXIST) {
1431fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            SLOGE("Mountpoint creation failed (%s)", strerror(errno));
1432fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            if (cleanupDm) {
1433fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root                Devmapper::destroy(idHash);
1434fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            }
1435fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            Loop::destroyByDevice(loopDevice);
1436fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            return -1;
1437fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        }
1438fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
1439fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
14406947904a76b69a1db20a3ddd30c0bcd281922fdeJeff Sharkey    if (Fat::doMount(dmDevice, mountPoint, true, false, true, 0, ownerGid,
1441fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root                     0227, false)) {
1442fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        SLOGE("Image mount failed (%s)", strerror(errno));
1443fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        if (cleanupDm) {
1444fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            Devmapper::destroy(idHash);
1445fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        }
1446fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        Loop::destroyByDevice(loopDevice);
1447fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        return -1;
1448fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
1449fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
1450cbacf78eff70bd43bb899e164ec2ab409bc0904cKenny Root    mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
1451fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    if (mDebug) {
1452fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        SLOGD("Image %s mounted", img);
1453fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
1454fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    return 0;
1455fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root}
1456fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
145749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehatint VolumeManager::mountVolume(const char *label) {
145849e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    Volume *v = lookupVolume(label);
145949e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
146049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    if (!v) {
146149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        errno = ENOENT;
146249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        return -1;
146349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    }
146449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
1465a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    return v->mountVol();
1466a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat}
1467a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1468508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Rootint VolumeManager::listMountedObbs(SocketClient* cli) {
1469508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    char device[256];
1470508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    char mount_path[256];
1471508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    char rest[256];
1472508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    FILE *fp;
1473508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    char line[1024];
1474508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
1475508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    if (!(fp = fopen("/proc/mounts", "r"))) {
1476508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1477508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        return -1;
1478508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    }
1479508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
1480508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    // Create a string to compare against that has a trailing slash
148193ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root    int loopDirLen = strlen(Volume::LOOPDIR);
1482508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    char loopDir[loopDirLen + 2];
1483508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    strcpy(loopDir, Volume::LOOPDIR);
1484508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    loopDir[loopDirLen++] = '/';
1485508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    loopDir[loopDirLen] = '\0';
1486508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
1487508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    while(fgets(line, sizeof(line), fp)) {
1488508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        line[strlen(line)-1] = '\0';
1489508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
1490508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        /*
1491508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root         * Should look like:
1492508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root         * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
1493508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root         */
1494508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1495508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
1496508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        if (!strncmp(mount_path, loopDir, loopDirLen)) {
1497508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            int fd = open(device, O_RDONLY);
1498508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            if (fd >= 0) {
1499508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root                struct loop_info64 li;
1500508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root                if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
1501508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root                    cli->sendMsg(ResponseCode::AsecListResult,
1502508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root                            (const char*) li.lo_file_name, false);
1503508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root                }
1504508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root                close(fd);
1505508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            }
1506508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        }
1507508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    }
1508508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
1509508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    fclose(fp);
1510508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    return 0;
1511508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root}
1512508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
1513eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehatint VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
1514eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    Volume *v = lookupVolume(label);
1515eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat
1516eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    if (!v) {
1517eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        errno = ENOENT;
1518eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        return -1;
1519eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    }
1520eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat
1521eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    if (strcmp(method, "ums")) {
1522eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        errno = ENOSYS;
1523eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        return -1;
1524eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    }
1525eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat
1526eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    if (v->getState() != Volume::State_Shared) {
1527eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        *enabled = false;
1528b9aed74b146beb7499ebc5775e8ae179d16900efSan Mehat    } else {
1529b9aed74b146beb7499ebc5775e8ae179d16900efSan Mehat        *enabled = true;
1530eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    }
1531eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    return 0;
1532eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat}
1533eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat
1534a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehatint VolumeManager::shareVolume(const char *label, const char *method) {
1535a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    Volume *v = lookupVolume(label);
1536a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1537a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (!v) {
1538a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = ENOENT;
1539a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
1540a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
1541a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1542a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    /*
1543a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat     * Eventually, we'll want to support additional share back-ends,
1544a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat     * some of which may work while the media is mounted. For now,
1545a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat     * we just support UMS
1546a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat     */
1547a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (strcmp(method, "ums")) {
1548a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = ENOSYS;
1549a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
1550a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
1551a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1552a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (v->getState() == Volume::State_NoMedia) {
1553a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = ENODEV;
1554a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
1555a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
1556a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
155749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    if (v->getState() != Volume::State_Idle) {
1558a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        // You need to unmount manually befoe sharing
155949e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        errno = EBUSY;
156049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        return -1;
156149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    }
156249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
15633b17005083be230509480ea65ae67c237142fadaKen Sumrall    if (mVolManagerDisabled) {
15643b17005083be230509480ea65ae67c237142fadaKen Sumrall        errno = EBUSY;
15653b17005083be230509480ea65ae67c237142fadaKen Sumrall        return -1;
15663b17005083be230509480ea65ae67c237142fadaKen Sumrall    }
15673b17005083be230509480ea65ae67c237142fadaKen Sumrall
15682dfe297ec47559dbe2297a72bea71cf515c03797Mike Lockwood    dev_t d = v->getShareDevice();
1569a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
1570a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        // This volume does not support raw disk access
1571a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = EINVAL;
1572a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
1573a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
1574a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1575a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    int fd;
1576a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    char nodepath[255];
1577d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    int written = snprintf(nodepath,
1578a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat             sizeof(nodepath), "/dev/block/vold/%d:%d",
1579346c5b20cbbced7edacf240015c4a89e5b2ca44fColin Cross             major(d), minor(d));
1580a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1581d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    if ((written < 0) || (size_t(written) >= sizeof(nodepath))) {
1582d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        SLOGE("shareVolume failed: couldn't construct nodepath");
1583d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig        return -1;
1584d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig    }
1585d1c226fce359e6de2b7334bf202c8f97af9fb9e0rpcraig
158697f2fc110b2ace7914671c2f5852379bd78922e4Mike Lockwood    if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
158797ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
1588a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
1589a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
1590a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1591a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (write(fd, nodepath, strlen(nodepath)) < 0) {
159297ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
1593a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        close(fd);
1594a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
1595a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
1596a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1597a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    close(fd);
1598a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    v->handleVolumeShared();
1599a28056b38275003895ff5d9576681aca01544822Mike Lockwood    if (mUmsSharingCount++ == 0) {
1600a28056b38275003895ff5d9576681aca01544822Mike Lockwood        FILE* fp;
1601a28056b38275003895ff5d9576681aca01544822Mike Lockwood        mSavedDirtyRatio = -1; // in case we fail
1602a28056b38275003895ff5d9576681aca01544822Mike Lockwood        if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1603a28056b38275003895ff5d9576681aca01544822Mike Lockwood            char line[16];
1604a28056b38275003895ff5d9576681aca01544822Mike Lockwood            if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
1605a28056b38275003895ff5d9576681aca01544822Mike Lockwood                fprintf(fp, "%d\n", mUmsDirtyRatio);
1606a28056b38275003895ff5d9576681aca01544822Mike Lockwood            } else {
1607a28056b38275003895ff5d9576681aca01544822Mike Lockwood                SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
1608a28056b38275003895ff5d9576681aca01544822Mike Lockwood            }
1609a28056b38275003895ff5d9576681aca01544822Mike Lockwood            fclose(fp);
1610a28056b38275003895ff5d9576681aca01544822Mike Lockwood        } else {
1611a28056b38275003895ff5d9576681aca01544822Mike Lockwood            SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1612a28056b38275003895ff5d9576681aca01544822Mike Lockwood        }
1613a28056b38275003895ff5d9576681aca01544822Mike Lockwood    }
1614a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    return 0;
1615a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat}
1616a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1617a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehatint VolumeManager::unshareVolume(const char *label, const char *method) {
1618a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    Volume *v = lookupVolume(label);
1619a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1620a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (!v) {
1621a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = ENOENT;
1622a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
1623a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
1624a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1625a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (strcmp(method, "ums")) {
1626a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = ENOSYS;
1627a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
1628a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
1629a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1630a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (v->getState() != Volume::State_Shared) {
1631a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = EINVAL;
1632a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
1633a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
1634a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1635a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    int fd;
163697f2fc110b2ace7914671c2f5852379bd78922e4Mike Lockwood    if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
163797ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
1638a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
1639a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
1640a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1641a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    char ch = 0;
1642a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (write(fd, &ch, 1) < 0) {
164397ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
1644a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        close(fd);
1645a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
1646a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
1647a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1648a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    close(fd);
1649a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    v->handleVolumeUnshared();
1650a28056b38275003895ff5d9576681aca01544822Mike Lockwood    if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1651a28056b38275003895ff5d9576681aca01544822Mike Lockwood        FILE* fp;
1652a28056b38275003895ff5d9576681aca01544822Mike Lockwood        if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1653a28056b38275003895ff5d9576681aca01544822Mike Lockwood            fprintf(fp, "%d\n", mSavedDirtyRatio);
1654a28056b38275003895ff5d9576681aca01544822Mike Lockwood            fclose(fp);
1655a28056b38275003895ff5d9576681aca01544822Mike Lockwood        } else {
1656a28056b38275003895ff5d9576681aca01544822Mike Lockwood            SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1657a28056b38275003895ff5d9576681aca01544822Mike Lockwood        }
1658a28056b38275003895ff5d9576681aca01544822Mike Lockwood        mSavedDirtyRatio = -1;
1659a28056b38275003895ff5d9576681aca01544822Mike Lockwood    }
1660a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    return 0;
166149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat}
166249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
16633b17005083be230509480ea65ae67c237142fadaKen Sumrallextern "C" int vold_disableVol(const char *label) {
166429d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    VolumeManager *vm = VolumeManager::Instance();
16653b17005083be230509480ea65ae67c237142fadaKen Sumrall    vm->disableVolumeManager();
16663b17005083be230509480ea65ae67c237142fadaKen Sumrall    vm->unshareVolume(label, "ums");
16670b8b59719357fb80c330442787f7d5b1e332263bKen Sumrall    return vm->unmountVolume(label, true, false);
166829d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall}
166929d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
167029d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrallextern "C" int vold_getNumDirectVolumes(void) {
167129d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    VolumeManager *vm = VolumeManager::Instance();
167229d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    return vm->getNumDirectVolumes();
167329d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall}
167429d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
167529d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrallint VolumeManager::getNumDirectVolumes(void) {
167629d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    VolumeCollection::iterator i;
167729d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    int n=0;
167829d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
167929d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
168029d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        if ((*i)->getShareDevice() != (dev_t)0) {
168129d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall            n++;
168229d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        }
168329d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    }
168429d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    return n;
168529d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall}
168629d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
168729d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrallextern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
168829d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    VolumeManager *vm = VolumeManager::Instance();
168929d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    return vm->getDirectVolumeList(vol_list);
169029d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall}
169129d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
169229d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrallint VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
169329d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    VolumeCollection::iterator i;
169429d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    int n=0;
169529d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    dev_t d;
169629d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
169729d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
169829d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        if ((d=(*i)->getShareDevice()) != (dev_t)0) {
169929d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall            (*i)->getVolInfo(&vol_list[n]);
170029d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall            snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev),
1701346c5b20cbbced7edacf240015c4a89e5b2ca44fColin Cross                     "/dev/block/vold/%d:%d", major(d), minor(d));
170229d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall            n++;
170329d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        }
170429d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    }
170529d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
170629d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    return 0;
170729d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall}
170829d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
17090b8b59719357fb80c330442787f7d5b1e332263bKen Sumrallint VolumeManager::unmountVolume(const char *label, bool force, bool revert) {
171049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    Volume *v = lookupVolume(label);
171149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
171249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    if (!v) {
171349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        errno = ENOENT;
171449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        return -1;
171549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    }
171649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
1717a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (v->getState() == Volume::State_NoMedia) {
1718a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = ENODEV;
1719a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
1720a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
1721a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
172249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    if (v->getState() != Volume::State_Mounted) {
172397ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
1724a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat             v->getState());
172549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        errno = EBUSY;
1726319b1043bbbd410aa2d572d88b5936f26072d026Ken Sumrall        return UNMOUNT_NOT_MOUNTED_ERR;
172749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    }
172849e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
17291a06edaf4db4e9c520624bcc06e0e13ee470d90eSan Mehat    cleanupAsec(v, force);
173088705166ab82057090a070c6d4200c3d9db76f11San Mehat
17310b8b59719357fb80c330442787f7d5b1e332263bKen Sumrall    return v->unmountVol(force, revert);
173249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat}
173349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
1734425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrallextern "C" int vold_unmountAllAsecs(void) {
1735425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    int rc;
1736425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall
1737425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    VolumeManager *vm = VolumeManager::Instance();
1738425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    rc = vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT);
1739425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    if (vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_INT)) {
1740425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall        rc = -1;
1741425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    }
1742425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    return rc;
1743425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall}
1744425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall
1745425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall#define ID_BUF_LEN 256
1746425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall#define ASEC_SUFFIX ".asec"
1747425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall#define ASEC_SUFFIX_LEN (sizeof(ASEC_SUFFIX) - 1)
1748425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrallint VolumeManager::unmountAllAsecsInDir(const char *directory) {
1749425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    DIR *d = opendir(directory);
1750425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    int rc = 0;
1751425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall
1752425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    if (!d) {
1753425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall        SLOGE("Could not open asec dir %s", directory);
1754425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall        return -1;
1755425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    }
1756425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall
1757425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    size_t dirent_len = offsetof(struct dirent, d_name) +
17588c480f73eed963eeca9b7df3e4c4543c6e43b0d7Elliott Hughes            fpathconf(dirfd(d), _PC_NAME_MAX) + 1;
1759425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall
1760425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    struct dirent *dent = (struct dirent *) malloc(dirent_len);
1761425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    if (dent == NULL) {
1762425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall        SLOGE("Failed to allocate memory for asec dir");
1763425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall        return -1;
1764425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    }
1765425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall
1766425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    struct dirent *result;
1767425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    while (!readdir_r(d, dent, &result) && result != NULL) {
1768425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall        if (dent->d_name[0] == '.')
1769425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall            continue;
1770425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall        if (dent->d_type != DT_REG)
1771425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall            continue;
1772425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall        size_t name_len = strlen(dent->d_name);
1773425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall        if (name_len > 5 && name_len < (ID_BUF_LEN + ASEC_SUFFIX_LEN - 1) &&
1774425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall                !strcmp(&dent->d_name[name_len - 5], ASEC_SUFFIX)) {
1775425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall            char id[ID_BUF_LEN];
1776425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall            strlcpy(id, dent->d_name, name_len - 4);
1777425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall            if (unmountAsec(id, true)) {
1778425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall                /* Register the error, but try to unmount more asecs */
1779425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall                rc = -1;
1780425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall            }
1781425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall        }
1782425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    }
1783425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    closedir(d);
1784425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall
1785425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    free(dent);
1786425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall
1787425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall    return rc;
1788425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall}
1789425524dba1552ab3d2ad39e205e65d0a2af997f2Ken Sumrall
1790a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat/*
1791a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat * Looks up a volume by it's label or mount-point
1792a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat */
179349e2bce5b74129c26a35e25d4693cbfe98c4688eSan MehatVolume *VolumeManager::lookupVolume(const char *label) {
179449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    VolumeCollection::iterator i;
179549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
179649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1797a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        if (label[0] == '/') {
1798ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey            if (!strcmp(label, (*i)->getFuseMountpoint()))
1799a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat                return (*i);
1800a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        } else {
1801a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat            if (!strcmp(label, (*i)->getLabel()))
1802a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat                return (*i);
1803a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        }
180449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    }
180549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    return NULL;
180649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat}
1807a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
1808a19b250bd273455933ca3502cf2c2e0a803aff77San Mehatbool VolumeManager::isMountpointMounted(const char *mp)
1809a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat{
1810a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char device[256];
1811a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char mount_path[256];
1812a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char rest[256];
1813a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    FILE *fp;
1814a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    char line[1024];
1815a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
1816a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    if (!(fp = fopen("/proc/mounts", "r"))) {
181797ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1818a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        return false;
1819a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
1820a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
1821a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    while(fgets(line, sizeof(line), fp)) {
1822a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        line[strlen(line)-1] = '\0';
1823a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1824a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        if (!strcmp(mount_path, mp)) {
1825a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat            fclose(fp);
1826a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat            return true;
1827a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        }
1828a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
1829a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
1830a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    fclose(fp);
1831a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    return false;
1832a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat}
1833a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
18341a06edaf4db4e9c520624bcc06e0e13ee470d90eSan Mehatint VolumeManager::cleanupAsec(Volume *v, bool force) {
18358c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey    int rc = 0;
18368c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey
18378c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey    char asecFileName[255];
18388c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey
18398c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey    AsecIdCollection removeAsec;
18408c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey    AsecIdCollection removeObb;
184193ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root
184293ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root    for (AsecIdCollection::iterator it = mActiveContainers->begin(); it != mActiveContainers->end();
184393ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root            ++it) {
1844cbacf78eff70bd43bb899e164ec2ab409bc0904cKenny Root        ContainerData* cd = *it;
184593ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root
1846cbacf78eff70bd43bb899e164ec2ab409bc0904cKenny Root        if (cd->type == ASEC) {
18478c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey            if (findAsec(cd->id, asecFileName, sizeof(asecFileName))) {
18488c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey                SLOGE("Couldn't find ASEC %s; cleaning up", cd->id);
18498c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey                removeAsec.push_back(cd);
18508c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey            } else {
18518c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey                SLOGD("Found ASEC at path %s", asecFileName);
18528c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey                if (!strncmp(asecFileName, Volume::SEC_ASECDIR_EXT,
18538c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey                        strlen(Volume::SEC_ASECDIR_EXT))) {
18548c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey                    removeAsec.push_back(cd);
18558c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey                }
18568c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey            }
1857cbacf78eff70bd43bb899e164ec2ab409bc0904cKenny Root        } else if (cd->type == OBB) {
185893ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root            if (v == getVolumeForFile(cd->id)) {
18598c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey                removeObb.push_back(cd);
1860cbacf78eff70bd43bb899e164ec2ab409bc0904cKenny Root            }
1861cbacf78eff70bd43bb899e164ec2ab409bc0904cKenny Root        } else {
1862cbacf78eff70bd43bb899e164ec2ab409bc0904cKenny Root            SLOGE("Unknown container type %d!", cd->type);
18631a06edaf4db4e9c520624bcc06e0e13ee470d90eSan Mehat        }
18641a06edaf4db4e9c520624bcc06e0e13ee470d90eSan Mehat    }
186593ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root
18668c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey    for (AsecIdCollection::iterator it = removeAsec.begin(); it != removeAsec.end(); ++it) {
18678c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey        ContainerData *cd = *it;
18688c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey        SLOGI("Unmounting ASEC %s (dependent on %s)", cd->id, v->getLabel());
18698c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey        if (unmountAsec(cd->id, force)) {
18708c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey            SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
18718c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey            rc = -1;
18728c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey        }
18738c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey    }
18748c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey
18758c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey    for (AsecIdCollection::iterator it = removeObb.begin(); it != removeObb.end(); ++it) {
187693ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root        ContainerData *cd = *it;
18778c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey        SLOGI("Unmounting OBB %s (dependent on %s)", cd->id, v->getLabel());
187893ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root        if (unmountObb(cd->id, force)) {
187993ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root            SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
188093ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root            rc = -1;
188193ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root        }
188293ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root    }
188393ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root
188493ecb38daded7583a4a61f4f22519bb7a8a8c154Kenny Root    return rc;
18851a06edaf4db4e9c520624bcc06e0e13ee470d90eSan Mehat}
18861a06edaf4db4e9c520624bcc06e0e13ee470d90eSan Mehat
188771ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkeyint VolumeManager::mkdirs(char* path) {
188827cfee3fa4e44d3a542312938df12cadfad3425eCylen Yao    // Require that path lives under a volume we manage and is mounted
188971ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey    const char* emulated_source = getenv("EMULATED_STORAGE_SOURCE");
189071ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey    const char* root = NULL;
18915ab02e787a05eda1d3382654d5496d6c763c2474Marco Nelissen    if (emulated_source && !strncmp(path, emulated_source, strlen(emulated_source))) {
189271ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey        root = emulated_source;
189371ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey    } else {
189471ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey        Volume* vol = getVolumeForFile(path);
189527cfee3fa4e44d3a542312938df12cadfad3425eCylen Yao        if (vol && vol->getState() == Volume::State_Mounted) {
189671ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey            root = vol->getMountpoint();
189771ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey        }
189871ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey    }
189971ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey
190071ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey    if (!root) {
190127cfee3fa4e44d3a542312938df12cadfad3425eCylen Yao        SLOGE("Failed to find mounted volume for %s", path);
190271ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey        return -EINVAL;
190371ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey    }
190471ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey
190571ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey    /* fs_mkdirs() does symlink checking and relative path enforcement */
190671ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey    return fs_mkdirs(path, 0700);
190771ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey}
1908