2021-10-11 18:37:13 -03:00

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);
}