Annotation of src/sbin/gpt/resizedisk.c, Revision 1.6.2.2
1.6.2.2 ! snj 1: /*-
! 2: * Copyright (c) 2002 Marcel Moolenaar
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: *
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: *
! 15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 17: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 18: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 19: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 20: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 21: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 22: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 23: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 24: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 25: */
! 26:
! 27: #if HAVE_NBTOOL_CONFIG_H
! 28: #include "nbtool_config.h"
! 29: #endif
! 30:
! 31: #include <sys/cdefs.h>
! 32: #ifdef __FBSDID
! 33: __FBSDID("$FreeBSD: src/sbin/gpt/add.c,v 1.14 2006/06/22 22:05:28 marcel Exp $");
! 34: #endif
! 35: #ifdef __RCSID
! 36: __RCSID("$NetBSD: resizedisk.c,v 1.1 2014/09/23 07:47:54 jnemeth Exp $");
! 37: #endif
! 38:
! 39: #include <sys/bootblock.h>
! 40: #include <sys/types.h>
! 41:
! 42: #include <err.h>
! 43: #include <stddef.h>
! 44: #include <stdio.h>
! 45: #include <stdlib.h>
! 46: #include <string.h>
! 47: #include <unistd.h>
! 48:
! 49: #include "map.h"
! 50: #include "gpt.h"
! 51:
! 52: static uint64_t sector, size;
! 53:
! 54: const char resizediskmsg[] = "resizedisk [-s size] device ...";
! 55:
! 56: __dead static void
! 57: usage_resizedisk(void)
! 58: {
! 59:
! 60: fprintf(stderr,
! 61: "usage: %s %s\n", getprogname(), resizediskmsg);
! 62: exit(1);
! 63: }
! 64:
! 65: /*
! 66: * relocate the secondary GPT based on the following criteria:
! 67: * - size not specified
! 68: * - disk has not changed size, do nothing
! 69: * - disk has grown, relocate secondary
! 70: * - disk has shrunk, create new secondary
! 71: * - size specified
! 72: * - size is larger then disk or same as current location, do nothing
! 73: * - relocate or create new secondary
! 74: * - when shrinking, verify that table fits
! 75: */
! 76: static void
! 77: resizedisk(int fd)
! 78: {
! 79: map_t *gpt, *tpg;
! 80: map_t *tbl, *lbt;
! 81: map_t *mbrmap;
! 82: struct gpt_hdr *hdr;
! 83: struct gpt_ent *ent;
! 84: struct mbr *mbr;
! 85: uint64_t last, oldloc, newloc, lastdata, gpt_size;
! 86: int i;
! 87:
! 88: last = mediasz / secsz - 1;
! 89: lastdata = 0;
! 90: newloc = 0;
! 91:
! 92: if (sector > last) {
! 93: warnx("%s: specified size is larger then the disk",
! 94: device_name);
! 95: return;
! 96: }
! 97:
! 98: mbrmap = map_find(MAP_TYPE_PMBR);
! 99: if (mbrmap == NULL || mbrmap->map_start != 0) {
! 100: warnx("%s: error: no valid Protective MBR found", device_name);
! 101: return;
! 102: }
! 103: mbr = mbrmap->map_data;
! 104:
! 105: gpt = map_find(MAP_TYPE_PRI_GPT_HDR);
! 106: ent = NULL;
! 107: if (gpt == NULL) {
! 108: warnx("%s: error: no primary GPT header; run create or recover",
! 109: device_name);
! 110: return;
! 111: }
! 112: hdr = gpt->map_data;
! 113: oldloc = le64toh(hdr->hdr_lba_alt);
! 114:
! 115: tpg = map_find(MAP_TYPE_SEC_GPT_HDR);
! 116: if (tpg == NULL)
! 117: if (gpt_gpt(fd, oldloc, 1))
! 118: tpg = map_find(MAP_TYPE_SEC_GPT_HDR);
! 119:
! 120: tbl = map_find(MAP_TYPE_PRI_GPT_TBL);
! 121: lbt = map_find(MAP_TYPE_SEC_GPT_TBL);
! 122: if (tbl == NULL) {
! 123: warnx("%s: error: run recover -- trust me", device_name);
! 124: return;
! 125: }
! 126:
! 127: gpt_size = tbl->map_size;
! 128: if (sector == oldloc) {
! 129: warnx("%s: device is already the specified size", device_name);
! 130: return;
! 131: }
! 132: if (sector == 0 && last == oldloc) {
! 133: warnx("%s: device hasn't changed size", device_name);
! 134: return;
! 135: }
! 136:
! 137: for (ent = tbl->map_data; ent <
! 138: (struct gpt_ent *)((char *)tbl->map_data +
! 139: le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)); ent++) {
! 140: if (!gpt_uuid_is_nil(ent->ent_type) &&
! 141: (le64toh(ent->ent_lba_end) > lastdata)) {
! 142: lastdata = le64toh(ent->ent_lba_end);
! 143: }
! 144: }
! 145: if (sector - gpt_size <= lastdata) {
! 146: warnx("%s: not enough space at %" PRIu64
! 147: " for secondary GPT table", device_name, sector);
! 148: return;
! 149: }
! 150: if (last - gpt_size <= lastdata) {
! 151: warnx("%s: not enough space for new secondary GPT table",
! 152: device_name);
! 153: return;
! 154: }
! 155:
! 156: if (sector > oldloc)
! 157: newloc = sector;
! 158: if (sector > 0 && sector < oldloc && last >= oldloc)
! 159: newloc = sector;
! 160: if (sector == 0 && last > oldloc)
! 161: newloc = last;
! 162: if (newloc > 0) {
! 163: if (tpg == NULL) {
! 164: warnx("%s: error: no secondary GPT header; run recover",
! 165: device_name);
! 166: return;
! 167: }
! 168: if (lbt == NULL) {
! 169: warnx("%s: error: run recover -- trust me",
! 170: device_name);
! 171: return;
! 172: }
! 173: tpg->map_start = newloc;
! 174: lbt->map_start = newloc - gpt_size;
! 175: } else {
! 176: if (sector > 0)
! 177: newloc = sector;
! 178: else
! 179: newloc = last;
! 180: tpg = map_add(newloc, 1LL, MAP_TYPE_SEC_GPT_HDR,
! 181: calloc(1, secsz));
! 182: lbt = map_add(newloc - gpt_size, gpt_size, MAP_TYPE_SEC_GPT_TBL,
! 183: tbl->map_data);
! 184: memcpy(tpg->map_data, gpt->map_data, secsz);
! 185: }
! 186:
! 187: hdr = gpt->map_data;
! 188: hdr->hdr_lba_alt = tpg->map_start;
! 189: hdr->hdr_crc_self = 0;
! 190: hdr->hdr_lba_end = htole64(lbt->map_start - 1);
! 191: hdr->hdr_crc_self =
! 192: htole32(crc32(gpt->map_data, GPT_HDR_SIZE));
! 193: gpt_write(fd, gpt);
! 194:
! 195: hdr = tpg->map_data;
! 196: hdr->hdr_lba_self = htole64(tpg->map_start);
! 197: hdr->hdr_lba_alt = htole64(gpt->map_start);
! 198: hdr->hdr_lba_end = htole64(lbt->map_start - 1);
! 199: hdr->hdr_lba_table = htole64(lbt->map_start);
! 200: hdr->hdr_crc_self = 0;
! 201: hdr->hdr_crc_self =
! 202: htole32(crc32(tpg->map_data, GPT_HDR_SIZE));
! 203: gpt_write(fd, lbt);
! 204: gpt_write(fd, tpg);
! 205:
! 206: for (i = 0; i < 4; i++)
! 207: if (mbr->mbr_part[0].part_typ == MBR_PTYPE_PMBR)
! 208: break;
! 209: if (i == 4) {
! 210: warnx("%s: no valid PMBR partition found", device_name);
! 211: return;
! 212: }
! 213: if (last > 0xffffffff) {
! 214: mbr->mbr_part[0].part_size_lo = htole16(0xffff);
! 215: mbr->mbr_part[0].part_size_hi = htole16(0xffff);
! 216: } else {
! 217: mbr->mbr_part[0].part_size_lo = htole16(last);
! 218: mbr->mbr_part[0].part_size_hi = htole16(last >> 16);
! 219: }
! 220: gpt_write(fd, mbrmap);
! 221:
! 222: return;
! 223: }
! 224:
! 225: int
! 226: cmd_resizedisk(int argc, char *argv[])
! 227: {
! 228: char *p;
! 229: int ch, fd;
! 230: int64_t human_num;
! 231:
! 232: while ((ch = getopt(argc, argv, "s:")) != -1) {
! 233: switch(ch) {
! 234: case 's':
! 235: if (sector > 0 || size > 0)
! 236: usage_resizedisk();
! 237: sector = strtoll(optarg, &p, 10);
! 238: if (sector < 1)
! 239: usage_resizedisk();
! 240: if (*p == '\0')
! 241: break;
! 242: if (*p == 's' || *p == 'S') {
! 243: if (*(p + 1) == '\0')
! 244: break;
! 245: else
! 246: usage_resizedisk();
! 247: }
! 248: if (*p == 'b' || *p == 'B') {
! 249: if (*(p + 1) == '\0') {
! 250: size = sector;
! 251: sector = 0;
! 252: break;
! 253: } else
! 254: usage_resizedisk();
! 255: }
! 256: if (dehumanize_number(optarg, &human_num) < 0)
! 257: usage_resizedisk();
! 258: size = human_num;
! 259: sector = 0;
! 260: break;
! 261: default:
! 262: usage_resizedisk();
! 263: }
! 264: }
! 265:
! 266: if (argc == optind)
! 267: usage_resizedisk();
! 268:
! 269: while (optind < argc) {
! 270: fd = gpt_open(argv[optind++]);
! 271: if (fd == -1) {
! 272: warn("unable to open device '%s'", device_name);
! 273: continue;
! 274: }
! 275:
! 276: if (size % secsz != 0) {
! 277: warnx("Size in bytes must be a multiple of sector "
! 278: "size;");
! 279: warnx("the sector size for %s is %d bytes.",
! 280: device_name, secsz);
! 281: continue;
! 282: }
! 283: if (size > 0)
! 284: sector = size / secsz - 1;
! 285:
! 286: resizedisk(fd);
! 287:
! 288: gpt_close(fd);
! 289: }
! 290:
! 291: return 0;
! 292: }
CVSweb <webmaster@jp.NetBSD.org>