• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
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>
30 #include <linux/msdos_fs.h>
31 
32 #include "vold.h"
33 #include "blkdev.h"
34 #include "diskmbr.h"
35 #include "media.h"
36 
37 #define DEBUG_BLKDEV 0
38 
39 static blkdev_list_t *list_root = NULL;
40 
41 static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major,
42                                 int minor, char *type, struct media *media);
43 
fat_valid_media(unsigned char media)44 static int fat_valid_media(unsigned char media)
45 {
46         return 0xf8 <= media || media == 0xf0;
47 }
48 
blkdev_get_devpath(blkdev_t * blk)49 char *blkdev_get_devpath(blkdev_t *blk)
50 {
51     char *dp = malloc(256);
52     sprintf(dp, "%s/vold/%d:%d", DEVPATH, blk->major, blk->minor);
53     return dp;
54 }
55 
blkdev_refresh(blkdev_t * blk)56 int blkdev_refresh(blkdev_t *blk)
57 {
58     int fd = 0;
59     char *devpath = NULL;
60     unsigned char *block = NULL;
61     int i, rc;
62 
63     if (!(block = malloc(512)))
64         goto out;
65 
66     /*
67      * Get the device size
68      */
69     devpath = blkdev_get_devpath(blk);
70 
71     if ((fd = open(devpath, O_RDONLY)) < 0) {
72         LOGE("Unable to open device '%s' (%s)", devpath, strerror(errno));
73         return -errno;
74     }
75 
76     if (ioctl(fd, BLKGETSIZE, &blk->nr_sec)) {
77         LOGE("Unable to get device size (%s)", strerror(errno));
78         return -errno;
79     }
80     close(fd);
81     free(devpath);
82 
83     /*
84      * Open the disk partition table
85      */
86     devpath = blkdev_get_devpath(blk->disk);
87     if ((fd = open(devpath, O_RDONLY)) < 0) {
88         LOGE("Unable to open device '%s' (%s)", devpath,
89              strerror(errno));
90         free(devpath);
91         return -errno;
92     }
93 
94     free(devpath);
95 
96     if ((rc = read(fd, block, 512)) != 512) {
97         LOGE("Unable to read device partition table (%d, %s)",
98              rc, strerror(errno));
99         goto out;
100     }
101 
102     /*
103      * If we're a disk, then process the partition table. Otherwise we're
104      * a partition so get the partition type
105      */
106 
107     if (blk->type == blkdev_disk) {
108         blk->nr_parts = 0;
109 
110         if ((block[0x1fe] != 0x55) || (block[0x1ff] != 0xAA)) {
111             LOGI("Disk %d:%d does not contain a partition table",
112                  blk->major, blk->minor);
113             goto out;
114         }
115 
116         for (i = 0; i < 4; i++) {
117             struct dos_partition part;
118 
119             dos_partition_dec(block + DOSPARTOFF + i * sizeof(struct dos_partition), &part);
120             if (part.dp_flag != 0 && part.dp_flag != 0x80) {
121                 struct fat_boot_sector *fb = (struct fat_boot_sector *) &block[0];
122 
123                 if (!i && fb->reserved && fb->fats && fat_valid_media(fb->media)) {
124                     LOGI("Detected FAT filesystem in partition table");
125                     break;
126                 } else {
127                     LOGI("Partition table looks corrupt");
128                     break;
129                 }
130             }
131             if (part.dp_size != 0 && part.dp_typ != 0)
132                 blk->nr_parts++;
133         }
134     } else if (blk->type == blkdev_partition) {
135         struct dos_partition part;
136 	int part_no;
137 
138         if (blk->media->media_type == media_mmc)
139             part_no = blk->minor % MMC_PARTS_PER_CARD -1;
140         else
141             part_no = blk->minor -1;
142 
143         if (part_no < 4) {
144             dos_partition_dec(block + DOSPARTOFF + part_no * sizeof(struct dos_partition), &part);
145             blk->part_type = part.dp_typ;
146         } else {
147             LOGW("Skipping partition %d", part_no);
148         }
149     }
150 
151  out:
152 
153     if (block)
154         free(block);
155 
156     char tmp[255];
157     char tmp2[32];
158     sprintf(tmp, "%s (blkdev %d:%d), %u secs (%u MB)",
159                  (blk->type == blkdev_disk ? "Disk" : "Partition"),
160                  blk->major, blk->minor,
161                  blk->nr_sec,
162                  (uint32_t) (((uint64_t) blk->nr_sec * 512) / 1024) / 1024);
163 
164     if (blk->type == blkdev_disk)
165         sprintf(tmp2, " %d partitions", blk->nr_parts);
166     else
167         sprintf(tmp2, " type 0x%x", blk->part_type);
168 
169     strcat(tmp, tmp2);
170     LOGI(tmp);
171 
172     close(fd);
173 
174     return 0;
175 }
176 
blkdev_create(blkdev_t * disk,char * devpath,int major,int minor,struct media * media,char * type)177 blkdev_t *blkdev_create(blkdev_t *disk, char *devpath, int major, int minor, struct media *media, char *type)
178 {
179     return _blkdev_create(disk, devpath, major, minor, type, media);
180 }
181 
_blkdev_create(blkdev_t * disk,char * devpath,int major,int minor,char * type,struct media * media)182 static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major,
183                                 int minor, char *type, struct media *media)
184 {
185     blkdev_t *new;
186     struct blkdev_list *list_entry;
187 
188     if (disk && disk->type != blkdev_disk) {
189         LOGE("Non disk parent specified for blkdev!");
190         return NULL;
191     }
192 
193     if (!(new = malloc(sizeof(blkdev_t))))
194         return NULL;
195 
196     memset(new, 0, sizeof(blkdev_t));
197 
198     if (!(list_entry = malloc(sizeof(struct blkdev_list)))) {
199         free (new);
200         return NULL;
201     }
202     list_entry->dev = new;
203     list_entry->next = NULL;
204 
205     if (!list_root)
206         list_root = list_entry;
207     else {
208         struct blkdev_list *list_scan = list_root;
209         while (list_scan->next)
210             list_scan = list_scan->next;
211         list_scan->next = list_entry;
212     }
213 
214     if (devpath)
215         new->devpath = strdup(devpath);
216     new->major = major;
217     new->minor = minor;
218     new->media = media;
219     new->nr_sec = 0xffffffff;
220 
221     if (disk)
222         new->disk = disk;
223     else
224         new->disk = new; // Note the self disk pointer
225 
226     /* Create device nodes */
227     char nodepath[255];
228     mode_t mode = 0660 | S_IFBLK;
229     dev_t dev = (major << 8) | minor;
230 
231     sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, major, minor);
232     if (mknod(nodepath, mode, dev) < 0) {
233         LOGE("Error making device nodes for '%s' (%s)",
234              nodepath, strerror(errno));
235     }
236 
237     if (!strcmp(type, "disk"))
238         new->type = blkdev_disk;
239     else if (!strcmp(type, "partition"))
240         new->type = blkdev_partition;
241     else {
242         LOGE("Unknown block device type '%s'", type);
243         new->type = blkdev_unknown;
244     }
245 
246     return new;
247 }
248 
blkdev_destroy(blkdev_t * blkdev)249 void blkdev_destroy(blkdev_t *blkdev)
250 {
251     struct blkdev_list *list_next;
252 
253     if (list_root->dev == blkdev) {
254         list_next = list_root->next;
255         free (list_root);
256         list_root = list_next;
257     } else {
258         struct blkdev_list *list_scan = list_root;
259         while (list_scan->next->dev != blkdev)
260             list_scan = list_scan -> next;
261         list_next = list_scan->next->next;
262         free(list_scan->next);
263         list_scan->next = list_next;
264     }
265 
266     if (blkdev->devpath)
267         free(blkdev->devpath);
268 
269     char nodepath[255];
270     sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, blkdev->major, blkdev->minor);
271     unlink(nodepath);
272 
273     free(blkdev);
274 }
275 
blkdev_lookup_by_path(char * devpath)276 blkdev_t *blkdev_lookup_by_path(char *devpath)
277 {
278     struct blkdev_list *list_scan = list_root;
279 
280     while (list_scan) {
281         if (!strcmp(list_scan->dev->devpath, devpath))
282             return list_scan->dev;
283         list_scan = list_scan->next;
284     }
285     return NULL;
286 }
287 
blkdev_lookup_by_devno(int maj,int min)288 blkdev_t *blkdev_lookup_by_devno(int maj, int min)
289 {
290     struct blkdev_list *list_scan = list_root;
291 
292     while (list_scan) {
293         if ((list_scan->dev->major == maj) &&
294             (list_scan->dev->minor == min))
295             return list_scan->dev;
296         list_scan = list_scan->next;
297     }
298     return NULL;
299 }
300 
301 /*
302  * Given a disk device, return the number of partitions which
303  * have yet to be processed.
304  */
blkdev_get_num_pending_partitions(blkdev_t * blk)305 int blkdev_get_num_pending_partitions(blkdev_t *blk)
306 {
307     struct blkdev_list *list_scan = list_root;
308     int num = blk->nr_parts;
309 
310     if (blk->type != blkdev_disk)
311         return -EINVAL;
312 
313     while (list_scan) {
314         if (list_scan->dev->type != blkdev_partition)
315             goto next;
316 
317         if (list_scan->dev->major != blk->major)
318             goto next;
319 
320         if (list_scan->dev->nr_sec != 0xffffffff &&
321             list_scan->dev->devpath) {
322             num--;
323         }
324  next:
325         list_scan = list_scan->next;
326     }
327     return num;
328 }
329 
330