1ca987d46SWarner Losh /*- 2ca987d46SWarner Losh * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3ca987d46SWarner Losh * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org> 4ca987d46SWarner Losh * All rights reserved. 5ca987d46SWarner Losh * 6ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 7ca987d46SWarner Losh * modification, are permitted provided that the following conditions 8ca987d46SWarner Losh * are met: 9ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 10ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 11ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 12ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 13ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 14ca987d46SWarner Losh * 15ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25ca987d46SWarner Losh * SUCH DAMAGE. 26ca987d46SWarner Losh */ 27ca987d46SWarner Losh 28ca987d46SWarner Losh #include <sys/cdefs.h> 29ca987d46SWarner Losh __FBSDID("$FreeBSD$"); 30ca987d46SWarner Losh 31ca987d46SWarner Losh #include <sys/disk.h> 32ca987d46SWarner Losh #include <sys/queue.h> 33ca987d46SWarner Losh #include <stand.h> 34ca987d46SWarner Losh #include <stdarg.h> 35ca987d46SWarner Losh #include <bootstrap.h> 36ca987d46SWarner Losh #include <part.h> 37c32dde31SWarner Losh #include <assert.h> 38ca987d46SWarner Losh 39ca987d46SWarner Losh #include "disk.h" 40ca987d46SWarner Losh 41ca987d46SWarner Losh #ifdef DISK_DEBUG 427325df02SKyle Evans # define DPRINTF(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) 43ca987d46SWarner Losh #else 4482c29d4fSToomas Soome # define DPRINTF(fmt, args...) ((void)0) 45ca987d46SWarner Losh #endif 46ca987d46SWarner Losh 47ca987d46SWarner Losh struct open_disk { 48ca987d46SWarner Losh struct ptable *table; 49ca987d46SWarner Losh uint64_t mediasize; 50ca987d46SWarner Losh uint64_t entrysize; 51ca987d46SWarner Losh u_int sectorsize; 52ca987d46SWarner Losh }; 53ca987d46SWarner Losh 54ca987d46SWarner Losh struct print_args { 55ca987d46SWarner Losh struct disk_devdesc *dev; 56ca987d46SWarner Losh const char *prefix; 57ca987d46SWarner Losh int verbose; 58ca987d46SWarner Losh }; 59ca987d46SWarner Losh 60ca987d46SWarner Losh /* Convert size to a human-readable number. */ 61ca987d46SWarner Losh static char * 62ca987d46SWarner Losh display_size(uint64_t size, u_int sectorsize) 63ca987d46SWarner Losh { 64ca987d46SWarner Losh static char buf[80]; 65ca987d46SWarner Losh char unit; 66ca987d46SWarner Losh 67ca987d46SWarner Losh size = size * sectorsize / 1024; 68ca987d46SWarner Losh unit = 'K'; 69ca987d46SWarner Losh if (size >= 10485760000LL) { 70ca987d46SWarner Losh size /= 1073741824; 71ca987d46SWarner Losh unit = 'T'; 72ca987d46SWarner Losh } else if (size >= 10240000) { 73ca987d46SWarner Losh size /= 1048576; 74ca987d46SWarner Losh unit = 'G'; 75ca987d46SWarner Losh } else if (size >= 10000) { 76ca987d46SWarner Losh size /= 1024; 77ca987d46SWarner Losh unit = 'M'; 78ca987d46SWarner Losh } 7941a1c642SToomas Soome snprintf(buf, sizeof(buf), "%4ld%cB", (long)size, unit); 80ca987d46SWarner Losh return (buf); 81ca987d46SWarner Losh } 82ca987d46SWarner Losh 83ca987d46SWarner Losh int 84ca987d46SWarner Losh ptblread(void *d, void *buf, size_t blocks, uint64_t offset) 85ca987d46SWarner Losh { 86ca987d46SWarner Losh struct disk_devdesc *dev; 87ca987d46SWarner Losh struct open_disk *od; 88ca987d46SWarner Losh 89ca987d46SWarner Losh dev = (struct disk_devdesc *)d; 90de04d704SWarner Losh od = (struct open_disk *)dev->dd.d_opendata; 91ca987d46SWarner Losh 92ca987d46SWarner Losh /* 93ca987d46SWarner Losh * The strategy function assumes the offset is in units of 512 byte 94ca987d46SWarner Losh * sectors. For larger sector sizes, we need to adjust the offset to 95ca987d46SWarner Losh * match the actual sector size. 96ca987d46SWarner Losh */ 97ca987d46SWarner Losh offset *= (od->sectorsize / 512); 98ca987d46SWarner Losh /* 99ca987d46SWarner Losh * As the GPT backup partition is located at the end of the disk, 100ca987d46SWarner Losh * to avoid reading past disk end, flag bcache not to use RA. 101ca987d46SWarner Losh */ 102de04d704SWarner Losh return (dev->dd.d_dev->dv_strategy(dev, F_READ | F_NORA, offset, 103ca987d46SWarner Losh blocks * od->sectorsize, (char *)buf, NULL)); 104ca987d46SWarner Losh } 105ca987d46SWarner Losh 106ca987d46SWarner Losh static int 107ca987d46SWarner Losh ptable_print(void *arg, const char *pname, const struct ptable_entry *part) 108ca987d46SWarner Losh { 109ca987d46SWarner Losh struct disk_devdesc dev; 110ca987d46SWarner Losh struct print_args *pa, bsd; 111ca987d46SWarner Losh struct open_disk *od; 112ca987d46SWarner Losh struct ptable *table; 113ca987d46SWarner Losh char line[80]; 114ca987d46SWarner Losh int res; 11571c96defSIan Lepore u_int sectsize; 11671c96defSIan Lepore uint64_t partsize; 117ca987d46SWarner Losh 118ca987d46SWarner Losh pa = (struct print_args *)arg; 119de04d704SWarner Losh od = (struct open_disk *)pa->dev->dd.d_opendata; 12071c96defSIan Lepore sectsize = od->sectorsize; 12171c96defSIan Lepore partsize = part->end - part->start + 1; 12241a1c642SToomas Soome snprintf(line, sizeof(line), " %s%s: %s", pa->prefix, pname, 12341a1c642SToomas Soome parttype2str(part->type)); 124ca987d46SWarner Losh if (pager_output(line)) 12541a1c642SToomas Soome return (1); 12641a1c642SToomas Soome 12741a1c642SToomas Soome if (pa->verbose) { 12841a1c642SToomas Soome /* Emit extra tab when the line is shorter than 3 tab stops */ 12941a1c642SToomas Soome if (strlen(line) < 24) 13041a1c642SToomas Soome (void) pager_output("\t"); 13141a1c642SToomas Soome 13241a1c642SToomas Soome snprintf(line, sizeof(line), "\t%s", 13341a1c642SToomas Soome display_size(partsize, sectsize)); 13441a1c642SToomas Soome if (pager_output(line)) 13541a1c642SToomas Soome return (1); 13641a1c642SToomas Soome } 13741a1c642SToomas Soome if (pager_output("\n")) 13841a1c642SToomas Soome return (1); 13941a1c642SToomas Soome 140ca987d46SWarner Losh res = 0; 141ca987d46SWarner Losh if (part->type == PART_FREEBSD) { 142ca987d46SWarner Losh /* Open slice with BSD label */ 143de04d704SWarner Losh dev.dd.d_dev = pa->dev->dd.d_dev; 144de04d704SWarner Losh dev.dd.d_unit = pa->dev->dd.d_unit; 145ca987d46SWarner Losh dev.d_slice = part->index; 14614243f8dSIan Lepore dev.d_partition = D_PARTNONE; 14771c96defSIan Lepore if (disk_open(&dev, partsize, sectsize) == 0) { 14871c96defSIan Lepore table = ptable_open(&dev, partsize, sectsize, ptblread); 149ca987d46SWarner Losh if (table != NULL) { 15041a1c642SToomas Soome snprintf(line, sizeof(line), " %s%s", 15141a1c642SToomas Soome pa->prefix, pname); 152ca987d46SWarner Losh bsd.dev = pa->dev; 153ca987d46SWarner Losh bsd.prefix = line; 154ca987d46SWarner Losh bsd.verbose = pa->verbose; 155ca987d46SWarner Losh res = ptable_iterate(table, &bsd, ptable_print); 156ca987d46SWarner Losh ptable_close(table); 157ca987d46SWarner Losh } 158ca987d46SWarner Losh disk_close(&dev); 159ca987d46SWarner Losh } 160ca987d46SWarner Losh } 161ca987d46SWarner Losh 162ca987d46SWarner Losh return (res); 163ca987d46SWarner Losh } 164ca987d46SWarner Losh 165ca987d46SWarner Losh int 166ca987d46SWarner Losh disk_print(struct disk_devdesc *dev, char *prefix, int verbose) 167ca987d46SWarner Losh { 168ca987d46SWarner Losh struct open_disk *od; 169ca987d46SWarner Losh struct print_args pa; 170ca987d46SWarner Losh 171ca987d46SWarner Losh /* Disk should be opened */ 172de04d704SWarner Losh od = (struct open_disk *)dev->dd.d_opendata; 173ca987d46SWarner Losh pa.dev = dev; 174ca987d46SWarner Losh pa.prefix = prefix; 175ca987d46SWarner Losh pa.verbose = verbose; 176ca987d46SWarner Losh return (ptable_iterate(od->table, &pa, ptable_print)); 177ca987d46SWarner Losh } 178ca987d46SWarner Losh 179ca987d46SWarner Losh int 180ca987d46SWarner Losh disk_read(struct disk_devdesc *dev, void *buf, uint64_t offset, u_int blocks) 181ca987d46SWarner Losh { 182ca987d46SWarner Losh struct open_disk *od; 183ca987d46SWarner Losh int ret; 184ca987d46SWarner Losh 185de04d704SWarner Losh od = (struct open_disk *)dev->dd.d_opendata; 186de04d704SWarner Losh ret = dev->dd.d_dev->dv_strategy(dev, F_READ, dev->d_offset + offset, 187ca987d46SWarner Losh blocks * od->sectorsize, buf, NULL); 188ca987d46SWarner Losh 189ca987d46SWarner Losh return (ret); 190ca987d46SWarner Losh } 191ca987d46SWarner Losh 192ca987d46SWarner Losh int 193ca987d46SWarner Losh disk_write(struct disk_devdesc *dev, void *buf, uint64_t offset, u_int blocks) 194ca987d46SWarner Losh { 195ca987d46SWarner Losh struct open_disk *od; 196ca987d46SWarner Losh int ret; 197ca987d46SWarner Losh 198de04d704SWarner Losh od = (struct open_disk *)dev->dd.d_opendata; 199de04d704SWarner Losh ret = dev->dd.d_dev->dv_strategy(dev, F_WRITE, dev->d_offset + offset, 200ca987d46SWarner Losh blocks * od->sectorsize, buf, NULL); 201ca987d46SWarner Losh 202ca987d46SWarner Losh return (ret); 203ca987d46SWarner Losh } 204ca987d46SWarner Losh 205ca987d46SWarner Losh int 206ca987d46SWarner Losh disk_ioctl(struct disk_devdesc *dev, u_long cmd, void *data) 207ca987d46SWarner Losh { 208de04d704SWarner Losh struct open_disk *od = dev->dd.d_opendata; 209ca987d46SWarner Losh 210ca987d46SWarner Losh if (od == NULL) 211ca987d46SWarner Losh return (ENOTTY); 212ca987d46SWarner Losh 213ca987d46SWarner Losh switch (cmd) { 214ca987d46SWarner Losh case DIOCGSECTORSIZE: 215ca987d46SWarner Losh *(u_int *)data = od->sectorsize; 216ca987d46SWarner Losh break; 217ca987d46SWarner Losh case DIOCGMEDIASIZE: 218ca987d46SWarner Losh if (dev->d_offset == 0) 219ca987d46SWarner Losh *(uint64_t *)data = od->mediasize; 220ca987d46SWarner Losh else 221ca987d46SWarner Losh *(uint64_t *)data = od->entrysize * od->sectorsize; 222ca987d46SWarner Losh break; 223ca987d46SWarner Losh default: 224ca987d46SWarner Losh return (ENOTTY); 225ca987d46SWarner Losh } 226ca987d46SWarner Losh 227ca987d46SWarner Losh return (0); 228ca987d46SWarner Losh } 229ca987d46SWarner Losh 230ca987d46SWarner Losh int 231ca987d46SWarner Losh disk_open(struct disk_devdesc *dev, uint64_t mediasize, u_int sectorsize) 232ca987d46SWarner Losh { 23332c52b48SAllan Jude struct disk_devdesc partdev; 234ca987d46SWarner Losh struct open_disk *od; 235ca987d46SWarner Losh struct ptable *table; 236ca987d46SWarner Losh struct ptable_entry part; 237ca987d46SWarner Losh int rc, slice, partition; 238ca987d46SWarner Losh 23915f5e297SToomas Soome if (sectorsize == 0) { 24015f5e297SToomas Soome DPRINTF("unknown sector size"); 24115f5e297SToomas Soome return (ENXIO); 24215f5e297SToomas Soome } 243ca987d46SWarner Losh rc = 0; 244ca987d46SWarner Losh od = (struct open_disk *)malloc(sizeof(struct open_disk)); 245ca987d46SWarner Losh if (od == NULL) { 2467325df02SKyle Evans DPRINTF("no memory"); 247ca987d46SWarner Losh return (ENOMEM); 248ca987d46SWarner Losh } 249de04d704SWarner Losh dev->dd.d_opendata = od; 250ca987d46SWarner Losh od->entrysize = 0; 251ca987d46SWarner Losh od->mediasize = mediasize; 252ca987d46SWarner Losh od->sectorsize = sectorsize; 25332c52b48SAllan Jude /* 25432c52b48SAllan Jude * While we are reading disk metadata, make sure we do it relative 25532c52b48SAllan Jude * to the start of the disk 25632c52b48SAllan Jude */ 25732c52b48SAllan Jude memcpy(&partdev, dev, sizeof(partdev)); 25832c52b48SAllan Jude partdev.d_offset = 0; 25914243f8dSIan Lepore partdev.d_slice = D_SLICENONE; 26014243f8dSIan Lepore partdev.d_partition = D_PARTNONE; 26132c52b48SAllan Jude 262436dbc42SAllan Jude dev->d_offset = 0; 26332c52b48SAllan Jude table = NULL; 26432c52b48SAllan Jude slice = dev->d_slice; 26532c52b48SAllan Jude partition = dev->d_partition; 26632c52b48SAllan Jude 267ed29b75cSToomas Soome DPRINTF("%s unit %d, slice %d, partition %d => %p", disk_fmtdev(dev), 268ed29b75cSToomas Soome dev->dd.d_unit, dev->d_slice, dev->d_partition, od); 269ca987d46SWarner Losh 270ca987d46SWarner Losh /* Determine disk layout. */ 27132c52b48SAllan Jude od->table = ptable_open(&partdev, mediasize / sectorsize, sectorsize, 272ca987d46SWarner Losh ptblread); 273ca987d46SWarner Losh if (od->table == NULL) { 2747325df02SKyle Evans DPRINTF("Can't read partition table"); 275ca987d46SWarner Losh rc = ENXIO; 276ca987d46SWarner Losh goto out; 277ca987d46SWarner Losh } 278ca987d46SWarner Losh 279ca987d46SWarner Losh if (ptable_getsize(od->table, &mediasize) != 0) { 280ca987d46SWarner Losh rc = ENXIO; 281ca987d46SWarner Losh goto out; 282ca987d46SWarner Losh } 283ca987d46SWarner Losh od->mediasize = mediasize; 284ca987d46SWarner Losh 285ca987d46SWarner Losh if (ptable_gettype(od->table) == PTABLE_BSD && 286ca987d46SWarner Losh partition >= 0) { 287ca987d46SWarner Losh /* It doesn't matter what value has d_slice */ 288ca987d46SWarner Losh rc = ptable_getpart(od->table, &part, partition); 289ca987d46SWarner Losh if (rc == 0) { 290ca987d46SWarner Losh dev->d_offset = part.start; 291ca987d46SWarner Losh od->entrysize = part.end - part.start + 1; 292ca987d46SWarner Losh } 29348990fceSBenno Rice } else if (ptable_gettype(od->table) == PTABLE_ISO9660) { 29448990fceSBenno Rice dev->d_offset = 0; 29548990fceSBenno Rice od->entrysize = mediasize; 296ca987d46SWarner Losh } else if (slice >= 0) { 297ca987d46SWarner Losh /* Try to get information about partition */ 298ca987d46SWarner Losh if (slice == 0) 299ca987d46SWarner Losh rc = ptable_getbestpart(od->table, &part); 300ca987d46SWarner Losh else 301ca987d46SWarner Losh rc = ptable_getpart(od->table, &part, slice); 302ca987d46SWarner Losh if (rc != 0) /* Partition doesn't exist */ 303ca987d46SWarner Losh goto out; 304ca987d46SWarner Losh dev->d_offset = part.start; 305ca987d46SWarner Losh od->entrysize = part.end - part.start + 1; 306ca987d46SWarner Losh slice = part.index; 307ca987d46SWarner Losh if (ptable_gettype(od->table) == PTABLE_GPT) { 308fa4b8179SWarner Losh partition = D_PARTISGPT; 309ca987d46SWarner Losh goto out; /* Nothing more to do */ 310fa4b8179SWarner Losh } else if (partition == D_PARTISGPT) { 311ca987d46SWarner Losh /* 312ca987d46SWarner Losh * When we try to open GPT partition, but partition 313ed29b75cSToomas Soome * table isn't GPT, reset partition value to 314ed29b75cSToomas Soome * D_PARTWILD and try to autodetect appropriate value. 315ca987d46SWarner Losh */ 316ed29b75cSToomas Soome partition = D_PARTWILD; 317ca987d46SWarner Losh } 318ed29b75cSToomas Soome 319ca987d46SWarner Losh /* 320ed29b75cSToomas Soome * If partition is D_PARTNONE, then disk_open() was called 321ed29b75cSToomas Soome * to open raw MBR slice. 322ed29b75cSToomas Soome */ 323ed29b75cSToomas Soome if (partition == D_PARTNONE) 324ed29b75cSToomas Soome goto out; 325ed29b75cSToomas Soome 326ed29b75cSToomas Soome /* 327ed29b75cSToomas Soome * If partition is D_PARTWILD and we are looking at a BSD slice, 328ca987d46SWarner Losh * then try to read BSD label, otherwise return the 329ca987d46SWarner Losh * whole MBR slice. 330ca987d46SWarner Losh */ 331ed29b75cSToomas Soome if (partition == D_PARTWILD && 332ca987d46SWarner Losh part.type != PART_FREEBSD) 333ca987d46SWarner Losh goto out; 334ca987d46SWarner Losh /* Try to read BSD label */ 335ca987d46SWarner Losh table = ptable_open(dev, part.end - part.start + 1, 336ca987d46SWarner Losh od->sectorsize, ptblread); 337ca987d46SWarner Losh if (table == NULL) { 3387325df02SKyle Evans DPRINTF("Can't read BSD label"); 339ca987d46SWarner Losh rc = ENXIO; 340ca987d46SWarner Losh goto out; 341ca987d46SWarner Losh } 342ca987d46SWarner Losh /* 343ed29b75cSToomas Soome * If slice contains BSD label and partition < 0, then 344ca987d46SWarner Losh * assume the 'a' partition. Otherwise just return the 345ca987d46SWarner Losh * whole MBR slice, because it can contain ZFS. 346ca987d46SWarner Losh */ 347ca987d46SWarner Losh if (partition < 0) { 348ca987d46SWarner Losh if (ptable_gettype(table) != PTABLE_BSD) 349ca987d46SWarner Losh goto out; 350ca987d46SWarner Losh partition = 0; 351ca987d46SWarner Losh } 352ca987d46SWarner Losh rc = ptable_getpart(table, &part, partition); 353ca987d46SWarner Losh if (rc != 0) 354ca987d46SWarner Losh goto out; 355ca987d46SWarner Losh dev->d_offset += part.start; 356ca987d46SWarner Losh od->entrysize = part.end - part.start + 1; 357ca987d46SWarner Losh } 358ca987d46SWarner Losh out: 359ca987d46SWarner Losh if (table != NULL) 360ca987d46SWarner Losh ptable_close(table); 361ca987d46SWarner Losh 362ca987d46SWarner Losh if (rc != 0) { 363ca987d46SWarner Losh if (od->table != NULL) 364ca987d46SWarner Losh ptable_close(od->table); 365ca987d46SWarner Losh free(od); 3667325df02SKyle Evans DPRINTF("%s could not open", disk_fmtdev(dev)); 367ca987d46SWarner Losh } else { 368ca987d46SWarner Losh /* Save the slice and partition number to the dev */ 369ca987d46SWarner Losh dev->d_slice = slice; 370ca987d46SWarner Losh dev->d_partition = partition; 3717325df02SKyle Evans DPRINTF("%s offset %lld => %p", disk_fmtdev(dev), 372ca987d46SWarner Losh (long long)dev->d_offset, od); 373ca987d46SWarner Losh } 374ca987d46SWarner Losh return (rc); 375ca987d46SWarner Losh } 376ca987d46SWarner Losh 377ca987d46SWarner Losh int 378ca987d46SWarner Losh disk_close(struct disk_devdesc *dev) 379ca987d46SWarner Losh { 380ca987d46SWarner Losh struct open_disk *od; 381ca987d46SWarner Losh 382de04d704SWarner Losh od = (struct open_disk *)dev->dd.d_opendata; 3837325df02SKyle Evans DPRINTF("%s closed => %p", disk_fmtdev(dev), od); 384ca987d46SWarner Losh ptable_close(od->table); 385ca987d46SWarner Losh free(od); 386ca987d46SWarner Losh return (0); 387ca987d46SWarner Losh } 388ca987d46SWarner Losh 389ca987d46SWarner Losh char * 390c32dde31SWarner Losh disk_fmtdev(struct devdesc *vdev) 391ca987d46SWarner Losh { 392c32dde31SWarner Losh struct disk_devdesc *dev = (struct disk_devdesc *)vdev; 393ca987d46SWarner Losh static char buf[128]; 394ca987d46SWarner Losh char *cp; 395ca987d46SWarner Losh 396c32dde31SWarner Losh assert(vdev->d_dev->dv_type == DEVT_DISK); 397de04d704SWarner Losh cp = buf + sprintf(buf, "%s%d", dev->dd.d_dev->dv_name, dev->dd.d_unit); 39814243f8dSIan Lepore if (dev->d_slice > D_SLICENONE) { 399ca987d46SWarner Losh #ifdef LOADER_GPT_SUPPORT 40014243f8dSIan Lepore if (dev->d_partition == D_PARTISGPT) { 401ca987d46SWarner Losh sprintf(cp, "p%d:", dev->d_slice); 402ca987d46SWarner Losh return (buf); 403ca987d46SWarner Losh } else 404ca987d46SWarner Losh #endif 405ca987d46SWarner Losh #ifdef LOADER_MBR_SUPPORT 406ca987d46SWarner Losh cp += sprintf(cp, "s%d", dev->d_slice); 407ca987d46SWarner Losh #endif 408ca987d46SWarner Losh } 40914243f8dSIan Lepore if (dev->d_partition > D_PARTNONE) 410ca987d46SWarner Losh cp += sprintf(cp, "%c", dev->d_partition + 'a'); 411ca987d46SWarner Losh strcat(cp, ":"); 412ca987d46SWarner Losh return (buf); 413ca987d46SWarner Losh } 414ca987d46SWarner Losh 415ca987d46SWarner Losh int 41617276525SWarner Losh disk_parsedev(struct devdesc **idev, const char *devspec, const char **path) 417ca987d46SWarner Losh { 418ca987d46SWarner Losh int unit, slice, partition; 419ca987d46SWarner Losh const char *np; 420ca987d46SWarner Losh char *cp; 42117276525SWarner Losh struct disk_devdesc *dev; 422ca987d46SWarner Losh 423*33bbe5ddSWarner Losh np = devspec + 4; /* Skip the leading 'disk' */ 42414243f8dSIan Lepore unit = -1; 425e77f4eb2SIan Lepore /* 426e77f4eb2SIan Lepore * If there is path/file info after the device info, then any missing 427e77f4eb2SIan Lepore * slice or partition info should be considered a request to search for 428e77f4eb2SIan Lepore * an appropriate partition. Otherwise we want to open the raw device 429e77f4eb2SIan Lepore * itself and not try to fill in missing info by searching. 430e77f4eb2SIan Lepore */ 431e77f4eb2SIan Lepore if ((cp = strchr(np, ':')) != NULL && cp[1] != '\0') { 43214243f8dSIan Lepore slice = D_SLICEWILD; 43314243f8dSIan Lepore partition = D_PARTWILD; 434e77f4eb2SIan Lepore } else { 435e77f4eb2SIan Lepore slice = D_SLICENONE; 436e77f4eb2SIan Lepore partition = D_PARTNONE; 437e77f4eb2SIan Lepore } 438e77f4eb2SIan Lepore 439ca987d46SWarner Losh if (*np != '\0' && *np != ':') { 440ca987d46SWarner Losh unit = strtol(np, &cp, 10); 441ca987d46SWarner Losh if (cp == np) 442ca987d46SWarner Losh return (EUNIT); 443ca987d46SWarner Losh #ifdef LOADER_GPT_SUPPORT 444ca987d46SWarner Losh if (*cp == 'p') { 445ca987d46SWarner Losh np = cp + 1; 446ca987d46SWarner Losh slice = strtol(np, &cp, 10); 447ca987d46SWarner Losh if (np == cp) 448ca987d46SWarner Losh return (ESLICE); 449ca987d46SWarner Losh /* we don't support nested partitions on GPT */ 450ca987d46SWarner Losh if (*cp != '\0' && *cp != ':') 451ca987d46SWarner Losh return (EINVAL); 452fa4b8179SWarner Losh partition = D_PARTISGPT; 453ca987d46SWarner Losh } else 454ca987d46SWarner Losh #endif 455ca987d46SWarner Losh #ifdef LOADER_MBR_SUPPORT 456ca987d46SWarner Losh if (*cp == 's') { 457ca987d46SWarner Losh np = cp + 1; 458ca987d46SWarner Losh slice = strtol(np, &cp, 10); 459ca987d46SWarner Losh if (np == cp) 460ca987d46SWarner Losh return (ESLICE); 461ca987d46SWarner Losh } 462ca987d46SWarner Losh #endif 463ca987d46SWarner Losh if (*cp != '\0' && *cp != ':') { 464ca987d46SWarner Losh partition = *cp - 'a'; 465ca987d46SWarner Losh if (partition < 0) 466ca987d46SWarner Losh return (EPART); 467ca987d46SWarner Losh cp++; 468ca987d46SWarner Losh } 469ca987d46SWarner Losh } else 470ca987d46SWarner Losh return (EINVAL); 471ca987d46SWarner Losh 472ca987d46SWarner Losh if (*cp != '\0' && *cp != ':') 473ca987d46SWarner Losh return (EINVAL); 47417276525SWarner Losh dev = malloc(sizeof(*dev)); 47517276525SWarner Losh if (dev == NULL) 47617276525SWarner Losh return (ENOMEM); 477de04d704SWarner Losh dev->dd.d_unit = unit; 478ca987d46SWarner Losh dev->d_slice = slice; 479ca987d46SWarner Losh dev->d_partition = partition; 48017276525SWarner Losh *idev = &dev->dd; 481ca987d46SWarner Losh if (path != NULL) 482ca987d46SWarner Losh *path = (*cp == '\0') ? cp: cp + 1; 483ca987d46SWarner Losh return (0); 484ca987d46SWarner Losh } 485