root/sbin/gpt/show.c
/*-
 * Copyright (c) 2002 Marcel Moolenaar
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $FreeBSD: src/sbin/gpt/show.c,v 1.14 2006/06/22 22:22:32 marcel Exp $
 */

#include <sys/param.h>

#include <err.h>
#include <libutil.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "gpt.h"

static bool show_guid = false;
static bool show_label = false;
static bool show_uuid = false;

static void
usage_show(void)
{
        fprintf(stderr, "usage: %s [-glu] device ...\n", getprogname());
        exit(1);
}

static const char *
friendly(uuid_t *t)
{
        static char *save_name1 = NULL;
        static char *save_name2 = NULL;

        if (show_uuid)
                goto unfriendly;

        uuid_addr_lookup(t, &save_name1, NULL);
        if (save_name1)
                return (save_name1);

unfriendly:
        if (save_name2) {
                free(save_name2);
                save_name2 = NULL;
        }
        uuid_to_string(t, &save_name2, NULL);
        return (save_name2);
}

static void
show(int fd __unused)
{
        uuid_t type, guid;
        off_t start;
        map_t *m, *p;
        struct mbr *mbr;
        struct gpt_ent *ent;
        size_t i, j;
        char *s, humansz[sizeof("99.9GB")], lwbuf[32];
        char utfbuf[NELEM(ent->ent_name) * 3 + 1];
        const char *name;
        int lbawidth;

        lbawidth = sprintf(lwbuf, "%ju", (uintmax_t)(mediasz / secsz));
        if (lbawidth < 5)
                lbawidth = 5;

        humanize_number(humansz, sizeof(humansz), (int64_t)mediasz, "B",
                        HN_AUTOSCALE, HN_FRACTIONAL | HN_NOSPACE);
        printf("Disk %s: %s (%ju %u-byte sectors)\n",
               device_name, humansz, (uintmax_t)(mediasz / secsz), secsz);

        printf("  %*s", lbawidth, "Start");
        printf("  %*s", lbawidth, "Sectors");
        printf("  %*s", (int)(sizeof(humansz) - 1), "Size");
        printf("  Index  Contents\n");

        for (m = map_first(); m != NULL; m = m->map_next) {
                printf("  %*ju", lbawidth, (uintmax_t)m->map_start);
                printf("  %*ju", lbawidth, (uintmax_t)m->map_size);
                humanize_number(humansz, sizeof(humansz),
                                (int64_t)(m->map_size * secsz), "B",
                                HN_AUTOSCALE, HN_FRACTIONAL | HN_NOSPACE);
                printf("  %*s", (int)(sizeof(humansz) - 1), humansz);
                putchar(' ');
                putchar(' ');
                if (m->map_index != MAP_NOENTRY)
                        printf("%5d", m->map_index);
                else
                        printf("    -");
                putchar(' ');
                putchar(' ');
                switch (m->map_type) {
                case MAP_TYPE_UNUSED:
                        printf("Unused");
                        break;
                case MAP_TYPE_MBR:
                        if (m->map_start != 0)
                                printf("Extended ");
                        printf("MBR");
                        break;
                case MAP_TYPE_GPT_PRI_HDR:
                        printf("Primary GPT header");
                        break;
                case MAP_TYPE_GPT_SEC_HDR:
                        printf("Secondary GPT header");
                        break;
                case MAP_TYPE_GPT_PRI_TBL:
                        printf("Primary GPT table");
                        break;
                case MAP_TYPE_GPT_SEC_TBL:
                        printf("Secondary GPT table");
                        break;
                case MAP_TYPE_MBR_PART:
                        p = m->map_data;
                        if (p->map_start != 0)
                                printf("Extended ");
                        printf("MBR part ");
                        mbr = p->map_data;
                        for (i = 0; i < 4; i++) {
                                start = le32toh(mbr->mbr_part[i].dp_start);
                                if (m->map_start == p->map_start + start)
                                        break;
                        }
                        if (i == 4) {
                                /* wasn't there */
                                printf("[partition not found?]");
                        } else {
                                name = NULL;
                                for (j = 0; j < NELEM(dos_ptypes); j++) {
                                        if (dos_ptypes[j].type ==
                                            mbr->mbr_part[i].dp_typ) {
                                                name = dos_ptypes[j].name;
                                                break;
                                        }
                                }
                                if (name != NULL)
                                        printf("- %s", name);
                                else
                                        printf("- %d", mbr->mbr_part[i].dp_typ);
                                if (mbr->mbr_part[i].dp_flag == 0x80)
                                        printf(" (active)");
                        }
                        break;
                case MAP_TYPE_GPT_PART:
                        printf("GPT part ");
                        ent = m->map_data;
                        if (show_label) {
                                utf16_to_utf8(ent->ent_name,
                                    NELEM(ent->ent_name),
                                    utfbuf, sizeof(utfbuf));
                                printf("- \"%s\"", utfbuf);
                        } else if (show_guid) {
                                s = NULL;
                                uuid_dec_le(&ent->ent_uuid, &guid);
                                uuid_to_string(&guid, &s, NULL);
                                printf("- %s", s);
                                free(s);
                                s = NULL;
                        } else {
                                uuid_dec_le(&ent->ent_type, &type);
                                printf("- %s", friendly(&type));
                        }
                        break;
                case MAP_TYPE_PMBR:
                        printf("PMBR");
                        mbr = m->map_data;
                        if (mbr->mbr_part[0].dp_typ == DOSPTYP_PMBR &&
                            mbr->mbr_part[0].dp_flag == 0x80)
                                printf(" (active)");
                        break;
                default:
                        printf("Unknown %#x", m->map_type);
                        break;
                }
                putchar('\n');
        }
}

int
cmd_show(int argc, char *argv[])
{
        int ch, fd;

        while ((ch = getopt(argc, argv, "ghlu")) != -1) {
                switch(ch) {
                case 'g':
                        show_guid = true;
                        break;
                case 'l':
                        show_label = true;
                        break;
                case 'u':
                        show_uuid = true;
                        break;
                case 'h':
                default:
                        usage_show();
                }
        }

        if (argc == optind)
                usage_show();

        while (optind < argc) {
                fd = gpt_open(argv[optind++]);
                if (fd == -1) {
                        warn("unable to open device '%s'", device_name);
                } else {
                        show(fd);
                        gpt_close(fd);
                }
                if (optind != argc)
                        putchar('\n');
        }

        return (0);
}