Devmapper.cpp revision d9a4e358614a0c5f60cc76c0636ee4bb02004a32
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <fcntl.h>
19#include <unistd.h>
20#include <errno.h>
21#include <string.h>
22
23#include <sys/types.h>
24#include <sys/ioctl.h>
25#include <sys/stat.h>
26
27#include <linux/kdev_t.h>
28
29#define LOG_TAG "Vold"
30
31#include <cutils/log.h>
32
33#include <sysutils/SocketClient.h>
34
35#include "Devmapper.h"
36
37int Devmapper::dumpState(SocketClient *c) {
38
39    char *buffer = (char *) malloc(1024 * 64);
40    if (!buffer) {
41        LOGE("Error allocating memory (%s)", strerror(errno));
42        return -1;
43    }
44    memset(buffer, 0, (1024 * 64));
45
46    char *buffer2 = (char *) malloc(4096);
47    if (!buffer2) {
48        LOGE("Error allocating memory (%s)", strerror(errno));
49        free(buffer);
50        return -1;
51    }
52
53    int fd;
54    if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
55        LOGE("Error opening devmapper (%s)", strerror(errno));
56        free(buffer);
57        free(buffer2);
58        return -1;
59    }
60
61    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
62    ioctlInit(io, (1024 * 64), NULL, 0);
63
64    if (ioctl(fd, DM_LIST_DEVICES, io)) {
65        LOGE("DM_LIST_DEVICES ioctl failed (%s)", strerror(errno));
66        free(buffer);
67        free(buffer2);
68        close(fd);
69        return -1;
70    }
71
72    struct dm_name_list *n = (struct dm_name_list *) (((char *) buffer) + io->data_start);
73    if (!n->dev) {
74        free(buffer);
75        free(buffer2);
76        close(fd);
77        return 0;
78    }
79
80    unsigned nxt = 0;
81    do {
82        n = (struct dm_name_list *) (((char *) n) + nxt);
83
84        memset(buffer2, 0, 4096);
85        struct dm_ioctl *io2 = (struct dm_ioctl *) buffer2;
86        ioctlInit(io2, 4096, n->name, 0);
87        if (ioctl(fd, DM_DEV_STATUS, io2)) {
88            if (errno != ENXIO) {
89                LOGE("DM_DEV_STATUS ioctl failed (%s)", strerror(errno));
90            }
91            io2 = NULL;
92        }
93
94        char *tmp;
95        if (!io2) {
96            asprintf(&tmp, "%s %llu:%llu (no status available)", n->name, MAJOR(n->dev), MINOR(n->dev));
97        } else {
98            asprintf(&tmp, "%s %llu:%llu %d %d 0x%.8x %llu:%llu", n->name, MAJOR(n->dev),
99                    MINOR(n->dev), io2->target_count, io2->open_count, io2->flags, MAJOR(io2->dev),
100                            MINOR(io2->dev));
101        }
102        c->sendMsg(0, tmp, false);
103        free(tmp);
104        nxt = n->next;
105    } while (nxt);
106
107    free(buffer);
108    free(buffer2);
109    close(fd);
110    return 0;
111}
112
113void Devmapper::ioctlInit(struct dm_ioctl *io, size_t dataSize,
114                          const char *name, unsigned flags) {
115    memset(io, 0, dataSize);
116    io->data_size = dataSize;
117    io->data_start = sizeof(struct dm_ioctl);
118    io->version[0] = 4;
119    io->version[1] = 0;
120    io->version[2] = 0;
121    io->flags = flags;
122    if (name) {
123        strncpy(io->name, name, sizeof(io->name));
124    }
125}
126
127int Devmapper::lookupActive(const char *name, char *ubuffer, size_t len) {
128    char *buffer = (char *) malloc(4096);
129    if (!buffer) {
130        LOGE("Error allocating memory (%s)", strerror(errno));
131        return -1;
132    }
133
134    int fd;
135    if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
136        LOGE("Error opening devmapper (%s)", strerror(errno));
137        free(buffer);
138        return -1;
139    }
140
141    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
142
143    ioctlInit(io, 4096, name, 0);
144    if (ioctl(fd, DM_DEV_STATUS, io)) {
145        if (errno != ENXIO) {
146            LOGE("DM_DEV_STATUS ioctl failed for lookup (%s)", strerror(errno));
147        }
148        free(buffer);
149        close(fd);
150        return -1;
151    }
152    close(fd);
153
154    unsigned minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
155    free(buffer);
156    snprintf(ubuffer, len, "/dev/block/dm-%u", minor);
157    return 0;
158}
159
160int Devmapper::create(const char *name, const char *loopFile, const char *key,
161                      unsigned int numSectors, char *ubuffer, size_t len) {
162    char *buffer = (char *) malloc(4096);
163    if (!buffer) {
164        LOGE("Error allocating memory (%s)", strerror(errno));
165        return -1;
166    }
167
168    int fd;
169    if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
170        LOGE("Error opening devmapper (%s)", strerror(errno));
171        free(buffer);
172        return -1;
173    }
174
175    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
176
177    // Create the DM device
178    ioctlInit(io, 4096, name, 0);
179
180    if (ioctl(fd, DM_DEV_CREATE, io)) {
181        LOGE("Error creating device mapping (%s)", strerror(errno));
182        free(buffer);
183        close(fd);
184        return -1;
185    }
186
187    // Set the legacy geometry
188    ioctlInit(io, 4096, name, 0);
189
190    char *geoParams = buffer + sizeof(struct dm_ioctl);
191    // bps=512 spc=8 res=32 nft=2 sec=8190 mid=0xf0 spt=63 hds=64 hid=0 bspf=8 rdcl=2 infs=1 bkbs=2
192    strcpy(geoParams, "0 64 63 0");
193    geoParams += strlen(geoParams) + 1;
194    geoParams = (char *) _align(geoParams, 8);
195    if (ioctl(fd, DM_DEV_SET_GEOMETRY, io)) {
196        LOGE("Error setting device geometry (%s)", strerror(errno));
197        free(buffer);
198        close(fd);
199        return -1;
200    }
201
202    // Retrieve the device number we were allocated
203    ioctlInit(io, 4096, name, 0);
204    if (ioctl(fd, DM_DEV_STATUS, io)) {
205        LOGE("Error retrieving devmapper status (%s)", strerror(errno));
206        free(buffer);
207        close(fd);
208        return -1;
209    }
210
211    unsigned minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
212    snprintf(ubuffer, len, "/dev/block/dm-%u", minor);
213
214    // Load the table
215    struct dm_target_spec *tgt;
216    tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
217
218    ioctlInit(io, 4096, name, DM_STATUS_TABLE_FLAG);
219    io->target_count = 1;
220    tgt->status = 0;
221
222    tgt->sector_start = 0;
223    tgt->length = numSectors;
224
225    strcpy(tgt->target_type, "crypt");
226
227    char *cryptParams = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
228    sprintf(cryptParams, "twofish %s 0 %s 0", key, loopFile);
229    cryptParams += strlen(cryptParams) + 1;
230    cryptParams = (char *) _align(cryptParams, 8);
231    tgt->next = cryptParams - buffer;
232
233    if (ioctl(fd, DM_TABLE_LOAD, io)) {
234        LOGE("Error loading mapping table (%s)", strerror(errno));
235        free(buffer);
236        close(fd);
237        return -1;
238    }
239
240    // Resume the new table
241    ioctlInit(io, 4096, name, 0);
242
243    if (ioctl(fd, DM_DEV_SUSPEND, io)) {
244        LOGE("Error Resuming (%s)", strerror(errno));
245        free(buffer);
246        close(fd);
247        return -1;
248    }
249
250    free(buffer);
251
252    close(fd);
253    return 0;
254}
255
256int Devmapper::destroy(const char *name) {
257    char *buffer = (char *) malloc(4096);
258    if (!buffer) {
259        LOGE("Error allocating memory (%s)", strerror(errno));
260        return -1;
261    }
262
263    int fd;
264    if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
265        LOGE("Error opening devmapper (%s)", strerror(errno));
266        free(buffer);
267        return -1;
268    }
269
270    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
271
272    // Create the DM device
273    ioctlInit(io, 4096, name, 0);
274
275    if (ioctl(fd, DM_DEV_REMOVE, io)) {
276        if (errno != ENXIO) {
277            LOGE("Error destroying device mapping (%s)", strerror(errno));
278        }
279        free(buffer);
280        close(fd);
281        return -1;
282    }
283
284    free(buffer);
285    close(fd);
286    return 0;
287}
288
289void *Devmapper::_align(void *ptr, unsigned int a)
290{
291        register unsigned long agn = --a;
292
293        return (void *) (((unsigned long) ptr + agn) & ~agn);
294}
295
296