geom_mbr.c revision 97078
1/*- 2 * Copyright (c) 2002 Poul-Henning Kamp 3 * Copyright (c) 2002 Networks Associates Technology, Inc. 4 * All rights reserved. 5 * 6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7 * and NAI Labs, the Security Research Division of Network Associates, Inc. 8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9 * DARPA CHATS research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The names of the authors may not be used to endorse or promote 20 * products derived from this software without specific prior written 21 * permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $FreeBSD: head/sys/geom/geom_mbr.c 97078 2002-05-21 20:33:49Z phk $ 36 */ 37 38#include <sys/param.h> 39#ifndef _KERNEL 40#include <stdio.h> 41#include <string.h> 42#include <signal.h> 43#include <sys/param.h> 44#include <stdlib.h> 45#include <err.h> 46#else 47#include <sys/systm.h> 48#include <sys/kernel.h> 49#include <sys/malloc.h> 50#include <sys/bio.h> 51#include <sys/lock.h> 52#include <sys/mutex.h> 53#endif 54 55#include <sys/errno.h> 56#include <sys/disklabel.h> 57#include <sys/sbuf.h> 58#include <geom/geom.h> 59#include <geom/geom_slice.h> 60 61#define MBR_CLASS_NAME "MBR" 62#define MBREXT_CLASS_NAME "MBREXT" 63 64static void 65g_dec_dos_partition(u_char *ptr, struct dos_partition *d) 66{ 67 68 d->dp_flag = ptr[0]; 69 d->dp_shd = ptr[1]; 70 d->dp_ssect = ptr[2]; 71 d->dp_scyl = ptr[3]; 72 d->dp_typ = ptr[4]; 73 d->dp_ehd = ptr[5]; 74 d->dp_esect = ptr[6]; 75 d->dp_ecyl = ptr[7]; 76 d->dp_start = g_dec_le4(ptr + 8); 77 d->dp_size = g_dec_le4(ptr + 12); 78} 79 80#if 0 81static void 82g_enc_dos_partition(u_char *ptr, struct dos_partition *d) 83{ 84 85 ptr[0] = d->dp_flag; 86 ptr[1] = d->dp_shd; 87 ptr[2] = d->dp_ssect; 88 ptr[3] = d->dp_scyl; 89 ptr[4] = d->dp_typ; 90 ptr[5] = d->dp_ehd; 91 ptr[6] = d->dp_esect; 92 ptr[7] = d->dp_ecyl; 93 g_enc_le4(ptr + 8, d->dp_start); 94 g_enc_le4(ptr + 12, d->dp_size); 95} 96#endif 97 98struct g_mbr_softc { 99 int type [NDOSPART]; 100 struct dos_partition dospart[NDOSPART]; 101}; 102 103static int 104g_mbr_start(struct bio *bp) 105{ 106 struct g_provider *pp; 107 struct g_geom *gp; 108 struct g_mbr_softc *mp; 109 struct g_slicer *gsp; 110 int index; 111 112 pp = bp->bio_to; 113 index = pp->index; 114 gp = pp->geom; 115 gsp = gp->softc; 116 mp = gsp->softc; 117 if (bp->bio_cmd == BIO_GETATTR) { 118 if (g_haveattr_int(bp, "MBR::type", mp->type[index])) 119 return (1); 120 } 121 return (0); 122} 123 124static void 125g_mbr_dumpconf(struct sbuf *sb, char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp) 126{ 127 struct g_mbr_softc *mp; 128 struct g_slicer *gsp; 129 130 g_slice_dumpconf(sb, indent, gp, cp, pp); 131 gsp = gp->softc; 132 mp = gsp->softc; 133 if (pp != NULL) { 134 sbuf_printf(sb, "%s<type>%d</type>\n", 135 indent, mp->type[pp->index]); 136 } 137} 138 139 140static struct dos_partition historical_bogus_partition_table[NDOSPART] = { 141 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 142 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 143 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 144 { 0x80, 0, 1, 0, DOSPTYP_386BSD, 255, 255, 255, 0, 50000, }, 145}; 146static struct dos_partition historical_bogus_partition_table_fixed[NDOSPART] = { 147 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 148 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 149 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 150 { 0x80, 0, 1, 0, DOSPTYP_386BSD, 254, 255, 255, 0, 50000, }, 151}; 152 153static void 154g_mbr_print(int i __unused, struct dos_partition *dp __unused) 155{ 156 157#if 0 158 g_hexdump(dp, sizeof(dp[0])); 159 printf("[%d] f:%02x typ:%d", i, dp->dp_flag, dp->dp_typ); 160 printf(" s(CHS):%d/%d/%d", dp->dp_scyl, dp->dp_shd, dp->dp_ssect); 161 printf(" e(CHS):%d/%d/%d", dp->dp_ecyl, dp->dp_ehd, dp->dp_esect); 162 printf(" s:%d l:%d\n", dp->dp_start, dp->dp_size); 163#endif 164} 165 166static struct g_geom * 167g_mbr_taste(struct g_class *mp, struct g_provider *pp, int insist) 168{ 169 struct g_geom *gp; 170 struct g_consumer *cp; 171 struct g_provider *pp2; 172 int error, i, npart; 173 struct dos_partition dp[NDOSPART]; 174 struct g_mbr_softc *ms; 175 struct g_slicer *gsp; 176 u_int fwsectors, sectorsize; 177 u_char *buf; 178 179 g_trace(G_T_TOPOLOGY, "mbr_taste(%s,%s)", mp->name, pp->name); 180 g_topology_assert(); 181 gp = g_slice_new(mp, NDOSPART, pp, &cp, &ms, sizeof *ms, g_mbr_start); 182 if (gp == NULL) 183 return (NULL); 184 gsp = gp->softc; 185 g_topology_unlock(); 186 gp->dumpconf = g_mbr_dumpconf; 187 npart = 0; 188 while (1) { /* a trick to allow us to use break */ 189 if (gp->rank != 2 && insist == 0) 190 break; 191 error = g_getattr("GEOM::fwsectors", cp, &fwsectors); 192 if (error) 193 fwsectors = 17; 194 error = g_getattr("GEOM::sectorsize", cp, §orsize); 195 if (error) 196 break; 197 if (!error && sectorsize != 512) 198 break; 199 gsp->frontstuff = sectorsize * fwsectors; 200 buf = g_read_data(cp, 0, sectorsize, &error); 201 if (buf == NULL || error != 0) 202 break; 203 if (buf[0x1fe] != 0x55 && buf[0x1ff] != 0xaa) { 204 g_free(buf); 205 break; 206 } 207 for (i = 0; i < NDOSPART; i++) 208 g_dec_dos_partition( 209 buf + DOSPARTOFF + i * sizeof(struct dos_partition), 210 dp + i); 211 g_free(buf); 212 if (bcmp(dp, historical_bogus_partition_table, 213 sizeof historical_bogus_partition_table) == 0) 214 break; 215 if (bcmp(dp, historical_bogus_partition_table_fixed, 216 sizeof historical_bogus_partition_table_fixed) == 0) 217 break; 218 npart = 0; 219 for (i = 0; i < NDOSPART; i++) { 220 if (dp[i].dp_flag != 0 && dp[i].dp_flag != 0x80) 221 continue; 222 if (dp[i].dp_size == 0) 223 continue; 224 g_mbr_print(i, dp + i); 225 npart++; 226 ms->type[i] = dp[i].dp_typ; 227 pp2 = g_slice_addslice(gp, i, 228 ((off_t)dp[i].dp_start) << 9ULL, 229 ((off_t)dp[i].dp_size) << 9ULL, 230 "%ss%d", gp->name, i + 1); 231 } 232 break; 233 } 234 g_topology_lock(); 235 error = g_access_rel(cp, -1, 0, 0); 236 if (npart > 0) { 237 g_new_magicspaces(gp, 3); 238 g_add_magicspace(gp, 0, "boot", 0, DOSPARTOFF, 0); 239 g_add_magicspace(gp, 1, "mbr", DOSPARTOFF, 4 * 16, 0); 240 g_add_magicspace(gp, 2, "signature", 510, 2, 0); 241 LIST_FOREACH(pp, &gp->provider, provider) 242 g_error_provider(pp, 0); 243 return (gp); 244 } 245 g_std_spoiled(cp); 246 return (NULL); 247} 248 249 250static struct g_class g_mbr_class = { 251 MBR_CLASS_NAME, 252 g_mbr_taste, 253 NULL, 254 G_CLASS_INITSTUFF 255}; 256 257DECLARE_GEOM_CLASS(g_mbr_class, g_mbr); 258 259#define NDOSEXTPART 32 260struct g_mbrext_softc { 261 int type [NDOSEXTPART]; 262}; 263 264static int 265g_mbrext_start(struct bio *bp) 266{ 267 struct g_provider *pp; 268 struct g_geom *gp; 269 struct g_mbrext_softc *mp; 270 struct g_slicer *gsp; 271 int index; 272 273 pp = bp->bio_to; 274 index = pp->index; 275 gp = pp->geom; 276 gsp = gp->softc; 277 mp = gsp->softc; 278 if (bp->bio_cmd == BIO_GETATTR) { 279 if (g_haveattr_int(bp, "MBR::type", mp->type[index])) 280 return (1); 281 } 282 return (0); 283} 284 285static void 286g_mbrext_dumpconf(struct sbuf *sb, char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp) 287{ 288 struct g_mbrext_softc *mp; 289 struct g_slicer *gsp; 290 291 g_slice_dumpconf(sb, indent, gp, cp, pp); 292 gsp = gp->softc; 293 mp = gsp->softc; 294 if (pp != NULL) { 295 sbuf_printf(sb, "%s<type>%d</type>\n", 296 indent, mp->type[pp->index]); 297 } 298} 299 300static void 301g_mbrext_print(int i, struct dos_partition *dp) 302{ 303 g_hexdump(dp, sizeof(dp[0])); 304 printf("[%d] f:%02x typ:%d", i, dp->dp_flag, dp->dp_typ); 305 printf(" s(CHS):%d/%d/%d", dp->dp_scyl, dp->dp_shd, dp->dp_ssect); 306 printf(" e(CHS):%d/%d/%d", dp->dp_ecyl, dp->dp_ehd, dp->dp_esect); 307 printf(" s:%d l:%d\n", dp->dp_start, dp->dp_size); 308} 309 310static struct g_geom * 311g_mbrext_taste(struct g_class *mp, struct g_provider *pp, int insist __unused) 312{ 313 struct g_geom *gp; 314 struct g_consumer *cp; 315 struct g_provider *pp2; 316 int error, i, slice; 317 struct g_mbrext_softc *ms; 318 off_t off; 319 u_char *buf; 320 struct dos_partition dp[4]; 321 u_int fwsectors, sectorsize; 322 struct g_slicer *gsp; 323 324 g_trace(G_T_TOPOLOGY, "g_mbrext_taste(%s,%s)", mp->name, pp->name); 325 g_topology_assert(); 326 if (strcmp(pp->geom->class->name, MBR_CLASS_NAME)) 327 return (NULL); 328 gp = g_slice_new(mp, NDOSEXTPART, pp, &cp, &ms, sizeof *ms, g_mbrext_start); 329 if (gp == NULL) 330 return (NULL); 331 gsp = gp->softc; 332 g_topology_unlock(); 333 gp->dumpconf = g_mbrext_dumpconf; 334 off = 0; 335 slice = 0; 336 while (1) { /* a trick to allow us to use break */ 337 error = g_getattr("MBR::type", cp, &i); 338 if (error || i != DOSPTYP_EXT) 339 break; 340 error = g_getattr("GEOM::fwsectors", cp, &fwsectors); 341 if (error) 342 fwsectors = 17; 343 error = g_getattr("GEOM::sectorsize", cp, §orsize); 344 if (error) 345 break; 346 if (!error && sectorsize != 512) 347 break; 348 gsp->frontstuff = sectorsize * fwsectors; 349 for (;;) { 350 buf = g_read_data(cp, off, sectorsize, &error); 351 if (buf == NULL || error != 0) 352 break; 353 if (buf[0x1fe] != 0x55 && buf[0x1ff] != 0xaa) 354 break; 355 for (i = 0; i < NDOSPART; i++) 356 g_dec_dos_partition( 357 buf + DOSPARTOFF + i * sizeof(struct dos_partition), 358 dp + i); 359 g_free(buf); 360 g_mbrext_print(0, dp); 361 g_mbrext_print(1, dp + 1); 362 if (dp[0].dp_flag == 0 && dp[0].dp_size != 0) { 363 pp2 = g_slice_addslice(gp, slice, 364 (((off_t)dp[0].dp_start) << 9ULL) + off, 365 ((off_t)dp[0].dp_size) << 9ULL, 366 "%*.*s%d", 367 strlen(gp->name) - 1, 368 strlen(gp->name) - 1, 369 gp->name, 370 slice + 5); 371 ms->type[slice] = dp[0].dp_typ; 372 slice++; 373 g_error_provider(pp2, 0); 374 } 375 if (dp[1].dp_flag != 0) 376 break; 377 if (dp[1].dp_typ != DOSPTYP_EXT) 378 break; 379 if (dp[1].dp_size == 0) 380 break; 381 off = ((off_t)dp[1].dp_start) << 9ULL; 382 } 383 break; 384 } 385 g_topology_lock(); 386 error = g_access_rel(cp, -1, 0, 0); 387 if (slice > 0) { 388 /* XXX: add magic spaces */ 389 return (gp); 390 } 391 392 g_topology_assert(); 393 g_std_spoiled(cp); 394 g_topology_assert(); 395 return (NULL); 396} 397 398 399static struct g_class g_mbrext_class = { 400 MBREXT_CLASS_NAME, 401 g_mbrext_taste, 402 NULL, 403 G_CLASS_INITSTUFF 404}; 405 406DECLARE_GEOM_CLASS(g_mbrext_class, g_mbrext); 407