1 1.1 christos /*- 2 1.1 christos * Copyright (c) 2002 Marcel Moolenaar 3 1.1 christos * All rights reserved. 4 1.1 christos * 5 1.1 christos * Redistribution and use in source and binary forms, with or without 6 1.1 christos * modification, are permitted provided that the following conditions 7 1.1 christos * are met: 8 1.1 christos * 9 1.1 christos * 1. Redistributions of source code must retain the above copyright 10 1.1 christos * notice, this list of conditions and the following disclaimer. 11 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 christos * notice, this list of conditions and the following disclaimer in the 13 1.1 christos * documentation and/or other materials provided with the distribution. 14 1.1 christos * 15 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 christos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 1.1 christos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 1.1 christos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 1.1 christos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 1.1 christos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 1.1 christos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 1.1 christos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 1.1 christos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 1.1 christos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 1.1 christos * 26 1.1 christos * CRC32 code derived from work by Gary S. Brown. 27 1.1 christos */ 28 1.1 christos 29 1.31 christos #if HAVE_NBTOOL_CONFIG_H 30 1.31 christos #include "nbtool_config.h" 31 1.31 christos #endif 32 1.31 christos 33 1.1 christos #include <sys/cdefs.h> 34 1.2 christos #ifdef __FBSDID 35 1.1 christos __FBSDID("$FreeBSD: src/sbin/gpt/gpt.c,v 1.16 2006/07/07 02:44:23 marcel Exp $"); 36 1.2 christos #endif 37 1.2 christos #ifdef __RCSID 38 1.91 christos __RCSID("$NetBSD: gpt.c,v 1.91 2025/02/23 20:47:19 christos Exp $"); 39 1.2 christos #endif 40 1.1 christos 41 1.1 christos #include <sys/param.h> 42 1.1 christos #include <sys/types.h> 43 1.1 christos #include <sys/stat.h> 44 1.2 christos #include <sys/ioctl.h> 45 1.25 jakllsch #include <sys/bootblock.h> 46 1.1 christos 47 1.1 christos #include <err.h> 48 1.1 christos #include <errno.h> 49 1.1 christos #include <fcntl.h> 50 1.1 christos #include <paths.h> 51 1.1 christos #include <stddef.h> 52 1.42 christos #include <stdarg.h> 53 1.1 christos #include <stdio.h> 54 1.1 christos #include <stdlib.h> 55 1.1 christos #include <string.h> 56 1.1 christos #include <unistd.h> 57 1.32 christos #include <ctype.h> 58 1.1 christos 59 1.1 christos #include "map.h" 60 1.1 christos #include "gpt.h" 61 1.49 christos #include "gpt_private.h" 62 1.1 christos 63 1.1 christos static uint32_t crc32_tab[] = { 64 1.1 christos 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 65 1.1 christos 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 66 1.1 christos 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 67 1.1 christos 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 68 1.1 christos 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 69 1.1 christos 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 70 1.1 christos 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 71 1.1 christos 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 72 1.1 christos 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 73 1.1 christos 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 74 1.1 christos 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 75 1.1 christos 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 76 1.1 christos 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 77 1.1 christos 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 78 1.1 christos 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 79 1.1 christos 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 80 1.1 christos 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 81 1.1 christos 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 82 1.1 christos 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 83 1.1 christos 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 84 1.1 christos 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 85 1.1 christos 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 86 1.1 christos 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 87 1.1 christos 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 88 1.1 christos 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 89 1.1 christos 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 90 1.1 christos 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 91 1.1 christos 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 92 1.1 christos 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 93 1.1 christos 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 94 1.1 christos 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 95 1.1 christos 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 96 1.1 christos 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 97 1.1 christos 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 98 1.1 christos 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 99 1.1 christos 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 100 1.1 christos 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 101 1.1 christos 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 102 1.1 christos 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 103 1.1 christos 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 104 1.1 christos 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 105 1.1 christos 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 106 1.1 christos 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 107 1.1 christos }; 108 1.1 christos 109 1.1 christos uint32_t 110 1.1 christos crc32(const void *buf, size_t size) 111 1.1 christos { 112 1.1 christos const uint8_t *p; 113 1.1 christos uint32_t crc; 114 1.1 christos 115 1.1 christos p = buf; 116 1.1 christos crc = ~0U; 117 1.1 christos 118 1.1 christos while (size--) 119 1.1 christos crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); 120 1.1 christos 121 1.1 christos return crc ^ ~0U; 122 1.1 christos } 123 1.1 christos 124 1.72 christos /* 125 1.72 christos * Produce a NUL-terminated utf-8 string from the non-NUL-terminated 126 1.72 christos * utf16 string. 127 1.72 christos */ 128 1.53 christos void 129 1.72 christos utf16_to_utf8(const uint16_t *s16, size_t s16len, uint8_t *s8, size_t s8len) 130 1.1 christos { 131 1.72 christos size_t s8idx, s16idx; 132 1.1 christos uint32_t utfchar; 133 1.1 christos unsigned int c; 134 1.1 christos 135 1.72 christos for (s16idx = 0; s16idx < s16len; s16idx++) 136 1.72 christos if (s16[s16idx] == 0) 137 1.72 christos break; 138 1.72 christos 139 1.72 christos s16len = s16idx; 140 1.1 christos s8idx = s16idx = 0; 141 1.1 christos while (s16idx < s16len) { 142 1.1 christos utfchar = le16toh(s16[s16idx++]); 143 1.1 christos if ((utfchar & 0xf800) == 0xd800) { 144 1.1 christos c = le16toh(s16[s16idx]); 145 1.1 christos if ((utfchar & 0x400) != 0 || (c & 0xfc00) != 0xdc00) 146 1.1 christos utfchar = 0xfffd; 147 1.1 christos else 148 1.1 christos s16idx++; 149 1.1 christos } 150 1.1 christos if (utfchar < 0x80) { 151 1.53 christos if (s8idx + 1 >= s8len) 152 1.53 christos break; 153 1.59 christos s8[s8idx++] = (uint8_t)utfchar; 154 1.1 christos } else if (utfchar < 0x800) { 155 1.53 christos if (s8idx + 2 >= s8len) 156 1.53 christos break; 157 1.59 christos s8[s8idx++] = (uint8_t)(0xc0 | (utfchar >> 6)); 158 1.59 christos s8[s8idx++] = (uint8_t)(0x80 | (utfchar & 0x3f)); 159 1.1 christos } else if (utfchar < 0x10000) { 160 1.53 christos if (s8idx + 3 >= s8len) 161 1.53 christos break; 162 1.59 christos s8[s8idx++] = (uint8_t)(0xe0 | (utfchar >> 12)); 163 1.59 christos s8[s8idx++] = (uint8_t)(0x80 | ((utfchar >> 6) & 0x3f)); 164 1.59 christos s8[s8idx++] = (uint8_t)(0x80 | (utfchar & 0x3f)); 165 1.1 christos } else if (utfchar < 0x200000) { 166 1.53 christos if (s8idx + 4 >= s8len) 167 1.53 christos break; 168 1.59 christos s8[s8idx++] = (uint8_t)(0xf0 | (utfchar >> 18)); 169 1.59 christos s8[s8idx++] = (uint8_t)(0x80 | ((utfchar >> 12) & 0x3f)); 170 1.59 christos s8[s8idx++] = (uint8_t)(0x80 | ((utfchar >> 6) & 0x3f)); 171 1.59 christos s8[s8idx++] = (uint8_t)(0x80 | (utfchar & 0x3f)); 172 1.1 christos } 173 1.1 christos } 174 1.53 christos s8[s8idx] = 0; 175 1.1 christos } 176 1.1 christos 177 1.72 christos /* 178 1.72 christos * Produce a non-NUL-terminated utf-16 string from the NUL-terminated 179 1.72 christos * utf8 string. 180 1.72 christos */ 181 1.1 christos void 182 1.1 christos utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len) 183 1.1 christos { 184 1.1 christos size_t s16idx, s8idx, s8len; 185 1.2 christos uint32_t utfchar = 0; 186 1.1 christos unsigned int c, utfbytes; 187 1.1 christos 188 1.1 christos s8len = 0; 189 1.1 christos while (s8[s8len++] != 0) 190 1.1 christos ; 191 1.1 christos s8idx = s16idx = 0; 192 1.1 christos utfbytes = 0; 193 1.1 christos do { 194 1.1 christos c = s8[s8idx++]; 195 1.1 christos if ((c & 0xc0) != 0x80) { 196 1.1 christos /* Initial characters. */ 197 1.1 christos if (utfbytes != 0) { 198 1.1 christos /* Incomplete encoding. */ 199 1.17 matt s16[s16idx++] = htole16(0xfffd); 200 1.1 christos if (s16idx == s16len) { 201 1.1 christos s16[--s16idx] = 0; 202 1.1 christos return; 203 1.1 christos } 204 1.1 christos } 205 1.1 christos if ((c & 0xf8) == 0xf0) { 206 1.1 christos utfchar = c & 0x07; 207 1.1 christos utfbytes = 3; 208 1.1 christos } else if ((c & 0xf0) == 0xe0) { 209 1.1 christos utfchar = c & 0x0f; 210 1.1 christos utfbytes = 2; 211 1.1 christos } else if ((c & 0xe0) == 0xc0) { 212 1.1 christos utfchar = c & 0x1f; 213 1.1 christos utfbytes = 1; 214 1.1 christos } else { 215 1.1 christos utfchar = c & 0x7f; 216 1.1 christos utfbytes = 0; 217 1.1 christos } 218 1.1 christos } else { 219 1.1 christos /* Followup characters. */ 220 1.1 christos if (utfbytes > 0) { 221 1.1 christos utfchar = (utfchar << 6) + (c & 0x3f); 222 1.1 christos utfbytes--; 223 1.1 christos } else if (utfbytes == 0) 224 1.59 christos utfbytes = (u_int)~0; 225 1.1 christos } 226 1.1 christos if (utfbytes == 0) { 227 1.1 christos if (utfchar >= 0x10000 && s16idx + 2 >= s16len) 228 1.17 matt utfchar = 0xfffd; 229 1.1 christos if (utfchar >= 0x10000) { 230 1.59 christos s16[s16idx++] = htole16((uint16_t) 231 1.59 christos (0xd800 | ((utfchar>>10) - 0x40))); 232 1.59 christos s16[s16idx++] = htole16((uint16_t) 233 1.59 christos (0xdc00 | (utfchar & 0x3ff))); 234 1.1 christos } else 235 1.59 christos s16[s16idx++] = htole16((uint16_t)utfchar); 236 1.1 christos if (s16idx == s16len) { 237 1.1 christos return; 238 1.1 christos } 239 1.1 christos } 240 1.1 christos } while (c != 0); 241 1.72 christos 242 1.72 christos while (s16idx < s16len) 243 1.72 christos s16[s16idx++] = 0; 244 1.1 christos } 245 1.1 christos 246 1.49 christos void * 247 1.49 christos gpt_read(gpt_t gpt, off_t lba, size_t count) 248 1.1 christos { 249 1.1 christos off_t ofs; 250 1.1 christos void *buf; 251 1.1 christos 252 1.49 christos count *= gpt->secsz; 253 1.1 christos buf = malloc(count); 254 1.1 christos if (buf == NULL) 255 1.49 christos return NULL; 256 1.1 christos 257 1.49 christos ofs = lba * gpt->secsz; 258 1.49 christos if (lseek(gpt->fd, ofs, SEEK_SET) == ofs && 259 1.49 christos read(gpt->fd, buf, count) == (ssize_t)count) 260 1.49 christos return buf; 261 1.1 christos 262 1.1 christos free(buf); 263 1.49 christos return NULL; 264 1.1 christos } 265 1.1 christos 266 1.1 christos int 267 1.49 christos gpt_write(gpt_t gpt, map_t map) 268 1.1 christos { 269 1.1 christos off_t ofs; 270 1.1 christos size_t count; 271 1.1 christos 272 1.59 christos count = (size_t)(map->map_size * gpt->secsz); 273 1.49 christos ofs = map->map_start * gpt->secsz; 274 1.49 christos if (lseek(gpt->fd, ofs, SEEK_SET) != ofs || 275 1.49 christos write(gpt->fd, map->map_data, count) != (ssize_t)count) 276 1.46 christos return -1; 277 1.49 christos gpt->flags |= GPT_MODIFIED; 278 1.46 christos return 0; 279 1.1 christos } 280 1.1 christos 281 1.1 christos static int 282 1.77 martin gpt_mbr(gpt_t gpt, off_t lba, unsigned int *next_index, off_t ext_offset) 283 1.1 christos { 284 1.1 christos struct mbr *mbr; 285 1.49 christos map_t m, p; 286 1.1 christos off_t size, start; 287 1.1 christos unsigned int i, pmbr; 288 1.1 christos 289 1.49 christos mbr = gpt_read(gpt, lba, 1); 290 1.42 christos if (mbr == NULL) { 291 1.49 christos gpt_warn(gpt, "Read failed"); 292 1.49 christos return -1; 293 1.42 christos } 294 1.1 christos 295 1.1 christos if (mbr->mbr_sig != htole16(MBR_SIG)) { 296 1.49 christos if (gpt->verbose) 297 1.49 christos gpt_msg(gpt, 298 1.49 christos "MBR not found at sector %ju", (uintmax_t)lba); 299 1.1 christos free(mbr); 300 1.49 christos return 0; 301 1.1 christos } 302 1.1 christos 303 1.1 christos /* 304 1.1 christos * Differentiate between a regular MBR and a PMBR. This is more 305 1.1 christos * convenient in general. A PMBR is one with a single partition 306 1.1 christos * of type 0xee. 307 1.1 christos */ 308 1.1 christos pmbr = 0; 309 1.1 christos for (i = 0; i < 4; i++) { 310 1.25 jakllsch if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED) 311 1.1 christos continue; 312 1.25 jakllsch if (mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR) 313 1.1 christos pmbr++; 314 1.82 jmcneill else if ((gpt->flags & GPT_HYBRID) == 0) 315 1.1 christos break; 316 1.1 christos } 317 1.1 christos if (pmbr && i == 4 && lba == 0) { 318 1.49 christos if (pmbr != 1) 319 1.49 christos gpt_warnx(gpt, "Suspicious PMBR at sector %ju", 320 1.49 christos (uintmax_t)lba); 321 1.49 christos else if (gpt->verbose > 1) 322 1.49 christos gpt_msg(gpt, "PMBR at sector %ju", (uintmax_t)lba); 323 1.61 christos p = map_add(gpt, lba, 1LL, MAP_TYPE_PMBR, mbr, 1); 324 1.49 christos goto out; 325 1.49 christos } 326 1.49 christos if (pmbr) 327 1.49 christos gpt_warnx(gpt, "Suspicious MBR at sector %ju", (uintmax_t)lba); 328 1.49 christos else if (gpt->verbose > 1) 329 1.49 christos gpt_msg(gpt, "MBR at sector %ju", (uintmax_t)lba); 330 1.1 christos 331 1.61 christos p = map_add(gpt, lba, 1LL, MAP_TYPE_MBR, mbr, 1); 332 1.1 christos if (p == NULL) 333 1.49 christos goto out; 334 1.49 christos 335 1.1 christos for (i = 0; i < 4; i++) { 336 1.25 jakllsch if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED || 337 1.25 jakllsch mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR) 338 1.1 christos continue; 339 1.1 christos start = le16toh(mbr->mbr_part[i].part_start_hi); 340 1.1 christos start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo); 341 1.1 christos size = le16toh(mbr->mbr_part[i].part_size_hi); 342 1.1 christos size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo); 343 1.1 christos if (start == 0 && size == 0) { 344 1.49 christos gpt_warnx(gpt, "Malformed MBR at sector %ju", 345 1.49 christos (uintmax_t)lba); 346 1.1 christos continue; 347 1.1 christos } 348 1.49 christos if (gpt->verbose > 2) 349 1.68 christos gpt_msg(gpt, "MBR part: flag=%#x type=%d, start=%ju, " 350 1.68 christos "size=%ju", mbr->mbr_part[i].part_flag, 351 1.42 christos mbr->mbr_part[i].part_typ, 352 1.42 christos (uintmax_t)start, (uintmax_t)size); 353 1.77 martin if (!MBR_IS_EXTENDED(mbr->mbr_part[i].part_typ)) { 354 1.77 martin start += lba; 355 1.61 christos m = map_add(gpt, start, size, MAP_TYPE_MBR_PART, p, 0); 356 1.1 christos if (m == NULL) 357 1.49 christos return -1; 358 1.77 martin m->map_index = *next_index; 359 1.77 martin (*next_index)++; 360 1.1 christos } else { 361 1.77 martin start += ext_offset; 362 1.77 martin if (gpt_mbr(gpt, start, next_index, 363 1.77 martin ext_offset ? ext_offset : start) == -1) 364 1.49 christos return -1; 365 1.1 christos } 366 1.1 christos } 367 1.49 christos return 0; 368 1.49 christos out: 369 1.49 christos if (p == NULL) { 370 1.49 christos free(mbr); 371 1.49 christos return -1; 372 1.49 christos } 373 1.49 christos return 0; 374 1.1 christos } 375 1.1 christos 376 1.29 jnemeth int 377 1.49 christos gpt_gpt(gpt_t gpt, off_t lba, int found) 378 1.1 christos { 379 1.1 christos off_t size; 380 1.1 christos struct gpt_ent *ent; 381 1.1 christos struct gpt_hdr *hdr; 382 1.34 christos char *p; 383 1.49 christos map_t m; 384 1.1 christos size_t blocks, tblsz; 385 1.1 christos unsigned int i; 386 1.1 christos uint32_t crc; 387 1.1 christos 388 1.49 christos hdr = gpt_read(gpt, lba, 1); 389 1.86 mlelstv if (hdr == NULL) { 390 1.86 mlelstv gpt_warn(gpt, "Read failed"); 391 1.49 christos return -1; 392 1.86 mlelstv } 393 1.1 christos 394 1.1 christos if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig))) 395 1.1 christos goto fail_hdr; 396 1.1 christos 397 1.1 christos crc = le32toh(hdr->hdr_crc_self); 398 1.1 christos hdr->hdr_crc_self = 0; 399 1.1 christos if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) { 400 1.49 christos if (gpt->verbose) 401 1.49 christos gpt_msg(gpt, "Bad CRC in GPT header at sector %ju", 402 1.49 christos (uintmax_t)lba); 403 1.1 christos goto fail_hdr; 404 1.1 christos } 405 1.1 christos 406 1.1 christos tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz); 407 1.49 christos blocks = tblsz / gpt->secsz + ((tblsz % gpt->secsz) ? 1 : 0); 408 1.1 christos 409 1.1 christos /* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */ 410 1.59 christos p = gpt_read(gpt, (off_t)le64toh((uint64_t)hdr->hdr_lba_table), blocks); 411 1.11 christos if (p == NULL) { 412 1.11 christos if (found) { 413 1.49 christos if (gpt->verbose) 414 1.49 christos gpt_msg(gpt, 415 1.49 christos "Cannot read LBA table at sector %ju", 416 1.49 christos (uintmax_t)le64toh(hdr->hdr_lba_table)); 417 1.49 christos return -1; 418 1.11 christos } 419 1.11 christos goto fail_hdr; 420 1.11 christos } 421 1.1 christos 422 1.1 christos if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) { 423 1.49 christos if (gpt->verbose) 424 1.49 christos gpt_msg(gpt, "Bad CRC in GPT table at sector %ju", 425 1.49 christos (uintmax_t)le64toh(hdr->hdr_lba_table)); 426 1.1 christos goto fail_ent; 427 1.1 christos } 428 1.1 christos 429 1.49 christos if (gpt->verbose > 1) 430 1.49 christos gpt_msg(gpt, "%s GPT at sector %ju", 431 1.49 christos (lba == 1) ? "Pri" : "Sec", (uintmax_t)lba); 432 1.1 christos 433 1.49 christos m = map_add(gpt, lba, 1, (lba == 1) 434 1.61 christos ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr, 1); 435 1.1 christos if (m == NULL) 436 1.1 christos return (-1); 437 1.1 christos 438 1.59 christos m = map_add(gpt, (off_t)le64toh((uint64_t)hdr->hdr_lba_table), 439 1.59 christos (off_t)blocks, 440 1.61 christos lba == 1 ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p, 1); 441 1.1 christos if (m == NULL) 442 1.1 christos return (-1); 443 1.1 christos 444 1.1 christos if (lba != 1) 445 1.11 christos return (1); 446 1.1 christos 447 1.1 christos for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 448 1.1 christos ent = (void*)(p + i * le32toh(hdr->hdr_entsz)); 449 1.34 christos if (gpt_uuid_is_nil(ent->ent_type)) 450 1.1 christos continue; 451 1.1 christos 452 1.59 christos size = (off_t)(le64toh((uint64_t)ent->ent_lba_end) - 453 1.59 christos le64toh((uint64_t)ent->ent_lba_start) + 1LL); 454 1.49 christos if (gpt->verbose > 2) { 455 1.34 christos char buf[128]; 456 1.34 christos gpt_uuid_snprintf(buf, sizeof(buf), "%s", 457 1.34 christos ent->ent_type); 458 1.49 christos gpt_msg(gpt, "GPT partition: type=%s, start=%ju, " 459 1.49 christos "size=%ju", buf, 460 1.49 christos (uintmax_t)le64toh(ent->ent_lba_start), 461 1.49 christos (uintmax_t)size); 462 1.1 christos } 463 1.59 christos m = map_add(gpt, (off_t)le64toh((uint64_t)ent->ent_lba_start), 464 1.61 christos size, MAP_TYPE_GPT_PART, ent, 0); 465 1.1 christos if (m == NULL) 466 1.1 christos return (-1); 467 1.1 christos m->map_index = i + 1; 468 1.1 christos } 469 1.11 christos return (1); 470 1.1 christos 471 1.1 christos fail_ent: 472 1.1 christos free(p); 473 1.1 christos 474 1.1 christos fail_hdr: 475 1.1 christos free(hdr); 476 1.1 christos return (0); 477 1.1 christos } 478 1.1 christos 479 1.49 christos gpt_t 480 1.70 christos gpt_open(const char *dev, int flags, int verbose, off_t mediasz, u_int secsz, 481 1.70 christos time_t timestamp) 482 1.1 christos { 483 1.49 christos int mode, found; 484 1.45 christos off_t devsz; 485 1.49 christos gpt_t gpt; 486 1.91 christos unsigned int idx; 487 1.1 christos 488 1.49 christos if ((gpt = calloc(1, sizeof(*gpt))) == NULL) { 489 1.55 jnemeth if (!(flags & GPT_QUIET)) 490 1.49 christos warn("Cannot allocate `%s'", dev); 491 1.49 christos return NULL; 492 1.49 christos } 493 1.49 christos gpt->flags = flags; 494 1.49 christos gpt->verbose = verbose; 495 1.49 christos gpt->mediasz = mediasz; 496 1.49 christos gpt->secsz = secsz; 497 1.70 christos gpt->timestamp = timestamp; 498 1.90 mlelstv gpt->uuidgen = 0; 499 1.49 christos 500 1.49 christos mode = (gpt->flags & GPT_READONLY) ? O_RDONLY : O_RDWR|O_EXCL; 501 1.49 christos 502 1.49 christos gpt->fd = opendisk(dev, mode, gpt->device_name, 503 1.49 christos sizeof(gpt->device_name), 0); 504 1.49 christos if (gpt->fd == -1) { 505 1.49 christos strlcpy(gpt->device_name, dev, sizeof(gpt->device_name)); 506 1.49 christos gpt_warn(gpt, "Cannot open"); 507 1.49 christos goto close; 508 1.42 christos } 509 1.1 christos 510 1.49 christos if (fstat(gpt->fd, &gpt->sb) == -1) { 511 1.49 christos gpt_warn(gpt, "Cannot stat"); 512 1.1 christos goto close; 513 1.42 christos } 514 1.1 christos 515 1.49 christos if ((gpt->sb.st_mode & S_IFMT) != S_IFREG) { 516 1.49 christos if (gpt->secsz == 0) { 517 1.43 jnemeth #ifdef DIOCGSECTORSIZE 518 1.49 christos if (ioctl(gpt->fd, DIOCGSECTORSIZE, &gpt->secsz) == -1) { 519 1.49 christos gpt_warn(gpt, "Cannot get sector size"); 520 1.44 christos goto close; 521 1.44 christos } 522 1.44 christos #endif 523 1.49 christos if (gpt->secsz == 0) { 524 1.49 christos gpt_warnx(gpt, "Sector size can't be 0"); 525 1.44 christos goto close; 526 1.44 christos } 527 1.42 christos } 528 1.49 christos if (gpt->mediasz == 0) { 529 1.44 christos #ifdef DIOCGMEDIASIZE 530 1.49 christos if (ioctl(gpt->fd, DIOCGMEDIASIZE, &gpt->mediasz) == -1) { 531 1.49 christos gpt_warn(gpt, "Cannot get media size"); 532 1.44 christos goto close; 533 1.44 christos } 534 1.43 jnemeth #endif 535 1.49 christos if (gpt->mediasz == 0) { 536 1.49 christos gpt_warnx(gpt, "Media size can't be 0"); 537 1.44 christos goto close; 538 1.44 christos } 539 1.44 christos } 540 1.1 christos } else { 541 1.62 christos gpt->flags |= GPT_FILE; 542 1.49 christos if (gpt->secsz == 0) 543 1.49 christos gpt->secsz = 512; /* Fixed size for files. */ 544 1.49 christos if (gpt->mediasz == 0) { 545 1.49 christos if (gpt->sb.st_size % gpt->secsz) { 546 1.86 mlelstv gpt_warn(gpt, "Media size not a multiple of sector size (%u)\n", gpt->secsz); 547 1.36 christos errno = EINVAL; 548 1.36 christos goto close; 549 1.36 christos } 550 1.49 christos gpt->mediasz = gpt->sb.st_size; 551 1.1 christos } 552 1.56 christos gpt->flags |= GPT_NOSYNC; 553 1.1 christos } 554 1.1 christos 555 1.1 christos /* 556 1.1 christos * We require an absolute minimum of 6 sectors. One for the MBR, 557 1.1 christos * 2 for the GPT header, 2 for the GPT table and one to hold some 558 1.1 christos * user data. Let's catch this extreme border case here so that 559 1.1 christos * we don't have to worry about it later. 560 1.1 christos */ 561 1.49 christos devsz = gpt->mediasz / gpt->secsz; 562 1.45 christos if (devsz < 6) { 563 1.62 christos gpt_warnx(gpt, "Need 6 sectors, we have %ju", 564 1.49 christos (uintmax_t)devsz); 565 1.1 christos goto close; 566 1.1 christos } 567 1.1 christos 568 1.49 christos if (gpt->verbose) { 569 1.49 christos gpt_msg(gpt, "mediasize=%ju; sectorsize=%u; blocks=%ju", 570 1.49 christos (uintmax_t)gpt->mediasz, gpt->secsz, (uintmax_t)devsz); 571 1.42 christos } 572 1.1 christos 573 1.57 christos if (map_init(gpt, devsz) == -1) 574 1.57 christos goto close; 575 1.1 christos 576 1.91 christos idx = 1; 577 1.91 christos if (gpt_mbr(gpt, 0LL, &idx, 0U) == -1) 578 1.1 christos goto close; 579 1.49 christos if ((found = gpt_gpt(gpt, 1LL, 1)) == -1) 580 1.1 christos goto close; 581 1.83 mlelstv 582 1.83 mlelstv if (found) { 583 1.83 mlelstv struct map *map; 584 1.83 mlelstv struct gpt_hdr *hdr; 585 1.84 mlelstv uint64_t lba; 586 1.83 mlelstv 587 1.83 mlelstv /* 588 1.83 mlelstv * read secondary GPT from position stored in primary header 589 1.83 mlelstv * when possible 590 1.83 mlelstv */ 591 1.83 mlelstv map = map_find(gpt, MAP_TYPE_PRI_GPT_HDR); 592 1.83 mlelstv hdr = map ? map->map_data : NULL; 593 1.84 mlelstv lba = le64toh(hdr->hdr_lba_alt); 594 1.84 mlelstv if (hdr && lba > 0 && lba < (uint64_t)devsz) { 595 1.84 mlelstv if (gpt_gpt(gpt, (off_t)lba, found) == -1) 596 1.83 mlelstv goto close; 597 1.83 mlelstv } 598 1.83 mlelstv } else { 599 1.83 mlelstv if (gpt_gpt(gpt, devsz - 1LL, found) == -1) 600 1.83 mlelstv goto close; 601 1.83 mlelstv } 602 1.1 christos 603 1.49 christos return gpt; 604 1.1 christos 605 1.1 christos close: 606 1.49 christos if (gpt->fd != -1) 607 1.49 christos close(gpt->fd); 608 1.87 mrg gpt_warn(gpt, "No GPT found"); 609 1.49 christos free(gpt); 610 1.49 christos return NULL; 611 1.1 christos } 612 1.1 christos 613 1.1 christos void 614 1.49 christos gpt_close(gpt_t gpt) 615 1.1 christos { 616 1.46 christos 617 1.78 martin if (gpt == NULL) 618 1.78 martin return; 619 1.78 martin 620 1.75 jnemeth if (!(gpt->flags & GPT_MODIFIED) || !(gpt->flags & GPT_SYNC)) 621 1.48 christos goto out; 622 1.48 christos 623 1.49 christos if (!(gpt->flags & GPT_NOSYNC)) { 624 1.47 christos #ifdef DIOCMWEDGES 625 1.47 christos int bits; 626 1.49 christos if (ioctl(gpt->fd, DIOCMWEDGES, &bits) == -1) 627 1.49 christos gpt_warn(gpt, "Can't update wedge information"); 628 1.48 christos else 629 1.48 christos goto out; 630 1.47 christos #endif 631 1.47 christos } 632 1.62 christos if (!(gpt->flags & GPT_FILE)) 633 1.62 christos gpt_msg(gpt, "You need to run \"dkctl %s makewedges\"" 634 1.62 christos " for the changes to take effect\n", gpt->device_name); 635 1.46 christos 636 1.48 christos out: 637 1.49 christos close(gpt->fd); 638 1.1 christos } 639 1.1 christos 640 1.67 joerg __printflike(2, 0) 641 1.66 christos static void 642 1.66 christos gpt_vwarnx(gpt_t gpt, const char *fmt, va_list ap, const char *e) 643 1.66 christos { 644 1.66 christos if (gpt && (gpt->flags & GPT_QUIET)) 645 1.66 christos return; 646 1.66 christos fprintf(stderr, "%s: ", getprogname()); 647 1.66 christos if (gpt) 648 1.66 christos fprintf(stderr, "%s: ", gpt->device_name); 649 1.66 christos vfprintf(stderr, fmt, ap); 650 1.66 christos if (e) 651 1.66 christos fprintf(stderr, " (%s)\n", e); 652 1.66 christos else 653 1.66 christos fputc('\n', stderr); 654 1.66 christos } 655 1.66 christos 656 1.42 christos void 657 1.49 christos gpt_warnx(gpt_t gpt, const char *fmt, ...) 658 1.42 christos { 659 1.42 christos va_list ap; 660 1.48 christos 661 1.49 christos va_start(ap, fmt); 662 1.66 christos gpt_vwarnx(gpt, fmt, ap, NULL); 663 1.49 christos va_end(ap); 664 1.49 christos } 665 1.49 christos 666 1.49 christos void 667 1.49 christos gpt_warn(gpt_t gpt, const char *fmt, ...) 668 1.49 christos { 669 1.49 christos va_list ap; 670 1.49 christos 671 1.49 christos va_start(ap, fmt); 672 1.66 christos gpt_vwarnx(gpt, fmt, ap, strerror(errno)); 673 1.49 christos va_end(ap); 674 1.49 christos } 675 1.49 christos 676 1.49 christos void 677 1.49 christos gpt_msg(gpt_t gpt, const char *fmt, ...) 678 1.49 christos { 679 1.49 christos va_list ap; 680 1.49 christos 681 1.66 christos if (gpt && (gpt->flags & GPT_QUIET)) 682 1.49 christos return; 683 1.66 christos if (gpt) 684 1.66 christos printf("%s: ", gpt->device_name); 685 1.42 christos va_start(ap, fmt); 686 1.42 christos vprintf(fmt, ap); 687 1.42 christos va_end(ap); 688 1.42 christos printf("\n"); 689 1.42 christos } 690 1.49 christos 691 1.49 christos struct gpt_hdr * 692 1.49 christos gpt_hdr(gpt_t gpt) 693 1.49 christos { 694 1.49 christos gpt->gpt = map_find(gpt, MAP_TYPE_PRI_GPT_HDR); 695 1.49 christos if (gpt->gpt == NULL) { 696 1.49 christos gpt_warnx(gpt, "No primary GPT header; run create or recover"); 697 1.49 christos return NULL; 698 1.49 christos } 699 1.49 christos 700 1.49 christos gpt->tpg = map_find(gpt, MAP_TYPE_SEC_GPT_HDR); 701 1.49 christos if (gpt->tpg == NULL) { 702 1.49 christos gpt_warnx(gpt, "No secondary GPT header; run recover"); 703 1.49 christos return NULL; 704 1.49 christos } 705 1.49 christos 706 1.49 christos gpt->tbl = map_find(gpt, MAP_TYPE_PRI_GPT_TBL); 707 1.49 christos gpt->lbt = map_find(gpt, MAP_TYPE_SEC_GPT_TBL); 708 1.49 christos if (gpt->tbl == NULL || gpt->lbt == NULL) { 709 1.49 christos gpt_warnx(gpt, "Corrupt maps, run recover"); 710 1.49 christos return NULL; 711 1.49 christos } 712 1.49 christos 713 1.49 christos return gpt->gpt->map_data; 714 1.49 christos } 715 1.49 christos 716 1.49 christos int 717 1.49 christos gpt_write_crc(gpt_t gpt, map_t map, map_t tbl) 718 1.49 christos { 719 1.49 christos struct gpt_hdr *hdr = map->map_data; 720 1.49 christos 721 1.49 christos hdr->hdr_crc_table = htole32(crc32(tbl->map_data, 722 1.49 christos le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz))); 723 1.49 christos hdr->hdr_crc_self = 0; 724 1.49 christos hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); 725 1.49 christos 726 1.49 christos if (gpt_write(gpt, map) == -1) { 727 1.49 christos gpt_warn(gpt, "Error writing crc map"); 728 1.49 christos return -1; 729 1.49 christos } 730 1.49 christos 731 1.49 christos if (gpt_write(gpt, tbl) == -1) { 732 1.49 christos gpt_warn(gpt, "Error writing crc table"); 733 1.49 christos return -1; 734 1.49 christos } 735 1.49 christos 736 1.49 christos return 0; 737 1.49 christos } 738 1.49 christos 739 1.49 christos int 740 1.49 christos gpt_write_primary(gpt_t gpt) 741 1.49 christos { 742 1.49 christos return gpt_write_crc(gpt, gpt->gpt, gpt->tbl); 743 1.49 christos } 744 1.49 christos 745 1.49 christos 746 1.49 christos int 747 1.49 christos gpt_write_backup(gpt_t gpt) 748 1.49 christos { 749 1.49 christos return gpt_write_crc(gpt, gpt->tpg, gpt->lbt); 750 1.49 christos } 751 1.49 christos 752 1.49 christos void 753 1.68 christos gpt_create_pmbr_part(struct mbr_part *part, off_t last, int active) 754 1.49 christos { 755 1.68 christos part->part_flag = active ? 0x80 : 0; 756 1.49 christos part->part_shd = 0x00; 757 1.49 christos part->part_ssect = 0x02; 758 1.49 christos part->part_scyl = 0x00; 759 1.49 christos part->part_typ = MBR_PTYPE_PMBR; 760 1.49 christos part->part_ehd = 0xfe; 761 1.49 christos part->part_esect = 0xff; 762 1.49 christos part->part_ecyl = 0xff; 763 1.49 christos part->part_start_lo = htole16(1); 764 1.49 christos if (last > 0xffffffff) { 765 1.49 christos part->part_size_lo = htole16(0xffff); 766 1.49 christos part->part_size_hi = htole16(0xffff); 767 1.49 christos } else { 768 1.59 christos part->part_size_lo = htole16((uint16_t)last); 769 1.91 christos part->part_size_hi = htole16((uint16_t)((uint64_t)last >> 16)); 770 1.49 christos } 771 1.49 christos } 772 1.49 christos 773 1.49 christos struct gpt_ent * 774 1.49 christos gpt_ent(map_t map, map_t tbl, unsigned int i) 775 1.49 christos { 776 1.49 christos struct gpt_hdr *hdr = map->map_data; 777 1.49 christos return (void *)((char *)tbl->map_data + i * le32toh(hdr->hdr_entsz)); 778 1.49 christos } 779 1.49 christos 780 1.49 christos struct gpt_ent * 781 1.49 christos gpt_ent_primary(gpt_t gpt, unsigned int i) 782 1.49 christos { 783 1.49 christos return gpt_ent(gpt->gpt, gpt->tbl, i); 784 1.49 christos } 785 1.49 christos 786 1.49 christos struct gpt_ent * 787 1.49 christos gpt_ent_backup(gpt_t gpt, unsigned int i) 788 1.49 christos { 789 1.49 christos return gpt_ent(gpt->tpg, gpt->lbt, i); 790 1.49 christos } 791 1.50 christos 792 1.50 christos int 793 1.50 christos gpt_usage(const char *prefix, const struct gpt_cmd *cmd) 794 1.50 christos { 795 1.50 christos const char **a = cmd->help; 796 1.50 christos size_t hlen = cmd->hlen; 797 1.50 christos size_t i; 798 1.50 christos 799 1.50 christos if (prefix == NULL) { 800 1.50 christos const char *pname = getprogname(); 801 1.54 christos const char *d1, *d2, *d = " <device>"; 802 1.50 christos int len = (int)strlen(pname); 803 1.54 christos if (strcmp(pname, "gpt") == 0) { 804 1.54 christos d1 = ""; 805 1.54 christos d2 = d; 806 1.54 christos } else { 807 1.54 christos d2 = ""; 808 1.54 christos d1 = d; 809 1.54 christos } 810 1.54 christos fprintf(stderr, "Usage: %s%s %s %s%s\n", pname, 811 1.54 christos d1, cmd->name, a[0], d2); 812 1.50 christos for (i = 1; i < hlen; i++) { 813 1.50 christos fprintf(stderr, 814 1.54 christos " %*s%s %s %s%s\n", len, "", 815 1.54 christos d1, cmd->name, a[i], d2); 816 1.50 christos } 817 1.50 christos } else { 818 1.50 christos for (i = 0; i < hlen; i++) 819 1.50 christos fprintf(stderr, "%s%s %s\n", prefix, cmd->name, a[i]); 820 1.50 christos } 821 1.50 christos return -1; 822 1.50 christos } 823 1.51 christos 824 1.51 christos off_t 825 1.51 christos gpt_last(gpt_t gpt) 826 1.51 christos { 827 1.51 christos return gpt->mediasz / gpt->secsz - 1LL; 828 1.51 christos } 829 1.51 christos 830 1.59 christos off_t 831 1.51 christos gpt_create(gpt_t gpt, off_t last, u_int parts, int primary_only) 832 1.51 christos { 833 1.91 christos off_t blocks, lastoff; 834 1.51 christos map_t map; 835 1.51 christos struct gpt_hdr *hdr; 836 1.51 christos struct gpt_ent *ent; 837 1.51 christos unsigned int i; 838 1.51 christos void *p; 839 1.51 christos 840 1.51 christos if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) != NULL || 841 1.51 christos map_find(gpt, MAP_TYPE_SEC_GPT_HDR) != NULL) { 842 1.69 christos gpt_warnx(gpt, "Device already contains a GPT, " 843 1.69 christos "destroy it first"); 844 1.51 christos return -1; 845 1.51 christos } 846 1.51 christos 847 1.51 christos /* Get the amount of free space after the MBR */ 848 1.51 christos blocks = map_free(gpt, 1LL, 0LL); 849 1.51 christos if (blocks == 0LL) { 850 1.51 christos gpt_warnx(gpt, "No room for the GPT header"); 851 1.51 christos return -1; 852 1.51 christos } 853 1.51 christos 854 1.51 christos /* Don't create more than parts entries. */ 855 1.51 christos if ((uint64_t)(blocks - 1) * gpt->secsz > 856 1.51 christos parts * sizeof(struct gpt_ent)) { 857 1.59 christos blocks = (off_t)((parts * sizeof(struct gpt_ent)) / gpt->secsz); 858 1.51 christos if ((parts * sizeof(struct gpt_ent)) % gpt->secsz) 859 1.51 christos blocks++; 860 1.51 christos blocks++; /* Don't forget the header itself */ 861 1.51 christos } 862 1.51 christos 863 1.51 christos /* Never cross the median of the device. */ 864 1.91 christos lastoff = (off_t)(((uint64_t)last + 1LL) >> 1); 865 1.91 christos if ((blocks + 1LL) > lastoff) 866 1.91 christos blocks = lastoff - 1LL; 867 1.51 christos 868 1.51 christos /* 869 1.51 christos * Get the amount of free space at the end of the device and 870 1.51 christos * calculate the size for the GPT structures. 871 1.51 christos */ 872 1.51 christos map = map_last(gpt); 873 1.51 christos if (map->map_type != MAP_TYPE_UNUSED) { 874 1.51 christos gpt_warnx(gpt, "No room for the backup header"); 875 1.51 christos return -1; 876 1.51 christos } 877 1.51 christos 878 1.51 christos if (map->map_size < blocks) 879 1.51 christos blocks = map->map_size; 880 1.51 christos if (blocks == 1LL) { 881 1.51 christos gpt_warnx(gpt, "No room for the GPT table"); 882 1.51 christos return -1; 883 1.51 christos } 884 1.51 christos 885 1.51 christos blocks--; /* Number of blocks in the GPT table. */ 886 1.51 christos 887 1.63 christos if (gpt_add_hdr(gpt, MAP_TYPE_PRI_GPT_HDR, 1) == -1) 888 1.51 christos return -1; 889 1.51 christos 890 1.59 christos if ((p = calloc((size_t)blocks, gpt->secsz)) == NULL) { 891 1.51 christos gpt_warnx(gpt, "Can't allocate the primary GPT table"); 892 1.51 christos return -1; 893 1.51 christos } 894 1.51 christos if ((gpt->tbl = map_add(gpt, 2LL, blocks, 895 1.61 christos MAP_TYPE_PRI_GPT_TBL, p, 1)) == NULL) { 896 1.51 christos free(p); 897 1.51 christos gpt_warnx(gpt, "Can't add the primary GPT table"); 898 1.51 christos return -1; 899 1.51 christos } 900 1.51 christos 901 1.51 christos hdr = gpt->gpt->map_data; 902 1.51 christos memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); 903 1.51 christos 904 1.51 christos /* 905 1.51 christos * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus 906 1.51 christos * contains padding we must not include in the size. 907 1.51 christos */ 908 1.51 christos hdr->hdr_revision = htole32(GPT_HDR_REVISION); 909 1.51 christos hdr->hdr_size = htole32(GPT_HDR_SIZE); 910 1.59 christos hdr->hdr_lba_self = htole64((uint64_t)gpt->gpt->map_start); 911 1.59 christos hdr->hdr_lba_alt = htole64((uint64_t)last); 912 1.59 christos hdr->hdr_lba_start = htole64((uint64_t)(gpt->tbl->map_start + blocks)); 913 1.59 christos hdr->hdr_lba_end = htole64((uint64_t)(last - blocks - 1LL)); 914 1.52 christos if (gpt_uuid_generate(gpt, hdr->hdr_guid) == -1) 915 1.52 christos return -1; 916 1.59 christos hdr->hdr_lba_table = htole64((uint64_t)(gpt->tbl->map_start)); 917 1.59 christos hdr->hdr_entries = htole32((uint32_t)(((uint64_t)blocks * gpt->secsz) / 918 1.59 christos sizeof(struct gpt_ent))); 919 1.51 christos if (le32toh(hdr->hdr_entries) > parts) 920 1.51 christos hdr->hdr_entries = htole32(parts); 921 1.51 christos hdr->hdr_entsz = htole32(sizeof(struct gpt_ent)); 922 1.51 christos 923 1.51 christos ent = gpt->tbl->map_data; 924 1.51 christos for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 925 1.52 christos if (gpt_uuid_generate(gpt, ent[i].ent_guid) == -1) 926 1.52 christos return -1; 927 1.51 christos } 928 1.51 christos 929 1.51 christos /* 930 1.51 christos * Create backup GPT if the user didn't suppress it. 931 1.51 christos */ 932 1.51 christos if (primary_only) 933 1.51 christos return last; 934 1.51 christos 935 1.63 christos if (gpt_add_hdr(gpt, MAP_TYPE_SEC_GPT_HDR, last) == -1) 936 1.51 christos return -1; 937 1.51 christos 938 1.51 christos if ((gpt->lbt = map_add(gpt, last - blocks, blocks, 939 1.61 christos MAP_TYPE_SEC_GPT_TBL, gpt->tbl->map_data, 0)) == NULL) { 940 1.51 christos gpt_warnx(gpt, "Can't add the secondary GPT table"); 941 1.51 christos return -1; 942 1.51 christos } 943 1.51 christos 944 1.51 christos memcpy(gpt->tpg->map_data, gpt->gpt->map_data, gpt->secsz); 945 1.51 christos 946 1.51 christos hdr = gpt->tpg->map_data; 947 1.59 christos hdr->hdr_lba_self = htole64((uint64_t)gpt->tpg->map_start); 948 1.59 christos hdr->hdr_lba_alt = htole64((uint64_t)gpt->gpt->map_start); 949 1.59 christos hdr->hdr_lba_table = htole64((uint64_t)gpt->lbt->map_start); 950 1.51 christos return last; 951 1.51 christos } 952 1.51 christos 953 1.52 christos static int 954 1.52 christos gpt_size_get(gpt_t gpt, off_t *size) 955 1.52 christos { 956 1.52 christos off_t sectors; 957 1.52 christos int64_t human_num; 958 1.52 christos char *p; 959 1.52 christos 960 1.52 christos if (*size > 0) 961 1.52 christos return -1; 962 1.52 christos sectors = strtoll(optarg, &p, 10); 963 1.52 christos if (sectors < 1) 964 1.52 christos return -1; 965 1.52 christos if (*p == '\0' || ((*p == 's' || *p == 'S') && p[1] == '\0')) { 966 1.52 christos *size = sectors * gpt->secsz; 967 1.52 christos return 0; 968 1.52 christos } 969 1.52 christos if ((*p == 'b' || *p == 'B') && p[1] == '\0') { 970 1.52 christos *size = sectors; 971 1.52 christos return 0; 972 1.52 christos } 973 1.52 christos if (dehumanize_number(optarg, &human_num) < 0) 974 1.52 christos return -1; 975 1.52 christos *size = human_num; 976 1.52 christos return 0; 977 1.52 christos } 978 1.52 christos 979 1.51 christos int 980 1.66 christos gpt_human_get(gpt_t gpt, off_t *human) 981 1.51 christos { 982 1.51 christos int64_t human_num; 983 1.51 christos 984 1.66 christos if (*human > 0) { 985 1.66 christos gpt_warn(gpt, "Already set to %jd new `%s'", (intmax_t)*human, 986 1.66 christos optarg); 987 1.52 christos return -1; 988 1.66 christos } 989 1.66 christos if (dehumanize_number(optarg, &human_num) < 0) { 990 1.66 christos gpt_warn(gpt, "Bad number `%s'", optarg); 991 1.52 christos return -1; 992 1.66 christos } 993 1.52 christos *human = human_num; 994 1.66 christos if (*human < 1) { 995 1.66 christos gpt_warn(gpt, "Number `%s' < 1", optarg); 996 1.52 christos return -1; 997 1.66 christos } 998 1.52 christos return 0; 999 1.52 christos } 1000 1.52 christos 1001 1.52 christos int 1002 1.52 christos gpt_add_find(gpt_t gpt, struct gpt_find *find, int ch) 1003 1.52 christos { 1004 1.51 christos switch (ch) { 1005 1.51 christos case 'a': 1006 1.66 christos if (find->all > 0) { 1007 1.66 christos gpt_warn(gpt, "-a is already set"); 1008 1.51 christos return -1; 1009 1.66 christos } 1010 1.51 christos find->all = 1; 1011 1.51 christos break; 1012 1.51 christos case 'b': 1013 1.66 christos if (gpt_human_get(gpt, &find->block) == -1) 1014 1.51 christos return -1; 1015 1.51 christos break; 1016 1.51 christos case 'i': 1017 1.66 christos if (gpt_uint_get(gpt, &find->entry) == -1) 1018 1.51 christos return -1; 1019 1.51 christos break; 1020 1.51 christos case 'L': 1021 1.52 christos if (gpt_name_get(gpt, &find->label) == -1) 1022 1.51 christos return -1; 1023 1.51 christos break; 1024 1.51 christos case 's': 1025 1.52 christos if (gpt_size_get(gpt, &find->size) == -1) 1026 1.51 christos return -1; 1027 1.51 christos break; 1028 1.51 christos case 't': 1029 1.51 christos if (!gpt_uuid_is_nil(find->type)) 1030 1.51 christos return -1; 1031 1.51 christos if (gpt_uuid_parse(optarg, find->type) != 0) 1032 1.51 christos return -1; 1033 1.51 christos break; 1034 1.51 christos default: 1035 1.66 christos gpt_warn(gpt, "Unknown find option `%c'", ch); 1036 1.51 christos return -1; 1037 1.51 christos } 1038 1.51 christos return 0; 1039 1.51 christos } 1040 1.51 christos 1041 1.51 christos int 1042 1.51 christos gpt_change_ent(gpt_t gpt, const struct gpt_find *find, 1043 1.79 jnemeth void (*cfn)(struct gpt_ent *, void *, int), void *v) 1044 1.51 christos { 1045 1.51 christos map_t m; 1046 1.51 christos struct gpt_ent *ent; 1047 1.51 christos unsigned int i; 1048 1.53 christos uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1]; 1049 1.51 christos 1050 1.51 christos if (!find->all ^ 1051 1.51 christos (find->block > 0 || find->entry > 0 || find->label != NULL 1052 1.51 christos || find->size > 0 || !gpt_uuid_is_nil(find->type))) 1053 1.51 christos return -1; 1054 1.51 christos 1055 1.91 christos if (gpt_hdr(gpt) == NULL) 1056 1.51 christos return -1; 1057 1.51 christos 1058 1.51 christos /* Relabel all matching entries in the map. */ 1059 1.51 christos for (m = map_first(gpt); m != NULL; m = m->map_next) { 1060 1.51 christos if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1) 1061 1.51 christos continue; 1062 1.51 christos if (find->entry > 0 && find->entry != m->map_index) 1063 1.51 christos continue; 1064 1.51 christos if (find->block > 0 && find->block != m->map_start) 1065 1.51 christos continue; 1066 1.51 christos if (find->size > 0 && find->size != m->map_size) 1067 1.51 christos continue; 1068 1.51 christos 1069 1.51 christos i = m->map_index - 1; 1070 1.51 christos 1071 1.51 christos ent = gpt_ent_primary(gpt, i); 1072 1.53 christos if (find->label != NULL) { 1073 1.73 christos utf16_to_utf8(ent->ent_name, 1074 1.73 christos __arraycount(ent->ent_name), 1075 1.73 christos utfbuf, __arraycount(utfbuf)); 1076 1.76 mlelstv if (strcmp((char *)find->label, (char *)utfbuf) != 0) 1077 1.51 christos continue; 1078 1.53 christos } 1079 1.51 christos 1080 1.51 christos if (!gpt_uuid_is_nil(find->type) && 1081 1.51 christos !gpt_uuid_equal(find->type, ent->ent_type)) 1082 1.51 christos continue; 1083 1.51 christos 1084 1.51 christos /* Change the primary entry. */ 1085 1.79 jnemeth (*cfn)(ent, v, 0); 1086 1.51 christos 1087 1.51 christos if (gpt_write_primary(gpt) == -1) 1088 1.51 christos return -1; 1089 1.51 christos 1090 1.51 christos ent = gpt_ent_backup(gpt, i); 1091 1.51 christos /* Change the secondary entry. */ 1092 1.79 jnemeth (*cfn)(ent, v, 1); 1093 1.51 christos 1094 1.51 christos if (gpt_write_backup(gpt) == -1) 1095 1.51 christos return -1; 1096 1.51 christos 1097 1.51 christos gpt_msg(gpt, "Partition %d %s", m->map_index, find->msg); 1098 1.51 christos } 1099 1.51 christos return 0; 1100 1.51 christos } 1101 1.51 christos 1102 1.51 christos int 1103 1.80 jnemeth gpt_change_hdr(gpt_t gpt, const struct gpt_find *find, 1104 1.80 jnemeth void (*cfn)(struct gpt_hdr *, void *, int), void *v) 1105 1.80 jnemeth { 1106 1.80 jnemeth struct gpt_hdr *hdr; 1107 1.80 jnemeth 1108 1.80 jnemeth if ((hdr = gpt_hdr(gpt)) == NULL) 1109 1.80 jnemeth return -1; 1110 1.80 jnemeth 1111 1.80 jnemeth /* Change the primary header. */ 1112 1.80 jnemeth (*cfn)(hdr, v, 0); 1113 1.80 jnemeth 1114 1.80 jnemeth if (gpt_write_primary(gpt) == -1) 1115 1.80 jnemeth return -1; 1116 1.80 jnemeth 1117 1.80 jnemeth hdr = gpt->tpg->map_data; 1118 1.80 jnemeth /* Change the secondary header. */ 1119 1.80 jnemeth (*cfn)(hdr, v, 1); 1120 1.80 jnemeth 1121 1.80 jnemeth if (gpt_write_backup(gpt) == -1) 1122 1.80 jnemeth return -1; 1123 1.80 jnemeth 1124 1.80 jnemeth gpt_msg(gpt, "Header %s", find->msg); 1125 1.80 jnemeth 1126 1.80 jnemeth return 0; 1127 1.80 jnemeth } 1128 1.80 jnemeth 1129 1.80 jnemeth int 1130 1.51 christos gpt_add_ais(gpt_t gpt, off_t *alignment, u_int *entry, off_t *size, int ch) 1131 1.51 christos { 1132 1.51 christos switch (ch) { 1133 1.51 christos case 'a': 1134 1.66 christos if (gpt_human_get(gpt, alignment) == -1) 1135 1.51 christos return -1; 1136 1.51 christos return 0; 1137 1.51 christos case 'i': 1138 1.66 christos if (gpt_uint_get(gpt, entry) == -1) 1139 1.51 christos return -1; 1140 1.51 christos return 0; 1141 1.51 christos case 's': 1142 1.52 christos if (gpt_size_get(gpt, size) == -1) 1143 1.51 christos return -1; 1144 1.51 christos return 0; 1145 1.51 christos default: 1146 1.66 christos gpt_warn(gpt, "Unknown alignment/index/size option `%c'", ch); 1147 1.51 christos return -1; 1148 1.51 christos } 1149 1.51 christos } 1150 1.51 christos 1151 1.51 christos off_t 1152 1.51 christos gpt_check_ais(gpt_t gpt, off_t alignment, u_int entry, off_t size) 1153 1.51 christos { 1154 1.51 christos if (entry == 0) { 1155 1.51 christos gpt_warnx(gpt, "Entry not specified"); 1156 1.51 christos return -1; 1157 1.51 christos } 1158 1.51 christos if (alignment % gpt->secsz != 0) { 1159 1.51 christos gpt_warnx(gpt, "Alignment (%#jx) must be a multiple of " 1160 1.51 christos "sector size (%#x)", (uintmax_t)alignment, gpt->secsz); 1161 1.51 christos return -1; 1162 1.51 christos } 1163 1.51 christos 1164 1.51 christos if (size % gpt->secsz != 0) { 1165 1.51 christos gpt_warnx(gpt, "Size (%#jx) must be a multiple of " 1166 1.51 christos "sector size (%#x)", (uintmax_t)size, gpt->secsz); 1167 1.51 christos return -1; 1168 1.51 christos } 1169 1.51 christos if (size > 0) 1170 1.51 christos return size / gpt->secsz; 1171 1.51 christos return 0; 1172 1.51 christos } 1173 1.64 christos 1174 1.64 christos static const struct nvd { 1175 1.64 christos const char *name; 1176 1.64 christos uint64_t mask; 1177 1.64 christos const char *description; 1178 1.64 christos } gpt_attr[] = { 1179 1.64 christos { 1180 1.64 christos "biosboot", 1181 1.64 christos GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE, 1182 1.64 christos "Legacy BIOS boot partition", 1183 1.64 christos }, 1184 1.64 christos { 1185 1.64 christos "bootme", 1186 1.64 christos GPT_ENT_ATTR_BOOTME, 1187 1.64 christos "Bootable partition", 1188 1.64 christos }, 1189 1.64 christos { 1190 1.64 christos "bootfailed", 1191 1.64 christos GPT_ENT_ATTR_BOOTFAILED, 1192 1.64 christos "Partition that marked bootonce failed to boot", 1193 1.64 christos }, 1194 1.64 christos { 1195 1.64 christos "bootonce", 1196 1.64 christos GPT_ENT_ATTR_BOOTONCE, 1197 1.64 christos "Attempt to boot this partition only once", 1198 1.64 christos }, 1199 1.64 christos { 1200 1.64 christos "noblockio", 1201 1.64 christos GPT_ENT_ATTR_NO_BLOCK_IO_PROTOCOL, 1202 1.64 christos "UEFI won't recognize file system for block I/O", 1203 1.64 christos }, 1204 1.64 christos { 1205 1.64 christos "required", 1206 1.64 christos GPT_ENT_ATTR_REQUIRED_PARTITION, 1207 1.64 christos "Partition required for platform to function", 1208 1.64 christos }, 1209 1.64 christos }; 1210 1.64 christos 1211 1.51 christos int 1212 1.64 christos gpt_attr_get(gpt_t gpt, uint64_t *attributes) 1213 1.64 christos { 1214 1.64 christos size_t i; 1215 1.64 christos int rv = 0; 1216 1.64 christos char *ptr; 1217 1.64 christos 1218 1.64 christos *attributes = 0; 1219 1.64 christos 1220 1.64 christos for (ptr = strtok(optarg, ","); ptr; ptr = strtok(NULL, ",")) { 1221 1.64 christos for (i = 0; i < __arraycount(gpt_attr); i++) 1222 1.64 christos if (strcmp(gpt_attr[i].name, ptr) == 0) 1223 1.64 christos break; 1224 1.64 christos if (i == __arraycount(gpt_attr)) { 1225 1.89 kre gpt_warnx(gpt, "Unrecognized attribute `%s'", ptr); 1226 1.89 kre rv = -1; 1227 1.64 christos } else 1228 1.64 christos *attributes |= gpt_attr[i].mask; 1229 1.64 christos } 1230 1.64 christos return rv; 1231 1.64 christos } 1232 1.64 christos 1233 1.64 christos void 1234 1.64 christos gpt_attr_help(const char *prefix) 1235 1.51 christos { 1236 1.64 christos size_t i; 1237 1.64 christos 1238 1.64 christos for (i = 0; i < __arraycount(gpt_attr); i++) 1239 1.64 christos printf("%s%10.10s\t%s\n", prefix, gpt_attr[i].name, 1240 1.64 christos gpt_attr[i].description); 1241 1.64 christos } 1242 1.64 christos 1243 1.64 christos const char * 1244 1.64 christos gpt_attr_list(char *buf, size_t len, uint64_t attributes) 1245 1.64 christos { 1246 1.64 christos size_t i; 1247 1.85 kre /* 1248 1.85 kre * a uint64_t (attributes) has at most 16 hex digits 1249 1.85 kre * in its representation, add 2 for "0x", and 2 more 1250 1.85 kre * for surrounding [ ], plus one for a trailing \0, 1251 1.85 kre * and we need 21 bytes, round that up to 24 1252 1.85 kre */ 1253 1.85 kre char xbuf[24]; 1254 1.85 kre 1255 1.64 christos strlcpy(buf, "", len); 1256 1.64 christos 1257 1.85 kre for (i = 0; i < __arraycount(gpt_attr); i++) { 1258 1.85 kre /* 1259 1.85 kre * if the attribute is specified in one of bits 1260 1.85 kre * 48..63, it should depend upon the defining 1261 1.85 kre * partition type for that attribute. Currently 1262 1.85 kre * we have no idea what that is, so... 1263 1.85 kre * 1264 1.85 kre * Also note that for some partition types, these 1265 1.85 kre * fields are not a single bit boolean, but several 1266 1.85 kre * bits to form a numeric value. That we could handle. 1267 1.85 kre */ 1268 1.85 kre 1269 1.64 christos if (attributes & gpt_attr[i].mask) { 1270 1.65 jnemeth strlcat(buf, buf[0] ? ", " : "", len); 1271 1.64 christos strlcat(buf, gpt_attr[i].name, len); 1272 1.85 kre #if 0 1273 1.85 kre /* 1274 1.85 kre * there are none currently defined, so this is untestable 1275 1.85 kre * (it does build however). 1276 1.85 kre */ 1277 1.85 kre if (gpt_attr[i].mask & (gpt_attr[i].mask - 1)) { 1278 1.89 kre /* This only happens in bits 46..63 */ 1279 1.85 kre 1280 1.85 kre /* 1281 1.85 kre * xbuf is big enough for "=65535\0" 1282 1.85 kre * which is the biggest possible value 1283 1.85 kre */ 1284 1.85 kre snprintf(xbuf, sizeof xbuf, "=%ju", 1285 1.85 kre (uintmax_t) ( 1286 1.85 kre (attributes & gpt_attr[i].mask) >> 1287 1.85 kre (ffs((int)(gpt_attr[i].mask >> 48)) + 47) 1288 1.85 kre )); 1289 1.85 kre 1290 1.85 kre strlcat(buf, xbuf, len); 1291 1.85 kre } 1292 1.85 kre #endif 1293 1.85 kre attributes &=~ gpt_attr[i].mask; 1294 1.64 christos } 1295 1.85 kre } 1296 1.85 kre 1297 1.85 kre if (attributes != 0) { 1298 1.85 kre snprintf(xbuf, sizeof xbuf, "[%#jx]", (uintmax_t)attributes); 1299 1.85 kre strlcat(buf, buf[0] ? ", " : "", len); 1300 1.85 kre strlcat(buf, xbuf, len); 1301 1.85 kre } 1302 1.85 kre 1303 1.64 christos return buf; 1304 1.51 christos } 1305 1.64 christos 1306 1.51 christos int 1307 1.51 christos gpt_attr_update(gpt_t gpt, u_int entry, uint64_t set, uint64_t clr) 1308 1.51 christos { 1309 1.51 christos struct gpt_hdr *hdr; 1310 1.51 christos struct gpt_ent *ent; 1311 1.51 christos unsigned int i; 1312 1.51 christos 1313 1.66 christos if (entry == 0 || (set == 0 && clr == 0)) { 1314 1.66 christos gpt_warnx(gpt, "Nothing to set"); 1315 1.51 christos return -1; 1316 1.66 christos } 1317 1.51 christos 1318 1.51 christos if ((hdr = gpt_hdr(gpt)) == NULL) 1319 1.51 christos return -1; 1320 1.51 christos 1321 1.51 christos if (entry > le32toh(hdr->hdr_entries)) { 1322 1.51 christos gpt_warnx(gpt, "Index %u out of range (%u max)", 1323 1.51 christos entry, le32toh(hdr->hdr_entries)); 1324 1.51 christos return -1; 1325 1.51 christos } 1326 1.51 christos 1327 1.51 christos i = entry - 1; 1328 1.51 christos ent = gpt_ent_primary(gpt, i); 1329 1.51 christos if (gpt_uuid_is_nil(ent->ent_type)) { 1330 1.51 christos gpt_warnx(gpt, "Entry at index %u is unused", entry); 1331 1.51 christos return -1; 1332 1.51 christos } 1333 1.51 christos 1334 1.51 christos ent->ent_attr &= ~clr; 1335 1.51 christos ent->ent_attr |= set; 1336 1.51 christos 1337 1.51 christos if (gpt_write_primary(gpt) == -1) 1338 1.51 christos return -1; 1339 1.51 christos 1340 1.51 christos ent = gpt_ent_backup(gpt, i); 1341 1.51 christos ent->ent_attr &= ~clr; 1342 1.51 christos ent->ent_attr |= set; 1343 1.51 christos 1344 1.51 christos if (gpt_write_backup(gpt) == -1) 1345 1.51 christos return -1; 1346 1.51 christos gpt_msg(gpt, "Partition %d attributes updated", entry); 1347 1.51 christos return 0; 1348 1.51 christos } 1349 1.51 christos 1350 1.51 christos int 1351 1.66 christos gpt_uint_get(gpt_t gpt, u_int *entry) 1352 1.51 christos { 1353 1.51 christos char *p; 1354 1.51 christos if (*entry > 0) 1355 1.51 christos return -1; 1356 1.59 christos *entry = (u_int)strtoul(optarg, &p, 10); 1357 1.66 christos if (*p != 0 || *entry < 1) { 1358 1.66 christos gpt_warn(gpt, "Bad number `%s'", optarg); 1359 1.51 christos return -1; 1360 1.66 christos } 1361 1.51 christos return 0; 1362 1.51 christos } 1363 1.52 christos int 1364 1.52 christos gpt_uuid_get(gpt_t gpt, gpt_uuid_t *uuid) 1365 1.52 christos { 1366 1.52 christos if (!gpt_uuid_is_nil(*uuid)) 1367 1.52 christos return -1; 1368 1.52 christos if (gpt_uuid_parse(optarg, *uuid) != 0) { 1369 1.81 christos gpt_warnx(gpt, "Can't parse uuid/type `%s'", optarg); 1370 1.52 christos return -1; 1371 1.52 christos } 1372 1.52 christos return 0; 1373 1.52 christos } 1374 1.52 christos 1375 1.52 christos int 1376 1.52 christos gpt_name_get(gpt_t gpt, void *v) 1377 1.52 christos { 1378 1.52 christos char **name = v; 1379 1.52 christos if (*name != NULL) 1380 1.52 christos return -1; 1381 1.52 christos *name = strdup(optarg); 1382 1.52 christos if (*name == NULL) { 1383 1.52 christos gpt_warn(gpt, "Can't copy string"); 1384 1.52 christos return -1; 1385 1.52 christos } 1386 1.52 christos return 0; 1387 1.52 christos } 1388 1.59 christos 1389 1.59 christos void 1390 1.59 christos gpt_show_num(const char *prompt, uintmax_t num) 1391 1.59 christos { 1392 1.59 christos #ifdef HN_AUTOSCALE 1393 1.59 christos char human_num[5]; 1394 1.59 christos if (humanize_number(human_num, 5, (int64_t)num , 1395 1.59 christos "", HN_AUTOSCALE, HN_NOSPACE|HN_B) < 0) 1396 1.59 christos human_num[0] = '\0'; 1397 1.59 christos #endif 1398 1.59 christos printf("%s: %ju", prompt, num); 1399 1.59 christos #ifdef HN_AUTOSCALE 1400 1.59 christos if (human_num[0] != '\0') 1401 1.60 christos printf(" (%s)", human_num); 1402 1.59 christos #endif 1403 1.59 christos printf("\n"); 1404 1.59 christos } 1405 1.63 christos 1406 1.63 christos int 1407 1.63 christos gpt_add_hdr(gpt_t gpt, int type, off_t loc) 1408 1.63 christos { 1409 1.63 christos void *p; 1410 1.63 christos map_t *t; 1411 1.63 christos const char *msg; 1412 1.63 christos 1413 1.63 christos switch (type) { 1414 1.63 christos case MAP_TYPE_PRI_GPT_HDR: 1415 1.63 christos t = &gpt->gpt; 1416 1.63 christos msg = "primary"; 1417 1.63 christos break; 1418 1.63 christos case MAP_TYPE_SEC_GPT_HDR: 1419 1.63 christos t = &gpt->tpg; 1420 1.63 christos msg = "secondary"; 1421 1.63 christos break; 1422 1.63 christos default: 1423 1.63 christos gpt_warnx(gpt, "Unknown GPT header type %d", type); 1424 1.63 christos return -1; 1425 1.63 christos } 1426 1.63 christos 1427 1.63 christos if ((p = calloc(1, gpt->secsz)) == NULL) { 1428 1.63 christos gpt_warn(gpt, "Error allocating %s GPT header", msg); 1429 1.63 christos return -1; 1430 1.63 christos } 1431 1.63 christos 1432 1.63 christos *t = map_add(gpt, loc, 1LL, type, p, 1); 1433 1.63 christos if (*t == NULL) { 1434 1.63 christos gpt_warn(gpt, "Error adding %s GPT header", msg); 1435 1.63 christos free(p); 1436 1.63 christos return -1; 1437 1.63 christos } 1438 1.63 christos return 0; 1439 1.63 christos } 1440