2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A/*LINTLIBRARY*/
2N/A
2N/A
2N/A#include <stdio.h>
2N/A#include <errno.h>
2N/A#include <memory.h>
2N/A#include <unistd.h>
2N/A#include <sys/types.h>
2N/A#include <sys/param.h>
2N/A#include <sys/dkio.h>
2N/A#include <sys/vtoc.h>
2N/A#include <strings.h>
2N/A#include <limits.h>
2N/A
2N/A/*
2N/A * To copy each field of vtoc individually for copying extvtoc
2N/A * to 32 bit vtoc and vs.
2N/A * Currently bootinfo and timestamp are not really supported.
2N/A */
2N/A
2N/A#define libadm_vtoc_copy(vs, vd) \
2N/A { \
2N/A int i; \
2N/A vd->v_bootinfo[0] = (unsigned)vs->v_bootinfo[0]; \
2N/A vd->v_bootinfo[1] = (unsigned)vs->v_bootinfo[1]; \
2N/A vd->v_bootinfo[2] = (unsigned)vs->v_bootinfo[2]; \
2N/A vd->v_sanity = (unsigned)vs->v_sanity; \
2N/A vd->v_version = (unsigned)vs->v_version; \
2N/A bcopy(vs->v_volume, vd->v_volume, LEN_DKL_VVOL); \
2N/A vd->v_sectorsz = vs->v_sectorsz; \
2N/A vd->v_nparts = vs->v_nparts; \
2N/A vd->v_version = (unsigned)vs->v_version; \
2N/A for (i = 0; i < 10; i++) \
2N/A vd->v_reserved[i] = (unsigned)vs->v_reserved[i];\
2N/A for (i = 0; i < V_NUMPAR; i++) { \
2N/A vd->v_part[i].p_tag = vs->v_part[i].p_tag; \
2N/A vd->v_part[i].p_flag = vs->v_part[i].p_flag; \
2N/A vd->v_part[i].p_start = (unsigned)vs->v_part[i].p_start;\
2N/A vd->v_part[i].p_size = (unsigned)vs->v_part[i].p_size; \
2N/A } \
2N/A for (i = 0; i < V_NUMPAR; i++) \
2N/A if ((sizeof (vd->timestamp[i]) != sizeof (vs->timestamp[i])) &&\
2N/A (vs->timestamp[i] > INT32_MAX)) \
2N/A vd->timestamp[i] = INT32_MAX; \
2N/A else \
2N/A vd->timestamp[i] = (unsigned)vs->timestamp[i]; \
2N/A bcopy(vs->v_asciilabel, vd->v_asciilabel, LEN_DKL_ASCII); \
2N/A }
2N/A
2N/A
2N/A/*
2N/A * Read VTOC - return partition number.
2N/A */
2N/Aint
2N/Aread_vtoc(int fd, struct vtoc *vtoc)
2N/A{
2N/A struct dk_cinfo dki_info;
2N/A
2N/A /*
2N/A * Read the vtoc.
2N/A */
2N/A if (ioctl(fd, DKIOCGVTOC, (caddr_t)vtoc) == -1) {
2N/A switch (errno) {
2N/A case EIO:
2N/A return (VT_EIO);
2N/A case EINVAL:
2N/A return (VT_EINVAL);
2N/A case ENOTSUP:
2N/A /* GPT labeled or disk > 1TB with no extvtoc support */
2N/A return (VT_ENOTSUP);
2N/A case EOVERFLOW:
2N/A return (VT_EOVERFLOW);
2N/A default:
2N/A return (VT_ERROR);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Sanity-check the vtoc.
2N/A */
2N/A if (vtoc->v_sanity != VTOC_SANE) {
2N/A return (VT_EINVAL);
2N/A }
2N/A
2N/A /*
2N/A * Convert older-style vtoc's.
2N/A */
2N/A switch (vtoc->v_version) {
2N/A case 0:
2N/A /*
2N/A * No vtoc information. Install default
2N/A * nparts/sectorsz and version. We are
2N/A * assuming that the driver returns the
2N/A * current partition information correctly.
2N/A */
2N/A
2N/A vtoc->v_version = V_VERSION;
2N/A if (vtoc->v_nparts == 0)
2N/A vtoc->v_nparts = V_NUMPAR;
2N/A if (vtoc->v_sectorsz == 0)
2N/A vtoc->v_sectorsz = DEV_BSIZE;
2N/A
2N/A break;
2N/A
2N/A case V_VERSION:
2N/A break;
2N/A
2N/A default:
2N/A return (VT_EINVAL);
2N/A }
2N/A
2N/A /*
2N/A * Return partition number for this file descriptor.
2N/A */
2N/A if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
2N/A switch (errno) {
2N/A case EIO:
2N/A return (VT_EIO);
2N/A case EINVAL:
2N/A return (VT_EINVAL);
2N/A default:
2N/A return (VT_ERROR);
2N/A }
2N/A }
2N/A if (dki_info.dki_partition > V_NUMPAR) {
2N/A return (VT_EINVAL);
2N/A }
2N/A return ((int)dki_info.dki_partition);
2N/A}
2N/A
2N/A/*
2N/A * Write VTOC
2N/A */
2N/Aint
2N/Awrite_vtoc(int fd, struct vtoc *vtoc)
2N/A{
2N/A int i;
2N/A /*
2N/A * Sanity-check the vtoc
2N/A */
2N/A if (vtoc->v_sanity != VTOC_SANE || vtoc->v_nparts > V_NUMPAR) {
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * since many drivers won't allow opening a device make sure
2N/A * all partitions aren't being set to zero. If all are zero then
2N/A * we have no way to set them to something else
2N/A */
2N/A
2N/A for (i = 0; i < (int)vtoc->v_nparts; i++)
2N/A if (vtoc->v_part[i].p_size > 0)
2N/A break;
2N/A if (i == (int)vtoc->v_nparts)
2N/A return (-1);
2N/A
2N/A /*
2N/A * Write the vtoc
2N/A */
2N/A if (ioctl(fd, DKIOCSVTOC, (caddr_t)vtoc) == -1) {
2N/A switch (errno) {
2N/A case EIO:
2N/A return (VT_EIO);
2N/A case EINVAL:
2N/A return (VT_EINVAL);
2N/A case ENOTSUP:
2N/A /* GPT labeled or disk > 1TB with no extvtoc support */
2N/A return (VT_ENOTSUP);
2N/A case EOVERFLOW:
2N/A return (VT_EOVERFLOW);
2N/A default:
2N/A return (VT_ERROR);
2N/A }
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Aread_extvtoc(int fd, struct extvtoc *extvtoc)
2N/A{
2N/A struct dk_cinfo dki_info;
2N/A struct vtoc oldvtoc;
2N/A struct vtoc *oldvtocp = &oldvtoc;
2N/A int ret;
2N/A
2N/A /*
2N/A * Read the vtoc.
2N/A */
2N/A if (ioctl(fd, DKIOCGEXTVTOC, (caddr_t)extvtoc) == -1) {
2N/A switch (errno) {
2N/A case EIO:
2N/A return (VT_EIO);
2N/A case EINVAL:
2N/A return (VT_EINVAL);
2N/A /* for disks > 1TB */
2N/A case ENOTSUP:
2N/A return (VT_ENOTSUP);
2N/A case EOVERFLOW:
2N/A return (VT_EOVERFLOW);
2N/A case ENOTTY:
2N/A
2N/A if ((ret = read_vtoc(fd, oldvtocp)) < 0)
2N/A return (ret);
2N/A
2N/A#ifdef _LP64
2N/A /*
2N/A * 64-bit vtoc and extvtoc have the same field sizes
2N/A * and offsets.
2N/A */
2N/A bcopy(oldvtocp, extvtoc, sizeof (struct extvtoc));
2N/A#else
2N/A bzero(extvtoc, sizeof (struct extvtoc));
2N/A libadm_vtoc_copy(oldvtocp, extvtoc);
2N/A#endif
2N/A return (ret);
2N/A
2N/A
2N/A default:
2N/A return (VT_ERROR);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Sanity-check the vtoc.
2N/A */
2N/A if (extvtoc->v_sanity != VTOC_SANE) {
2N/A return (VT_EINVAL);
2N/A }
2N/A
2N/A switch (extvtoc->v_version) {
2N/A case 0:
2N/A /*
2N/A * For pre-version 1 vtoc keep same functionality
2N/A * as read_vtoc.
2N/A */
2N/A
2N/A extvtoc->v_version = V_VERSION;
2N/A if (extvtoc->v_nparts == 0)
2N/A extvtoc->v_nparts = V_NUMPAR;
2N/A if (extvtoc->v_sectorsz == 0)
2N/A extvtoc->v_sectorsz = DEV_BSIZE;
2N/A
2N/A break;
2N/A
2N/A case V_VERSION:
2N/A break;
2N/A
2N/A default:
2N/A return (VT_EINVAL);
2N/A }
2N/A
2N/A /*
2N/A * Return partition number for this file descriptor.
2N/A */
2N/A if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
2N/A switch (errno) {
2N/A case EIO:
2N/A return (VT_EIO);
2N/A case EINVAL:
2N/A return (VT_EINVAL);
2N/A default:
2N/A return (VT_ERROR);
2N/A }
2N/A }
2N/A if (dki_info.dki_partition > V_NUMPAR) {
2N/A return (VT_EINVAL);
2N/A }
2N/A return ((int)dki_info.dki_partition);
2N/A}
2N/A
2N/A/*
2N/A * Write ext VTOC.
2N/A */
2N/Aint
2N/Awrite_extvtoc(int fd, struct extvtoc *extvtoc)
2N/A{
2N/A int i;
2N/A struct vtoc oldvtoc;
2N/A struct vtoc *oldvtocp = &oldvtoc;
2N/A /*
2N/A * Sanity-check the vtoc
2N/A */
2N/A if (extvtoc->v_sanity != VTOC_SANE || extvtoc->v_nparts > V_NUMPAR) {
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * since many drivers won't allow opening a device make sure
2N/A * all partitions aren't being set to zero. If all are zero then
2N/A * we have no way to set them to something else
2N/A */
2N/A
2N/A for (i = 0; i < (int)extvtoc->v_nparts; i++)
2N/A if (extvtoc->v_part[i].p_size > 0)
2N/A break;
2N/A if (i == (int)extvtoc->v_nparts)
2N/A return (-1);
2N/A
2N/A /*
2N/A * Write the extvtoc
2N/A */
2N/A if (ioctl(fd, DKIOCSEXTVTOC, (caddr_t)extvtoc) == -1) {
2N/A switch (errno) {
2N/A case EIO:
2N/A return (VT_EIO);
2N/A case EINVAL:
2N/A return (VT_EINVAL);
2N/A /* for disks > 1TB */
2N/A case ENOTSUP:
2N/A return (VT_ENOTSUP);
2N/A case EOVERFLOW:
2N/A return (VT_EOVERFLOW);
2N/A case ENOTTY:
2N/A#ifdef _LP64
2N/A /*
2N/A * 64-bit vtoc and extvtoc have the same field sizes
2N/A * and offsets.
2N/A */
2N/A bcopy(extvtoc, oldvtocp, sizeof (struct vtoc));
2N/A#else
2N/A bzero(oldvtocp, sizeof (struct vtoc));
2N/A libadm_vtoc_copy(extvtoc, oldvtocp);
2N/A
2N/A#endif
2N/A return (write_vtoc(fd, &oldvtoc));
2N/A
2N/A default:
2N/A return (VT_ERROR);
2N/A }
2N/A }
2N/A
2N/A return (0);
2N/A}