/*
* 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
* 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 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
* This file contains the code relating to label manipulation.
*/
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#include <sys/isa_defs.h>
#include <sys/efi_partition.h>
#include <errno.h>
#include <devid.h>
#include <libdevinfo.h>
#include "global.h"
#include "label.h"
#include "misc.h"
#include "main.h"
#include "partition.h"
#include "ctlr_scsi.h"
#include "checkdev.h"
#if defined(_FIRMWARE_NEEDS_FDISK)
#include "menu_fdisk.h"
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
#ifndef WD_NODE
#endif
#ifdef __STDC__
/*
* Prototypes for ANSI C compilers
*/
static int do_geometry_sanity_check(void);
extern int read_extvtoc(int, struct extvtoc *);
extern int write_extvtoc(int, struct extvtoc *);
#else /* __STDC__ */
/*
* Prototypes for non-ANSI C compilers
*/
static int do_geometry_sanity_check();
static int vtoc_to_label();
extern int read_extvtoc();
extern int write_extvtoc();
static int vtoc64_to_label();
#endif /* __STDC__ */
#ifdef DEBUG
#endif
/*
* This routine checks the given label to see if it is valid.
*/
int
{
/*
* Check the magic number.
*/
return (0);
/*
* Check the checksum.
*/
return (0);
return (1);
}
/*
* This routine checks or calculates the label checksum, depending on
* the mode it is called in.
*/
int
int mode;
{
/*
* If we are generating a checksum, don't include the checksum
* in the rolling xor.
*/
if (mode == CK_MAKESUM)
count -= 1;
/*
* Take the xor of all the half-words in the label.
*/
while (count--) {
}
/*
* If we are checking the checksum, the total will be zero for
* a correct checksum, so we can just return the sum.
*/
if (mode == CK_CHECKSUM)
return (sum);
/*
* If we are generating the checksum, fill it in.
*/
else {
return (0);
}
}
/*
* This routine is used to extract the id string from the string stored
* in a disk label. The problem is that the string in the label has
* the physical characteristics of the drive appended to it. The approach
* is to find the beginning of the physical attributes portion of the string
* and truncate it there.
*/
int
char *id;
{
register char *c;
/*
* Start at the end of the string. When we match the word ' cyl',
* we are at the beginning of the attributes.
*/
/*
* Remove any white space.
*/
for (; (((*(c - 1) == ' ') || (*(c - 1) == '\t')) &&
(c >= id)); c--);
break;
}
}
/*
* If we ran off the beginning of the string, something is wrong.
*/
if (c < id)
return (-1);
/*
* Truncate the string.
*/
*c = '\0';
return (0);
}
/*
* This routine is used by write_label() to do a quick sanity check on the
* supplied geometry. This is not a thorough check.
*
* The SCSI READ_CAPACITY command is used here to get the capacity of the
* disk. But, the available area to store data on a disk is usually less
* than this. So, if the specified geometry evaluates to a value which falls
* in this margin, then such illegal geometries can slip through the cracks.
*/
static int
{
err_print("Warning: Unable to get capacity."
" Cannot check geometry\n");
return (0); /* Just ignore this problem */
}
err_print("\nWarning: Current geometry overshoots "
"actual geometry of disk\n\n");
if (check("Continue labelling disk") != 0)
return (-1);
return (0); /* Just ignore this problem */
}
return (0);
}
/*
* create a clear EFI partition table when format is used
* to convert an SMI label to an EFI label
*/
int
{
int i;
err_print("SMI vtoc to EFI failed\n");
return (-1);
}
/*
* create a clear EFI partition table:
* s0 takes the whole disk except the primary EFI lable,
* backup EFI labels, and the reserved partition.
* s1-s6 are unassigned slices.
*/
- EFI_MIN_RESV_SIZE + 1;
/*
* s1-s6 are unassigned slices
*/
}
/*
* the reserved slice
*/
return (0);
}
/*
* This routine constructs and writes a label on the disk. It writes both
* the primary and backup labels. It assumes that there is a current
* partition map already defined. It also notifies the SunOS kernel of
* the label and partition information it has written on the disk.
*/
int
{
int nbackups;
char *new_label;
#if defined(_SUNOS_VTOC_8)
int i;
#endif /* defined(_SUNOS_VTOC_8) */
/*
* Check to see if any partitions used for svm, vxvm or live upgrade
* are on the disk. If so, refuse to label the disk, but only
* if we are trying to shrink a partition in use.
*/
err_print("Cannot label disk when "
"partitions are in use as described.\n");
return (-1);
}
/*
* If EFI label, then write it out to disk
*/
if (cur_label == L_TYPE_EFI) {
err_print("Warning: error writing EFI.\n");
error = -1;
}
return (error);
}
/*
* Fill in a label structure with the geometry information.
*/
#if defined(_SUNOS_VTOC_16)
#endif /* defined(_SUNOC_VTOC_16) */
#if defined(_SUNOS_VTOC_8)
/*
* Also fill in the current partition information.
*/
for (i = 0; i < NDKMAP; i++) {
}
#endif /* defined(_SUNOS_VTOC_8) */
/*
* Fill in the vtoc information
*/
/*
* Use the current label
*/
/*
* Put asciilabel in; on x86 it's in the vtoc, not the label.
*/
"%s cyl %d alt %d hd %d sec %d",
#if defined(_SUNOS_VTOC_16)
/*
* Also add in v_sectorsz, as the driver will.
*/
#endif /* defined(_SUNOS_VTOC_16) */
/*
* Generate the correct checksum.
*/
/*
* Convert the label into a vtoc
*/
return (-1);
}
/*
* Fill in the geometry info. This is critical that
* we do this before writing the vtoc.
*/
#if defined(_SUNOS_VTOC_16)
#endif /* defined(_SUNOS_VTOC_16) */
/*
* Make a quick check to see that the geometry is being
* written now is not way off from the actual capacity
* of the disk. This is only an appoximate check and
* is only for SCSI disks.
*/
if (SCSI && do_geometry_sanity_check() != 0) {
return (-1);
}
/*
* Lock out interrupts so we do things in sync.
*/
/*
* Do the ioctl to tell the kernel the geometry.
*/
err_print("Warning: error setting drive geometry.\n");
error = -1;
}
/*
* Write the vtoc. At the time of this writing, our
* drivers convert the vtoc back to a label, and
* then write both the primary and backup labels.
* This is not a requirement, however, as we
* always use an ioctl to read the vtoc from the
* driver, so it can do as it likes.
*/
err_print("Warning: error writing VTOC.\n");
error = -1;
}
/*
* Calculate where the backup labels went. They are always on
* the last alternate cylinder, but some older drives put them
* on head 2 instead of the last head. They are always on the
* first 5 odd sectors of the appropriate track.
*/
head = 2;
else
/*
* Read and verify the backup labels.
*/
nbackups = 0;
sec += 2) {
err_print("Warning: error reading"
"backup label.\n");
error = -1;
} else {
sizeof (struct dk_label)) == 0) {
nbackups++;
}
}
}
if (nbackups != BAD_LISTCNT) {
"no backup labels" : "some backup labels incorrect");
}
/*
* Mark the current disk as labelled and notify the kernel of what
* has happened.
*/
return (error);
}
/*
* Read the label from the disk.
* Do this via the read_extvtoc() library routine, then convert it to a label.
* We also need a DKIOCGGEOM ioctl to get the disk's geometry.
*/
int
{
return (-1);
}
}
int
{
char *v, *p, *r;
if (node == DI_NODE_NIL)
goto out;
"inquiry-vendor-id", &v) != 1)
goto out;
"inquiry-product-id", &p) != 1)
goto out;
"inquiry-revision-id", &r) != 1)
goto out;
goto out;
}
ret = 0;
out:
return (ret);
}
int
{
return (-1);
return (-1);
}
return (0);
}
int
{
return (0);
}
/* Since we are counting from zero, add 1 to capacity */
(*capacity)++;
return (0);
}
err_print("Fetch Capacity failed\n");
return (-1);
}
int
{
char *s;
char *v, *p;
if (option_msg && diag_msg)
err_print("devid_get failed\n");
return (-1);
}
s = (char *)devid;
if (option_msg && diag_msg)
err_print("DKIOCINFO failed\n");
return (-1);
}
return (-1);
v = s+12;
if (!(p = strchr(v, '=')))
return (-1);
p += 1;
return (-1);
}
return (0);
}
/*
* Issue uscsi_inquiry and read_capacity commands to
* retrieve the disk's Vendor, Product, Revision and
* Capacity information.
*/
int
{
return (-1);
}
}
}
}
return (0);
}
int
{
/* This could fail if there is no label already */
return (-1);
}
err_print("vtoc64_to_label failed\n");
return (-1);
}
return (-1);
}
return (0);
}
/*
* We've read a 64-bit label which has no geometry information. Use
* some heuristics to fake up a geometry that would match the disk in
* order to make the rest of format(1M) happy.
*/
static int
{
int i, nparts = 0;
/* XXX do a sanity check here for nparts */
err_print("vtoc64_to_label: unable to allocate lmap\n");
fullabort();
}
/*
* Copy necessary portions
* XXX Maybe we can use memcpy() ??
*/
for (i = 0; i < nparts; i++) {
sizeof (struct uuid));
}
}
return (0);
}
/*
*/
static int
{
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
struct dkl_partition *lmap;
#else
#endif /* defined(_SUNOS_VTOC_8) */
int i;
/*
* Sanity-check the vtoc
*/
return (-1);
}
/*
* Sanity check of geometry
*/
return (-1);
}
/*
* Copy necessary portions of the geometry information
*/
#if defined(_SUNOS_VTOC_16)
#endif /* defined(_SUNOS_VTOC_16) */
#if defined(_SUNOS_VTOC_8)
#endif /* defined(_SUNOS_VTOC_8) */
/*
* Copy vtoc structure fields into the disk label dk_vtoc
*/
for (i = 0; i < V_NUMPAR; i++) {
}
for (i = 0; i < 10; i++)
/*
* Note the conversion from starting sector number
* to starting cylinder number.
* Return error if division results in a remainder.
*
* Note: don't check, if probing virtual disk in Xen
* for that virtual disk will use fabricated # of headers
* and sectors per track which may cause the capacity
* not multiple of # of blocks per cylinder
*/
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
return (-1);
}
}
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
}
/*
* Finally, make a checksum
*/
#ifdef DEBUG
if (option_msg && diag_msg)
#endif
return (0);
}
/*
* Extract a vtoc structure out of a valid label
*/
int
{
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
struct dkl_partition *lpart;
#else
#endif /* defined(_SUNOS_VTOC_8) */
int i;
case 0:
/*
* No valid vtoc information in the label.
* Construct default p_flags and p_tags.
*/
}
break;
case V_VERSION:
#if defined(_SUNOS_VTOC_16)
#endif /* defined(_SUNOS_VTOC_16) */
}
for (i = 0; i < 10; i++)
break;
default:
return (-1);
}
/*
* XXX - this looks wrong to me....
* why are these values hardwired, rather than returned from
* the real disk label?
*/
#if defined(_SUNOS_VTOC_8)
/*
* Convert partitioning information.
* Note the conversion from starting cylinder number
* to starting sector number.
*/
}
#endif /* defined(_SUNOS_VTOC_8) */
return (0);
}
/*
* Input: File descriptor
* Output: 1 if disk has an EFI label, 0 otherwise.
*/
int
{
/* assume the disk has EFI label */
return (1);
}
return (0);
}
/* make sure the user specified something reasonable */
void
{
int i, j;
int overlap = 0;
/*
* make sure no partitions overlap
*/
for (i = 0; i < vtoc->efi_nparts; i++) {
/* It can't be unassigned and have an actual size */
"partition %d is \"unassigned\" but has a size of %llu\n", i,
}
continue;
}
if (resv_part != -1) {
"found duplicate reserved partition at %d\n", i);
}
resv_part = i;
"Warning: reserved partition size must be %d sectors\n",
}
"Partition %d starts at %llu\n",
i,
"It must be between %llu and %llu.\n",
}
vtoc->efi_first_u_lba) ||
"Partition %d ends at %llu\n",
i,
"It must be between %llu and %llu.\n",
}
for (j = 0; j < vtoc->efi_nparts; j++) {
if (!overlap) {
"label error: EFI Labels do not support overlapping partitions\n");
}
"Partition %d overlaps partition %d.\n", i, j);
overlap = 1;
}
}
}
}
/* make sure there is a reserved partition */
if (resv_part == -1) {
"no reserved partition found\n");
}
}
#ifdef DEBUG
static void
{
int i;
fmt_print("volume: ");
for (i = 0; i < LEN_DKL_VVOL; i++) {
break;
}
fmt_print("\n");
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
for (i = 0; i < NDKMAP; i++) {
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
fmt_print(", tag=%d, flag=%d",
fmt_print("\n");
}
fmt_print("bootinfo: ");
for (i = 0; i < 3; i++) {
}
fmt_print("\n");
fmt_print("reserved: ");
for (i = 0; i < 10; i++) {
if ((i % 4) == 3)
fmt_print("\n");
}
fmt_print("\n");
fmt_print("timestamp:\n");
for (i = 0; i < NDKMAP; i++) {
if ((i % 4) == 3)
fmt_print("\n");
}
fmt_print("\n");
fmt_print("pad:\n");
fmt_print("\n\n");
}
#endif /* DEBUG */