1 /* $NetBSD: device.c,v 1.1.1.1 2008/12/22 00:17:57 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. 5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. 6 * 7 * This file is part of LVM2. 8 * 9 * This copyrighted material is made available to anyone wishing to use, 10 * modify, copy, or redistribute it subject to the terms and conditions 11 * of the GNU Lesser General Public License v.2.1. 12 * 13 * You should have received a copy of the GNU Lesser General Public License 14 * along with this program; if not, write to the Free Software Foundation, 15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 */ 17 18 #include "lib.h" 19 #include "lvm-types.h" 20 #include "device.h" 21 #include "metadata.h" 22 #include "filter.h" 23 #include "xlate.h" 24 25 /* See linux/genhd.h and fs/partitions/msdos */ 26 27 #define PART_MAGIC 0xAA55 28 #define PART_MAGIC_OFFSET UINT64_C(0x1FE) 29 #define PART_OFFSET UINT64_C(0x1BE) 30 31 struct partition { 32 uint8_t boot_ind; 33 uint8_t head; 34 uint8_t sector; 35 uint8_t cyl; 36 uint8_t sys_ind; /* partition type */ 37 uint8_t end_head; 38 uint8_t end_sector; 39 uint8_t end_cyl; 40 uint32_t start_sect; 41 uint32_t nr_sects; 42 } __attribute__((packed)); 43 44 static int _is_partitionable(struct device *dev) 45 { 46 int parts = max_partitions(MAJOR(dev->dev)); 47 48 if ((parts <= 1) || (MINOR(dev->dev) % parts)) 49 return 0; 50 51 return 1; 52 } 53 54 static int _has_partition_table(struct device *dev) 55 { 56 int ret = 0; 57 unsigned p; 58 uint16_t buf[SECTOR_SIZE/sizeof(uint16_t)]; 59 uint16_t *part_magic; 60 struct partition *part; 61 62 if (!dev_open(dev)) { 63 stack; 64 return -1; 65 } 66 67 if (!dev_read(dev, UINT64_C(0), sizeof(buf), &buf)) 68 goto_out; 69 70 /* FIXME Check for other types of partition table too */ 71 72 /* Check for msdos partition table */ 73 part_magic = buf + PART_MAGIC_OFFSET/sizeof(buf[0]); 74 if ((*part_magic == xlate16(PART_MAGIC))) { 75 part = (struct partition *) (buf + PART_OFFSET/sizeof(buf[0])); 76 for (p = 0; p < 4; p++, part++) { 77 /* Table is invalid if boot indicator not 0 or 0x80 */ 78 if ((part->boot_ind & 0x7f)) { 79 ret = 0; 80 break; 81 } 82 /* Must have at least one non-empty partition */ 83 if (part->nr_sects) 84 ret = 1; 85 } 86 } 87 88 out: 89 if (!dev_close(dev)) 90 stack; 91 92 return ret; 93 } 94 95 int is_partitioned_dev(struct device *dev) 96 { 97 if (!_is_partitionable(dev)) 98 return 0; 99 100 return _has_partition_table(dev); 101 } 102 103 #if 0 104 #include <sys/stat.h> 105 #include <sys/mman.h> 106 #include <stdio.h> 107 #include <unistd.h> 108 #include <fcntl.h> 109 #include <ctype.h> 110 111 #include <errno.h> 112 #include <sys/ioctl.h> 113 #include <linux/fs.h> 114 #include <linux/major.h> 115 #include <linux/genhd.h> 116 117 int _get_partition_type(struct dev_filter *filter, struct device *d); 118 119 #define MINOR_PART(dev) (MINOR((dev)->dev) % max_partitions(MINOR((dev)->dev))) 120 121 int is_extended_partition(struct device *d) 122 { 123 return (MINOR_PART(d) > 4) ? 1 : 0; 124 } 125 126 struct device *dev_primary(struct dev_mgr *dm, struct device *d) 127 { 128 struct device *ret; 129 130 ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d)); 131 /* FIXME: Needs replacing with a 'refresh' */ 132 if (!ret) { 133 init_dev_scan(dm); 134 ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d)); 135 } 136 137 return ret; 138 139 } 140 141 int partition_type_is_lvm(struct dev_mgr *dm, struct device *d) 142 { 143 int pt; 144 145 pt = _get_partition_type(dm, d); 146 147 if (!pt) { 148 if (is_whole_disk(dm, d)) 149 /* FIXME: Overloaded pt=0 in error cases */ 150 return 1; 151 else { 152 log_error 153 ("%s: missing partition table " 154 "on partitioned device", d->name); 155 return 0; 156 } 157 } 158 159 if (is_whole_disk(dm, d)) { 160 log_error("%s: looks to possess partition table", d->name); 161 return 0; 162 } 163 164 /* check part type */ 165 if (pt != LVM_PARTITION && pt != LVM_NEW_PARTITION) { 166 log_error("%s: invalid partition type 0x%x " 167 "(must be 0x%x)", d->name, pt, LVM_NEW_PARTITION); 168 return 0; 169 } 170 171 if (pt == LVM_PARTITION) { 172 log_error 173 ("%s: old LVM partition type found - please change to 0x%x", 174 d->name, LVM_NEW_PARTITION); 175 return 0; 176 } 177 178 return 1; 179 } 180 181 int _get_partition_type(struct dev_mgr *dm, struct device *d) 182 { 183 int pv_handle = -1; 184 struct device *primary; 185 ssize_t read_ret; 186 ssize_t bytes_read = 0; 187 char *buffer; 188 unsigned short *s_buffer; 189 struct partition *part; 190 loff_t offset = 0; 191 loff_t extended_offset = 0; 192 int part_sought; 193 int part_found = 0; 194 int first_partition = 1; 195 int extended_partition = 0; 196 int p; 197 198 if (!(primary = dev_primary(dm, d))) { 199 log_error 200 ("Failed to find main device containing partition %s", 201 d->name); 202 return 0; 203 } 204 205 if (!(buffer = dm_malloc(SECTOR_SIZE))) { 206 log_error("Failed to allocate partition table buffer"); 207 return 0; 208 } 209 210 /* Get partition table */ 211 if ((pv_handle = open(primary->name, O_RDONLY)) < 0) { 212 log_error("%s: open failed: %s", primary->name, 213 strerror(errno)); 214 return 0; 215 } 216 217 s_buffer = (unsigned short *) buffer; 218 part = (struct partition *) (buffer + 0x1be); 219 part_sought = MINOR_PART(dm, d); 220 221 do { 222 bytes_read = 0; 223 224 if (llseek(pv_handle, offset * SECTOR_SIZE, SEEK_SET) == -1) { 225 log_error("%s: llseek failed: %s", 226 primary->name, strerror(errno)); 227 return 0; 228 } 229 230 while ((bytes_read < SECTOR_SIZE) && 231 (read_ret = 232 read(pv_handle, buffer + bytes_read, 233 SECTOR_SIZE - bytes_read)) != -1) 234 bytes_read += read_ret; 235 236 if (read_ret == -1) { 237 log_error("%s: read failed: %s", primary->name, 238 strerror(errno)); 239 return 0; 240 } 241 242 if (s_buffer[255] == 0xAA55) { 243 if (is_whole_disk(dm, d)) 244 return -1; 245 } else 246 return 0; 247 248 extended_partition = 0; 249 250 /* Loop through primary partitions */ 251 for (p = 0; p < 4; p++) { 252 if (part[p].sys_ind == DOS_EXTENDED_PARTITION || 253 part[p].sys_ind == LINUX_EXTENDED_PARTITION 254 || part[p].sys_ind == WIN98_EXTENDED_PARTITION) { 255 extended_partition = 1; 256 offset = extended_offset + part[p].start_sect; 257 if (extended_offset == 0) 258 extended_offset = part[p].start_sect; 259 if (first_partition == 1) 260 part_found++; 261 } else if (first_partition == 1) { 262 if (p == part_sought) { 263 if (part[p].sys_ind == 0) { 264 /* missing primary? */ 265 return 0; 266 } 267 } else 268 part_found++; 269 } else if (!part[p].sys_ind) 270 part_found++; 271 272 if (part_sought == part_found) 273 return part[p].sys_ind; 274 275 } 276 first_partition = 0; 277 } 278 while (extended_partition == 1); 279 280 return 0; 281 } 282 #endif 283