root/usr/src/cmd/devinfo/devinfo.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/*        All Rights Reserved   */

/*
 *      Two output fields under the -i option will always be
 *      output as zero, since they are not supported by Sun:
 *              Software version, and
 *              Drive id number.
 *      AT&T filled these 2 fields with data from their "pdsector",
 *      which Sun doesn't support per se.
 */


#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dkio.h>
#include <sys/efi_partition.h>
#include <sys/vtoc.h>
#include <sys/mkdev.h>
#include <errno.h>

#define DRERR   2
#define OPENERR 2

/*
 * Standard I/O file descriptors.
 */
#define STDOUT  1               /* Standard output */
#define STDERR  2               /* Standard error */

static  void    partinfo(int fd, char *device);
static  void    devinfo(struct dk_geom *geom, int fd, char *device);
static  int     readvtoc(int fd, char *name, struct extvtoc *vtoc);
static  int     warn(char *what, char *why);
static  void    usage(void);

int
main(int argc, char **argv)
{
        struct dk_geom  geom;
        int errflg, iflg, pflg, fd, c;
        char *device;

        iflg = 0;
        pflg = 0;
        errflg = 0;
        while ((c = getopt(argc, argv, "i:p:")) != EOF) {
                switch (c) {
                        case 'i':
                                iflg++;
                                device = optarg;
                                break;
                        case 'p':
                                pflg++;
                                device = optarg;
                                break;
                        case '?':
                                errflg++;
                                break;
                        default:
                                errflg++;
                                break;
                }
                if (errflg)
                        usage();
        }
        if ((optind > argc) || (optind == 1) || (pflg && iflg))
                usage();

        if ((fd = open(device, O_RDONLY)) < 0) {
                (void) fprintf(stderr, "devinfo: %s: %s\n",
                        device, strerror(errno));
                exit(OPENERR);
        }

        if (iflg) {
                if (ioctl(fd, DKIOCGGEOM, &geom) == -1) {
                        if (errno == ENOTSUP) {
                                (void) warn(device,
"This operation is not supported on EFI labeled devices");
                        } else {
                                (void) warn(device,
"Unable to read Disk geometry");
                        }
                        (void) close(fd);
                        exit(DRERR);
                }
                devinfo(&geom, fd, device);
        }
        if (pflg)
                partinfo(fd, device);
        (void) close(fd);
        return (0);
}

static void
partinfo(int fd, char *device)
{
        int i;
        int     slice;
        major_t maj;
        minor_t min;
        struct stat64 statbuf;
        struct extvtoc vtdata;
        struct dk_gpt *efi;

        i = stat64(device, &statbuf);
        if (i < 0)
                exit(DRERR);
        maj = major(statbuf.st_rdev);
        min = minor(statbuf.st_rdev);

        if ((slice = readvtoc(fd, device, &vtdata)) >= 0) {

                (void) printf("%s\t%0lx\t%0lx\t%llu\t%llu\t%x\t%x\n",
                        device, maj, min,
                        vtdata.v_part[slice].p_start,
                        vtdata.v_part[slice].p_size,
                        vtdata.v_part[slice].p_flag,
                        vtdata.v_part[slice].p_tag);
        } else if ((slice == VT_ENOTSUP) &&
            (slice = efi_alloc_and_read(fd, &efi)) >= 0) {
                (void) printf("%s\t%lx\t%lx\t%lld\t%lld\t%hx\t%hx\n",
                        device, maj, min,
                        efi->efi_parts[slice].p_start,
                        efi->efi_parts[slice].p_size,
                        efi->efi_parts[slice].p_flag,
                        efi->efi_parts[slice].p_tag);
        } else {
                exit(DRERR);
        }
}

static void
devinfo(struct dk_geom *geom, int fd, char *device)
{
        int i;
        unsigned int nopartitions, sectorcyl, bytes;
        struct extvtoc vtdata;
/*
 *      unsigned int version = 0;
 *      unsigned int driveid = 0;
 */

        nopartitions = 0;
        sectorcyl = 0;
        bytes = 0;

        if (readvtoc(fd, device, &vtdata) < 0)
                exit(DRERR);
        sectorcyl = geom->dkg_nhead  *  geom->dkg_nsect;
        bytes = vtdata.v_sectorsz;
/*
 *      these are not supported by Sun.
 *
 *      driveid = osect0->newsect0.pdinfo.driveid;
 *      version = osect0->newsect0.pdinfo.version;
 */
        for (i = 0; i < V_NUMPAR; i++)  {
                if (vtdata.v_part[i].p_size != 0x00)
                        nopartitions++;
        }
/*
 *      (void) printf("%s       %0x     %0x     %d      %d      %d\n",
 *              device, version, driveid, sectorcyl, bytes, nopartitions);
 */
        (void) printf("%s       %0x     %0x     %d      %d      %d\n",
                device, 0, 0, sectorcyl, bytes, nopartitions);
}


/*
 * readvtoc()
 *
 * Read a partition map.
 */
static int
readvtoc(int fd, char *name, struct extvtoc *vtoc)
{
        int     retval;

        retval = read_extvtoc(fd, vtoc);

        switch (retval) {
                case (VT_ERROR):
                        return (warn(name, strerror(errno)));
                case (VT_EIO):
                        return (warn(name, "I/O error accessing VTOC"));
                case (VT_EINVAL):
                        return (warn(name, "Invalid field in VTOC"));
                }

        return (retval);
}


/*
 * warn()
 *
 * Print an error message. Always returns -1.
 */
static int
warn(char *what, char *why)
{
        static char     myname[]  = "devinfo";
        static char     between[] = ": ";
        static char     after[]   = "\n";

        (void) write(STDERR, myname, (uint_t)strlen(myname));
        (void) write(STDERR, between, (uint_t)strlen(between));
        (void) write(STDERR, what, (uint_t)strlen(what));
        (void) write(STDERR, between, (uint_t)strlen(between));
        (void) write(STDERR, why, (uint_t)strlen(why));
        (void) write(STDERR, after, (uint_t)strlen(after));
        return (-1);
}

static void
usage(void)
{
        (void) fprintf(stderr, "Usage: devinfo -p device\n"
                "       devinfo -i device \n");
        exit(2);
}