17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
5342440ePrasad Singamsetty * Common Development and Distribution License (the "License").
6342440ePrasad Singamsetty * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
227c478bdstevel@tonic-gate/*	  All Rights Reserved  	*/
237c478bdstevel@tonic-gate
247c478bdstevel@tonic-gate
257c478bdstevel@tonic-gate/*	Copyright (c) 1984 AT&T	*/
267c478bdstevel@tonic-gate/*	  All Rights Reserved  	*/
277c478bdstevel@tonic-gate
287c478bdstevel@tonic-gate
297c478bdstevel@tonic-gate/*
30342440ePrasad Singamsetty * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
317c478bdstevel@tonic-gate * Use is subject to license terms.
327c478bdstevel@tonic-gate */
337c478bdstevel@tonic-gate
347c478bdstevel@tonic-gate/*
357c478bdstevel@tonic-gate * Print a disk partition map (volume table of contents, or VTOC).
367c478bdstevel@tonic-gate */
377c478bdstevel@tonic-gate
387c478bdstevel@tonic-gate#include <errno.h>
397c478bdstevel@tonic-gate#include <fcntl.h>
407c478bdstevel@tonic-gate#include <unistd.h>
417c478bdstevel@tonic-gate#include <stdlib.h>
427c478bdstevel@tonic-gate#include <string.h>
437c478bdstevel@tonic-gate#include <stdio.h>
447c478bdstevel@tonic-gate#include <limits.h>
457c478bdstevel@tonic-gate
467c478bdstevel@tonic-gate#include <sys/types.h>
477c478bdstevel@tonic-gate#include <sys/stat.h>
487c478bdstevel@tonic-gate#include <sys/dkio.h>
497c478bdstevel@tonic-gate#include <sys/vtoc.h>
507c478bdstevel@tonic-gate#include <sys/mnttab.h>
517c478bdstevel@tonic-gate#include <sys/vfstab.h>
527c478bdstevel@tonic-gate#include <sys/mkdev.h>
537c478bdstevel@tonic-gate
547c478bdstevel@tonic-gate#include <sys/efi_partition.h>
557c478bdstevel@tonic-gate/*
567c478bdstevel@tonic-gate * Assumes V_NUMPAR must be a power of 2.
577c478bdstevel@tonic-gate *
587c478bdstevel@tonic-gate * for V_NUMPAR = 8, we have
597c478bdstevel@tonic-gate * 	parttn(x)=(x & 0x07)	noparttn(x)=(x & 0x3fff8)
607c478bdstevel@tonic-gate *
617c478bdstevel@tonic-gate * for V_NUMPAR = 16, we have
627c478bdstevel@tonic-gate * 	parttn(x)=(x & 0x0f)	noparttn(x)=(x & 0x3fff0)
637c478bdstevel@tonic-gate */
647c478bdstevel@tonic-gate#define	parttn(x)	(x % V_NUMPAR)
657c478bdstevel@tonic-gate#define	noparttn(x)	(x & (MAXMIN & ~(V_NUMPAR-1)))
667c478bdstevel@tonic-gate
677c478bdstevel@tonic-gate/*
687c478bdstevel@tonic-gate * Disk freespace structure.
697c478bdstevel@tonic-gate */
707c478bdstevel@tonic-gatetypedef struct {
717c478bdstevel@tonic-gate	u_longlong_t	fr_start;	/* Start of free space */
727c478bdstevel@tonic-gate	u_longlong_t	fr_size;	/* Length of free space */
737c478bdstevel@tonic-gate} freemap_t;
747c478bdstevel@tonic-gate
75342440ePrasad Singamsettystatic	freemap_t	*findfree(struct dk_geom *, struct extvtoc *);
767c478bdstevel@tonic-gatestatic	int	partcmp(const void *, const void *);
777c478bdstevel@tonic-gatestatic	int	partcmp64(const void *, const void *);
787c478bdstevel@tonic-gatestatic	int	prtvtoc(char *);
79342440ePrasad Singamsettystatic	void	putfree(struct extvtoc *, freemap_t *);
807c478bdstevel@tonic-gatestatic	void	putfree64(struct dk_gpt *, freemap_t *);
81342440ePrasad Singamsettystatic	void	puttable(struct dk_geom *, struct extvtoc *, freemap_t *,
827c478bdstevel@tonic-gate			char *, char **);
837c478bdstevel@tonic-gatestatic	void	puttable64(struct dk_gpt *, freemap_t *,
847c478bdstevel@tonic-gate			char *, char **);
857c478bdstevel@tonic-gatestatic	int	readgeom(int, char *, struct dk_geom *);
86342440ePrasad Singamsettystatic	int	readvtoc(int, char *, struct extvtoc *);
877c478bdstevel@tonic-gatestatic	int	readefi(int, char *, struct dk_gpt **);
887c478bdstevel@tonic-gatestatic	void	usage(void);
897c478bdstevel@tonic-gatestatic	int	warn(char *, char *);
907c478bdstevel@tonic-gatestatic	char	*safe_strdup(char *);
917c478bdstevel@tonic-gate
927c478bdstevel@tonic-gate/*
937c478bdstevel@tonic-gate * External variables.
947c478bdstevel@tonic-gate */
957c478bdstevel@tonic-gateextern char	*getfullrawname();
967c478bdstevel@tonic-gate/*
977c478bdstevel@tonic-gate * Static variables.
987c478bdstevel@tonic-gate */
997c478bdstevel@tonic-gatestatic short	fflag;			/* Print freespace shell assignments */
1007c478bdstevel@tonic-gatestatic short	hflag;			/* Omit headers */
1017c478bdstevel@tonic-gatestatic short	sflag;			/* Omit all but the column header */
1027c478bdstevel@tonic-gatestatic char	*fstab = VFSTAB;	/* Fstab pathname */
1037c478bdstevel@tonic-gatestatic char	*mnttab = MNTTAB;	/* mnttab pathname */
1047c478bdstevel@tonic-gatestatic char	*progname;		/* Last qualifier of arg0 */
1057c478bdstevel@tonic-gate
1067c478bdstevel@tonic-gateint
1077c478bdstevel@tonic-gatemain(int ac, char **av)
1087c478bdstevel@tonic-gate{
1097c478bdstevel@tonic-gate	int		idx;
1107c478bdstevel@tonic-gate
1117c478bdstevel@tonic-gate	if (progname = strrchr(av[0], '/'))
1127c478bdstevel@tonic-gate		++progname;
1137c478bdstevel@tonic-gate	else
1147c478bdstevel@tonic-gate		progname = av[0];
1157c478bdstevel@tonic-gate	while ((idx = getopt(ac, av, "fhst:m:")) != -1)
1167c478bdstevel@tonic-gate		switch (idx) {
1177c478bdstevel@tonic-gate		case 'f':
1187c478bdstevel@tonic-gate			++fflag;
1197c478bdstevel@tonic-gate			break;
1207c478bdstevel@tonic-gate		case 'h':
1217c478bdstevel@tonic-gate			++hflag;
1227c478bdstevel@tonic-gate			break;
1237c478bdstevel@tonic-gate		case 's':
1247c478bdstevel@tonic-gate			++sflag;
1257c478bdstevel@tonic-gate			break;
1267c478bdstevel@tonic-gate		case 't':
1277c478bdstevel@tonic-gate			fstab = optarg;
1287c478bdstevel@tonic-gate			break;
1297c478bdstevel@tonic-gate		case 'm':
1307c478bdstevel@tonic-gate			mnttab = optarg;
1317c478bdstevel@tonic-gate			break;
1327c478bdstevel@tonic-gate		default:
1337c478bdstevel@tonic-gate			usage();
1347c478bdstevel@tonic-gate		}
1357c478bdstevel@tonic-gate	if (optind >= ac)
1367c478bdstevel@tonic-gate		usage();
1377c478bdstevel@tonic-gate	idx = 0;
1387c478bdstevel@tonic-gate	while (optind < ac)
1397c478bdstevel@tonic-gate		idx |= prtvtoc(av[optind++]);
1407c478bdstevel@tonic-gate	return (idx == 0 ? 0 : 1);
1417c478bdstevel@tonic-gate}
1427c478bdstevel@tonic-gate
1437c478bdstevel@tonic-gatestatic freemap_t	*freemap;
1447c478bdstevel@tonic-gate/*
1457c478bdstevel@tonic-gate * findfree(): Find free space on a disk.
1467c478bdstevel@tonic-gate */
1477c478bdstevel@tonic-gatestatic freemap_t *
148342440ePrasad Singamsettyfindfree(struct dk_geom *geom, struct extvtoc *vtoc)
1497c478bdstevel@tonic-gate{
150342440ePrasad Singamsetty	struct extpartition	*part;
151342440ePrasad Singamsetty	struct extpartition	**list;
1527c478bdstevel@tonic-gate	freemap_t		*freeidx;
153342440ePrasad Singamsetty	diskaddr_t		fullsize;
1547c478bdstevel@tonic-gate	ulong_t			cylsize;
155342440ePrasad Singamsetty	struct extpartition	*sorted[V_NUMPAR + 1];
1567c478bdstevel@tonic-gate
1577c478bdstevel@tonic-gate	freemap = calloc(sizeof (freemap_t), V_NUMPAR + 1);
1587c478bdstevel@tonic-gate	cylsize  = (geom->dkg_nsect) * (geom->dkg_nhead);
159342440ePrasad Singamsetty	fullsize = (diskaddr_t)(geom->dkg_ncyl) * cylsize;
1607c478bdstevel@tonic-gate	if (vtoc->v_nparts > V_NUMPAR) {
1617c478bdstevel@tonic-gate		(void) warn("putfree()", "Too many partitions on disk!");
1627c478bdstevel@tonic-gate		exit(1);
1637c478bdstevel@tonic-gate	}
1647c478bdstevel@tonic-gate	list = sorted;
1657c478bdstevel@tonic-gate	for (part = vtoc->v_part; part < vtoc->v_part + vtoc->v_nparts; ++part)
1667c478bdstevel@tonic-gate		if (part->p_size && part->p_tag != V_BACKUP)
1677c478bdstevel@tonic-gate			*list++ = part;
1687c478bdstevel@tonic-gate	*list = 0;
1697c478bdstevel@tonic-gate	qsort((char *)sorted, (uint_t)(list - sorted),
1707c478bdstevel@tonic-gate		sizeof (*sorted), partcmp);
1717c478bdstevel@tonic-gate	freeidx = freemap;
1727c478bdstevel@tonic-gate	freeidx->fr_start = 0;
1737c478bdstevel@tonic-gate	for (list = sorted; (part = *list) != NULL; ++list)
1747c478bdstevel@tonic-gate		if (part->p_start <= freeidx->fr_start)
1757c478bdstevel@tonic-gate			freeidx->fr_start += part->p_size;
1767c478bdstevel@tonic-gate		else {
1777c478bdstevel@tonic-gate			freeidx->fr_size = part->p_start - freeidx->fr_start;
1787c478bdstevel@tonic-gate			(++freeidx)->fr_start = part->p_start + part->p_size;
1797c478bdstevel@tonic-gate		}
1807c478bdstevel@tonic-gate	if (freeidx->fr_start < fullsize) {
1817c478bdstevel@tonic-gate		freeidx->fr_size = fullsize - freeidx->fr_start;
1827c478bdstevel@tonic-gate		++freeidx;
1837c478bdstevel@tonic-gate	}
1847c478bdstevel@tonic-gate	freeidx->fr_start = freeidx->fr_size = 0;
1857c478bdstevel@tonic-gate	return (freemap);
1867c478bdstevel@tonic-gate}
1877c478bdstevel@tonic-gate
1887c478bdstevel@tonic-gate/*
1897c478bdstevel@tonic-gate * findfree64(): Find free space on a disk.
1907c478bdstevel@tonic-gate */
1917c478bdstevel@tonic-gatestatic freemap_t *
1927c478bdstevel@tonic-gatefindfree64(struct dk_gpt *efi)
1937c478bdstevel@tonic-gate{
1947c478bdstevel@tonic-gate	struct dk_part		*part;
1957c478bdstevel@tonic-gate	struct dk_part		**list;
1967c478bdstevel@tonic-gate	freemap_t		*freeidx;
1977c478bdstevel@tonic-gate	diskaddr_t		fullsize;
1987c478bdstevel@tonic-gate	struct dk_part		**sorted;
1997c478bdstevel@tonic-gate
2007c478bdstevel@tonic-gate	freemap = calloc(sizeof (freemap_t), efi->efi_nparts + 1);
2017c478bdstevel@tonic-gate	sorted = calloc(sizeof (struct dk_part), efi->efi_nparts + 1);
2027c478bdstevel@tonic-gate	fullsize = efi->efi_last_u_lba;
2037c478bdstevel@tonic-gate	list = sorted;
2047c478bdstevel@tonic-gate	for (part = efi->efi_parts;
2057c478bdstevel@tonic-gate	    part < efi->efi_parts + efi->efi_nparts;
2067c478bdstevel@tonic-gate	    ++part)
2077c478bdstevel@tonic-gate		if (part->p_size && part->p_tag != V_BACKUP)
2087c478bdstevel@tonic-gate			*list++ = part;
2097c478bdstevel@tonic-gate	*list = 0;
2107c478bdstevel@tonic-gate	qsort((char *)sorted, (uint_t)(list - sorted),
2117c478bdstevel@tonic-gate		sizeof (*sorted), partcmp64);
2127c478bdstevel@tonic-gate	freeidx = freemap;
2137c478bdstevel@tonic-gate	freeidx->fr_start = efi->efi_first_u_lba;
2147c478bdstevel@tonic-gate	for (list = sorted; (part = *list) != NULL; ++list)
2157c478bdstevel@tonic-gate		if (part->p_start == freeidx->fr_start)
2167c478bdstevel@tonic-gate			freeidx->fr_start += part->p_size;
2177c478bdstevel@tonic-gate		else {
2187c478bdstevel@tonic-gate			freeidx->fr_size = part->p_start - freeidx->fr_start;
2197c478bdstevel@tonic-gate			(++freeidx)->fr_start = part->p_start + part->p_size;
2207c478bdstevel@tonic-gate		}
2217c478bdstevel@tonic-gate	if (freeidx->fr_start < fullsize) {
2227c478bdstevel@tonic-gate		freeidx->fr_size = fullsize - freeidx->fr_start;
2237c478bdstevel@tonic-gate		++freeidx;
2247c478bdstevel@tonic-gate	}
2257c478bdstevel@tonic-gate	freeidx->fr_start = freeidx->fr_size = 0;
2267c478bdstevel@tonic-gate	return (freemap);
2277c478bdstevel@tonic-gate}
2287c478bdstevel@tonic-gate
2297c478bdstevel@tonic-gate/*
2307c478bdstevel@tonic-gate * getmntpt()
2317c478bdstevel@tonic-gate *
2327c478bdstevel@tonic-gate * Get the filesystem mountpoint of each partition on the disk
2337c478bdstevel@tonic-gate * from the fstab or mnttab. Returns a pointer to an array of pointers to
2347c478bdstevel@tonic-gate * directory names (indexed by partition number).
2357c478bdstevel@tonic-gate */
2367c478bdstevel@tonic-gatestatic char **
2377c478bdstevel@tonic-gategetmntpt(major_t slot, minor_t nopartminor)
2387c478bdstevel@tonic-gate{
2397c478bdstevel@tonic-gate	int idx;
2407c478bdstevel@tonic-gate	FILE *file;
2417c478bdstevel@tonic-gate	char devbuf[PATH_MAX], *item;
2427c478bdstevel@tonic-gate	static char *list[V_NUMPAR];
2437c478bdstevel@tonic-gate	struct stat sb;
2447c478bdstevel@tonic-gate	struct mnttab mtab;
2457c478bdstevel@tonic-gate	struct vfstab vtab;
2467c478bdstevel@tonic-gate
2477c478bdstevel@tonic-gate	for (idx = 0; idx < V_NUMPAR; ++idx)
2487c478bdstevel@tonic-gate		list[idx] = NULL;
2497c478bdstevel@tonic-gate
2507c478bdstevel@tonic-gate	/* read mnttab for partition mountpoints */
2517c478bdstevel@tonic-gate	if ((file = fopen(mnttab, "r")) == NULL) {
2527c478bdstevel@tonic-gate		(void) warn(mnttab, strerror(errno));
2537c478bdstevel@tonic-gate	} else {
2547c478bdstevel@tonic-gate		while (getmntent(file, &mtab) == 0) {
2557c478bdstevel@tonic-gate			item = mtab.mnt_special;
2567c478bdstevel@tonic-gate			if ((item == NULL) || (mtab.mnt_mountp == NULL))
2577c478bdstevel@tonic-gate				continue;
2587c478bdstevel@tonic-gate
2597c478bdstevel@tonic-gate			/*
2607c478bdstevel@tonic-gate			 * Is it from /dev?
2617c478bdstevel@tonic-gate			 */
2627c478bdstevel@tonic-gate			if (strncmp(item, "/dev/", strlen("/dev/") != 0))
2637c478bdstevel@tonic-gate				continue;
2647c478bdstevel@tonic-gate
2657c478bdstevel@tonic-gate			/*
2667c478bdstevel@tonic-gate			 * Is it a character device?
2677c478bdstevel@tonic-gate			 */
2687c478bdstevel@tonic-gate			(void) snprintf(devbuf, sizeof (devbuf), "/dev/r%s",
2697c478bdstevel@tonic-gate			    item + strlen("/dev/"));
2707c478bdstevel@tonic-gate
2717c478bdstevel@tonic-gate			if ((stat(devbuf, &sb) != 0) ||
2727c478bdstevel@tonic-gate			    ((sb.st_mode & S_IFMT) != S_IFCHR))
2737c478bdstevel@tonic-gate				continue;
2747c478bdstevel@tonic-gate
2757c478bdstevel@tonic-gate			/*
2767c478bdstevel@tonic-gate			 * device must match input slot and nopartminor
2777c478bdstevel@tonic-gate			 */
2787c478bdstevel@tonic-gate			if ((major(sb.st_rdev) != slot) ||
2797c478bdstevel@tonic-gate			    (noparttn(minor(sb.st_rdev)) != nopartminor))
2807c478bdstevel@tonic-gate				continue;
2817c478bdstevel@tonic-gate
2827c478bdstevel@tonic-gate			list[parttn(minor(sb.st_rdev))] =
2837c478bdstevel@tonic-gate			    safe_strdup(mtab.mnt_mountp);
2847c478bdstevel@tonic-gate		}
2857c478bdstevel@tonic-gate		(void) fclose(file);
2867c478bdstevel@tonic-gate	}
2877c478bdstevel@tonic-gate
2887c478bdstevel@tonic-gate	if ((file = fopen(fstab, "r")) == NULL) {
2897c478bdstevel@tonic-gate		(void) warn(fstab, strerror(errno));
2907c478bdstevel@tonic-gate		return (list);
2917c478bdstevel@tonic-gate	}
2927c478bdstevel@tonic-gate
2937c478bdstevel@tonic-gate	/*
2947c478bdstevel@tonic-gate	 * Look for the disk in the vfstab so that we can report its mount
2957c478bdstevel@tonic-gate	 * point even if it isn't currently mounted.
2967c478bdstevel@tonic-gate	 */
2977c478bdstevel@tonic-gate	while (getvfsent(file, &vtab) == 0) {
2987c478bdstevel@tonic-gate		item = vtab.vfs_special;
2997c478bdstevel@tonic-gate		if ((item == NULL) || (vtab.vfs_mountp == NULL))
3007c478bdstevel@tonic-gate			continue;
3017c478bdstevel@tonic-gate
3027c478bdstevel@tonic-gate		if (strncmp(item, "/dev/", strlen("/dev/")) != 0)
3037c478bdstevel@tonic-gate			continue;
3047c478bdstevel@tonic-gate
3057c478bdstevel@tonic-gate		/*
3067c478bdstevel@tonic-gate		 * Is it a character device?
3077c478bdstevel@tonic-gate		 */
3087c478bdstevel@tonic-gate		(void) snprintf(devbuf, sizeof (devbuf), "/dev/r%s",
3097c478bdstevel@tonic-gate		    item + strlen("/dev/"));
3107c478bdstevel@tonic-gate
3117c478bdstevel@tonic-gate		if ((stat(devbuf, &sb) != 0) ||
3127c478bdstevel@tonic-gate		    ((sb.st_mode & S_IFMT) != S_IFCHR))
3137c478bdstevel@tonic-gate			continue;
3147c478bdstevel@tonic-gate
3157c478bdstevel@tonic-gate		/*
3167c478bdstevel@tonic-gate		 * device must match input slot and nopartminor
3177c478bdstevel@tonic-gate		 */
3187c478bdstevel@tonic-gate		if ((major(sb.st_rdev) != slot) ||
3197c478bdstevel@tonic-gate		    (noparttn(minor(sb.st_rdev)) != nopartminor))
3207c478bdstevel@tonic-gate			continue;
3217c478bdstevel@tonic-gate
3227c478bdstevel@tonic-gate		/*
3237c478bdstevel@tonic-gate		 * use mnttab entry if both tables have entries
3247c478bdstevel@tonic-gate		 */
3257c478bdstevel@tonic-gate		if (list[parttn(minor(sb.st_rdev))] != NULL)
3267c478bdstevel@tonic-gate			continue;
3277c478bdstevel@tonic-gate
3287c478bdstevel@tonic-gate		list[parttn(minor(sb.st_rdev))] = safe_strdup(vtab.vfs_mountp);
3297c478bdstevel@tonic-gate	}
3307c478bdstevel@tonic-gate	(void) fclose(file);
3317c478bdstevel@tonic-gate
3327c478bdstevel@tonic-gate	return (list);
3337c478bdstevel@tonic-gate}
3347c478bdstevel@tonic-gate
3357c478bdstevel@tonic-gate/*
3367c478bdstevel@tonic-gate * partcmp(): Qsort() key comparison of partitions by starting sector numbers.
3377c478bdstevel@tonic-gate */
3387c478bdstevel@tonic-gatestatic int
3397c478bdstevel@tonic-gatepartcmp(const void *one, const void *two)
3407c478bdstevel@tonic-gate{
3417c478bdstevel@tonic-gate	return ((*(struct partition **)one)->p_start -
3427c478bdstevel@tonic-gate		(*(struct partition **)two)->p_start);
3437c478bdstevel@tonic-gate}
3447c478bdstevel@tonic-gate
3457c478bdstevel@tonic-gatestatic int
3467c478bdstevel@tonic-gatepartcmp64(const void *one, const void *two)
3477c478bdstevel@tonic-gate{
3487c478bdstevel@tonic-gate	if ((*(struct dk_part **)one)->p_start >
3497c478bdstevel@tonic-gate		(*(struct dk_part **)two)->p_start)
3507c478bdstevel@tonic-gate	    return (1);
3517c478bdstevel@tonic-gate	else if ((*(struct dk_part **)one)->p_start <
3527c478bdstevel@tonic-gate		(*(struct dk_part **)two)->p_start)
3537c478bdstevel@tonic-gate	    return (-1);
3547c478bdstevel@tonic-gate	else
3557c478bdstevel@tonic-gate	    return (0);
3567c478bdstevel@tonic-gate
3577c478bdstevel@tonic-gate}
3587c478bdstevel@tonic-gate
3597c478bdstevel@tonic-gate/*
3607c478bdstevel@tonic-gate * prtvtoc(): Read and print a VTOC.
3617c478bdstevel@tonic-gate */
3627c478bdstevel@tonic-gatestatic int
3637c478bdstevel@tonic-gateprtvtoc(char *devname)
3647c478bdstevel@tonic-gate{
3657c478bdstevel@tonic-gate	int		fd;
3667c478bdstevel@tonic-gate	int		idx;
3677c478bdstevel@tonic-gate	freemap_t	*freemap;
3687c478bdstevel@tonic-gate	struct stat	sb;
369342440ePrasad Singamsetty	struct extvtoc	vtoc;
3707c478bdstevel@tonic-gate	int		geo;
3717c478bdstevel@tonic-gate	struct dk_geom	geom;
3727c478bdstevel@tonic-gate	char		*name;
3737c478bdstevel@tonic-gate	int		newvtoc = 0;
3747c478bdstevel@tonic-gate	struct dk_gpt	*efi;
3757c478bdstevel@tonic-gate
3767c478bdstevel@tonic-gate	name = getfullrawname(devname);
3777c478bdstevel@tonic-gate	if (name == NULL)
3787c478bdstevel@tonic-gate		return (warn(devname,
3797c478bdstevel@tonic-gate		    "internal administrative call (getfullrawname) failed"));
3807c478bdstevel@tonic-gate	if (strcmp(name, "") == 0)
3817c478bdstevel@tonic-gate		name = devname;
3827c478bdstevel@tonic-gate	if ((fd = open(name, O_NONBLOCK|O_RDONLY)) < 0)
3837c478bdstevel@tonic-gate		return (warn(name, strerror(errno)));
3847c478bdstevel@tonic-gate	if (fstat(fd, &sb) < 0)
3857c478bdstevel@tonic-gate		return (warn(name, strerror(errno)));
3867c478bdstevel@tonic-gate	if ((sb.st_mode & S_IFMT) != S_IFCHR)
3877c478bdstevel@tonic-gate		return (warn(name, "Not a raw device"));
3887c478bdstevel@tonic-gate
3897c478bdstevel@tonic-gate	geo = (readgeom(fd, name, &geom) == 0);
3907c478bdstevel@tonic-gate	if (geo) {
3917c478bdstevel@tonic-gate		if ((idx = readvtoc(fd, name, &vtoc)) == VT_ENOTSUP) {
3927c478bdstevel@tonic-gate			idx = (readefi(fd, name, &efi) == 0);
3937c478bdstevel@tonic-gate			newvtoc = 1;
3947c478bdstevel@tonic-gate		} else
3957c478bdstevel@tonic-gate			idx = (idx == 0);
3967c478bdstevel@tonic-gate	}
3977c478bdstevel@tonic-gate	(void) close(fd);
3987c478bdstevel@tonic-gate	if ((!geo) || (!idx))
3997c478bdstevel@tonic-gate		return (-1);
4007c478bdstevel@tonic-gate	if (!newvtoc)
4017c478bdstevel@tonic-gate		freemap = findfree(&geom, &vtoc);
4027c478bdstevel@tonic-gate	else
4037c478bdstevel@tonic-gate		freemap = findfree64(efi);
4047c478bdstevel@tonic-gate	if (fflag) {
4057c478bdstevel@tonic-gate		if (!newvtoc)
4067c478bdstevel@tonic-gate			putfree(&vtoc, freemap);
4077c478bdstevel@tonic-gate		else
4087c478bdstevel@tonic-gate			putfree64(efi, freemap);
4097c478bdstevel@tonic-gate	} else {
4107c478bdstevel@tonic-gate		if (!newvtoc)
4117c478bdstevel@tonic-gate			puttable(&geom, &vtoc, freemap, devname,
4127c478bdstevel@tonic-gate			    getmntpt(major(sb.st_rdev),
4137c478bdstevel@tonic-gate			    noparttn(minor(sb.st_rdev))));
4147c478bdstevel@tonic-gate		else
4157c478bdstevel@tonic-gate			puttable64(efi, freemap, devname,
4167c478bdstevel@tonic-gate			    getmntpt(major(sb.st_rdev),
4177c478bdstevel@tonic-gate			    noparttn(minor(sb.st_rdev))));
4187c478bdstevel@tonic-gate	}
4197c478bdstevel@tonic-gate	if (newvtoc)
4207c478bdstevel@tonic-gate		efi_free(efi);
4217c478bdstevel@tonic-gate	return (0);
4227c478bdstevel@tonic-gate}
4237c478bdstevel@tonic-gate
4247c478bdstevel@tonic-gate/*
4257c478bdstevel@tonic-gate * putfree():
4267c478bdstevel@tonic-gate *
4277c478bdstevel@tonic-gate * Print shell assignments for disk free space. FREE_START and FREE_SIZE
4287c478bdstevel@tonic-gate * represent the starting block and number of blocks of the first chunk
4297c478bdstevel@tonic-gate * of free space. FREE_PART lists the unassigned partitions.
4307c478bdstevel@tonic-gate */
4317c478bdstevel@tonic-gatestatic void
432342440ePrasad Singamsettyputfree(struct extvtoc *vtoc, freemap_t *freemap)
4337c478bdstevel@tonic-gate{
4347c478bdstevel@tonic-gate	freemap_t *freeidx;
4357c478bdstevel@tonic-gate	ushort_t idx;
4367c478bdstevel@tonic-gate	int free_count = 0;
4377c478bdstevel@tonic-gate
4387c478bdstevel@tonic-gate	for (freeidx = freemap; freeidx->fr_size; ++freeidx)
4397c478bdstevel@tonic-gate		free_count++;
4407c478bdstevel@tonic-gate
4417c478bdstevel@tonic-gate	(void) printf("FREE_START=%llu FREE_SIZE=%llu FREE_COUNT=%d FREE_PART=",
4427c478bdstevel@tonic-gate	    freemap->fr_start, freemap->fr_size, free_count);
4437c478bdstevel@tonic-gate
4447c478bdstevel@tonic-gate	for (idx = 0; idx < vtoc->v_nparts; ++idx) {
4457c478bdstevel@tonic-gate		if (vtoc->v_part[idx].p_size == 0 && idx != 2)
4467c478bdstevel@tonic-gate			(void) printf("%x", idx);
4477c478bdstevel@tonic-gate	}
4487c478bdstevel@tonic-gate	(void) printf("\n");
4497c478bdstevel@tonic-gate}
4507c478bdstevel@tonic-gate
4517c478bdstevel@tonic-gatestatic void
4527c478bdstevel@tonic-gateputfree64(struct dk_gpt *efi, freemap_t *freemap)
4537c478bdstevel@tonic-gate{
4547c478bdstevel@tonic-gate	freemap_t *freeidx;
4557c478bdstevel@tonic-gate	ushort_t idx;
4567c478bdstevel@tonic-gate	int free_count = 0;
4577c478bdstevel@tonic-gate
4587c478bdstevel@tonic-gate	for (freeidx = freemap; freeidx->fr_size; ++freeidx)
4597c478bdstevel@tonic-gate		free_count++;
4607c478bdstevel@tonic-gate
4617c478bdstevel@tonic-gate	(void) printf("FREE_START=%llu FREE_SIZE=%llu FREE_COUNT=%d FREE_PART=",
4627c478bdstevel@tonic-gate	    freemap->fr_start, freemap->fr_size, free_count);
4637c478bdstevel@tonic-gate
4647c478bdstevel@tonic-gate	for (idx = 0; idx < efi->efi_nparts; ++idx) {
4657c478bdstevel@tonic-gate		if (efi->efi_parts[idx].p_size == 0 && idx != 2)
4667c478bdstevel@tonic-gate			(void) printf("%x", idx);
4677c478bdstevel@tonic-gate	}
4687c478bdstevel@tonic-gate	(void) printf("\n");
4697c478bdstevel@tonic-gate}
4707c478bdstevel@tonic-gate
4717c478bdstevel@tonic-gate/*
4727c478bdstevel@tonic-gate * puttable(): Print a human-readable VTOC.
4737c478bdstevel@tonic-gate */
4747c478bdstevel@tonic-gatestatic void
475342440ePrasad Singamsettyputtable(struct dk_geom *geom, struct extvtoc *vtoc, freemap_t *freemap,
4767c478bdstevel@tonic-gate    char *name, char **mtab)
4777c478bdstevel@tonic-gate{
4787c478bdstevel@tonic-gate	ushort_t	idx;
4797c478bdstevel@tonic-gate	ulong_t	cylsize;
4807c478bdstevel@tonic-gate
4817c478bdstevel@tonic-gate	cylsize = (geom->dkg_nsect) * (geom->dkg_nhead);
4827c478bdstevel@tonic-gate	if (!hflag && !sflag) {
4837c478bdstevel@tonic-gate		(void) printf("* %s", name);
4847c478bdstevel@tonic-gate		if (*vtoc->v_volume)
4857c478bdstevel@tonic-gate			(void) printf(" (volume \"%.8s\")", vtoc->v_volume);
4867c478bdstevel@tonic-gate
4877c478bdstevel@tonic-gate		(void) printf(" partition map\n");
4887c478bdstevel@tonic-gate		(void) printf("*\n* Dimensions:\n");
4897c478bdstevel@tonic-gate		(void) printf("* %7u bytes/sector\n", vtoc->v_sectorsz);
4907c478bdstevel@tonic-gate		(void) printf("* %7u sectors/track\n", geom->dkg_nsect);
4917c478bdstevel@tonic-gate		(void) printf("* %7u tracks/cylinder\n", geom->dkg_nhead);
4927c478bdstevel@tonic-gate		(void) printf("* %7lu sectors/cylinder\n", cylsize);
4937c478bdstevel@tonic-gate		(void) printf("* %7u cylinders\n", geom->dkg_pcyl);
4947c478bdstevel@tonic-gate		(void) printf("* %7u accessible cylinders\n", geom->dkg_ncyl);
4957c478bdstevel@tonic-gate		(void) printf("*\n* Flags:\n");
4967c478bdstevel@tonic-gate		(void) printf("*   1: unmountable\n");
4977c478bdstevel@tonic-gate		(void) printf("*  10: read-only\n*\n");
4987c478bdstevel@tonic-gate
4997c478bdstevel@tonic-gate		if (freemap->fr_size) {
5007c478bdstevel@tonic-gate			(void) printf("* Unallocated space:\n");
5017c478bdstevel@tonic-gate			(void) printf("*\tFirst     Sector    Last\n");
5027c478bdstevel@tonic-gate			(void) printf("*\tSector     Count    Sector \n");
5037c478bdstevel@tonic-gate			do {
5047c478bdstevel@tonic-gate				(void) printf("*   %9llu %9llu %9llu\n",
5057c478bdstevel@tonic-gate				    freemap->fr_start, freemap->fr_size,
5067c478bdstevel@tonic-gate				    freemap->fr_size + freemap->fr_start - 1);
5077c478bdstevel@tonic-gate			} while ((++freemap)->fr_size);
5087c478bdstevel@tonic-gate			(void) printf("*\n");
5097c478bdstevel@tonic-gate		}
5107c478bdstevel@tonic-gate	}
5117c478bdstevel@tonic-gate	if (!hflag)  {
5127c478bdstevel@tonic-gate		(void) printf(\
5137c478bdstevel@tonic-gate"*                          First     Sector    Last\n"
5147c478bdstevel@tonic-gate"* Partition  Tag  Flags    Sector     Count    Sector  Mount Directory\n");
5157c478bdstevel@tonic-gate	}
5167c478bdstevel@tonic-gate	for (idx = 0; idx < vtoc->v_nparts; ++idx) {
5177c478bdstevel@tonic-gate		if (vtoc->v_part[idx].p_size == 0)
5187c478bdstevel@tonic-gate			continue;
519342440ePrasad Singamsetty		(void) printf("      %2u  %5u    %02x  %9llu %9llu %9llu",
5207c478bdstevel@tonic-gate		    idx, vtoc->v_part[idx].p_tag, vtoc->v_part[idx].p_flag,
5217c478bdstevel@tonic-gate		    vtoc->v_part[idx].p_start, vtoc->v_part[idx].p_size,
5227c478bdstevel@tonic-gate		    vtoc->v_part[idx].p_start + vtoc->v_part[idx].p_size - 1);
5237c478bdstevel@tonic-gate		if (mtab && mtab[idx])
5247c478bdstevel@tonic-gate			(void) printf("   %s", mtab[idx]);
5257c478bdstevel@tonic-gate		(void) printf("\n");
5267c478bdstevel@tonic-gate	}
5277c478bdstevel@tonic-gate}
5287c478bdstevel@tonic-gate
5297c478bdstevel@tonic-gate/*
5307c478bdstevel@tonic-gate * puttable(): Print a human-readable VTOC.
5317c478bdstevel@tonic-gate */
5327c478bdstevel@tonic-gatestatic void
5337c478bdstevel@tonic-gateputtable64(struct dk_gpt *efi, freemap_t *freemap, char *name,
5347c478bdstevel@tonic-gate	char **mtab)
5357c478bdstevel@tonic-gate{
5367c478bdstevel@tonic-gate	ushort_t	idx;
5377c478bdstevel@tonic-gate
5387c478bdstevel@tonic-gate	if (!hflag && !sflag) {
5397c478bdstevel@tonic-gate		(void) printf("* %s", name);
5407c478bdstevel@tonic-gate		for (idx = 0; idx < efi->efi_nparts; idx++)
5417c478bdstevel@tonic-gate		    if (efi->efi_parts[idx].p_tag == V_RESERVED &&
5427c478bdstevel@tonic-gate			*efi->efi_parts[idx].p_name)
5437c478bdstevel@tonic-gate			    (void) printf(" (volume \"%.8s\")",
5447c478bdstevel@tonic-gate				    efi->efi_parts[idx].p_name);
5457c478bdstevel@tonic-gate		(void) printf(" partition map\n");
5467c478bdstevel@tonic-gate		(void) printf("*\n* Dimensions:\n");
5477c478bdstevel@tonic-gate		(void) printf("* %7u bytes/sector\n", efi->efi_lbasize);
5487c478bdstevel@tonic-gate		(void) printf("* %llu sectors\n", efi->efi_last_lba + 1);
5497c478bdstevel@tonic-gate		(void) printf("* %llu accessible sectors\n",
5507c478bdstevel@tonic-gate		    efi->efi_last_u_lba - efi->efi_first_u_lba + 1);
5517c478bdstevel@tonic-gate		(void) printf("*\n* Flags:\n");
5527c478bdstevel@tonic-gate		(void) printf("*   1: unmountable\n");
5537c478bdstevel@tonic-gate		(void) printf("*  10: read-only\n*\n");
5547c478bdstevel@tonic-gate
5557c478bdstevel@tonic-gate		if (freemap->fr_size) {
5567c478bdstevel@tonic-gate			(void) printf("* Unallocated space:\n");
5577c478bdstevel@tonic-gate			(void) printf("*\tFirst     Sector    Last\n");
5587c478bdstevel@tonic-gate			(void) printf("*\tSector     Count    Sector \n");
5597c478bdstevel@tonic-gate			do {
5607c478bdstevel@tonic-gate				(void) printf("*   %9llu %9llu %9llu\n",
5617c478bdstevel@tonic-gate				    freemap->fr_start, freemap->fr_size,
5627c478bdstevel@tonic-gate				    freemap->fr_size + freemap->fr_start - 1);
5637c478bdstevel@tonic-gate			} while ((++freemap)->fr_size);
5647c478bdstevel@tonic-gate			(void) printf("*\n");
5657c478bdstevel@tonic-gate		}
5667c478bdstevel@tonic-gate	}
5677c478bdstevel@tonic-gate	if (!hflag)  {
5687c478bdstevel@tonic-gate		(void) printf(\
5697c478bdstevel@tonic-gate"*                          First     Sector    Last\n"
5707c478bdstevel@tonic-gate"* Partition  Tag  Flags    Sector     Count    Sector  Mount Directory\n");
5717c478bdstevel@tonic-gate	}
5727c478bdstevel@tonic-gate	for (idx = 0; idx < efi->efi_nparts; ++idx) {
5737c478bdstevel@tonic-gate	    if (efi->efi_parts[idx].p_size == 0)
5747c478bdstevel@tonic-gate		    continue;
5757c478bdstevel@tonic-gate	    (void) printf("      %2u  %5u    %02x  %9llu %9llu %9llu",
5767c478bdstevel@tonic-gate		idx, efi->efi_parts[idx].p_tag, efi->efi_parts[idx].p_flag,
5777c478bdstevel@tonic-gate		efi->efi_parts[idx].p_start, efi->efi_parts[idx].p_size,
5787c478bdstevel@tonic-gate		efi->efi_parts[idx].p_start + efi->efi_parts[idx].p_size - 1);
5797c478bdstevel@tonic-gate	    if ((idx < 7) && mtab && mtab[idx])
5807c478bdstevel@tonic-gate		    (void) printf("   %s", mtab[idx]);
5817c478bdstevel@tonic-gate	    (void) printf("\n");
5827c478bdstevel@tonic-gate	}
5837c478bdstevel@tonic-gate}
5847c478bdstevel@tonic-gate
5857c478bdstevel@tonic-gate/*
5867c478bdstevel@tonic-gate * readgeom(): Read the disk geometry.
5877c478bdstevel@tonic-gate */
5887c478bdstevel@tonic-gatestatic int
5897c478bdstevel@tonic-gatereadgeom(int fd, char *name, struct dk_geom *geom)
5907c478bdstevel@tonic-gate{
5917c478bdstevel@tonic-gate	char err_string[128];
5927c478bdstevel@tonic-gate
5937c478bdstevel@tonic-gate	if ((ioctl(fd, DKIOCGGEOM, geom) < 0) && (errno != ENOTSUP)) {
5947c478bdstevel@tonic-gate		(void) sprintf(err_string,
5957c478bdstevel@tonic-gate		    "Unable to read Disk geometry errno = 0x%x",
5967c478bdstevel@tonic-gate		    errno);
5977c478bdstevel@tonic-gate		return (warn(name, err_string));
5987c478bdstevel@tonic-gate	} else if (errno == ENOTSUP) {
5997c478bdstevel@tonic-gate		(void) memset(geom, 0, sizeof (struct dk_geom));
6007c478bdstevel@tonic-gate	}
6017c478bdstevel@tonic-gate	return (0);
6027c478bdstevel@tonic-gate}
6037c478bdstevel@tonic-gate
6047c478bdstevel@tonic-gate/*
6057c478bdstevel@tonic-gate * readvtoc(): Read a partition map.
6067c478bdstevel@tonic-gate */
6077c478bdstevel@tonic-gatestatic int
608342440ePrasad Singamsettyreadvtoc(int fd, char *name, struct extvtoc *vtoc)
6097c478bdstevel@tonic-gate{
6107c478bdstevel@tonic-gate	int	retval;
6117c478bdstevel@tonic-gate
612342440ePrasad Singamsetty	if ((retval = read_extvtoc(fd, vtoc)) >= 0)
6137c478bdstevel@tonic-gate		return (0);
6147c478bdstevel@tonic-gate
6157c478bdstevel@tonic-gate	switch (retval) {
6167c478bdstevel@tonic-gate	case (VT_EIO):
6177c478bdstevel@tonic-gate		return (warn(name, "Unable to read VTOC"));
6187c478bdstevel@tonic-gate	case (VT_EINVAL):
6197c478bdstevel@tonic-gate		return (warn(name, "Invalid VTOC"));
6207c478bdstevel@tonic-gate	case (VT_ERROR):
6217c478bdstevel@tonic-gate		return (warn(name, "Unknown problem reading VTOC"));
6227c478bdstevel@tonic-gate	}
6237c478bdstevel@tonic-gate	return (retval);
6247c478bdstevel@tonic-gate}
6257c478bdstevel@tonic-gate
6267c478bdstevel@tonic-gate/*
6277c478bdstevel@tonic-gate * readefi(): Read a partition map.
6287c478bdstevel@tonic-gate */
6297c478bdstevel@tonic-gatestatic int
6307c478bdstevel@tonic-gatereadefi(int fd, char *name, struct dk_gpt **efi)
6317c478bdstevel@tonic-gate{
6327c478bdstevel@tonic-gate	int	retval;
6337c478bdstevel@tonic-gate
6347c478bdstevel@tonic-gate	if ((retval = efi_alloc_and_read(fd, efi)) >= 0)
6357c478bdstevel@tonic-gate		return (0);
6367c478bdstevel@tonic-gate
6377c478bdstevel@tonic-gate	switch (retval) {
6387c478bdstevel@tonic-gate	case (VT_EIO):
6397c478bdstevel@tonic-gate		return (warn(name, "Unable to read VTOC"));
6407c478bdstevel@tonic-gate	case (VT_EINVAL):
6417c478bdstevel@tonic-gate		return (warn(name, "Invalid VTOC"));
6427c478bdstevel@tonic-gate	case (VT_ERROR):
6437c478bdstevel@tonic-gate		return (warn(name, "Unknown problem reading VTOC"));
6447c478bdstevel@tonic-gate	}
6457c478bdstevel@tonic-gate	return (retval);
6467c478bdstevel@tonic-gate}
6477c478bdstevel@tonic-gate
6487c478bdstevel@tonic-gatestatic char *
6497c478bdstevel@tonic-gatesafe_strdup(char *str)
6507c478bdstevel@tonic-gate{
6517c478bdstevel@tonic-gate	char *ret;
6527c478bdstevel@tonic-gate	if ((ret = strdup(str)) == NULL) {
6537c478bdstevel@tonic-gate		(void) warn("memory allocation", strerror(errno));
6547c478bdstevel@tonic-gate		exit(1);
6557c478bdstevel@tonic-gate	}
6567c478bdstevel@tonic-gate	return (ret);
6577c478bdstevel@tonic-gate}
6587c478bdstevel@tonic-gate
6597c478bdstevel@tonic-gate/*
6607c478bdstevel@tonic-gate * usage(): Print a helpful message and exit.
6617c478bdstevel@tonic-gate */
6627c478bdstevel@tonic-gatestatic void
6637c478bdstevel@tonic-gateusage()
6647c478bdstevel@tonic-gate{
6657c478bdstevel@tonic-gate	(void) fprintf(stderr, "Usage:\t%s [ -fhs ] [ -t fstab ] [ -m mnttab ] "
6667c478bdstevel@tonic-gate	    "rawdisk ...\n", progname);
6677c478bdstevel@tonic-gate	exit(1);
6687c478bdstevel@tonic-gate}
6697c478bdstevel@tonic-gate
6707c478bdstevel@tonic-gate/*
6717c478bdstevel@tonic-gate * warn(): Print an error message. Always returns -1.
6727c478bdstevel@tonic-gate */
6737c478bdstevel@tonic-gatestatic int
6747c478bdstevel@tonic-gatewarn(char *what, char *why)
6757c478bdstevel@tonic-gate{
6767c478bdstevel@tonic-gate	(void) fprintf(stderr, "%s: %s: %s\n", progname, what, why);
6777c478bdstevel@tonic-gate	return (-1);
6787c478bdstevel@tonic-gate}
679