1105816Sphk/* 2121921Smarcel * Copyright (c) 2003 Marcel Moolenaar 3121921Smarcel * All rights reserved. 4121921Smarcel * 5121921Smarcel * Redistribution and use in source and binary forms, with or without 6121921Smarcel * modification, are permitted provided that the following conditions 7121921Smarcel * are met: 8121921Smarcel * 9121921Smarcel * 1. Redistributions of source code must retain the above copyright 10121921Smarcel * notice, this list of conditions and the following disclaimer. 11121921Smarcel * 2. Redistributions in binary form must reproduce the above copyright 12121921Smarcel * notice, this list of conditions and the following disclaimer in the 13121921Smarcel * documentation and/or other materials provided with the distribution. 14121921Smarcel * 15121921Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16121921Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17121921Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18121921Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19121921Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20121921Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21121921Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22121921Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23121921Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24121921Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25121921Smarcel * 26121921Smarcel * CRC32 code derived from work by Gary S. Brown. 27105816Sphk */ 28105816Sphk 29105816Sphk#include <sys/cdefs.h> 30105816Sphk__FBSDID("$FreeBSD$"); 31105816Sphk 32105816Sphk#include <sys/types.h> 33105816Sphk#include <sys/disklabel.h> 34105816Sphk#include <sys/diskmbr.h> 35121921Smarcel#include <sys/gpt.h> 36121921Smarcel#include <sys/stat.h> 37121921Smarcel 38121921Smarcel#include <errno.h> 39121921Smarcel#include <fcntl.h> 40105816Sphk#include <paths.h> 41121921Smarcel#include <stddef.h> 42121921Smarcel#include <stdio.h> 43121921Smarcel#include <stdlib.h> 44121921Smarcel#include <string.h> 45121921Smarcel#include <unistd.h> 46121921Smarcel#include <uuid.h> 47121921Smarcel 48105816Sphk#include "libdisk.h" 49105816Sphk 50121921Smarcelstatic uuid_t _efi = GPT_ENT_TYPE_EFI; 51121921Smarcelstatic uuid_t _fbsd = GPT_ENT_TYPE_FREEBSD; 52121921Smarcelstatic uuid_t _swap = GPT_ENT_TYPE_FREEBSD_SWAP; 53121921Smarcelstatic uuid_t _ufs = GPT_ENT_TYPE_FREEBSD_UFS; 54121921Smarcel 55121921Smarcelstatic uint32_t crc32_tab[] = { 56121921Smarcel 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 57121921Smarcel 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 58121921Smarcel 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 59121921Smarcel 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 60121921Smarcel 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 61121921Smarcel 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 62121921Smarcel 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 63121921Smarcel 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 64121921Smarcel 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 65121921Smarcel 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 66121921Smarcel 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 67121921Smarcel 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 68121921Smarcel 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 69121921Smarcel 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 70121921Smarcel 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 71121921Smarcel 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 72121921Smarcel 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 73121921Smarcel 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 74121921Smarcel 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 75121921Smarcel 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 76121921Smarcel 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 77121921Smarcel 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 78121921Smarcel 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 79121921Smarcel 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 80121921Smarcel 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 81121921Smarcel 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 82121921Smarcel 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 83121921Smarcel 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 84121921Smarcel 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 85121921Smarcel 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 86121921Smarcel 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 87121921Smarcel 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 88121921Smarcel 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 89121921Smarcel 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 90121921Smarcel 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 91121921Smarcel 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 92121921Smarcel 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 93121921Smarcel 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 94121921Smarcel 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 95121921Smarcel 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 96121921Smarcel 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 97121921Smarcel 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 98121921Smarcel 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 99121921Smarcel}; 100121921Smarcel 101122839Smarcelstatic uint32_t 102121921Smarcelcrc32(const void *buf, size_t size) 103121921Smarcel{ 104121921Smarcel const uint8_t *p; 105121921Smarcel uint32_t crc; 106121921Smarcel 107121921Smarcel p = buf; 108121921Smarcel crc = ~0U; 109121921Smarcel 110121921Smarcel while (size--) 111121921Smarcel crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); 112121921Smarcel 113121921Smarcel return (crc ^ ~0U); 114121921Smarcel} 115121921Smarcel 116121921Smarcelstatic int 117121921Smarcelwrite_pmbr(int fd, const struct disk *disk) 118121921Smarcel{ 119121921Smarcel struct dos_partition dp; 120121921Smarcel char *buffer; 121121921Smarcel u_long nsects; 122121921Smarcel int error; 123121921Smarcel 124125124Smarcel error = 0; 125121921Smarcel nsects = disk->media_size / disk->sector_size; 126161135Smarcel nsects--; /* The GPT starts at LBA 1 */ 127161135Smarcel 128121921Smarcel buffer = calloc(disk->sector_size, 1); 129121921Smarcel if (buffer == NULL) 130121921Smarcel return (ENOMEM); 131121921Smarcel buffer[DOSMAGICOFFSET] = DOSMAGIC & 0xff; 132121921Smarcel buffer[DOSMAGICOFFSET + 1] = DOSMAGIC >> 8; 133121921Smarcel 134121921Smarcel dp.dp_flag = 0; 135121921Smarcel dp.dp_shd = dp.dp_ssect = dp.dp_scyl = 0xff; 136121921Smarcel dp.dp_typ = DOSPTYP_PMBR; 137121921Smarcel dp.dp_ehd = dp.dp_esect = dp.dp_ecyl = 0xff; 138121921Smarcel dp.dp_start = 1; 139121921Smarcel dp.dp_size = (nsects > 0xffffffffu) ? ~0u : nsects; 140121921Smarcel memcpy(buffer + DOSPARTOFF, &dp, DOSPARTSIZE); 141121921Smarcel 142121921Smarcel if (lseek(fd, 0L, SEEK_SET) != 0L || 143121921Smarcel write(fd, buffer, disk->sector_size) != disk->sector_size) 144121921Smarcel error = (errno) ? errno : EAGAIN; 145121921Smarcel 146121921Smarcel free(buffer); 147121921Smarcel return (error); 148121921Smarcel} 149121921Smarcel 150121921Smarcelstatic int 151121921Smarcelread_gpt(int fd, const struct disk *disk, struct gpt_hdr *hdr, 152121921Smarcel struct gpt_ent *tbl) 153121921Smarcel{ 154121921Smarcel char *buffer; 155121921Smarcel off_t off; 156121921Smarcel size_t nsects, sz; 157121921Smarcel int error, i; 158121921Smarcel 159125124Smarcel error = 0; 160121921Smarcel nsects = disk->gpt_size * sizeof(struct gpt_ent) / disk->sector_size; 161121921Smarcel nsects++; 162121921Smarcel sz = nsects * disk->sector_size; 163121921Smarcel buffer = malloc(sz); 164121921Smarcel if (buffer == NULL) 165121921Smarcel return (ENOMEM); 166121921Smarcel 167121921Smarcel if (lseek(fd, disk->sector_size, SEEK_SET) != disk->sector_size || 168121921Smarcel read(fd, buffer, disk->sector_size) != disk->sector_size) { 169121921Smarcel error = (errno) ? errno : EAGAIN; 170121921Smarcel goto bail; 171121921Smarcel } 172121921Smarcel if (memcmp(buffer, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0) { 173121921Smarcel /* 174121921Smarcel * No GPT on disk. Create one out of thin air. 175121921Smarcel */ 176121921Smarcel bzero(&hdr[0], sizeof(struct gpt_hdr)); 177121921Smarcel memcpy(hdr[0].hdr_sig, GPT_HDR_SIG, sizeof(hdr[0].hdr_sig)); 178121921Smarcel hdr[0].hdr_revision = GPT_HDR_REVISION; 179121921Smarcel hdr[0].hdr_size = offsetof(struct gpt_hdr, padding); 180121921Smarcel hdr[0].hdr_lba_self = 1; 181121921Smarcel hdr[0].hdr_lba_alt = disk->media_size / disk->sector_size - 1L; 182121921Smarcel hdr[0].hdr_lba_start = disk->lba_start; 183121921Smarcel hdr[0].hdr_lba_end = disk->lba_end; 184121921Smarcel uuid_create(&hdr[0].hdr_uuid, NULL); 185121921Smarcel hdr[0].hdr_lba_table = 2; 186121921Smarcel hdr[0].hdr_entries = disk->gpt_size; 187121921Smarcel hdr[0].hdr_entsz = sizeof(struct gpt_ent); 188121921Smarcel hdr[1] = hdr[0]; 189121921Smarcel hdr[1].hdr_lba_self = hdr[0].hdr_lba_alt; 190121921Smarcel hdr[1].hdr_lba_alt = hdr[0].hdr_lba_self; 191121921Smarcel hdr[1].hdr_lba_table = disk->lba_end + 1; 192121921Smarcel 193121921Smarcel for (i = 0; i < disk->gpt_size; i++) { 194121921Smarcel bzero(&tbl[i], sizeof(struct gpt_ent)); 195121921Smarcel uuid_create(&tbl[i].ent_uuid, NULL); 196121921Smarcel } 197121921Smarcel 198121921Smarcel goto bail; 199121921Smarcel } 200121921Smarcel 201121921Smarcel /* 202121921Smarcel * We have a GPT on disk. Read it. 203121921Smarcel */ 204121921Smarcel memcpy(&hdr[0], buffer, sizeof(struct gpt_hdr)); 205121921Smarcel off = hdr->hdr_lba_table * disk->sector_size; 206121921Smarcel if (lseek(fd, off, SEEK_SET) != off || 207121921Smarcel read(fd, buffer, sz) != sz) { 208121921Smarcel error = (errno) ? errno : EAGAIN; 209121921Smarcel goto bail; 210121921Smarcel } 211121921Smarcel memcpy(tbl, buffer, sizeof(struct gpt_ent) * disk->gpt_size); 212121921Smarcel off = hdr->hdr_lba_alt * disk->sector_size; 213121921Smarcel if (lseek(fd, off, SEEK_SET) != off || 214121921Smarcel read(fd, buffer, disk->sector_size) != disk->sector_size) { 215121921Smarcel error = (errno) ? errno : EAGAIN; 216121921Smarcel goto bail; 217121921Smarcel } 218121921Smarcel memcpy(&hdr[1], buffer, sizeof(struct gpt_hdr)); 219121921Smarcel 220121921Smarcelbail: 221121921Smarcel free(buffer); 222121921Smarcel return (error); 223121921Smarcel} 224121921Smarcel 225121921Smarcelstatic int 226121921Smarcelupdate_gpt(int fd, const struct disk *disk, struct gpt_hdr *hdr, 227121921Smarcel struct gpt_ent *tbl) 228121921Smarcel{ 229122025Smarcel struct gpt_ent *save; 230121921Smarcel char *buffer; 231121921Smarcel struct chunk *c; 232121921Smarcel off_t off; 233121921Smarcel size_t bufsz; 234122025Smarcel int error, idx, sav; 235121921Smarcel 236125124Smarcel error = 0; 237125124Smarcel 238122025Smarcel /* 239122025Smarcel * Save the entries of those chunks that have an index. They are 240122025Smarcel * the ones that exist on disk already. 241122025Smarcel */ 242122025Smarcel sav = 0; 243122025Smarcel for (c = disk->chunks->part; c != NULL; c = c->next) { 244122025Smarcel if ((c->flags & CHUNK_HAS_INDEX)) 245122025Smarcel sav++; 246122025Smarcel } 247122025Smarcel if (sav > 0) { 248122025Smarcel save = malloc(sav * sizeof(struct gpt_ent)); 249122025Smarcel if (save == NULL) 250122025Smarcel abort(); 251122025Smarcel sav = 0; 252122025Smarcel for (c = disk->chunks->part; c != NULL; c = c->next) { 253122025Smarcel if ((c->flags & CHUNK_HAS_INDEX)) { 254122025Smarcel idx = CHUNK_FTOI(c->flags); 255122025Smarcel save[sav] = tbl[idx]; 256122025Smarcel c->flags ^= CHUNK_ITOF(idx); 257122025Smarcel c->flags |= CHUNK_ITOF(sav); 258122025Smarcel sav++; 259122025Smarcel } 260122025Smarcel } 261122025Smarcel } else 262122025Smarcel save = NULL; 263122025Smarcel 264122025Smarcel /* 265122025Smarcel * Clear the table entries. 266122025Smarcel */ 267122025Smarcel for (idx = 0; idx < disk->gpt_size; idx++) { 268122025Smarcel uuid_create_nil(&tbl[idx].ent_type, NULL); 269122025Smarcel tbl[idx].ent_lba_start = 0; 270122025Smarcel tbl[idx].ent_lba_end = 0; 271122025Smarcel tbl[idx].ent_attr = 0; 272122025Smarcel bzero(tbl[idx].ent_name, sizeof(tbl[idx].ent_name)); 273122025Smarcel } 274122025Smarcel 275122025Smarcel /* 276122025Smarcel * Repopulate the table from the chunks, possibly using saved 277122025Smarcel * information. 278122025Smarcel */ 279121921Smarcel idx = 0; 280121921Smarcel for (c = disk->chunks->part; c != NULL; c = c->next) { 281121921Smarcel if (!(c->flags & CHUNK_HAS_INDEX)) { 282121921Smarcel switch (c->type) { 283121921Smarcel case freebsd: 284121921Smarcel tbl[idx].ent_type = _fbsd; 285121921Smarcel break; 286121921Smarcel case efi: 287121921Smarcel tbl[idx].ent_type = _efi; 288121921Smarcel break; 289121921Smarcel case part: 290121921Smarcel switch (c->subtype) { 291121921Smarcel case FS_SWAP: 292121921Smarcel tbl[idx].ent_type = _swap; 293121921Smarcel break; 294121921Smarcel case FS_BSDFFS: 295121921Smarcel tbl[idx].ent_type = _ufs; 296121921Smarcel break; 297121921Smarcel default: 298121921Smarcel return (EINVAL); 299121921Smarcel } 300121921Smarcel break; 301121921Smarcel default: 302121921Smarcel return (EINVAL); 303121921Smarcel } 304122025Smarcel } else { 305122025Smarcel sav = CHUNK_FTOI(c->flags); 306122025Smarcel tbl[idx].ent_type = save[sav].ent_type; 307122025Smarcel memcpy(tbl[idx].ent_name, save[sav].ent_name, 308122025Smarcel sizeof(tbl[idx].ent_name)); 309122025Smarcel } 310121931Smarcel tbl[idx].ent_lba_start = c->offset; 311121931Smarcel tbl[idx].ent_lba_end = c->end; 312122025Smarcel 313122025Smarcel idx++; 314122025Smarcel if (idx == disk->gpt_size) 315122025Smarcel return (ENOSPC); 316121921Smarcel } 317122025Smarcel if (save != NULL) 318122025Smarcel free(save); 319121921Smarcel 320121921Smarcel hdr[0].hdr_crc_table = crc32(tbl, 321121921Smarcel disk->gpt_size * sizeof(struct gpt_ent)); 322121921Smarcel hdr[0].hdr_crc_self = 0; 323121921Smarcel hdr[0].hdr_crc_self = crc32(&hdr[0], hdr[0].hdr_size); 324121921Smarcel 325121921Smarcel hdr[1].hdr_crc_table = hdr[0].hdr_crc_table; 326121921Smarcel hdr[1].hdr_crc_self = 0; 327121921Smarcel hdr[1].hdr_crc_self = crc32(&hdr[1], hdr[1].hdr_size); 328121921Smarcel 329121921Smarcel /* 330121921Smarcel * Write the new GPT back to the disk. 331121921Smarcel */ 332121921Smarcel bufsz = disk->gpt_size * sizeof(struct gpt_ent); 333121921Smarcel if (bufsz == 0 || bufsz % disk->sector_size) 334121921Smarcel bufsz += disk->sector_size; 335121921Smarcel bufsz = (bufsz / disk->sector_size) * disk->sector_size; 336121921Smarcel buffer = calloc(1, bufsz); 337121921Smarcel 338121921Smarcel memcpy(buffer, &hdr[0], sizeof(struct gpt_hdr)); 339121921Smarcel off = hdr[0].hdr_lba_self * disk->sector_size; 340121921Smarcel if (lseek(fd, off, SEEK_SET) != off || 341121921Smarcel write(fd, buffer, disk->sector_size) != disk->sector_size) { 342121921Smarcel error = (errno) ? errno : EAGAIN; 343121921Smarcel goto bail; 344121921Smarcel } 345121921Smarcel memcpy(buffer, &hdr[1], sizeof(struct gpt_hdr)); 346121921Smarcel off = hdr[1].hdr_lba_self * disk->sector_size; 347121921Smarcel if (lseek(fd, off, SEEK_SET) != off || 348121921Smarcel write(fd, buffer, disk->sector_size) != disk->sector_size) { 349121921Smarcel error = (errno) ? errno : EAGAIN; 350121921Smarcel goto bail; 351121921Smarcel } 352121921Smarcel memcpy(buffer, tbl, disk->gpt_size * sizeof(struct gpt_ent)); 353121921Smarcel off = hdr[0].hdr_lba_table * disk->sector_size; 354121921Smarcel if (lseek(fd, off, SEEK_SET) != off || 355121921Smarcel write(fd, buffer, bufsz) != bufsz) { 356121921Smarcel error = (errno) ? errno : EAGAIN; 357121921Smarcel goto bail; 358121921Smarcel } 359121921Smarcel off = hdr[1].hdr_lba_table * disk->sector_size; 360121921Smarcel if (lseek(fd, off, SEEK_SET) != off || 361121921Smarcel write(fd, buffer, bufsz) != bufsz) { 362121921Smarcel error = (errno) ? errno : EAGAIN; 363121921Smarcel goto bail; 364121921Smarcel } 365121921Smarcel 366121921Smarcelbail: 367121921Smarcel free(buffer); 368121921Smarcel return (error); 369121921Smarcel} 370121921Smarcel 371105816Sphkint 372121921SmarcelWrite_Disk(const struct disk *disk) 373105816Sphk{ 374121921Smarcel char devname[64]; 375121921Smarcel struct gpt_hdr *hdr; 376121921Smarcel struct gpt_ent *tbl; 377121921Smarcel int error, fd; 378121921Smarcel 379121921Smarcel hdr = malloc(sizeof(struct gpt_hdr) * 2); 380121921Smarcel if (hdr == NULL) 381121921Smarcel return (ENOMEM); 382121921Smarcel tbl = malloc(sizeof(struct gpt_ent) * disk->gpt_size); 383121921Smarcel if (tbl == NULL) { 384121921Smarcel free(hdr); 385121921Smarcel return (ENOMEM); 386121921Smarcel } 387121921Smarcel 388121921Smarcel snprintf(devname, sizeof(devname), "%s%s", _PATH_DEV, disk->name); 389121921Smarcel fd = open(devname, O_RDWR); 390121921Smarcel if (fd == -1) { 391121921Smarcel free(tbl); 392121921Smarcel free(hdr); 393121921Smarcel return (errno); 394121921Smarcel } 395121921Smarcel 396121921Smarcel /* 397121921Smarcel * We can always write the PMBR, because we reject disks that do not 398121921Smarcel * have a PMBR and are not virgin. 399121921Smarcel */ 400121921Smarcel error = write_pmbr(fd, disk); 401121921Smarcel if (error) 402121921Smarcel goto bail; 403121921Smarcel 404121921Smarcel /* 405121921Smarcel * Read the existing GPT from disk or otherwise create one out of 406121921Smarcel * thin air. This way we can preserve the UUIDs and the entry names 407121921Smarcel * when updating it. 408121921Smarcel */ 409121921Smarcel error = read_gpt(fd, disk, hdr, tbl); 410121921Smarcel if (error) 411121921Smarcel goto bail; 412121921Smarcel 413121921Smarcel /* 414121921Smarcel * Update and write the in-memory copy of the GPT. 415121921Smarcel */ 416121921Smarcel error = update_gpt(fd, disk, hdr, tbl); 417121921Smarcel 418121921Smarcelbail: 419121921Smarcel close(fd); 420121921Smarcel free(tbl); 421121921Smarcel free(hdr); 422121921Smarcel return (error); 423105816Sphk} 424