blob: 131fd5a2613317e94aa58e2fb315670d75ce86a7 [file] [log] [blame]
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001
2/*
3 * Copyright (C) 2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <stdlib.h>
19#include <string.h>
20#include <dirent.h>
21#include <errno.h>
22#include <fcntl.h>
23
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <sys/mman.h>
28
29#include <linux/fs.h>
The Android Open Source Project13f797d2009-02-10 15:44:07 -080030#include <linux/msdos_fs.h>
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080031
32#include "vold.h"
33#include "blkdev.h"
34#include "diskmbr.h"
35
36#define DEBUG_BLKDEV 0
37
38static blkdev_list_t *list_root = NULL;
39
40static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major,
The Android Open Source Project13f797d2009-02-10 15:44:07 -080041 int minor, char *type, struct media *media);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080042
The Android Open Source Project13f797d2009-02-10 15:44:07 -080043static int fat_valid_media(unsigned char media)
44{
45 return 0xf8 <= media || media == 0xf0;
46}
47
48char *blkdev_get_devpath(blkdev_t *blk)
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080049{
The Android Open Source Project13f797d2009-02-10 15:44:07 -080050 char *dp = malloc(256);
51 sprintf(dp, "%s/vold/%d:%d", DEVPATH, blk->major, blk->minor);
52 return dp;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080053}
54
The Android Open Source Project13f797d2009-02-10 15:44:07 -080055int blkdev_refresh(blkdev_t *blk)
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080056{
The Android Open Source Project13f797d2009-02-10 15:44:07 -080057 int fd = 0;
58 char *devpath = NULL;
59 unsigned char *block = NULL;
60 int i, rc;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080061
The Android Open Source Project13f797d2009-02-10 15:44:07 -080062 if (!(block = malloc(512)))
63 goto out;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080064
65 /*
The Android Open Source Project13f797d2009-02-10 15:44:07 -080066 * Get the device size
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080067 */
The Android Open Source Project13f797d2009-02-10 15:44:07 -080068 devpath = blkdev_get_devpath(blk);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080069
The Android Open Source Project13f797d2009-02-10 15:44:07 -080070 if ((fd = open(devpath, O_RDONLY)) < 0) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -080071 LOGE("Unable to open device '%s' (%s)", devpath, strerror(errno));
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080072 return -errno;
73 }
74
75 if (ioctl(fd, BLKGETSIZE, &blk->nr_sec)) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -080076 LOGE("Unable to get device size (%m)");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080077 return -errno;
78 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -080079 close(fd);
80 free(devpath);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080081
The Android Open Source Project13f797d2009-02-10 15:44:07 -080082 /*
83 * Open the disk partition table
84 */
85 devpath = blkdev_get_devpath(blk->disk);
86 if ((fd = open(devpath, O_RDONLY)) < 0) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -080087 LOGE("Unable to open device '%s' (%s)", devpath,
The Android Open Source Project13f797d2009-02-10 15:44:07 -080088 strerror(errno));
89 free(devpath);
90 return -errno;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080091 }
92
The Android Open Source Project13f797d2009-02-10 15:44:07 -080093 free(devpath);
94
95 if ((rc = read(fd, block, 512)) != 512) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -080096 LOGE("Unable to read device partition table (%d, %s)",
The Android Open Source Project13f797d2009-02-10 15:44:07 -080097 rc, strerror(errno));
98 goto out;
99 }
100
101 /*
102 * If we're a disk, then process the partition table. Otherwise we're
103 * a partition so get the partition type
104 */
105
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800106 if (blk->type == blkdev_disk) {
107 blk->nr_parts = 0;
108
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800109 if ((block[0x1fe] != 0x55) || (block[0x1ff] != 0xAA)) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800110 LOG_VOL("Disk %d:%d does not contain a partition table",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800111 blk->major, blk->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800112 goto out;
113 }
114
115 for (i = 0; i < 4; i++) {
116 struct dos_partition part;
117
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800118 dos_partition_dec(block + DOSPARTOFF + i * sizeof(struct dos_partition), &part);
119 if (part.dp_flag != 0 && part.dp_flag != 0x80) {
120 struct fat_boot_sector *fb = (struct fat_boot_sector *) &block[0];
121
122 if (!i && fb->reserved && fb->fats && fat_valid_media(fb->media)) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800123 LOG_VOL("Detected FAT filesystem in partition table");
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800124 break;
125 } else {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800126 LOG_VOL("Partition table looks corrupt");
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800127 break;
128 }
129 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800130 if (part.dp_size != 0 && part.dp_typ != 0)
131 blk->nr_parts++;
132 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800133 } else if (blk->type == blkdev_partition) {
134 struct dos_partition part;
135 int part_no = blk->minor -1;
136
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800137 dos_partition_dec(block + DOSPARTOFF + part_no * sizeof(struct dos_partition), &part);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800138 blk->part_type = part.dp_typ;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800139 }
140
141 out:
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800142
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800143 if (block)
144 free(block);
145
146 char tmp[255];
147 char tmp2[32];
148 sprintf(tmp, "%s (blkdev %d:%d), %u secs (%u MB)",
149 (blk->type == blkdev_disk ? "Disk" : "Partition"),
150 blk->major, blk->minor,
151 blk->nr_sec,
152 ((blk->nr_sec * 512) / 1024) / 1024);
153
154 if (blk->type == blkdev_disk)
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800155 sprintf(tmp2, " %d partitions", blk->nr_parts);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800156 else
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800157 sprintf(tmp2, " type 0x%x", blk->part_type);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800158
159 strcat(tmp, tmp2);
160 LOG_VOL(tmp);
161
162 close(fd);
163
164 return 0;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800165}
166
167blkdev_t *blkdev_create(blkdev_t *disk, char *devpath, int major, int minor, struct media *media, char *type)
168{
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800169 return _blkdev_create(disk, devpath, major, minor, type, media);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800170}
171
172static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major,
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800173 int minor, char *type, struct media *media)
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800174{
175 blkdev_t *new;
176 struct blkdev_list *list_entry;
177
178 if (disk && disk->type != blkdev_disk) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800179 LOGE("Non disk parent specified for blkdev!");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800180 return NULL;
181 }
182
183 if (!(new = malloc(sizeof(blkdev_t))))
184 return NULL;
185
186 memset(new, 0, sizeof(blkdev_t));
187
188 if (!(list_entry = malloc(sizeof(struct blkdev_list)))) {
189 free (new);
190 return NULL;
191 }
192 list_entry->dev = new;
193 list_entry->next = NULL;
194
195 if (!list_root)
196 list_root = list_entry;
197 else {
198 struct blkdev_list *list_scan = list_root;
199 while (list_scan->next)
200 list_scan = list_scan->next;
201 list_scan->next = list_entry;
202 }
203
204 if (devpath)
205 new->devpath = strdup(devpath);
206 new->major = major;
207 new->minor = minor;
208 new->media = media;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800209 new->nr_sec = 0xffffffff;
210
211 if (disk)
212 new->disk = disk;
213 else
214 new->disk = new; // Note the self disk pointer
215
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800216 /* Create device nodes */
217 char nodepath[255];
218 mode_t mode = 0666 | S_IFBLK;
219 dev_t dev = (major << 8) | minor;
220
221 sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, major, minor);
222 if (mknod(nodepath, mode, dev) < 0) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800223 LOGE("Error making device nodes for '%s' (%s)",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800224 nodepath, strerror(errno));
225 }
226
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800227 if (!strcmp(type, "disk"))
228 new->type = blkdev_disk;
229 else if (!strcmp(type, "partition"))
230 new->type = blkdev_partition;
231 else {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800232 LOGE("Unknown block device type '%s'", type);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800233 new->type = blkdev_unknown;
234 }
235
236 return new;
237}
238
239void blkdev_destroy(blkdev_t *blkdev)
240{
241 struct blkdev_list *list_next;
242
243 if (list_root->dev == blkdev) {
244 list_next = list_root->next;
245 free (list_root);
246 list_root = list_next;
247 } else {
248 struct blkdev_list *list_scan = list_root;
249 while (list_scan->next->dev != blkdev)
250 list_scan = list_scan -> next;
251 list_next = list_scan->next->next;
252 free(list_scan->next);
253 list_scan->next = list_next;
254 }
255
256 if (blkdev->devpath)
257 free(blkdev->devpath);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800258
259 char nodepath[255];
260 sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, blkdev->major, blkdev->minor);
261 unlink(nodepath);
262
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800263 free(blkdev);
264}
265
266blkdev_t *blkdev_lookup_by_path(char *devpath)
267{
268 struct blkdev_list *list_scan = list_root;
269
270 while (list_scan) {
271 if (!strcmp(list_scan->dev->devpath, devpath))
272 return list_scan->dev;
273 list_scan = list_scan->next;
274 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800275 return NULL;
276}
277
278blkdev_t *blkdev_lookup_by_devno(int maj, int min)
279{
280 struct blkdev_list *list_scan = list_root;
281
282 while (list_scan) {
283 if ((list_scan->dev->major == maj) &&
284 (list_scan->dev->minor == min))
285 return list_scan->dev;
286 list_scan = list_scan->next;
287 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800288 return NULL;
289}
290
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800291/*
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800292 * Given a disk device, return the number of partitions which
293 * have yet to be processed.
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800294 */
295int blkdev_get_num_pending_partitions(blkdev_t *blk)
296{
297 struct blkdev_list *list_scan = list_root;
298 int num = blk->nr_parts;
299
300 if (blk->type != blkdev_disk)
301 return -EINVAL;
302
303 while (list_scan) {
304 if (list_scan->dev->type != blkdev_partition)
305 goto next;
306
307 if (list_scan->dev->major != blk->major)
308 goto next;
309
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800310 if (list_scan->dev->nr_sec != 0xffffffff &&
311 list_scan->dev->devpath) {
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800312 num--;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800313 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800314 next:
315 list_scan = list_scan->next;
316 }
317 return num;
318}
319