[BACK]Return to migrate.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sbin / gpt

Annotation of src/sbin/gpt/migrate.c, Revision 1.22

1.1       christos    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:
1.15      christos   27: #if HAVE_NBTOOL_CONFIG_H
                     28: #include "nbtool_config.h"
                     29: #endif
                     30:
1.1       christos   31: #include <sys/cdefs.h>
1.2       christos   32: #ifdef __FBSDID
1.1       christos   33: __FBSDID("$FreeBSD: src/sbin/gpt/migrate.c,v 1.16 2005/09/01 02:42:52 marcel Exp $");
1.2       christos   34: #endif
                     35: #ifdef __RCSID
1.22    ! christos   36: __RCSID("$NetBSD: migrate.c,v 1.21 2014/10/03 20:30:06 christos Exp $");
1.2       christos   37: #endif
1.1       christos   38:
                     39: #include <sys/types.h>
1.3       he         40: #include <sys/param.h>
1.17      christos   41: #ifdef HAVE_NBTOOL_CONFIG_H
                     42: #include <nbinclude/sys/bootblock.h>
                     43: #include <nbinclude/sys/disklabel.h>
                     44: #else
1.9       jnemeth    45: #include <sys/bootblock.h>
1.1       christos   46: #include <sys/disklabel.h>
1.17      christos   47: #endif
1.1       christos   48:
                     49: #include <err.h>
                     50: #include <stddef.h>
                     51: #include <stdio.h>
                     52: #include <stdlib.h>
                     53: #include <string.h>
                     54: #include <unistd.h>
                     55:
                     56: #include "map.h"
                     57: #include "gpt.h"
                     58:
                     59: /*
                     60:  * Allow compilation on platforms that do not have a BSD label.
                     61:  * The values are valid for amd64, i386 and ia64 disklabels.
1.15      christos   62:  * XXX: use disklabel_params from disklabel.c
1.1       christos   63:  */
                     64: #ifndef LABELOFFSET
                     65: #define        LABELOFFSET     0
                     66: #endif
                     67: #ifndef LABELSECTOR
                     68: #define        LABELSECTOR     1
                     69: #endif
1.15      christos   70: #ifndef RAW_PART
                     71: #define        RAW_PART        3
                     72: #endif
1.1       christos   73:
1.10      jnemeth    74: /* FreeBSD filesystem types that don't match corresponding NetBSD types */
                     75: #define        FREEBSD_FS_VINUM        14
                     76: #define        FREEBSD_FS_ZFS          27
                     77:
1.1       christos   78: static int force;
                     79: static int slice;
                     80:
1.4       riz        81: const char migratemsg[] = "migrate [-fs] device ...";
                     82:
1.5       joerg      83: __dead static void
1.1       christos   84: usage_migrate(void)
                     85: {
                     86:
                     87:        fprintf(stderr,
1.4       riz        88:            "usage: %s %s\n", getprogname(), migratemsg);
1.1       christos   89:        exit(1);
                     90: }
                     91:
                     92: static struct gpt_ent*
                     93: migrate_disklabel(int fd, off_t start, struct gpt_ent *ent)
                     94: {
                     95:        char *buf;
                     96:        struct disklabel *dl;
                     97:        off_t ofs, rawofs;
                     98:        int i;
                     99:
                    100:        buf = gpt_read(fd, start + LABELSECTOR, 1);
                    101:        dl = (void*)(buf + LABELOFFSET);
                    102:
                    103:        if (le32toh(dl->d_magic) != DISKMAGIC ||
                    104:            le32toh(dl->d_magic2) != DISKMAGIC) {
                    105:                warnx("%s: warning: FreeBSD slice without disklabel",
                    106:                    device_name);
1.12      christos  107:                free(buf);
1.1       christos  108:                return (ent);
                    109:        }
                    110:
                    111:        rawofs = le32toh(dl->d_partitions[RAW_PART].p_offset) *
                    112:            le32toh(dl->d_secsize);
                    113:        for (i = 0; i < le16toh(dl->d_npartitions); i++) {
                    114:                if (dl->d_partitions[i].p_fstype == FS_UNUSED)
                    115:                        continue;
                    116:                ofs = le32toh(dl->d_partitions[i].p_offset) *
                    117:                    le32toh(dl->d_secsize);
                    118:                if (ofs < rawofs)
                    119:                        rawofs = 0;
                    120:        }
                    121:        rawofs /= secsz;
                    122:
                    123:        for (i = 0; i < le16toh(dl->d_npartitions); i++) {
                    124:                switch (dl->d_partitions[i].p_fstype) {
                    125:                case FS_UNUSED:
                    126:                        continue;
                    127:                case FS_SWAP: {
1.19      christos  128:                        gpt_uuid_create(GPT_TYPE_FREEBSD_SWAP, ent->ent_type,
                    129:                            ent->ent_name, sizeof(ent->ent_name));
1.1       christos  130:                        break;
                    131:                }
                    132:                case FS_BSDFFS: {
1.19      christos  133:                        gpt_uuid_create(GPT_TYPE_FREEBSD_UFS, ent->ent_type,
                    134:                            ent->ent_name, sizeof(ent->ent_name));
1.1       christos  135:                        break;
                    136:                }
1.10      jnemeth   137:                case FREEBSD_FS_VINUM: {
1.19      christos  138:                        gpt_uuid_create(GPT_TYPE_FREEBSD_VINUM, ent->ent_type,
                    139:                            ent->ent_name, sizeof(ent->ent_name));
1.1       christos  140:                        break;
                    141:                }
1.10      jnemeth   142:                case FREEBSD_FS_ZFS: {
1.19      christos  143:                        gpt_uuid_create(GPT_TYPE_FREEBSD_ZFS, ent->ent_type,
                    144:                            ent->ent_name, sizeof(ent->ent_name));
1.8       jnemeth   145:                        break;
                    146:                }
1.1       christos  147:                default:
                    148:                        warnx("%s: warning: unknown FreeBSD partition (%d)",
                    149:                            device_name, dl->d_partitions[i].p_fstype);
                    150:                        continue;
                    151:                }
                    152:
                    153:                ofs = (le32toh(dl->d_partitions[i].p_offset) *
                    154:                    le32toh(dl->d_secsize)) / secsz;
                    155:                ofs = (ofs > 0) ? ofs - rawofs : 0;
                    156:                ent->ent_lba_start = htole64(start + ofs);
                    157:                ent->ent_lba_end = htole64(start + ofs +
                    158:                    le32toh(dl->d_partitions[i].p_size) - 1LL);
                    159:                ent++;
                    160:        }
                    161:
1.12      christos  162:        free(buf);
1.1       christos  163:        return (ent);
                    164: }
                    165:
1.9       jnemeth   166: static struct gpt_ent*
                    167: migrate_netbsd_disklabel(int fd, off_t start, struct gpt_ent *ent)
                    168: {
                    169:        char *buf;
                    170:        struct disklabel *dl;
                    171:        off_t ofs, rawofs;
                    172:        int i;
                    173:
                    174:        buf = gpt_read(fd, start + LABELSECTOR, 1);
                    175:        dl = (void*)(buf + LABELOFFSET);
                    176:
                    177:        if (le32toh(dl->d_magic) != DISKMAGIC ||
                    178:            le32toh(dl->d_magic2) != DISKMAGIC) {
                    179:                warnx("%s: warning: NetBSD slice without disklabel",
                    180:                    device_name);
1.12      christos  181:                free(buf);
1.9       jnemeth   182:                return (ent);
                    183:        }
                    184:
                    185:        rawofs = le32toh(dl->d_partitions[RAW_PART].p_offset) *
                    186:            le32toh(dl->d_secsize);
                    187:        for (i = 0; i < le16toh(dl->d_npartitions); i++) {
                    188:                if (dl->d_partitions[i].p_fstype == FS_UNUSED)
                    189:                        continue;
                    190:                ofs = le32toh(dl->d_partitions[i].p_offset) *
                    191:                    le32toh(dl->d_secsize);
                    192:                if (ofs < rawofs)
                    193:                        rawofs = 0;
                    194:        }
                    195:        rawofs /= secsz;
                    196:
                    197:        for (i = 0; i < le16toh(dl->d_npartitions); i++) {
                    198:                switch (dl->d_partitions[i].p_fstype) {
                    199:                case FS_UNUSED:
                    200:                        continue;
                    201:                case FS_SWAP: {
1.19      christos  202:                        gpt_uuid_create(GPT_TYPE_NETBSD_SWAP, ent->ent_type,
                    203:                            ent->ent_name, sizeof(ent->ent_name));
1.9       jnemeth   204:                        break;
                    205:                }
                    206:                case FS_BSDFFS: {
1.19      christos  207:                        gpt_uuid_create(GPT_TYPE_NETBSD_FFS, ent->ent_type,
                    208:                            ent->ent_name, sizeof(ent->ent_name));
1.9       jnemeth   209:                        break;
                    210:                }
                    211:                case FS_BSDLFS: {
1.19      christos  212:                        gpt_uuid_create(GPT_TYPE_NETBSD_LFS, ent->ent_type,
                    213:                            ent->ent_name, sizeof(ent->ent_name));
1.9       jnemeth   214:                        break;
                    215:                }
                    216:                case FS_RAID: {
1.19      christos  217:                        gpt_uuid_create(GPT_TYPE_NETBSD_RAIDFRAME, ent->ent_type,
                    218:                            ent->ent_name, sizeof(ent->ent_name));
1.9       jnemeth   219:                        break;
                    220:                }
                    221:                case FS_CCD: {
1.19      christos  222:                        gpt_uuid_create(GPT_TYPE_NETBSD_CCD, ent->ent_type,
                    223:                            ent->ent_name, sizeof(ent->ent_name));
1.9       jnemeth   224:                        break;
                    225:                }
                    226:                case FS_CGD: {
1.19      christos  227:                        gpt_uuid_create(GPT_TYPE_NETBSD_CGD, ent->ent_type,
                    228:                            ent->ent_name, sizeof(ent->ent_name));
1.9       jnemeth   229:                        break;
                    230:                }
                    231:                default:
                    232:                        warnx("%s: warning: unknown NetBSD partition (%d)",
                    233:                            device_name, dl->d_partitions[i].p_fstype);
                    234:                        continue;
                    235:                }
                    236:
                    237:                ofs = (le32toh(dl->d_partitions[i].p_offset) *
                    238:                    le32toh(dl->d_secsize)) / secsz;
                    239:                ofs = (ofs > 0) ? ofs - rawofs : 0;
1.11      jnemeth   240:                ent->ent_lba_start = htole64(ofs);
                    241:                ent->ent_lba_end = htole64(ofs +
1.9       jnemeth   242:                    le32toh(dl->d_partitions[i].p_size) - 1LL);
                    243:                ent++;
                    244:        }
                    245:
1.12      christos  246:        free(buf);
1.9       jnemeth   247:        return (ent);
                    248: }
                    249:
1.1       christos  250: static void
                    251: migrate(int fd)
                    252: {
                    253:        off_t blocks, last;
                    254:        map_t *gpt, *tpg;
                    255:        map_t *tbl, *lbt;
                    256:        map_t *map;
                    257:        struct gpt_hdr *hdr;
                    258:        struct gpt_ent *ent;
                    259:        struct mbr *mbr;
                    260:        uint32_t start, size;
                    261:        unsigned int i;
                    262:
                    263:        last = mediasz / secsz - 1LL;
                    264:
                    265:        map = map_find(MAP_TYPE_MBR);
                    266:        if (map == NULL || map->map_start != 0) {
                    267:                warnx("%s: error: no partitions to convert", device_name);
                    268:                return;
                    269:        }
                    270:
                    271:        mbr = map->map_data;
                    272:
                    273:        if (map_find(MAP_TYPE_PRI_GPT_HDR) != NULL ||
                    274:            map_find(MAP_TYPE_SEC_GPT_HDR) != NULL) {
                    275:                warnx("%s: error: device already contains a GPT", device_name);
                    276:                return;
                    277:        }
                    278:
                    279:        /* Get the amount of free space after the MBR */
                    280:        blocks = map_free(1LL, 0LL);
                    281:        if (blocks == 0LL) {
                    282:                warnx("%s: error: no room for the GPT header", device_name);
                    283:                return;
                    284:        }
                    285:
                    286:        /* Don't create more than parts entries. */
                    287:        if ((uint64_t)(blocks - 1) * secsz > parts * sizeof(struct gpt_ent)) {
                    288:                blocks = (parts * sizeof(struct gpt_ent)) / secsz;
                    289:                if ((parts * sizeof(struct gpt_ent)) % secsz)
                    290:                        blocks++;
                    291:                blocks++;               /* Don't forget the header itself */
                    292:        }
                    293:
                    294:        /* Never cross the median of the device. */
                    295:        if ((blocks + 1LL) > ((last + 1LL) >> 1))
                    296:                blocks = ((last + 1LL) >> 1) - 1LL;
                    297:
                    298:        /*
                    299:         * Get the amount of free space at the end of the device and
                    300:         * calculate the size for the GPT structures.
                    301:         */
                    302:        map = map_last();
                    303:        if (map->map_type != MAP_TYPE_UNUSED) {
                    304:                warnx("%s: error: no room for the backup header", device_name);
                    305:                return;
                    306:        }
                    307:
                    308:        if (map->map_size < blocks)
                    309:                blocks = map->map_size;
                    310:        if (blocks == 1LL) {
                    311:                warnx("%s: error: no room for the GPT table", device_name);
                    312:                return;
                    313:        }
                    314:
                    315:        blocks--;               /* Number of blocks in the GPT table. */
                    316:        gpt = map_add(1LL, 1LL, MAP_TYPE_PRI_GPT_HDR, calloc(1, secsz));
                    317:        tbl = map_add(2LL, blocks, MAP_TYPE_PRI_GPT_TBL,
                    318:            calloc(blocks, secsz));
                    319:        if (gpt == NULL || tbl == NULL)
                    320:                return;
                    321:
                    322:        lbt = map_add(last - blocks, blocks, MAP_TYPE_SEC_GPT_TBL,
                    323:            tbl->map_data);
                    324:        tpg = map_add(last, 1LL, MAP_TYPE_SEC_GPT_HDR, calloc(1, secsz));
                    325:
                    326:        hdr = gpt->map_data;
                    327:        memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig));
                    328:        hdr->hdr_revision = htole32(GPT_HDR_REVISION);
                    329:        /*
                    330:         * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus
                    331:         * contains padding we must not include in the size.
                    332:         */
1.18      christos  333:        hdr->hdr_size = htole32(GPT_HDR_SIZE);
1.1       christos  334:        hdr->hdr_lba_self = htole64(gpt->map_start);
                    335:        hdr->hdr_lba_alt = htole64(tpg->map_start);
                    336:        hdr->hdr_lba_start = htole64(tbl->map_start + blocks);
                    337:        hdr->hdr_lba_end = htole64(lbt->map_start - 1LL);
1.21      christos  338:        gpt_uuid_generate(hdr->hdr_guid);
1.1       christos  339:        hdr->hdr_lba_table = htole64(tbl->map_start);
                    340:        hdr->hdr_entries = htole32((blocks * secsz) / sizeof(struct gpt_ent));
                    341:        if (le32toh(hdr->hdr_entries) > parts)
                    342:                hdr->hdr_entries = htole32(parts);
                    343:        hdr->hdr_entsz = htole32(sizeof(struct gpt_ent));
                    344:
                    345:        ent = tbl->map_data;
                    346:        for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
1.21      christos  347:                gpt_uuid_generate(ent[i].ent_guid);
1.1       christos  348:        }
                    349:
                    350:        /* Mirror partitions. */
                    351:        for (i = 0; i < 4; i++) {
                    352:                start = le16toh(mbr->mbr_part[i].part_start_hi);
                    353:                start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo);
                    354:                size = le16toh(mbr->mbr_part[i].part_size_hi);
                    355:                size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo);
                    356:
                    357:                switch (mbr->mbr_part[i].part_typ) {
1.9       jnemeth   358:                case MBR_PTYPE_UNUSED:
1.1       christos  359:                        continue;
1.9       jnemeth   360:                case MBR_PTYPE_386BSD: {        /* FreeBSD */
1.1       christos  361:                        if (slice) {
1.19      christos  362:                                gpt_uuid_create(GPT_TYPE_FREEBSD,
                    363:                                    ent->ent_type, ent->ent_name,
                    364:                                    sizeof(ent->ent_name));
1.1       christos  365:                                ent->ent_lba_start = htole64((uint64_t)start);
                    366:                                ent->ent_lba_end = htole64(start + size - 1LL);
                    367:                                ent++;
                    368:                        } else
                    369:                                ent = migrate_disklabel(fd, start, ent);
                    370:                        break;
                    371:                }
1.9       jnemeth   372:                case MBR_PTYPE_NETBSD:
                    373:                        ent = migrate_netbsd_disklabel(fd, start, ent);
                    374:                        break;
                    375:                case MBR_PTYPE_EFI: {
1.19      christos  376:                        gpt_uuid_create(GPT_TYPE_EFI,
                    377:                            ent->ent_type, ent->ent_name,
                    378:                            sizeof(ent->ent_name));
1.1       christos  379:                        ent->ent_lba_start = htole64((uint64_t)start);
                    380:                        ent->ent_lba_end = htole64(start + size - 1LL);
                    381:                        ent++;
                    382:                        break;
                    383:                }
                    384:                default:
                    385:                        if (!force) {
                    386:                                warnx("%s: error: unknown partition type (%d)",
                    387:                                    device_name, mbr->mbr_part[i].part_typ);
                    388:                                return;
                    389:                        }
                    390:                }
                    391:        }
                    392:        ent = tbl->map_data;
                    393:
                    394:        hdr->hdr_crc_table = htole32(crc32(ent, le32toh(hdr->hdr_entries) *
                    395:            le32toh(hdr->hdr_entsz)));
                    396:        hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
                    397:
                    398:        gpt_write(fd, gpt);
                    399:        gpt_write(fd, tbl);
                    400:
                    401:        /*
                    402:         * Create backup GPT.
                    403:         */
                    404:        memcpy(tpg->map_data, gpt->map_data, secsz);
                    405:        hdr = tpg->map_data;
                    406:        hdr->hdr_lba_self = htole64(tpg->map_start);
                    407:        hdr->hdr_lba_alt = htole64(gpt->map_start);
                    408:        hdr->hdr_lba_table = htole64(lbt->map_start);
                    409:        hdr->hdr_crc_self = 0;                  /* Don't ever forget this! */
                    410:        hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
                    411:
                    412:        gpt_write(fd, lbt);
                    413:        gpt_write(fd, tpg);
                    414:
                    415:        map = map_find(MAP_TYPE_MBR);
                    416:        mbr = map->map_data;
                    417:        /*
                    418:         * Turn the MBR into a Protective MBR.
                    419:         */
1.16      christos  420:        memset(mbr->mbr_part, 0, sizeof(mbr->mbr_part));
1.13      jakllsch  421:        mbr->mbr_part[0].part_shd = 0x00;
                    422:        mbr->mbr_part[0].part_ssect = 0x02;
                    423:        mbr->mbr_part[0].part_scyl = 0x00;
1.14      jakllsch  424:        mbr->mbr_part[0].part_typ = MBR_PTYPE_PMBR;
1.13      jakllsch  425:        mbr->mbr_part[0].part_ehd = 0xfe;
1.1       christos  426:        mbr->mbr_part[0].part_esect = 0xff;
                    427:        mbr->mbr_part[0].part_ecyl = 0xff;
                    428:        mbr->mbr_part[0].part_start_lo = htole16(1);
                    429:        if (last > 0xffffffff) {
                    430:                mbr->mbr_part[0].part_size_lo = htole16(0xffff);
                    431:                mbr->mbr_part[0].part_size_hi = htole16(0xffff);
                    432:        } else {
                    433:                mbr->mbr_part[0].part_size_lo = htole16(last);
                    434:                mbr->mbr_part[0].part_size_hi = htole16(last >> 16);
                    435:        }
                    436:        gpt_write(fd, map);
                    437: }
                    438:
                    439: int
                    440: cmd_migrate(int argc, char *argv[])
                    441: {
                    442:        int ch, fd;
                    443:
                    444:        /* Get the migrate options */
                    445:        while ((ch = getopt(argc, argv, "fs")) != -1) {
                    446:                switch(ch) {
                    447:                case 'f':
                    448:                        force = 1;
                    449:                        break;
                    450:                case 's':
                    451:                        slice = 1;
                    452:                        break;
                    453:                default:
                    454:                        usage_migrate();
                    455:                }
                    456:        }
                    457:
                    458:        if (argc == optind)
                    459:                usage_migrate();
                    460:
                    461:        while (optind < argc) {
1.22    ! christos  462:                fd = gpt_open(argv[optind++], 0);
        !           463:                if (fd == -1)
1.1       christos  464:                        continue;
                    465:
                    466:                migrate(fd);
                    467:
                    468:                gpt_close(fd);
                    469:        }
                    470:
                    471:        return (0);
                    472: }

CVSweb <webmaster@jp.NetBSD.org>