text: /*
   * 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);
  }
  