Files
Arquivotheca.Solaris-2.5/cmd/format/label.c
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

630 lines
15 KiB
C
Executable File

/*
* Copyright (c) 1991 by Sun Microsystems, Inc.
*/
#pragma ident "@(#)label.c 1.16 95/04/07 SMI"
/*
* This file contains the code relating to label manipulation.
*/
#include "global.h"
#include "label.h"
#include "misc.h"
#include "main.h"
#include "partition.h"
#include <string.h>
#include <memory.h>
#include <sys/vtoc.h>
#ifdef i386
#include <sys/dktp/fdisk.h>
#include "menu_fdisk.h"
#endif
extern int read_vtoc(int, struct vtoc *);
extern int write_vtoc(int, struct vtoc *);
/*
* This routine checks the given label to see if it is valid.
*/
int
checklabel(label)
register struct dk_label *label;
{
/*
* Check the magic number.
*/
if (label->dkl_magic != DKL_MAGIC)
return (0);
/*
* Check the checksum.
*/
if (checksum(label, CK_CHECKSUM) != 0)
return (0);
return (1);
}
/*
* This routine checks or calculates the label checksum, depending on
* the mode it is called in.
*/
int
checksum(label, mode)
struct dk_label *label;
int mode;
{
register short *sp, sum = 0;
register short count = (sizeof (struct dk_label)) / (sizeof (short));
/*
* If we are generating a checksum, don't include the checksum
* in the rolling xor.
*/
if (mode == CK_MAKESUM)
count -= 1;
sp = (short *)label;
/*
* Take the xor of all the half-words in the label.
*/
while (count--) {
sum ^= *sp++;
}
/*
* 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 {
label->dkl_cksum = sum;
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
trim_id(id)
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.
*/
for (c = id + strlen(id); c >= id; c--) {
if (strncmp(c, " cyl", strlen(" cyl")) == 0) {
/*
* 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 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
write_label()
{
int error = 0, head, sec, i;
struct dk_label label;
struct dk_label new_label;
struct vtoc vtoc;
struct dk_geom geom;
int nbackups;
/*
* Fill in a label structure with the geometry information.
*/
(void) memset((char *)&label, 0, sizeof (struct dk_label));
(void) memset((char *)&new_label, 0, sizeof (struct dk_label));
label.dkl_pcyl = pcyl;
label.dkl_ncyl = ncyl;
label.dkl_acyl = acyl;
#ifdef i386
label.dkl_bcyl = bcyl;
#endif
label.dkl_nhead = nhead;
label.dkl_nsect = nsect;
label.dkl_apc = apc;
label.dkl_intrlv = 1;
label.dkl_rpm = cur_dtype->dtype_rpm;
#ifdef sparc
/*
* Also fill in the current partition information.
*/
for (i = 0; i < NDKMAP; i++) {
label.dkl_map[i] = cur_parts->pinfo_map[i];
}
#endif
label.dkl_magic = DKL_MAGIC;
/*
* Fill in the vtoc information
*/
label.dkl_vtoc = cur_parts->vtoc;
/*
* Use the current label
*/
bcopy(cur_disk->v_volume, label.dkl_vtoc.v_volume, LEN_DKL_VVOL);
/*
* Put asciilabel in; on x86 it's in the vtoc, not the label.
*/
(void) sprintf(label.dkl_asciilabel, "%s cyl %d alt %d hd %d sec %d",
cur_dtype->dtype_asciilabel, ncyl, acyl, nhead, nsect);
#ifdef i386
/*
* Also add in v_sectorsz, as the driver will. Everyone
* else is assuming DEV_BSIZE, so we do the same.
*/
label.dkl_vtoc.v_sectorsz = DEV_BSIZE;
#endif
/*
* Generate the correct checksum.
*/
(void) checksum(&label, CK_MAKESUM);
/*
* Convert the label into a vtoc
*/
if (label_to_vtoc(&vtoc, &label) == -1) {
return (-1);
}
/*
* Fill in the geometry info. This is critical that
* we do this before writing the vtoc.
*/
bzero((caddr_t)&geom, sizeof (struct dk_geom));
geom.dkg_ncyl = ncyl;
geom.dkg_acyl = acyl;
#ifdef i386
geom.dkg_bcyl = bcyl;
#endif
geom.dkg_nhead = nhead;
geom.dkg_nsect = nsect;
geom.dkg_intrlv = 1;
geom.dkg_apc = apc;
geom.dkg_rpm = cur_dtype->dtype_rpm;
geom.dkg_pcyl = pcyl;
/*
* Lock out interrupts so we do things in sync.
*/
enter_critical();
/*
* Do the ioctl to tell the kernel the geometry.
*/
if (ioctl(cur_file, DKIOCSGEOM, &geom) == -1) {
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.
*/
if (write_vtoc(cur_file, &vtoc) != 0) {
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.
*/
if (cur_ctype->ctype_flags & CF_BLABEL)
head = 2;
else
head = nhead - 1;
/*
* Read and verify the backup labels.
*/
nbackups = 0;
for (sec = 1; sec < BAD_LISTCNT * 2 + 1; sec += 2) {
if ((*cur_ops->op_rdwr)(DIR_READ, cur_file,
((chs2bn(ncyl + acyl - 1, head, sec)) + solaris_offset),
1, (caddr_t)&new_label, F_NORMAL)) {
err_print("Warning: error reading backup label.\n");
error = -1;
} else {
if (bcmp((char *)&label, (char *)&new_label,
sizeof (struct dk_label)) == 0) {
nbackups++;
}
}
}
if (nbackups != BAD_LISTCNT) {
err_print("Warning: %s\n", nbackups == 0 ?
"no backup labels" :
"some backup labels incorrect");
}
/*
* Mark the current disk as labelled and notify the kernel of what
* has happened.
*/
cur_disk->disk_flags |= DSK_LABEL;
#ifdef sparc
if (notify_unix())
error = -1;
#endif
exit_critical();
return (error);
}
/*
* Read the label from the disk.
* Do this via the read_vtoc() library routine,
* then convert it to a label. We also need
* a DKIOCGGEOM ioctl to get the disk's geometry.
*/
int
read_label(int fd, struct dk_label *label)
{
struct vtoc vtoc;
struct dk_geom geom;
if (read_vtoc(fd, &vtoc) < 0 ||
ioctl(fd, DKIOCGGEOM, &geom) == -1) {
return (-1);
}
return (vtoc_to_label(label, &vtoc, &geom));
}
/*
* Convert vtoc/geom to label.
*/
int
vtoc_to_label(struct dk_label *label, struct vtoc *vtoc,
struct dk_geom *geom)
{
#ifdef sparc
struct dk_map *lmap;
#elif defined(i386)
struct dkl_partition *lmap;
#else
#error No Platform defined.
#endif
struct partition *vpart;
long nblks;
int i;
(void) memset((char *)label, 0, sizeof (struct dk_label));
/*
* Sanity-check the vtoc
*/
if (vtoc->v_sanity != VTOC_SANE || vtoc->v_sectorsz != DEV_BSIZE ||
vtoc->v_nparts != V_NUMPAR) {
return (-1);
}
/*
* Sanity check of geometry
*/
if (geom->dkg_ncyl == 0 || geom->dkg_nhead == 0 ||
geom->dkg_nsect == 0) {
return (-1);
}
label->dkl_magic = DKL_MAGIC;
/*
* Copy necessary portions of the geometry information
*/
label->dkl_rpm = geom->dkg_rpm;
label->dkl_pcyl = geom->dkg_pcyl;
label->dkl_apc = geom->dkg_apc;
label->dkl_intrlv = geom->dkg_intrlv;
label->dkl_ncyl = geom->dkg_ncyl;
label->dkl_acyl = geom->dkg_acyl;
#ifdef i386
label->dkl_bcyl = geom->dkg_bcyl;
#endif
label->dkl_nhead = geom->dkg_nhead;
label->dkl_nsect = geom->dkg_nsect;
#ifdef sparc
label->dkl_obs1 = geom->dkg_obs1;
label->dkl_obs2 = geom->dkg_obs2;
label->dkl_obs3 = geom->dkg_obs3;
#endif
label->dkl_write_reinstruct = geom->dkg_write_reinstruct;
label->dkl_read_reinstruct = geom->dkg_read_reinstruct;
/*
* Copy vtoc structure fields into the disk label dk_vtoc
*/
label->dkl_vtoc.v_sanity = vtoc->v_sanity;
label->dkl_vtoc.v_nparts = vtoc->v_nparts;
label->dkl_vtoc.v_version = vtoc->v_version;
(void) memcpy(label->dkl_vtoc.v_volume, vtoc->v_volume,
LEN_DKL_VVOL);
for (i = 0; i < V_NUMPAR; i++) {
label->dkl_vtoc.v_part[i].p_tag = vtoc->v_part[i].p_tag;
label->dkl_vtoc.v_part[i].p_flag = vtoc->v_part[i].p_flag;
}
(void) memcpy((char *)label->dkl_vtoc.v_bootinfo,
(char *)vtoc->v_bootinfo, sizeof (vtoc->v_bootinfo));
(void) memcpy((char *)label->dkl_vtoc.v_reserved,
(char *)vtoc->v_reserved, sizeof (vtoc->v_reserved));
(void) memcpy((char *)label->dkl_vtoc.v_timestamp,
(char *)vtoc->timestamp, sizeof (vtoc->timestamp));
(void) memcpy(label->dkl_asciilabel, vtoc->v_asciilabel,
LEN_DKL_ASCII);
/*
* Note the conversion from starting sector number
* to starting cylinder number.
* Return error if division results in a remainder.
*/
#ifdef sparc
lmap = label->dkl_map;
#elif defined(i386)
lmap = label->dkl_vtoc.v_part;
#else
#error No Platfrom defined.
#endif
vpart = vtoc->v_part;
nblks = (int) label->dkl_nsect * (int)label->dkl_nhead;
for (i = 0; i < NDKMAP; i++, lmap++, vpart++) {
if ((vpart->p_start % nblks) != 0 ||
(vpart->p_size % nblks) != 0) {
return (-1);
}
#ifdef sparc
lmap->dkl_cylno = vpart->p_start / nblks;
lmap->dkl_nblk = vpart->p_size;
#elif defined(i386)
lmap->p_start = vpart->p_start;
lmap->p_size = vpart->p_size;
#else
#error No Platform defined.
#endif
}
/*
* Finally, make a checksum
*/
(void) checksum(label, CK_MAKESUM);
return (0);
}
/*
* Extract a vtoc structure out of a valid label
*/
int
label_to_vtoc(struct vtoc *vtoc, struct dk_label *label)
{
#ifdef sparc
struct dk_map2 *lpart;
struct dk_map *lmap;
#elif defined(i386)
struct dkl_partition *lpart;
struct dkl_partition *lmap;
#else
#error No Platform defined.
#endif
struct partition *vpart;
int i;
long nblks;
(void) memset((char *)vtoc, 0, sizeof (struct vtoc));
switch (label->dkl_vtoc.v_version) {
case 0:
/*
* No valid vtoc information in the label.
* Construct default p_flags and p_tags.
*/
vpart = vtoc->v_part;
for (i = 0; i < V_NUMPAR; i++, vpart++) {
vpart->p_tag = default_vtoc_map[i].p_tag;
vpart->p_flag = default_vtoc_map[i].p_flag;
}
break;
case V_VERSION:
vpart = vtoc->v_part;
lpart = label->dkl_vtoc.v_part;
for (i = 0; i < V_NUMPAR; i++, vpart++, lpart++) {
vpart->p_tag = lpart->p_tag;
vpart->p_flag = lpart->p_flag;
#ifdef i386
vpart->p_start = lpart->p_start;
vpart->p_size = lpart->p_size;
#endif
}
(void) memcpy(vtoc->v_volume, label->dkl_vtoc.v_volume,
LEN_DKL_VVOL);
(void) memcpy((char *)vtoc->v_bootinfo,
(char *)label->dkl_vtoc.v_bootinfo,
sizeof (vtoc->v_bootinfo));
(void) memcpy((char *)vtoc->v_reserved,
(char *)label->dkl_vtoc.v_reserved,
sizeof (vtoc->v_reserved));
(void) memcpy((char *)vtoc->timestamp,
(char *)label->dkl_vtoc.v_timestamp,
sizeof (vtoc->timestamp));
break;
default:
return (-1);
}
vtoc->v_sanity = VTOC_SANE;
vtoc->v_version = V_VERSION;
vtoc->v_sectorsz = DEV_BSIZE;
vtoc->v_nparts = V_NUMPAR;
(void) memcpy(vtoc->v_asciilabel, label->dkl_asciilabel,
LEN_DKL_ASCII);
#ifdef sparc
/*
* Convert partitioning information.
* Note the conversion from starting cylinder number
* to starting sector number.
*/
lmap = label->dkl_map;
vpart = vtoc->v_part;
nblks = label->dkl_nsect * label->dkl_nhead;
for (i = 0; i < V_NUMPAR; i++, vpart++, lmap++) {
vpart->p_start = lmap->dkl_cylno * nblks;
vpart->p_size = lmap->dkl_nblk;
}
#endif
return (0);
}
#ifdef FOR_DEBUGGING_ONLY
int
dump_label(label)
struct dk_label *label;
{
int i;
fmt_print("%s\n", label->dkl_asciilabel);
fmt_print("version: %d\n", label->dkl_vtoc.v_version);
fmt_print("volume: ");
for (i = 0; i < LEN_DKL_VVOL; i++) {
if (label->dkl_vtoc.v_volume[i] == 0)
break;
fmt_print("%c", label->dkl_vtoc.v_volume[i]);
}
fmt_print("\n");
fmt_print("v_nparts: %d\n", label->dkl_vtoc.v_nparts);
fmt_print("v_sanity: %lx\n", label->dkl_vtoc.v_sanity);
#ifdef sparc
fmt_print("rpm: %d\n", label->dkl_rpm);
fmt_print("pcyl: %d\n", label->dkl_pcyl);
fmt_print("apc: %d\n", label->dkl_apc);
fmt_print("obs1: %d\n", label->dkl_obs1);
fmt_print("obs2: %d\n", label->dkl_obs2);
fmt_print("intrlv: %d\n", label->dkl_intrlv);
fmt_print("ncyl: %d\n", label->dkl_ncyl);
fmt_print("acyl: %d\n", label->dkl_acyl);
fmt_print("nhead: %d\n", label->dkl_nhead);
fmt_print("nsect: %d\n", label->dkl_nsect);
fmt_print("obs3: %d\n", label->dkl_obs3);
fmt_print("obs4: %d\n", label->dkl_obs4);
#elif defined(i386)
fmt_print("rpm: %d\n", label->dkl_rpm);
fmt_print("pcyl: %d\n", label->dkl_pcyl);
fmt_print("apc: %d\n", label->dkl_apc);
fmt_print("intrlv: %d\n", label->dkl_intrlv);
fmt_print("ncyl: %d\n", label->dkl_ncyl);
fmt_print("acyl: %d\n", label->dkl_acyl);
fmt_print("nhead: %d\n", label->dkl_nhead);
fmt_print("nsect: %d\n", label->dkl_nsect);
fmt_print("bcyl: %d\n", label->dkl_bcyl);
fmt_print("skew: %d\n", label->dkl_skew);
#else
#error No Platform defined.
#endif
fmt_print("magic: %0x\n", label->dkl_magic);
fmt_print("cksum: %0x\n", label->dkl_cksum);
for (i = 0; i < NDKMAP; i++) {
#ifdef sparc
fmt_print("%c: cyl=%d, blocks=%d", i+'a',
label->dkl_map[i].dkl_cylno,
label->dkl_map[i].dkl_nblk);
#elif defined(i386)
fmt_print("%c: start=%d, blocks=%d", i+'a',
label->dkl_vtoc.v_part[i].p_start,
label->dkl_vtoc.v_part[i].p_size);
#else
#error No Platform defined.
#endif
fmt_print(", tag=%d, flag=%d",
label->dkl_vtoc.v_part[i].p_tag,
label->dkl_vtoc.v_part[i].p_flag);
fmt_print("\n");
}
fmt_print("read_reinstruct: %d\n", label->dkl_read_reinstruct);
fmt_print("write_reinstruct: %d\n", label->dkl_write_reinstruct);
fmt_print("bootinfo: ");
for (i = 0; i < 3; i++) {
fmt_print("0x%x ", label->dkl_vtoc.v_bootinfo[i]);
}
fmt_print("\n");
fmt_print("reserved: ");
for (i = 0; i < 10; i++) {
if ((i % 4) == 3)
fmt_print("\n");
fmt_print("0x%x ", label->dkl_vtoc.v_reserved[i]);
}
fmt_print("\n");
fmt_print("timestamp:\n");
for (i = 0; i < NDKMAP; i++) {
if ((i % 4) == 3)
fmt_print("\n");
fmt_print("0x%x ", label->dkl_vtoc.v_timestamp[i]);
}
fmt_print("\n");
fmt_print("pad:\n");
dump("", label->dkl_pad, LEN_DKL_PAD, HEX_ONLY);
fmt_print("\n\n");
}
#endif FOR_DEBUGGING_ONLY