195 lines
4.5 KiB
C
195 lines
4.5 KiB
C
|
|
#ifndef lint
|
|
static char sccsid[] = "@(#)label.c 1.1 94/10/31";
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1987 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
/*
|
|
* This file contains the code relating to label manipulation.
|
|
*/
|
|
#include "global.h"
|
|
|
|
/*
|
|
* 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)
|
|
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;
|
|
|
|
/*
|
|
* Fill in a label structure with the geometry information.
|
|
*/
|
|
bzero((char *)&label, sizeof (struct dk_label));
|
|
(void) sprintf(label.dkl_asciilabel, "%s cyl %d alt %d hd %d sec %d",
|
|
cur_dtype->dtype_asciilabel, ncyl, acyl, nhead, nsect);
|
|
label.dkl_pcyl = pcyl;
|
|
label.dkl_ncyl = ncyl;
|
|
label.dkl_acyl = acyl;
|
|
label.dkl_nhead = nhead;
|
|
label.dkl_nsect = nsect;
|
|
label.dkl_apc = apc;
|
|
label.dkl_intrlv = 1;
|
|
label.dkl_rpm = cur_dtype->dtype_rpm;
|
|
/*
|
|
* Also fill in the current partition information.
|
|
*/
|
|
for (i = 0; i < NDKMAP; i++)
|
|
label.dkl_map[i] = cur_parts->pinfo_map[i];
|
|
label.dkl_magic = DKL_MAGIC;
|
|
/*
|
|
* Generate the correct checksum.
|
|
*/
|
|
(void) checksum(&label, CK_MAKESUM);
|
|
/*
|
|
* Lock out interrupts so we don't write half of the copies of the
|
|
* label.
|
|
*/
|
|
enter_critical();
|
|
/*
|
|
* Write and verify the primary label.
|
|
*/
|
|
if ((*cur_ops->rdwr)(DIR_WRITE, cur_file, 0, 1,
|
|
(caddr_t)&label, F_NORMAL) ||
|
|
(*cur_ops->rdwr)(DIR_READ, cur_file, 0, 1,
|
|
(caddr_t)&new_label, F_NORMAL)) {
|
|
eprint("Warning: error writing primary label.\n");
|
|
error = -1;
|
|
}
|
|
|
|
/*
|
|
* Calcualate where the backup labels go. 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;
|
|
/*
|
|
* Write and verify the backup labels.
|
|
*/
|
|
for (sec = 1; sec < BAD_LISTCNT * 2 + 1; sec += 2) {
|
|
if ((*cur_ops->rdwr)(DIR_WRITE, cur_file,
|
|
chs2bn(ncyl + acyl - 1, head, sec), 1,
|
|
(caddr_t)&label, F_NORMAL) ||
|
|
(*cur_ops->rdwr)(DIR_READ, cur_file,
|
|
chs2bn(ncyl + acyl - 1, head, sec), 1,
|
|
(caddr_t)&new_label, F_NORMAL)) {
|
|
eprint("Warning: error writing backup label.\n");
|
|
error = -1;
|
|
}
|
|
}
|
|
/*
|
|
* Mark the current disk as labelled and notify the kernel of what
|
|
* has happened.
|
|
*/
|
|
cur_disk->disk_flags |= DSK_LABEL;
|
|
if (notify_unix())
|
|
error = -1;
|
|
exit_critical();
|
|
return (error);
|
|
}
|
|
|